v0.86 sources and binaries (earliest available on website)

This commit is contained in:
Mark Aufflick 2011-10-18 14:49:35 +11:00
commit cf770f0a3d
92 changed files with 41037 additions and 0 deletions

410
CHANGES Normal file
View File

@ -0,0 +1,410 @@
Changes in KEGS v0.86 since v0.85 (03/23/04)
- Add patch for Solaris sound by Jonathan Kalbfeld.
- Fix so that F4 enters config panel even while running Prosel-16
- Major mouse pointer changes, based on some ideas from Geoff Weiss.
The GSOS mouse now exactly tracks the host pointer automatically.
- Fixed an accidental debug halt when Prosel-16 disables the keyboard/mouse.
Changes in KEGS v0.85 since v0.84 (01/09/04)
- Fix some minor 65816 bank-crossing bugs.
- Add -noignhalt to allow user to stop on code red halts.
- Fix Win32 capslock problem as reported by Edward Moore
- Fixed DreamVoir app on the sample image (it was corrupt)
Changes in KEGS v0.84 since v0.83 (11/21/03)
- Add new speed, 8.0MHz directly using right-clicking or F6.
- Sim speed and Video update interval added to Config panel.
- Various cycle timing bugs in engine_c.c fixed.
- Add Config Panel entry to mask serial output to 7-bit, to enable PR#2 to
work better with an external telnet.
- In Config Panel file selection, typing a letter jumps to the first file
beginning with that letter.
- Fixed various serial socket bugs. Now you can disconnect a telnet session
and start a new one, and a Linux hang is fixed.
- Default GS memory size increased to 8MB.
- Small fix to double-hires color table.
- X windows can now send displays to other-endian X servers.
Changes in KEGS v0.83 since v0.82 (11/19/03)
- Add Memory Size to config panel, with support for up to 14MB of memory
(Geoff Weiss)
- Add $C04F EMUBYTE support which Bernie II the Rescue defined. (Geoff Weiss)
- Fix $CFFF code red's reported by David Wilson.
- Add smartport $C70A Format routine (David Wilson).
Changes in KEGS v0.82 since v0.81 (11/06/03)
- Fix superhires display glitch introduced in v0.81.
- Improved border handling--XMAS demo looks great.
- Fix some X build problems introduced in v0.81.
Changes in KEGS v0.81 since v0.80 (11/04/03)
- Code Red/Yellow warnings about emulation stability
- Windows file browsing fixes
- Built-in C600 ROM for Apple II 5.25" game compatibility
- Turns key repeat back on when exiting from X-windows version
- Windows F8 captures the cursor
Changes in KEGS v0.80 since v0.71 (10/31/03)
- Configuration Panel means no more hand-editing configuration files
- All emulator state is now saved in "config.kegs"
- 3200 color pictures! Video system much improved for display accuracy.
- F8 Pointer grabbing works on Mac
- ZipGS emulation
Changes in KEGS v0.71 since v0.70 (11/20/02)
- Improved double-hires colors a lot. -dhr140 is no longer the default
- Airheart relies on the PC going from 0xffff to 0x0000, so I undid the
change from KEGS v0.54 which allowed PC to overflow to 0x10000.
This slows KEGS down by about 5%.
- Fixed X shared memory bug in KEGS v0.70 with fix from Jonathan Stark.
Changes in KEGS v0.70 since v0.60 (11/18/02)
- New buttons: Middle button is enter-debugger, and right button changes speed
- New function key mapping (see README.kegs)
- Mac OS X port
- Win32 port
- Centralized much of what had been "xdriver.c" code into video.c, to move
true platform-specific stuff into the various *driver.c codes.
Kimage struct tracks video display buffers in a dev-independent way.
From video.c, the calls to the platform code start with "x_" mostly.
Code in video.c cleaned up somewhat.
Borders are now always in native buffer format, while text/hires/
and superhires are in 8-bit buffers and translated to native later.
- Mac and Windows sound are all done in one process--no child sound process.
- Revamped key press handling and mouse clicks--all is now handled in
adb.c for a consistent user interface. Now KEGS implements the
same function keys on all platforms. See README.kegs for fn key maps.
- I copied the debugger help from Frederic Devernay's KEGS-SDL port.
- Fixed an old IWM bug causing bad nibblization due to using uninit vars.
- Gilles Tschopp workaround to use corrupted 2IMG files (from KEGS-OSX).
- Gilles Tschopp provided code to zero //gs memory at startup (from KEGS-OSX)
- Simple code to try to use Mac Diskcopy format disks
- Ignore writes to 0xc0a8
- Search in $HOME and the launch directory (for mac) for kegs_conf/ROM
- Remove font65.sim file by integrating it into kegsfont.h.
- "-bw" option forces black and white hires mode.
Changes in KEGS v0.60 since v0.59 (10/03/00)
- The 16-bit colors were still wrong due to another coding error. It would
be much easier to get this right if I had a 16-bit color display...
A user says it works now.
Changes in KEGS v0.59 since v0.58 (7/07/00)
- Added support for multiple paths to the default files and also multiple
names for many default files. This should make the .rpm distribution
work better.
- Add another keycode to mean break according to mic@research.nj.nec.com.
- Add support for various ROMs to get plugged into slot 1-7.
- Fix code so that it should compile on 64-bit platforms.
Changes in KEGS v0.58 since v0.57 (2/08/00)
- Setting the execute bit on the disk image no longer means no-write-thru.
Too many new users were getting confused by this.
- Fixed another bug with Apple //e bank switching created by v0.56
Reported by phoenyx.
- Add command line option "-v" to turn on some verbose debugging flags.
- Fixed potential core-dump bug with non-8 bit visuals.
- Fixed double-lo-res color problem.
- The X driver should work with any visual depth display now and get the
colors right. Ian Schmidt reported his 16-bit card had bad colors.
Changes in KEGS v0.57 since v0.56 (12/27/99)
- Another try at making timezone stuff work across all Unix variants.
Let me know if the time in the Apple //gs control panel doesn't
match your real local time.
- Fix a bug created in v0.56 where the fast //e bank switch code had a typo.
This prevented ZBasic from working correctly.
Changes in KEGS v0.56 since v0.55 (10/31/99)
- Faster Apple //e bank switch emulation.
- Simplified number of global variables for various softswitches.
- Fixed a bug which made 3.5" and 5.25" disk access much slower than necessary.
- Improved scan-line interrupt accuracy (lets MEGADEMO run).
- Improved sound interrupt accuracy (was hoping this would fix some sound
issues, but it doesn't seem to help).
- Add Mode_switch as an alias for the Option key
- I noticed the //gs self-tests were broken again--fixed.
Changes in KEGS v0.55 since v0.54 (10/19/99)
- In LOG_PC debug aid, add cycles to the trace
- Fix MEGADEMO bug where 3.5" disks weren't properly ejected. Needed to
look at iwm.motor_on35 not iwm.motor_on.
- Temp fix for MEGADEMO to not halt if shadow-in-all-banks is on in $c036.
- Another MEGADEMO fix to not take a scan-line int if the SCB was cleared
right before the raster got to this line.
- Fix bug in smartport.c that was causing core dumps if you tried to init
a disk is s7dx.
Changes in KEGS v0.54 since v0.53 (10/10/99)
- Add support for Out Of This World's direct reading of ADB RAM loc 0xb to
get key status. This lets shift/control work in OOTW.
- Code simplification to get rid of most set_halt() calls and use halt_printf.
- Speed improvement: track kpc (merged kbank and pc in one 32 bit variable)
which makes the inner loop faster. This does make KEGS not
accurately model a 65816 code crossing bank boundaries, but just
about every other emulator gets it wrong, and the speed improvement
is 5-10%. And I don't know of any code which relies on it
working correctly.
- Fix to allow better GS/OS compatibility: after each smartport call,
set 0x7f8 = 0xc7.
- Fixed ZipGS emulation bug where KEGS was not re-locking Zip at the right
time, which made double-hires not work after booting GS/OS.
Changes in KEGS v0.53 since v0.52 (8/3/99)
- Move all the "fcycles" timing calculations to use double instead of float.
- Fix display shadowing bug reported by "phoenyx" which caused the text
display to not always be updated correctly with funny bank switching.
- Added the "Home" key as an alias for the '=' on the keypad.
- Changed the way X modifiers are interpreted to increase compatibility of
Caps Lock to more X servers.
- Add -dhr140 option to use old double-hires color mode that results in
exactly 140 horizontal pixels with no bleeding. It's set default
to "on" for now while I work out double-hires colors.
- Started adding some ZipGS compatibility--control panels run, but all
the controls are effectively ignored by KEGS.
Changes in KEGS v0.52 since v0.51 (6/27/99)
- Small speed-up of interpreter loop to avoid checking the global variable
"halt_sim" after every instruction.
- Smartport fixes to avoid halts when the SCSI CD player NDA is installed.
- Fix to autodetect X visual depth (it didn't work at all in v0.51).
- Fix to HP binary--KEGS v0.51 hit an HP linker bug which caused the
executable to not run correctly. (It didn't obey an assembly-
language alignment command correctly). Re-ordering the object
list works around the problem.
Changes in KEGS v0.51 since v0.50 (6/1/99)
- Fixed many bugs that crept into scanline interrupts over the last few months.
- RAM size is now settable on the commandline: -mem 0x400000 will use
a 4MB expansion RAM card (giving you 4.25MB of memory with ROM 01).
- VBL time used to be a variable (which was wrong)--it's now always the
same number of cycles.
- Typo preventing joystick_driver.c from compiling fixed.
- Auto senses X visual depth, searching for 8 bit, then 15 bit, then 24,
then 16 bit visuals. Can still override this with commandline.
Changes in KEGS v0.50 since v0.49 (5/31/99)
- Added Linux joystick support with code provided by Jonathan Stark.
Activate with "-joystick" command line option.
- Small improvements in s7 device handling. If you have no s7 devices or no
bootable devices, KEGS launches Applesoft.
- Bug fix in scan-line interrupts--they were occurring at the wrong time
previously.
- Rewrote double-hires color routines. They're still not quite right,
but it's a lot better than it used to be.
Changes in KEGS v0.49 since v0.48 (5/3/99)
- Fixed a key-repeat bug in v0.48 caused usually with shift-key sequences.
- Fixed bug where GNO would not work with ROM 03. ROM area at $C071-$C07F
is different from ROM 01.
- Ian Schmidt pointed out a special Ensoniq case where an oscillator in
one-shot mode can cause it's partner to start if it is in swap mode.
- Integrated in Geoff Weiss's Solaris x86 ports. I might have broken it
making a few last-minute changes...
Changes in KEGS v0.48 since v0.47 (4/13/99)
- Even better ADB key repeat--key rollover works more like a real Apple //gs.
- IWM fix: some "smarport" modes were being activated sometimes during
normal 3.5" accesses, resulting in some games not loading correctly.
- Some fixes to serial port emulation to handle programs writing to
the serial port in MIDI mode when the chars will not be consumed.
- Smartport fix to set zero-page locations $42-$47, needed by some poorly-
written game loaders
- The "oscilloscope" effect in some sound-demos now shows the sounds
being played.
Changes in KEGS v0.47 since v0.46 (4/7/99)
- ADB fix #1: reading $c010 should give key-down status better
- ADB fix #2: key repeat was stopping if modifier key pressed
- ADB fix #3: The game "Pirates" was crashing on startup due to a small bug.
- Bard's Tale 2 was freezing on startup due to a bug in the WAI instruction.
- Major serial port rewrite. Diversi-Tune now runs and sound OK (but there
are some small problems) and serial port emulation is better.
Changes in KEGS v0.46 since v0.45 (3/21/99)
- Fix for undefined var in engine_c.c. Oops.
- Fix for old bug in engine_c.c causing KEGS to sometimes misinterpret
instructions which cross page boundaries. Was causing Thexder not
to work, at least.
Changes in KEGS v0.45 since v0.44 (3/20/99)
- Fix for COP instruction in engine_c.c. Pointed out by Kelvin Sherlock.
- Major fixes to Ensoniq emulation, SynthLab sounds much better.
- Fix to iwm.c to deal with corrupt 2IMG archives a little better.
Changes in KEGS v0.44 since v0.43 (2/23/99)
- -audio 0 option would often cause programs to hang. Bug was that the
audio rate was defaulting to '0' which confused KEGS.
- Made keycode 0x072 be the XK_Break key for XFree86
Changes in KEGS v0.43 since v0.42 (2/19/99)
- Support .nib 5.25" format as read-only
- Faster 3.5" nibblization routines (should make startup faster)
- Fixed a very-old 3.5" disk writing bug that made bit-copiers not work
Changes in KEGS v0.42 since v0.41 (2/1/99)
- Include <errno.h> to fix Linux compile problem
- Fix relative branch timing bug that was making IWM emulation flaky
(backward branches should count as 3 cycles if to the same page,
and 4 if to a different page in emulation mode. Bug always counted
them as 4)
- Gave up on fast 5.25" writes--KEGS always slows to 1MHz for 5.25"
writes since the timing and kludges just got too annoying.
- add "-arate 22050" option to change audio sample rate on the command-line.
Slower audio rates can hit more audio bugs (I'm working on them).
- fixed little-endian bug in smartport.c and partls.c
- fixed side border redraw bug that would sometimes leave super-hires
images on the right-side border.
Changes in KEGS v0.41 since v0.40 (1/19/99)
- Fixed bug where fill-line mode would not always redraw the screen correctly
- Changed some // comments to /* */ to help David Wilson's Solaris port
- Fixed little-endian bugs in smartport.c preventing mounting of
parititioned disks. Fix submitted by Jonathan Stark.
- Christopher Neufeld noted that fast space/delete option in the control
panel caused KEGS to hit breakpoints. I fixed this and fast arrows and
fast mouse options (they are now just ignored).
- Solaris port by David Wilson now provides a Makefile_solaris
Changes in KEGS v0.40 since v0.39 (10/25/98)
- 15 and 24 bit depth displays now supported (though somewhat slower than
8 bit displays). But Super-hires displays now show 256
simultaneous colors on a 16- or 24-bit X display.
Select a 15-bit display with the cmd line option "-15" and
a 24-bit display with "-24". Otherwise, KEGS defaults to looking
for an 8-bit display, and fails if it cannot find one.
- Some border fixes--border colors now update correctly when palette
changes occur (like via F10).
- Alias F1 to ESC for OS/2.
Changes in KEGS v0.39 since v0.38 (9/13/98)
- OS/2 port by Tschopp Gilles
- handle cr&lf better in disk_conf
- Drive letters work and are not confused with partition names, so
s7d1 = D:\images\cd:1 will open partition 1 correctly.
- KEGS no longer uses system() to do file copies, it does it all
using POSIX calls.
- Unix-specific socket calls moved from scc.c to scc_driver.h
- Default X handler re-installed properly now for better debug
- Nasty core dump bug found and fixed by Tschopp Gilles in disk switch code
Changes in KEGS v0.38 since v0.37 (7/28/98)
- IWM bugs:
- fast_disk_emul off under GS/OS caused I/O errors.
KEGS was always slowing down to 1MHz when 5.25" drive was on, when
it should have been obeying the $C036 register.
- bug in IWM on little-endian processors
- disk ejection should now work, but a beta user claimed some bugs on
x86 Linux.
- 2IMG support, but only lightly tested.
- Removed some internal breaks on access to $C0B0 for tool033.
- Modulae also stumbled into some breakpoints by writing to $C02F,
which does nothing.
- Screen refresh simplified (for me) by redrawing the screen while
raster is on first scan-line, rather than line 200.
However, a side effect is some of the graphics during the XMAS DEMO
look a bit choppier.
- More SCC fixes to avoid breakpoints under GNO.
- Start support for sound under Linux, but it sounds horrible right now.
Any Linux sound gurus want to help out?
- Fixed possible array-overrun bug in video.c around border effects.
Maybe shared memory works under x86 Linux now?
- Made changes for OS/2 port to fopen() text files. From Blue Neon.
Changes in KEGS v0.37 since v0.36 (7/13/98)
- Linux PPC port completed and functional. KEGS has been tested to
run quite well and quite fast on a 240MHz 604e running
MkLinux pre-DR3.
- Change LITTLE_ENDIAN define to KEGS_LITTLE_ENDIAN since Linux
always defines LITTLE_ENDIAN as a silly macro.
- Dumb bug in IWM 3.5" routines could cause core dumps if disk arm moved
from outer track to inner track very quickly.
- Deleted some breakpoints that some Second Sight searching code would hit.
- Ignore some SCC reset commands GNO would use that caused KEGS to stop.
- Handle odd partitions better--some //gs formatted Zips had a blocksize
of 0, which defaults to 512 now.
- Handle some keysyms better to avoid MkLinux bug with keysym 0.
Changes in KEGS v0.36 since v0.35 (5/30/98)
- Linux x86 port completed and functional with help from Karl Pfleger
- Linux clock fixes--should handle daylight savings better on Linux
- LITTLE_ENDIAN defines
- Start making fixes for NeXTStep due to Eric Sunshine
- Fixed bug in HP asm code with I/O fetches--caused //gs selftests to fail
and a bug in scc.c was also causing self-tests to fail.
Changes in KEGS v0.35 since v0.34 (5/17/98)
- engine_c.c fully implemented--KEGS now has a version completely written
in C, and now portable to other Unix machines.
- KEGS got another 5% faster with more tweaks to the asm dispatch loop.
Changes in KEGS v0.34 since v0.33
- KEGS is 10-15% faster due to finally implementing a planned recoding
of the dispatch loop.
Changes in KEGS v0.33 since v0.32 (5/7/98)
- Fixed bug in engine_s.s that prevented compiling on pre-10.20 systems.
- ADB mouse interrupts work now. Fixed "bug" where GSHK would think
mouse button was depressed at startup. (GS/OS is looking at mouse
button 1 status, which accidentally was reading as down).
- ADB emulation of read char_sets and read_kbd_layouts now matches a real
//gs.
- optimization to allow dereferencing page_info[] even if BANK_IO is set,
to get a small speed improvement in engines_s:dispatch().
- SCC logs are 'Z' at the disas prompt.
- Tool decoded is 'T' at the disas prompt.
- SCC changes to support slot 1 == port 6501 and slot 2 == port 6502,
with limited interrupt support. Most serial tasks won't work still,
but some do. PR#1/2 and IN#1/2 work fine. getty under GNO doesn't.
- -audio [0/1] forces audio off/on. This just stops the sound playing--
internally all Ensoniq interrupts/etc are fully emulated. If display
is not using shared memory (i.e., it's remote), audio defaults to off.
(but can be forced on with -audio 1).
- -display {foo} sends X display to {foo}.
Changes in KEGS v0.32 since v0.31 (10/23/97)
- Faster dispatch loop, for a 10-15% overall performance improvement
- Fixed sound bug where Oversampler would make KEGS halt (Oversampler
said turn on 128 oscillators, and KEGS tried to...)
- Fixed bug where KEGS would not work on 24-bit displays due to a typo.
- Added frame skipping support (-skip n) and auto frame skipping if you
are not using shared memory (like displaying KEGS to a remote machine).
- Added -noshm support for forcing off shared memory, so you can see how
much it helps.
Changes in KEGS v0.31 since v0.30 (9/23/97)
- New mouse handling--Press F8 to hide X windows cursor and constrain
cursor inside window. Makes using the mouse much easier.
F8 toggles back to normal.
- Add revision to status area.
- Remove "slow memory" calculation. KEGS was emulating slowing down to
1MHz to write to slow memory (bank $E0 or $E1). But true //gs
accelerators have a smarter trick, so I just removed it from
KEGS. KEGS still slows down for I/O reads and writes.
This eliminates the confusing 40MHz speed numbers you'd sometimes get.
KEGS can also now run faster when it would have slowed down to
1MHz before.
- Turn off accurate IWM emulation be default, for much faster emulation.
Bit copiers won't work by default now. Toggle accurate IWM
with F7. Accurate IWM forces 1MHz speed for 5.25" and 2.5MHz for
3.5", but less accurate IWM runs as fast as possible.
- Add optional size to s7dx entries in disk_conf, to allow using /dev/rfloppy.
- Allow mounting partitions by number, instead of just by name, since some
Mac-formatted Zip disks don't have partition names.
- Add -ignbadacc to ignore bad memory accesses.
- Increase MAX_C030_TIMES. Otherwise, fast workstations could generate too
many clicks per VBL, causing an assertion to fail.
- Small speed increase detecting changes in the superhires screen.
- Alt_L is now Open-Apple, and Alt_R is Closed-Apple.
- KEGS now uses just one private colormap, so xwd can get screendumps.

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>KEGSMAC</string>
<key>CFBundleIconFile</key>
<string>kegsicon.icns</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1 @@
APPL????

View File

@ -0,0 +1,4 @@
{
IBClasses = ();
IBVersion = 1;
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>152 85 356 240 0 0 1280 832 </string>
<key>IBEditorPositions</key>
<dict>
<key>29</key>
<string>69 252 182 44 0 0 1280 832 </string>
</dict>
<key>IBFramework Version</key>
<string>291.0</string>
<key>IBSystem Version</key>
<string>6R73</string>
<key>targetFramework</key>
<string>IBCarbonFramework</string>
</dict>
</plist>

View File

@ -0,0 +1,169 @@
<?xml version="1.0" standalone="yes"?>
<object class="NSIBObjectData">
<string name="targetFramework">IBCarbonFramework</string>
<object name="rootObject" class="NSCustomObject" id="1">
<string name="customClass">NSApplication</string>
</object>
<array count="18" name="allObjects">
<object class="IBCarbonMenu" id="29">
<string name="title">main</string>
<array count="3" name="items">
<object class="IBCarbonMenuItem" id="185">
<string name="title">KEGSMAC</string>
<object name="submenu" class="IBCarbonMenu" id="184">
<string name="title">KEGSMAC</string>
<array count="3" name="items">
<object class="IBCarbonMenuItem" id="187">
<string name="title">About KEGSMAC</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">abou</ostype>
</object>
<object class="IBCarbonMenuItem" id="199">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem" id="198">
<string name="title">Quit</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">quit</ostype>
</object>
</array>
<string name="name">_NSAppleMenu</string>
</object>
</object>
<object class="IBCarbonMenuItem" id="127">
<string name="title">File</string>
<object name="submenu" class="IBCarbonMenu" id="131">
<string name="title">File</string>
<array count="1" name="items">
<object class="IBCarbonMenuItem" id="200">
<string name="title">Configuration F4</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">KCFG</ostype>
<string name="helpTagText">Enter KEGS Configuration Panel</string>
</object>
</array>
</object>
</object>
<object class="IBCarbonMenuItem" id="192">
<string name="title">Window</string>
<object name="submenu" class="IBCarbonMenu" id="195">
<string name="title">Window</string>
<array count="6" name="items">
<object class="IBCarbonMenuItem" id="197">
<string name="title">Zoom Window</string>
<ostype name="command">zoom</ostype>
</object>
<object class="IBCarbonMenuItem" id="190">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize Window</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">mini</ostype>
</object>
<object class="IBCarbonMenuItem" id="191">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize All Windows</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">mina</ostype>
</object>
<object class="IBCarbonMenuItem" id="194">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem" id="196">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Bring All to Front</string>
<ostype name="command">bfrt</ostype>
</object>
<object class="IBCarbonMenuItem" id="193">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Arrange in Front</string>
<int name="keyEquivalentModifier">1572864</int>
<ostype name="command">frnt</ostype>
</object>
</array>
<string name="name">_NSWindowsMenu</string>
</object>
</object>
</array>
<string name="name">_NSMainMenu</string>
</object>
<reference idRef="127"/>
<reference idRef="131"/>
<object class="IBCarbonMenuItem" id="153">
<string name="title">Window</string>
<object name="submenu" class="IBCarbonMenu">
<string name="title">Window</string>
<array count="5" name="items">
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize Window</string>
<string name="keyEquivalent">m</string>
<ostype name="command">mini</ostype>
</object>
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize All Windows</string>
<string name="keyEquivalent">m</string>
<int name="keyEquivalentModifier">1572864</int>
<ostype name="command">mini</ostype>
</object>
<object class="IBCarbonMenuItem">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Bring All to Front</string>
<ostype name="command">frnt</ostype>
</object>
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Bring in Front</string>
<int name="keyEquivalentModifier">1572864</int>
<ostype name="command">frnt</ostype>
</object>
</array>
<string name="name">_NSWindowsMenu</string>
</object>
</object>
<reference idRef="184"/>
<reference idRef="185"/>
<reference idRef="187"/>
<reference idRef="190"/>
<reference idRef="191"/>
<reference idRef="192"/>
<reference idRef="193"/>
<reference idRef="194"/>
<reference idRef="195"/>
<reference idRef="196"/>
<reference idRef="197"/>
<reference idRef="198"/>
<reference idRef="199"/>
<reference idRef="200"/>
</array>
<array count="18" name="allParents">
<reference idRef="1"/>
<reference idRef="29"/>
<reference idRef="127"/>
<reference idRef="29"/>
<reference idRef="185"/>
<reference idRef="29"/>
<reference idRef="184"/>
<reference idRef="195"/>
<reference idRef="195"/>
<reference idRef="29"/>
<reference idRef="195"/>
<reference idRef="195"/>
<reference idRef="192"/>
<reference idRef="195"/>
<reference idRef="195"/>
<reference idRef="184"/>
<reference idRef="184"/>
<reference idRef="131"/>
</array>
<dictionary count="2" name="nameTable">
<string>Files Owner</string>
<reference idRef="1"/>
<string>MenuBar</string>
<reference idRef="29"/>
</dictionary>
<unsigned_int name="nextObjectID">201</unsigned_int>
</object>

Binary file not shown.

0
KEGSMAC.app/Icon? Normal file
View File

113
README.compile Normal file
View File

@ -0,0 +1,113 @@
NOTE: The build process changed as of KEGS v0.70!
General build instructions:
--------------------------
You need to build with a make utility. I've only tested GNU make.
There's a default Makefile, which should work for nearly any environment.
The Makefile includes a file called "vars" which defines the platform-
dependent variables. You need to make vars point to the appropriate
file for your machine.
This makes my maintenance of the diverse platforms a bit easier.
WIN32 build instructions:
------------------------
See the file README.win32 for build instructions and other information
for Microsoft Windows.
Mac OS X build instructions (the default):
------------------------------------------
KEGS is easy to compile. Just cd to the src directory and type "make".
KEGS requires perl to be in your path (or just edit the vars file to give
the full path to wherever you installed perl). Perl version 4 or 5 is
fine.
After the "make" has finished, it will create the application KEGSMAC.
To run, see README.mac.
X86 Linux build instructions:
----------------------------
Use the vars_x86linux file with:
rm vars; ln -s vars_x86linux vars
make
KEGS assumes perl is in your path. If it is somewhere else, you need to edit
the "PERL = perl" line in the vars file and make it point to the correct place.
For audio, KEGS needs access to /dev/dsp. If the permissions do not allow
KEGS to access /dev/dsp, it can fail with a cryptic error message. As root,
just do: "chmod 666 /dev/dsp".
PowerPC Linux build instructions:
----------------------------
Use the vars_linuxppc vars file by:
rm vars; ln -s vars_linuxppc vars
make
KEGS assumes perl is in your path. If it is somewhere else, you need to edit
the "PERL = perl" line in the vars file and make it point to the correct place.
Audio is currently disabled by default, but you can try turning it on
by runnning "kegs -audio 1". It sounds horrible to me, but sounds do
come out.
Solaris SPARC build instructions:
--------------------------------
Use the vars_solaris vars file by:
rm vars; ln -s vars_solaris vars
make
KEGS assumes perl is in your path. If it is somewhere else, you need to edit
the "PERL = perl" line in the vars file and make it point to the correct place.
Audio is currently disabled by default, but you can try turning it on
by runnning "kegs -audio 1".
Solaris x86 build instructions:
--------------------------------
Use the vars_x86solaris vars file by:
rm vars; ln -s vars_x86solaris vars
make
KEGS assumes perl is in your path. If it is somewhere else, you need to edit
the "PERL = perl" line in the vars file and make it point to the correct place.
Audio is currently disabled by default, but you can try turning it on
by runnning "kegs -audio 1".
HP-UX assembly-emulation instructions:
-------------------------------------
Use the vars_hp vars file by:
rm vars; ln -s vars_hp vars
Edit the Makefile, and remove "engine_c.o" from the "OBJECTS1=" line at
the top. Then just type "make".
Other platform "C" build instructions:
-------------------------------------
I don't know--you tell me. If you are porting to an X-windows and
Unix-based machine, it should be easy. Start with vars_x86linux if
you are a little-endian machine, or vars_linuxppc if you are big
endian. Don't define -DKEGS_LITTLE_ENDIAN unless your processor is
little-endian (x86, Alpha). Mac, Sun, MIPS, HP, Motorola, and IBM are
big-endian.

989
README.kegs Normal file
View File

@ -0,0 +1,989 @@
KEGS: Kent's Emulated GS version 0.86
http://kegs.sourceforge.net/
What is this?
-------------
KEGS is an Apple IIgs emulator for Mac OS X, Linux, and Win32.
The Apple IIgs was the last released computer in the Apple II line.
It first was sold in 1986.
KEGS supports all Apple IIgs graphics modes (which include all Apple //e
modes), plus plays all Apple IIgs sounds accurately. It supports
limited serial port emulation through sockets, or can use real serial ports
on Windows and Mac OS X.
The ROMs and GS/OS (the Apple IIgs operating system) are not included
with KEGS since they are not freely distributable. KEGS is a little
user-hostile now, so if something doesn't work, let me know what went
wrong, and I'll try to help you out. See my email address at the end of
this file.
KEGS features:
-------------
Fast 65816 emulation:
About 80MHz on a P4 1.7GHz or a G4 1GHz.
Emulates low-level 5.25" and 3.5" drive accesses (even nibble-copiers work!).
Emulates classic Apple II sound and 32-voice Ensoniq sound.
All sound is played in 16-bit stereo at 48KHz (44100 on a Mac).
Emulates all Apple IIgs graphics modes, including border effects.
Can handle mixed-displays (superhires at the top, lores at the bottom).
Always does 60 full screen video updates per second.
Even supports 3200-color pictures.
Mouse and joystick support.
Emulates all Apple IIgs memory "tricks" for full compatibility.
Low-level ADB keyboard and mouse emulation enables Wolfenstein 3D to run.
Clock chip emulation makes the host time available to the Apple IIgs.
Emulated battery RAM remembers control panel settings.
Limited SCC (serial port) emulation to enable PR#1/2 IN#1/2 and other
serial programs to work.
KEGS by default emulates a 8MB Apple IIgs, but you can change this with
the "-mem" command line option.
KEGS is so accurate, even the built-in ROM selftests pass (you must be in
2.8MHz speed mode to pass the self-tests).
Release info:
------------
Included files:
CHANGES - Description of changes since last release
README.kegs - you're here
README.compile - Describes how to build KEGS
README.linux.rpm - Describes how to install KEGS's RPM for Linux
README.win32 - Win32 special directions
README.mac - Mac OS X special directions
INTERNALS.overview - description of how KEGS code works
INTERNALS.xdriver - Describes the xdriver.c routines for porting
INTERNALS.iwm - Describes the internal 3.5" and 5.25" disk
handling routines
kegs - the executable, for HP-UX 10.20+
kegs.spec - The Linux spec file for making an RPM
kegs_conf - disk image configuration info
to_pro - Hard-to-use ProDOS volume creator
partls - Lists partitions on Apple-partitioned hard
drives or CD-ROMs
src/ - All the source code, with a Makefile
You need to provide:
1) Patience.
2) a ROM file called "ROM", "ROM.01" or "ROM.03" in the KEGS directory.
It can be either from a ROM 01 (131072 bytes long) or from a
ROM 03 machine (262144 bytes long.)
3) A disk image to boot. This can be either "raw" format or 2IMG.
See discussion below. GS/OS would be best.
Getting ROMs
------------
You need a copy of the memory from fe/0000 - ff/ffff from a ROM 01 GS
or fc/0000 - ff/ffff from a ROM 03 GS, and put that in a file called
"ROM". I'll eventually write detailed instructions on how to do this.
Running KEGS:
------------
The distribution comes in 3 parts: a source-only distribution (kegs.xxx.tar.gz),
along with two binary distributions for Mac and Windows.
See the README.compile file for more info about compiling for Linux.
On all platforms except the Mac, you must start KEGS from a terminal
window. KEGS will open a new window and use the window you started it from
as a "debug" window.
On a MAC, you need to place the "config.kegs" file someplace where KEGS
can find it. The simplest place is in your home directory, so copy it there
with the Finder (or using the Terminal).
Start kegs by Double-clicking the KEGSMAC icon on a MAC, or by running
the executable (kegswin on Windows, and kegs on Linux). KEGSMAC can
be run by the Terminal window as well (which enables access to more debug
information) by typing: "./KEGSMAC.app/Contents/MacOS/KEGSMAC".
Assuming all goes well, KEGS will then boot up but probably not find any
disk images. See below for how to tell KEGS what disk images to use.
Tip: Hitting "F8" locks the mouse in the window (and hides the host cursor)
until you hit "F8" again.
Disk Images:
-----------
You tell KEGS what disk images to use through the Configuration panel.
You enter the Configuration panel by pressing F4 at any time. Then select,
"Disk Configuration". Each slot and drive that can be loaded with an image
is listed. "s5d1" means slot 5, drive 1. Slot 5 devices are 3.5" 800K disks,
and slot 6 devices are 5.25" 140K disks. Slot 7 devices are virtual hard
drives, and can be any size at all (although ProDOS-formatted drives
should be less than 32MB).
Just use the arrow keys to navigate to the device entry to change,
and then select it by pressing Return. A scrollable file selection
interface is presented, letting you located your image files. To
save navigation, you can press Tab to toggle between entering a path
manually, and using the selector. Press Return on ".." entries to go up
a directory level. When you find the image you want, just press Return.
If the image has partitions that KEGS supports, another selection
dialog will have you select which partition to mount. You will probably
only have partitions on direct devices you mount. For instance, on a
Mac, /dev/disk1 is usually the CDROM drive.
KEGS can handle "raw", .dsk, .po, 2IMG, 5.25" ".nib" images, some Mac
Diskcopy images and partitioned images. The .dsk and .po formats you often
find on the web are really "raw" formats, and so they work fine. KEGS uses
the host file permissions to encode the read/write status of the image.
An image is the representation of an Apple IIgs disk, but in a file on
your computer. For 3.5" disks, for example, a raw image would be exactly
800K bytes long (819200 bytes). KEGS intercepts the emulated GS accesses to
the image, and does the correct reads and writes of the Unix file instead.
To do "useful" things with KEGS, you need to get a bootable disk image.
You can go to http://www.info.apple.com/support/oldersoftwarelist.html and
get Apple IIgs System 6. Unfortunately, Apple now only has .sea files which
are executable files for Macintosh only. You need a macintosh to execute
those programs, which creates Disk Copy image files with no special extensions
(and with spaces in the names). Once you get those files back to your
host machine, you can use them by listing them in kegs_conf.
KEGS also supports partitioned devices. For instance, if you have a CD-ROM
on your computer, just pop an Apple II CD in, and KEGS can mount it, if
you have a Unix-base system (Linux, any Unix, and Mac OS X).
If you're on a Mac, be careful letting KEGS use your HFS partitions--
GSOS has many HFS bugs when it is writing.
If you do not have any disk mounted in s7d1, KEGS will jump into BASIC.
Support for 5.25" nibblized images is read-only for now (since the
format is kinda simplistic, it's tricky for KEGS to write to it).
Just mount your image, like "disk.nib" in the kegs_conf file like
any .dsk or .po image.
Key summary:
-----------
F1: Alias of Command
F2: Alias of Option
F3: Alias of ESC for OS/2 compatibility.
F4: Configuration Panel
F6: Toggle through the 4 speeds: Unlimited, 1MHz, 2.8MHz, 8.0MHz
Shift-F6: Enter KEGS debugger
F7: Toggle fast_disk_emul on/off
F8: Toggle pointer hiding on/off.
F9: Invert the sense of the joystick.
Shift-F9: Swap x and y joystick/paddle axes.
F10: Attempt to change the a2vid_palette (only useful on 8-bit color display)
F11: Full screen mode (does not do anything yet).
F12: Alias of Pause/Break which is treated as Reset
F2, Alt_R, Meta_r, Menu, Print, Mode_switch, Option: Option key
F1, Alt_L, Meta_L, Cancel, Scroll_lock, Command: Command key
Num_Lock: Keypad "Clear".
F12, Pause, Break: Reset
"Home": Alias for "=" on the keypad (since my Unix keyboard doesn't have an =).
Using KEGS:
----------
The host computer mouse is the Apple IIgs mouse and joystick by default.
By default, the host pointer is not constrained inside the window and
remains visible. Press F8 to hide the cursor and constrain the mouse. F8
again toggles out of constrain mode. When the GSOS desktop is running,
KEGS hides the host cursor automatically and enables special tracking
which forces the emulated cursor to follow the host cursor. If this doesn't
work right under some program, just press F8 for better compatibility.
The default joystick is the mouse position. Upper left is 0,0. Lower right
is 255,255. Press Shift-F9 to swap the X and Y axes. Press F9 to reverse
the sense of both paddles (so 0 becomes 255, etc). Swapping and
reversing are convenient with paddle-based games like "Little Brick Out"
so that the mouse will be moving like the paddle on the screen. "Little
Brick Out" is on the DOS 3.3 master disk. The joystick does not work
properly if the pointer is constrained in the window.
If you have a real joystick on Linux, start KEGS with "-joystick" and
you should be able to use it. Real joysticks should also work on Windows.
The left mouse button is the mouse button for KEGS. The right mouse
button (if you have it) or F6 toggles between four speed modes. Mode 0
(the default) means run as fast as possible. Mode 1 means run at 1MHz.
Mode 2 means run at 2.8MHz. Mode 3 means run at 8.0MHz (about the speed
of a ZipGS accelerator). Most Apple //e (or earlier) games need to be
run at 1MHz. Many Apple IIgs demos must run at 2.8MHz or they crash. Try
running ornery programs at 2.8MHz. 3200 pictures generally only display
correctly at 2.8MHz or sometimes 8.0MHz.
The middle mouse button or Shift-F6 causes KEGS to stop emulation, and enter
the debugger. You can continue with "g" then return in the debug window.
You can also disassemble memory, etc. The section "Debugging KEGS"
above describes the debugger interface a little more.
KEGS has no pop-up menus or other interactive interfaces (other than
the debug window). Input to the debug window is only acted upon when
the emulation is stopped by hitting a breakpoint or pressing the right-most
mouse button.
Quitting KEGS:
-------------
Just close the main KEGS window, and KEGS will exit cleanly. Or you
can select Quit from the menu. Or enter ctrl-c in the debugger window.
Or press the middle-mouse button in the emulation window, and then type
"q" return in the debug window.
Debugging KEGS:
--------------
KEGS by default now continues emulation even when it detects buggy programs
running. (Now I know why Appleworks GS always seemed to crash!).
KEGS divides buggy programs into two severities: Code Yellow and Code Red.
The status is displayed in words in the text area under the emulation window.
If nothing's wrong, nothing is printed.
A Yellow bug is a mild bug where an Apple IIgs program merely read an
invalid location. Although completely harmless, it indicates the potential
for some Apple IIgs program bug which may become more severe shortly.
For instance, closing the "About This Apple IIgs" window in the Finder
causes a code yellow alert, but it seems quite harmless.
A Code Red bug is a more serious problem. The Apple IIgs program either
tried to write non-existent memory, entered an invalid system state, or
perhaps just tried to use an Apple IIgs feature which KEGS does not implement
yet. Note that entering GSBUG tends to cause a Code Red alert always, so if
you intended to enter it, you can ignore it. My recommendation is to
save work immediately (to new files) and restart KEGS if you get into the
Red mode.
KEGS also supports breakpoints and watchpoints. In the debug window, you
set a breakpoint at an address by typing the address, followed by a 'B'
(it must be in caps). To set a breakpoint on the interrupt jump point,
type:
e1/0010B
To list all breakpoints, just type 'B' with no number in front of it.
To delete a breakpoint, enter its address followed by 'D', so
e1/0010D
deletes the above breakpoint. The addresses work like the IIgs monitor:
once you change banks, you can use shortcut addresses:
e1/0010B
14B
will add breakpoints at e1/0010 and e1/0014.
This is a "transparent" breakpoint--memory is not changed. But any
read or write to that address will cause KEGS to halt. So you can
set breakpoints on I/O addresses, or ROM, or whatever. Setting a breakpoint
slows KEGS down somewhat, but only on accesses to the 256 byte "page"
the breakpoint is on. Breakpoints are not just instruction breakpoints,
they also cause KEGS to halt on any data access, too (usually called
watchpoints).
Frederic Devernay has written a nice help screen available in the
debugger when you type "h".
KEGS command-line option summary:
--------------------------------
-mem {mem_amt}: KEGS will use mem_amt as the amount of expansion RAM in
the IIgs. This memory is in addition to the 256KB on a ROM 01
motherboard, or 1MB on a ROM 03. The memory is in bytes,
and it will be rounded down to the nearest 64KB. "-mem 0x800000"
will use 8MB of expansion RAM (the default).
-badrd: Causes KEGS to halt on any access to invalid memory addresses.
Useful for debugging. By default, KEGS allows reads to invalid
memory since the Finder does some (especially when you open the
About window, and then close it). But KEGS warns you about these
accesses in the debug window. In general, these warnings
indicate buggy programs. If the warnings get severe, it's
a good sign you should quit KEGS and start over before the
emulated program crashes. -badrd would be the default for KEGS
if it wasn't for the Finder's About window's problem.
-ignbadacc: Causes KEGS to allow reads & writes to invalid memory
addresses without printing any warnings. Useful for running
extremely buggy programs so you don't have to see all the warning
messages scroll by.
-skip: KEGS will "skip" that many screen redraws between refreshes.
-skip 0 will do 60 frames per second, -skip 1 will do 30 fps,
-skip 5 will do 10 fps.
-audio [0/1]: Forces audio [off/on]. By default, audio is on unless
the X display is a remote machine or shared memory is off.
This switch can override the default. -audio 0 causes KEGS to
not fork the background audio process, but Ensoniq emulation
is still 100% accurate, just the sound is not sent to the
workstation speaker. Audio defaults off on Linux for now.
-arate {num}: Forces audio sample rate to {num}. 44100 and 48000 are
usual, you can try 22050 to reduce KEGS's overhead. On a reasonably
fast machine (>250MHz or so), you shouldn't need to mess with this.
-dhr140: Will use the old Double-hires color algorithm that results in
exactly 140 colors across the screen, as opposed to the blending
being done by default.
X-Windows/Linux options
-15: KEGS will only look for a 15-bit X-Window display.
-16: KEGS will only look for a 16-bit X-Window display (not tested, probably
will get red colors wrong).
-24: KEGS will only look for a 24-bit X-Window display.
-display {machine:0.0}: Same as setting the environment variable DISPLAY.
Sends X display to {machine:0.0}.
-joystick: Will use /dev/js0 as the joystick.
-noshm: KEGS will not try to used shared memory for the X graphics display.
This will make KEGS much slower on graphics-intensive tasks,
by as much as a factor of 10! By default, -noshm causes an
effective -skip of 3 which is 15 fps. You can override this
default by specifying a -skip explicitly.
Command/Option keys:
-------------------
If you have a workstation keyboard with the new Windows keys, you can
use them as the command/option keys. This is what I use. Since many people
don't have the PC keyboard, there are several alternatives.
The following keys are Option (closed-apple) (not all keyboards have all
keys): F2, Meta_R, Alt_R, Cancel, Print_screen, Mode_switch, Option,
or the Windows key just to the right of the spacebar. The following keys are
Command (open-apple): F1, Meta_L, Alt_L, Menu, Scroll_lock, Command,
the Windows key left of the spacebar, and the Windows key on the far right
that looks like a pull-down menu. You can use F1 and F2 if you cannot make
anything else work.
If you can't get any of these to work on your machine, let me know.
Note that X Windows often has other things mapped to Meta- and Alt-
key sequences, so they often don't get passed through to KEGS. So it's
best to use another key instead of Alt or Meta.
The joystick/paddle buttons are just the Command and Option keys.
Reset:
-----
The reset key is Pause/Break or F12. You must hit it with Ctrl to get it to
take effect (just like a real Apple IIgs). Ctrl-Command-Reset
forces a reboot. Ctrl-Command-Option-Reset enters selftests.
Selftests will pass if you force speed to 2.8MHz using the middle
button. Watch out for ctrl-shift-Break--it will likely kill your
X Windows session.
Control Panel:
-------------
You can get to the Apple IIgs control panel (unless some application
has locked it out) using Ctrl-Command-ESC.
How to use "to_pro":
-------------------
This lame utility serves two purposes: It "formats" large disk images,
and lets you move files from Unix into the simulator. It does this
by taking the files you provide, and putting them onto Unix file called
"POOF1" that is an image in ProDOS format.
So, if you have a wolfdemo.bxy file from an FTP site, you can get it
into the emulator by:
to_pro -800 wolfdemo.bxy
which creates an 800K Unix file called "POOF1". POOF1 is now an
image that can be loaded into KEGS, and when you catalog it, it will
have wolfdemo.bxy on it.
To create a 4MB image:
to_pro -4096 wolfdemo.bxy
which puts wolfdemo.bxy on a much larger image.
I don't know what happens if the file, wolfdemo.bxy, is bigger than
the image...it probably crashes.
Even if you want to format a "blank" image, you have to put something in it.
Like:
echo "This is a lame utility" > foo
to_pro -16384 foo
...creates a 16MB POOF1 with the file foo on it. Just delete foo
from within KEGS.
See? I told you it was a lame utility!
to_pro can handle up to 51 files at a time--for example:
to_pro -32000 *.shk
...would put all *.shk files in the current Unix directory into a 31.25MB
image called POOF1.
To_pro tries to truncate Unix filenames to the 15 character ProDOS
limit, and converts all punctuation to dots. I've tested it enough
that it has worked for my purposes.
The algorithm to_pro uses to create a disk volume is possibly suspect.
I recommend reformatting any images again inside KEGS (using GS/OS, for
instance) just to make sure the directory structure is good. To_pro
is intended to put files into images quickly and easily, and then to
copy the files off of those images onto images formatted from within
KEGS by an Apple IIgs OS.
Since ProDOS cannot handle > 32MB images, make sure you run to_pro with
arguments under 32767. I personally haven't tried a partition bigger
than 30000K (about 2.5MB short of the maximum). Well, you can use bigger
images if you format them HFS, but I don't trust the GS/OS HFS driver.
To_pro automatically sets the ProDOS filetype of files ending in ".shk"
to $E0.
Details on config.kegs and disk images
--------------------------------------
The file "config.kegs" describes the images KEGS will use. The sample
file has all the lines commented out with '#' to show sample uses.
Remember, KEGS will boot s7d1 (unless you've changed that using the
Apple IIgs control panel), so you must put an image in that slot.
Changing disks in slot 7 does not work, but you can move around
disks in slots 5 and 6. This allows you to "eject" disks and change them.
This is especially useful for multi-disk 5.25" programs.
KEGS uses the Unix permissions on raw disk images to decide how to load
it into the emulator. If the file is unreadable, it cannot load the
image (duh).
KEGS, by default, runs the IWM (3.5" and 5.25" disks) emulation in an
"approximate" mode, called "fast_disk_emul". In this mode, KEGS
emulates the hardware "faster" than real, meaning the data the code
being emulated expects is made available much faster than on a real
Apple IIgs, providing a nice speed boost. For instance, the 5.25"
drives run 10x the real speed usually. Almost everything will work
except for nibble copiers, which don't like the data coming this fast.
(Meaning, unless you're using a nibble copier, you shouldn't run into an
issue. All games/demos/etc run fine in this mode). To make nibble
copiers work, Press F7.
KEGS can read in the ".nib" nibblized disk format, but as read-only mode. If
the emulated image is no longer ProDOS or DOS 3.3 standard, KEGS will
automatically treat the image as "Not-write-through-to-Image" from then
on. This mode means KEGS will continue to emulate the disk properly in
memory, but it cannot encode the changes in the standard .dsk or .nib
image format. It prints a message saying it has done so. However,
the "disk" in emulation is fully useable as long as KEGS is running. A
standard reformatting will not cause an image to flip to not-write-
through-to-Image, but running things like a "drive-speed" test will cause
further changes not to propagate to the Unix file. You will need
to "eject" the image and re-insert it before writes will take effect.
In full accuracy mode (i.e., not fast_disk_emul), 5.25" drive accesses
force KEGS to run at 1MHz, and 3.5" drive accesses force KEGS to run at
2.5MHz.
KEGS Timing:
-----------
KEGS supports running at four speeds: 1MHz, 2.8MHz, 8.0MHz, and Unlimited.
Pressing the middle mouse button cycles between these modes. The 1MHz
and 2.8MHz speeds force KEGS to run at exactly those speeds, providing
accurate reproduction of a real Apple IIgs.
KEGS will always run at 1MHz at least. If it is unable to keep up,
it will extend the emulated time to maintain the illusion of running
at 1MHz. That is, it may do just 40 screen refreshes per real second,
instead of the usual 60. This happens rarely.
If you force KEGS to run at 1MHz, it will strive to run at exactly
1MHz (well, really 1.024MHz). If it is running faster (almost always),
it will pause briefly several times a second to maintain the 1MHz speed. It
does this in a friendly way that makes time available to other tasks.
This makes older Apple II games very playable just like a
real Apple IIgs on slow speed. KEGS is running at exactly the same
speed as an Apple //e when in 1MHz mode. The 1MHz mode you set
through the right mouse button overrides the "fast" mode you can access
through the control panel. But, 3.5" accesses will "speed up" to 2.8MHz
to enable that code to operate correctly while the 3.5" disk is being
accessed.
If you force KEGS to run at 2.8MHz, KEGS tries to run at exactly 2.8MHz. But
like a real unaccelerated Apple IIgs, if you set the control panel to
"slow", it will really be running at 1MHz. Accesses to 5.25" disk
automatically slow down to 1MHz, when running the IWM in accurate
mode (F7). KEGS may not be able to keep up with some programs running
at 2.8MHz due to video and sound overheads on lower-end machines. If
that happens, it effectively runs slower by extending the emulated
"second", like in the 1MHz mode. You can tell this is happening
when Eff MHz in the status area falls below 2.5MHz. If KEGS is running
faster than 2.8MHz, it takes small pauses to slow down, just like in
1MHz. Many Apple IIgs demos must be run at 2.8MHz. The built-in
selftests (cmd-option-ctrl-Reset) must run at 2.8MHz. Many Apple IIgs
action games are more playable at 2.8MHz.
The 8.0MHz setting means follow the ZipGS-selected speed, but don't go
faster than 8.0MHz. If your host computer cannot keep up, then the
emulated second will be extended. You can use the ZipGS control panel,
or ZIPPY.GS on the sample disk image to set the emulated ZipGS speed to
anything from 1MHz to 8MHz in .5MHz increments.
The Unlimited setting means run as fast as possible, whatever speed that
is (but always above 1MHz). Eff MHz gives you the current Apple IIgs
equivalent speed. Many games will be unplayable at the unlimited
setting. Setting the IIgs control panel speed to "slow" will slow down
to 1MHz.
Sound output has an interesting relationship to KEGS timing. KEGS must
play one second of sound per second of emulated time. Normally, this
works out exactly right. But as noted above, if KEGS can't maintain the
needed speed, it extends the emulated second. If it extends the second
to 1.4 real seconds, that means KEGS only produces 1.0 second of sound
data every 1.4 seconds--the sound breaks up!
In all cases, 1MHz to KEGS is 1.024MHz. And 2.8MHz to KEGS is 2.52MHz
(trying to approximate the slowdown causes by memory refresh on a real
Apple IIgs). It's just easier to say 1MHz and 2.8MHz.
KEGS SAMPLE_DISK:
----------------
I'm providing a sample disk of freely available utilities/programs to
demonstrate a little of what KEGS can do. I'm also including my simple
changes to a benchmark called "SPEEDTEST" to make it run under ProDOS and
time itself automatically. The SAMPLE_DISK is not bootable since I'm
not sure if I can distribute PRODOS (the OS).
SPEEDTEST:
---------
In the folder "SPEEDTEST", there are two BASIC programs. OLD.SPEEDTEST
is the old, unmodified DOS 3.3 emulator benchmark by Clayten Hamacher.
It does not run properly under ProDOS 8. My modified version is
SPEED.PRO, meaning converted to ProDOS. I made few modifications, other
than to make the benchmarks time themselves.
To run, just say "RUN SPEED.PRO". To run benchmarks, press "B". If
you say "A)ll tests", make sure you have a 5.25" disk image in s6d1!
(A blank 140K image will work fine).
This modified SPEED.PRO can run on ANY Apple IIgs emulator (or on the real
thing).
GSOS7, GSOS5, BYE.SYSTEM:
------------------------
These are handy utilities I use on my s7d1 boot disk. Get a GS/OS 6.x
bootable disk image. (See GSOS.INFO file for how to get GS/OS).
Remove "PRODOS" from that disk's root directory, and copy GSOS7 to
the root directory. Then copy SYSTEM/P8 to PRODOS. Then move
BASIC.System into SYSTEM/. Then copy BYE.SYSTEM to the root directory,
then move BASIC.SYSTEM back to the root directory.
What all this means is that now the root directory of your system disk
is: GSOS7, (other stuff), PRODOS, BYE.SYSTEM, and BASIC.SYSTEM.
When you boot, ProDOS will boot (this is PRODOS 8) and will search
for the first *.SYSTEM file, and run it. BYE.SYSTEM just does a BYE
command, which puts you in the PRODOS 8 textual launcher.
If you now select GSOS7 (the first entry, already highlighted, just
hit return), it will boot GSOS on slot 7. (Use GSOS5 to boot slot5).
Or, just move down and select BASIC.SYSTEM to go to BASIC. A very simple
program launcher!?
Note that I didn't write GSOS5 or GSOS7--I just made a one byte hack
to the default GS/OS launcher. No real wizardry is going on here.
SHRINKIT3.4, GSHK1.1:
--------------------
Useful for unpacking .SHK files you can download off of the net.
Always use GSHK (GS/OS version of ShrinkIt) for GS programs since
they may have resource forks. It's also faster. GSHK must be run from GS/OS.
LISTV2.0:
--------
ProDOS 8 text file lister, useful for viewing text files.
Wolfenstein3D:
------
Wolfenstein 3D for the Apple IIgs. No kidding! Must be run from GS/OS.
SOUND22:
-------
Cool little ProDOS 8 program (SOUND.EDITOR) that plays hi-fidelity
(relatively) through the old Apple II speaker. This is included as a
demonstration of how accurate KEGS sound emulation is.
Sound.Smith.95:
--------------
GS/OS application that plays SoundSmith songs, which are spreadsheet music,
like MODs. I included some sample songs--FILE.11, FILE.16, FILE.17, and
SPACE.HARRIER. Enjoy!
SOLITAIRE:
---------
Klondike. I like the interface on this game.
CAT.DOCTOR:
----------
From Prosel8 (which is now public domain), this utility is very handy for
sorting directories (among other things). Useful for arranging GSOS7,
and BYE.SYSTEM mentioned above.
BGSOUND:
-------
This CDA lets you play Soundsmith songs in the background while other
applications are running. Very handy for playing Solitaire with some music.
DOCVu.CDA:
---------
This CDA shows the current DOC contents in real-time. It has neat visual
effects while playing Soundsmith songs.
Zippy.gs
--------
Very useful ProDOS 8 program by Andy McFadden for setting ZipGS parameters.
In KEGS, you'll want to use this to change the Zip speed to less than
100% to make the "Unlimited" speed become limited to 7.5MHz, which is
useful for some games.
KEGS: What works:
-----------------
Basically, just about every Apple II program works.
KEGS is EXTREMELY compatible. But, I haven't tested everything. Let
me know if you find a program which is not working correctly.
Some old Apple II 5.25" games require the old C600 ROM image, and don't work
with the default Apple IIgs ROM. This is not KEGS's fault--these games
don't run on a real Apple IIgs either. KEGS has built-in the old Apple II
Disk PROM which you can enable by using the IIgs control panel to set
Slot 6 to "Your Card". This allows many more Apple II games to run, and
is the recommended setting.
The NinjaForce Megademo mostly works, but sometimes hangs in the BBS Demo.
Just skip that demo if it happens.
The California Demo hangs at startup unless you use the IIgs control panel
to boot from slot 5, and then do a ctrl-Open_Apple-Reset to boot--doing
the above lets it work fine. This seems to be a bug in the demo.
KEGS bugs:
---------
KEGS's serial port emulation is very limited now, and only for
adventurous souls.
On a ROM03, KEGS makes a patch to the ROM image (inside emulation, not
to the Unix file) to fix a bug in the ROM code. Both ROM01 and ROM03
are patched to enable use of more than 8MB of memory. I then patch the ROM
self-tests to make the ROM checksum pass. But other programs, like
the Apple IIgs Diagnostic Disk, will detect a ROM checksum mismatch.
Don't worry about it.
Sound breaks up if KEGS is unable to keep up--it should only be happening
if you are trying to force KEGS to run at 2.8MHz, but cannot due to
sound and video overhead.
Sound emulation:
---------------
KEGS supports very accurate classic Apple II sound (clicking of the
speaker using $C030) and fairly accurate Ensoniq sound.
When KEGS determines that no sound has been produced for more than
5 seconds, it turns off the sound calculation routines for a small
speedup. It describes that it has done this by saying "Pausing sound"
in the debug window. However, when sound restarts, it sometimes
"breaks-up" a little. I will work on fixes for this.
If your display is not using shared memory, audio defaults to off unless
you override it with "-audio 1".
SCC emulation:
-------------
KEGS emulates the two serial ports on a IIgs as being two Unix sockets.
Port 1 (printer port) is at socket address 6501, and port 2 (modem)
is at socket address 6502.
In KEGS, from APPLESOFT, if you PR#1, all output will then be sent to
socket port 6501. You can see it by connecting to the port using
any method you like, but a simple, easy way is to use telnet. In
another Unix window, do: "telnet localhost 6501" and then you
will see all the output going to the "printer".
Under APPLESOFT, you can PR#1 and IN#1. This gets input from the
socket also. You can type in the telnet window, it will be sent on
to the emulated IIgs. Telnet on Unix defaults to "line mode" which
buffers keys you type until you hit return. This can be a bit distracting,
and can be disabled by hitting Ctrl-] and then "mode char". This
causes a few {{ chars to show up in KEGS--just ignore this for now.
You may want to go to the F4 Config Panel and set "mask off high bit"
for serial port accesses to make PR#2 work a little nicer.
That's about it. Proterm and Appleworks GS can talk to the modem port
fine, but it's limited in its usefulness. I have printed from
Printshop, but it's a bit pointless since it's sending out Imagewriter
printer codes which doesn't look like anything. You can "print" from
BASIC by using something like PR#1 in KEGS and
"telnet localhost 6501 | tee file.out" in another window.
Feel free to let me know what doesn't work, but a lot is known not
to work. GNO's tty interface may work, but I'm having problems
testing it.
KEGS status area:
----------------
The status area is updated once each second. It displays info I am
(or was at some time) interested in seeing.
Line 1: (Emulation speed info)
dcycs: number of seconds since KEGS was started
sim MHz: Effective speed of KEGS instruction emulation, not counting
overhead for video or sound routines.
Eff MHz: Above, but with overhead accounted for. Eff MHz is the
speed of an equivalent true Apple IIgs. This is extremely
accurate.
sec: The number of real seconds that have passed during on of KEGS's
emulated seconds. Should be 1.00 +/- .01. Under 1
means KEGS is running a bit fast, over 1 means KEGS is
running slow. When you force speed to 2.5MHz, if KEGS
can't keep up, it extends sec, so you can see how slow
it's really going here.
vol: Apple IIgs main audio volume control, in hex, from 0-F.
pal: Super-hires palette that is unavailable. KEGS needs one palette
for the standard Apple // graphics mode on an 8-bit display,
and it grabs the least-used palette. Defaults to 0xe.
You can try changing it with F10. If you change it to a
palette that is not least used, KEGS changes it back in
one second. Any superhires lines using the unavailable
palette will have their colors mapped into the
closest-matching "lores" colors, to minimize visual
impact.
Limit: Prints which speed setting the user has requested: 1MHz, 2.8MHz,
or Unlimited.
Line 2: (Video and X info)
xfer: In hex, number of bytes transferred to the X screen per second.
xred_cs: Percentage of Unix processor cycles that were spent in the X
server (or other processes on the machine).
ch_in: Percentage of Unix processor cycles spent checking for X input Events.
ref_l: Percentage of Unix processor cycles spent scanning the Apple IIgs
memory for changes to the current display screen memory,
and copying those changes to internal XImage buffers.
ref_x: Percentage of Unix processor cycles spent sending those XImage buffers
to the X server. Very similar to xred_cs.
Line 3: (Interpreter overhead)
Ints: Number of Apple IIgs interrupts over the last second.
I/O: Rate of I/O through the fake smartport interface (hard drives).
Does not count 3.5" or 5.25" disk accesses.
BRK: Number of BRKs over the last second.
COP: Number of COPs over the last second.
Eng: Number of calls to the main instruction interpreter loop in the
last second. All "interrupts" or other special behavior
causes the main interpreter loop to exit. A high call
rate here indicates a lot of overhead. 12000-15000 is normal.
20000+ indicates some sort of problem.
act: Some instructions are handled by the main interpreter loop returning
special status "actions" to main event loop. This is the
number over the last second. Should be low.
hev: This tracks HALT_EVENTs. KEGS returns to the main loop to recalc
effective speed whenever any speed-changing I/O location is
touched. See the code, mostly in moremem.c
esi: This counts the number of superhires scan-line interrupts
taken in the last second.
edi: This counts the number of Ensoniq "special events" over the last
second. A sound that stops playing always causes a KEGS
event, even if it doesn't cause a IIgs interrupt.
Line 4: (Ensoniq DOC info)
snd1,2,3,4: Percentage of Unix processor cycles spent handling various
sound activities. snd1 is the total sum of all sound overhead.
st: Percentage of Unix cycles spent starting new Ensoniq oscillators.
est: Percentage of Unix cycles spent looking for 0 bytes in sounds.
x.yz: This final number is the average number of oscillators playing
over the last second. Up to 4.00 is low overhead, over
20.0 is high overhead.
Line 5: (Ensoniq DOC info)
snd_plays: Number of calls to a routine called sound_play, which
plays Ensoniq sounds. Always called at least 60 times per sec.
doc_ev: Number of Ensoniq (DOC) events in the last second. A sound
stopping is an event, but changing a parameter of a sound
while it is playing is also an event.
st_snd: Number of sounds that were started in the last second.
snd_parms: Number of times a sound parameter was changed while it
was playing.
Line 6: (IWM info)
For each IWM device, this line displays the current track (and side for
3.5" disks). If a disk is spinning, there will be an "*" next to the
track number. Only updated once a second, so the disk arm moving may
appear to jump by several tracks. "fast_disk_emul:1" shows that KEGS
is using less accurate, but faster, IWM emulation. Press F7 to toggle
to accurate disk emulation.
Documentation To-Do:
-------------------
Describe the tracing and breakpoint debug features.
Describe the debug interface.
Describe how the code works.
Describe more of what's known to work.
Describe my changes to SPEEDTEST.
KEGS To-Do:
----------
Better serial port emulation (printing, comm)
Better nibblized images.
Fix the Ensoniq bugs to make sound more accurate.
-------------------
If you have any problems/questions/etc., just let me know.
Special thanks to Jeff Smoot of climbingwashington.com for letting me use
the picture of a keg in the Mac icon.
Kent Dickey
kadickey@alumni.princeton.edu
X Window (Linux) interface information:
--------------------------------------------
Every version of Linux is different. Supporting this is very difficult
especially since I do not run Linux myself.
If KEGS fails to start, try the following options:
kegs -audio 0 -noshm
There may be a bug with drawing the border on x86 Linux with Shared Memory--
add the options "-noshm -skip 0" to fix this up (but lose some graphics
performance, sorry). Try KEGS without these options first, but use
this as a workaround if necessary.
If you want the display to go somewhere different, make sure the shell
environment variable $DISPLAY is set, or give the command-line argument
"-display {foo}".
KEGS also forks off a subprocess to help handle the sound if audio is
active. If KEGS crashes in a unusual way (a core dump, for instance),
you may have to manually kill the subprocess. ("ps -ef| grep kegs;kill
xxxxx").
User geoff@gwlink.net adds some notes for mounting disks/floppies/CDs under
Solaris:
To use a CDROM, insert the CD and let Volume Management mount it.
Edit kegs_conf and use the filesystem that shows up in the "df -k"
listing. The volume name of the CDROM must be included. For example,
a CDROM in an IDE drive would look like this:
/vol/dev/dsk/c1t0d0/ciscocd
A CDROM in a SCSI drive would look like this:
/vol/dev/dsk/c0t6d0/j1170_10804
To provide low-level ADB emulation, KEGS turns off Unix key repeat when the
focus is in the KEGS window. It should be turned back on every time
the pointer leaves the KEGS window, but sometimes it doesn't. Re-running
KEGS (and then quitting it quickly) should turn key-repeat back on,
or you can type 'xset r' in another terminal window.
Sometimes the converse is true--key repeat is "on" when the cursor is
in the KEGS window. Moving the cursor out of the window and then
back in should solve it. This is sometimes noticeable when running
Wolfenstein 3D GS. I haven't spent much time debugging the problem.
I think it may be the X Server.
KEGS uses a private color-map for its X-window in 8-bit mode. This
may cause colormap "flash" when your cursor enters the window.
KEGS details/troubleshooting
----------------------------
KEGS will work on all platforms with a 15/16-bit, 24-bit, or 32-bit
color display. KEGS also supports an 8-bit display on X windows only.
On all platforms, it autodetects the color depth--no color switching
is necessary as long as you're at a supported depth.
Disk Image Details
Images loaded into slot 6 (drive 1 or 2) are assumed to be 140K
5.25" disks, which is usually have the extension ".dsk". Images
loaded into slot 5 (drive 1 or 2) are assumed to be 800K disk images
and can be in any supported imahe format (including partitions, if
you have 800K partitions). Images loaded into slot 7 (drives 1
through 32) can be in any format and can be any size up to 4GB.
KEGS boots s7d1 by default. You can change this using the emulated IIgs
control panel, just like a real Apple IIgs. KEGS emulates a IIgs with
two 5.25" drives in slot 6, two 3.5" drives in slot 5, and up to 32
"hard drives" in slot 7. However, the current Configuration Panel only
lets you set through s7d11.
Config.kegs file
----------------
KEGS saves your preferences and disk image names in the file config.kegs.
KEGS searches for this file in the directory KEGS was started in, in
your home directory, or in the Resources directory (on a Mac) of the app.
It needs to find one someplace, so putting it in your home directory is
usually the easiest.
The config.kegs file is a simple text file. You need to quit KEGS before
editing the file. The BRAM data is also kept in this file, with separate
BRAM contents for ROM 01 and ROM 03 (so if you switch ROM versions, you
don't lose all your BRAM preferences).
If you're trying to use a real host device (CD-ROM, or hard drive, or
floppy), you should make the permissions on the /dev/disk* files something
like (meaning, everyone should have read permission):
brw-r--r-- 1 root operator 14, 0 Jun 10 00:01 /dev/disk2
You can do this on a Mac with:
sudo chmod 644 /dev/disk2
Running KEGS as root is NOT recommended.
The s6d* and s5d* drives support disk swapping and disk ejecting, but
the s7d* drives do not.

252
README.linux.partitions Normal file
View File

@ -0,0 +1,252 @@
[ This info provided by Mike Thomas <phoenyx@texas.net> ]
[ Updated 10/30/2003 by Kent: This file mentions editing "kegs.conf" to ]
[ mount images--this is now replaced by the built-in Configuration Panel. ]
Setup and configuration for x86 Linux:
--------------------------------------
KEGS is very easy to setup on your Linux box, but not foolproof. First
you will need to decide where it will live. When doing this you will
have to take into consideration any users of your machine. It really
doesn't matter where it goes but it should have it's own directory and
any supplied sub-directories should be there. You may decide to use the
/usr/local path where most systems recommend you install applications.
Again, this is entirely up to you. On my system I have a separate
partition for KEGS and all the miscellaneous files I've accumulated for
it. This makes it easy for me to reinstall the system should the need
arise. Since I fool around with a large variety of software and OS's
this happens more often than it would for normal users.
Once you have put the files into the proper place you will need to
compile it. You should not need to be 'root' to do this part. The file
README.compile explains the steps required for this. Basically all you
should need to do is set the vars link to point to the file
vars_x86linux. You will want to check the file and make sure it is
accurate for your system. On my Redhat 6.0 system the default compile
setup works fine. I use the pentium GCC compiler instead of the
supplied EGCS since it seems to build better binaries. I do not
recommend using optimization levels higher than 2. Once you have
successfully built the binaries you will need to copy them to the KEGS
directory. At a minimum copy the file kegs and to_pro.
Ok, now that you have the binaries you're almost ready. You will need a
copy of the IIgs rom placed in the KEGS directory. It should be named
ROM. You will also need some disk images. This is the hardest part.
You will need to create an HD image to work with. Kent mentions an easy
way in his readme. From the shell type this:
echo "testfile" > testfile
to_pro -16384 testfile
If you're using bash try this:
echo "testfile" > testfile
./to_pro -16384 testfile
This should create a 16 megabyte HD image. This image will NOT be properly
formatted to boot a system. The block zero is not properly setup. There is no
easy way to fix this with the current KEGS/Linux system. There seems to be a
problem formating HD files for Prodos using KEGS. The system will easily erase
them but this doesn't help you. One solution is to make the primary boot drive
use a disk partition. This is more involved and will be explained later.
Another solution is to have access to the utility Block.Warden or some other
P8 block utility. What you need to do is copy the boot blocks (blocks 0 and 1)
from any bootable disk to the HD image. With that done you can now install
GS/OS.
Make sure you set the proper file permissions on files needed by KEGS. You
will not be able to properly use it while logged on as root. KEGS uses the
file permissions to test if it should write the image to disk or the memory
image. As root, KEGS will never write the image since it thinks root
always has execute privilege. The main files which you will need read/write
access to are bram.data.1 and disk_conf. I suggest you have read access to all
the other files in the directory.
Once you've got all the proper permissions set, log onto the system with your
normal account. Start up X and a shell and cd to the KEGS directory. Assuming
you have the disk images for GS/OS edit your disk_conf file so it looks
similar to this:
# boot from install disk
s7d1 = /usr/local/fst/gsos1
# our HD image
# you should rename POOF1 file created with to_pro
# I use *.hdv to be compatible with other utilities
s7d2 = /usr/local/fst/boot.hdv
# other GSOS images
s7d3 = /usr/local/fst/gsos2
...
If you include all the GSOS images this way you will have a simple setup.
Execute KEGS. For now go with the simplest command line possible. Since the
newer versions support auto detect on video resolutions this should be the
command kegs by itself. Hopefully you will boot into the emulator. If so,
install GSOS and you're ready to go.
Sound
-----
Kent says sound doesn't work under Linux. This is partially true and much
depends on the sound system you have installed. I have been successful with
sound on both Soundblaster and Soundpro systems. For long compositions the
sound may break up but it is functional for games and system sounds.
System Video Setup
------------------
This is rather personal and based upon system hardware so I'll just give you my
thoughts and setup info on this. My normal X system is configured
@ 1152x864 15bpp due to constraints in the X server for my video system. I
have custom configured it to boot into this mode and then I change to 800x600
by using the CTRL+ALT+(keypad)PLUS sequence when I use KEGS. This makes the
system much easier to read.
KEGS and disk partitions
------------------------
Kent mentions using partitions in his readme file but doesn't go into much
details. I suspect this is mostly for accessing CD-roms. But it also works
well for HFS and Prodos formatted partitions also. Linux can also handle HFS
partitions but not Prodos. To accomplish this you will need some free space on
your hard disk to create the partitions. You should not attempt this unless you
know what you are doing. You have been warned!
This task is not easy, nor is it supported by Kent. This was done and tested
on my own system so I know it works. You will need the HFS support utilities
for Linux. These are available on several Linux software sites. The primary
need for these utilities is to change an ext2fs partition to an HFS partition.
You can also use them to format the HFS volumes and copy files to and from
the partition. Newer versions of the Linux kernel support HFS file systems but
you will still need the utilities to create the original volume.
You must decide how you want to divide this partition. You can use it all for
HFS or you can create Prodos volumes and HFS volumes. There are pros and cons
for using Prodos partitions instead of files. The pros, it is a little faster
than using an HD file. It is a real Prodos partition, formatted by KEGS. The
cons, It must be backed up by using software on the emulator. You can't just
copy the HD file to another drive.
You must weigh these pros and cons and decide for yourself. Of course you
are not limited to using partitions. I have a mix of partitions and files
which works quite well. I like the P8 partitions for holding my boot system
and applications. I back them up with GSHK to an HFS volume which I can then
transfer to another drive if I need even more security.
If you decide to use the whole partition for HFS then all you need to do is
run the HFS utilities and setup the HFS volume. Read the documentation which
comes with the utility package and follow it faithfully.
If you want to use P8 and HFS partitions you have some more work to do. If
you have never worked with low level partitions or are worried about destroying
your HD then you should probably forget this. For this to work you will have
to change the partition table on your HD. This can and most likely will ruin
any data you already have on there. I can not state this enough. Back up any
important data on the hard drive! It is possible to change the partitions in
Linux and not destroy the system. I have done this on mine but I also used
the last defined partition to make the changes and designed the system for
change should it be necessary.
For those of you who know how to handle this, take the partition you have
decided to use for KEGS and divide it into at least one 32 meg partition.
More is better but you will have to use the emulator to back up any drives
setup this way since Linux can't access a Prodos partition (yet). I have setup
4 32 meg P8 partitions and several smaller HFS partitions of about 96 megs.
The reason I use smaller HFS partitions is because HFS isn't real efficient
with larger drives, but that's another story. The reason for the separate
HFS partitions is so Linux can mount the HFS volumes like any other file system.
I find this works quite easily for accessing files instead of using the HFS
utilities. Just my opinion though. For P8 utilities you will still need to
use the HFS utility and configure the drive as an HFS volume. This lets KEGS
read the partition when it loads the partition the first time. KEGS doesn't
like the Linux file system.
Ok, everybody got their partitions defined? You want to use the HFS tools
and setup all the partitions (P8 and HFS) as HFS volumes. Next you will have
to setup the HFS partitions. No, I'm not repeating myself. This is not the same
thing as the low level partitions. HFS volumes have their own partition table.
For our purposes the table will only hold one partition on each whole volume.
The utility will give you the block count when you setup the partitions,
write it down so you don't forget. After you have the volume partition setup
you can format the drive. Yeah I know you made a Prodos partition but it
doesn't hurt anything and KEGS will be able to read the partition when it
boots up.
Well, I think I covered everything needed to set them up. Now you will need to
edit the /etc/fstab file. Make sure there are no references to the original
partition. If you want to access the HFS volumes you will need to add them to
this file. You will also need to make sure that your Linux can understand the
HFS format. Most newer kernels will as long as you've compiled it into the
kernel or set it up as a module. KEGS doesn't need these entries to access
the volumes, they are just here for your convenience. In fact, if you don't
need Linux access I suggest you either leave them out or set them up as
NOAUTO and mount them only when needed. Unmount them when finished to avoid
any potential problems also. Do not give Linux access to any P8 partitions.
For one thing it can't recognize them and most likely will give you problems
when you boot the system. For safety's sake the only partition I have listed
in my /etc/fstab is a volume called transfer. You must set the filetype to HFS
so Linux doesn't complain about the partitions if you mount them.
Ok, all partitions are defined, the /etc/fstab is setup correct, now you need
to change the permissions on the device files associated with the partitions.
This allows you to access the files as a normal user. (Thanks Kent, guess I
got too involved and forgot it should be treated like the CD). You will need
to reboot to ensure the system sees the new partitions and has the correct
/dev/hd?# device files. If you setup the partitions with fdisk you should know
the correct hd info to select the files. For the sake of example let's assume
the device is HDB and the partitions numbers are 1,2,3. From the shell,
cd /dev
chmod 666 /dev/hdb1
chmod 666 /dev/hdb2
chmod 666 /dev/hdb3
After you start KEGS you can format the Prodos partitions. If you use the
method mentioned earlier for installing GS/OS you will want to quit the
installer and run the advanced disk utilities on the utilities disk, then
quit back to the installer program or reboot.
Now I know this all sounds like a lot of trouble but (IMHO) it's worth it. For
one thing, KEGS will format a Prodos partition without problems (unlike an HD
file image) which makes a great boot system. And with GS/OS 6.01 you can access
large HFS volumes for storage and GS applications. You can also download from
the net to the HFS volume (if it's mounted) and avoid the trouble of copying
files to an image with to_pro. Not to mention the fact that the newest GNO
works with HFS drives.
One more note, if you use HFS you will need to patch the HFS fst. There is a
one byte bug which mis-calculates HFS block sizes and WILL trash your HFS
drive. The patch is at several places on the net or ask someone in one of
the comp.sys.apple2 news groups.
Miscellanea
-----------
To ease access to the KEGS binary, make an executable script which contains
any command line parms you need. Then put this script somewhere in the path
so you can execute it from any shell. Depending on the desktop you use you
may want to setup links for editing the disk_conf file also. With GNO/ME you
can launch KEGS without the shell but I don't recommend this since you won't
know what happened when it dies. With KDE you can set up the launcher to use
a shell, this is much better but until you have your setup stable you will
want to use a regular terminal so you can keep track of what's going on. Like
GNO/ME, the KDE shell will close as soon as KEGS quits with an error.
Thanks
------
I hope this info helps you enjoy KEGS. Many thanks to Kent for creating this
fine emulator and for putting up with me bugging him with 'bug' reports. Many
of these weren't actually bugs but were my own fault due to lack of knowledge
about *nix systems. But Kent was prompt in fixing the ones which truly were
bugs. Thanks to him I can now play my favorite game, Questron 2 (gs version)
which requires a player disk in slot 5. I know no other emulator which can
actually play this game.
Mike Thomas

41
README.mac Normal file
View File

@ -0,0 +1,41 @@
MAC OS X port of KEGS (KEGSMAC): http://kegs.sourceforge.net
-------------------------------------------------------------
There is a different port of KEGS to Mac OS X called KEGS-OSX.
You can get it from http://casags.net/.
This port is not leveraged from KEGS-OSX (which is based on SDL).
This is a Mac OS X Carbon port. It will not work on Mac OS 9.
Everything pretty much works, but 8-bit color doesn't work. Make sure your
Mac is set to Thousands or Millions of colors.
Usage:
-----
Like most other KEGS versions, KEGSMAC is usually run from a Terminal
window. Just type "./KEGSMAC.app/Contents/MacOS/KEGSMAC" in the directory
you installed/compiled it in. You need to have a ROM file (named
ROM, ROM.01, or ROM.03) and a config.kegs in the same directory or in your
home directory (read the README--these files are searched for in various
places).
KEGSMAC can also be run from the Finder, but if you do this, there
will be no debug window at all. This is not well tested, yet.
To quit, either click the window close box, or select Quit from the menu.
You can also middle-click (if you have a 3-button mouse) or
Shift-F6 to get the debugger in the terminal window, and then type "q".
Compile directions
------------------
In order to compile,
1) cd into the src/ directory
2) copy vars_mac to vars
3) run make
You can contact me at kadickey@alumni.princeton.edu

51
README.win32 Normal file
View File

@ -0,0 +1,51 @@
WIN32 port of KEGS (KEGSWIN)
----------------------------
There is a different port of KEGS by akilgard called KEGS32.
You can get it from http://www.geocities.com/akilgard/kegs32.
This port is leveraged from KEGS32, but mostly a rewrite (perhaps
for the worse). The joystick code was taken without too many
modifications.
This port is alpha quality. Seriously. Don't expect much.
This is a bare-bones Win32 port. It was compiled with Mingw2.0,
which you can download at: http://www.mingw.org/. I also had
previously installed cygwin at http://www.cygwin.com/. Installing
these two beasts is a bit of a pain, so I'll eventually write up
directions (I hope).
Sound works, the mouse works, and a joystick might work (ported
from KEGS32). The user-interface is just like every other KEGS
version (i.e., bad), so you can just read the standard README file.
Only tested on a 32-bit graphics display, although I think 16-bit and
24-bit will work. 8-bit definitely does not work. There are many
other bugs I just haven't had time to list yet.
Usage:
-----
Like most other KEGS versions, KEGSWIN must be run from a terminal
window (command.com is fine). Just type "KEGSWIN" in the directory
you installed/compiled it in. You need to have a ROM file (named
ROM, ROM.01, or ROM.03) and a kegs_conf in the same directory (or
read the README--these files are searched for in various places).
To quit, either click the close box, or force quit the application.
You can also middle-click (if you have a 3-button mouse) or
Shift-F6 to get the debugger in the terminal window, and then type "q".
Compile directions
------------------
In order to compile,
1) cd into the src/ directory
2) rm vars
3) ln -s vars_win32 vars
3) ./make_win
You can contact me at kadickey@alumni.princeton.edu

11
config.kegs Normal file
View File

@ -0,0 +1,11 @@
# KEGS configuration file version 0.80
s5d1 = XMAS_DEMO
s5d2 =
s6d1 = #dos33.dsk
s6d2 =
s7d1 = NUCLEUS03

BIN
kegswin.exe Executable file

Binary file not shown.

239
src/INTERNALS.iwm Normal file
View File

@ -0,0 +1,239 @@
KEGS's Apple //gs IWM emulation routines.
The IWM code does 5.25" and 3.5" reads & writes, and updates the Unix disk
image on writes. It is also nearly cycle-accurate--Let me know if you
have a program which can detect it's not a real Apple II. There are
a few 5.25" features missing (No 1/4 or 1/2 tracks, no support for Unix nibble
images, limited disk switching), but what's there is pretty accurate.
The low-level code support 1/4 and 1/2 tracks--it's the arm movement
and image-handling routines which don't. And lack of Unix nibble images
are also due to lack of higher-level routines to make those features work.
How my disk emulation works: The routines have a nibblized image of each
track of each drive (two 5.25" and two 3.5" drives are supported) in memory.
The nibble images are declared as arrays, but it could be made to use
more dynamic memory allocation.
Each track's data format is a series of two-byte pairs. The first byte
of the pair is the number of bits in this disk byte, and the second byte
is the value. So a size of 8 is normal. A size of 10 means that there
are 2 sync bits written before this byte on the disk. So for 5.25" disk
accesses, 40 cycles need to pass in the simulator before providing a
valid nibble. Partial nibbles are correctly formed if a read happens
too early (this actually makes things slower, but is required if you
want to make nibble copiers work). Similarly, writing to the disk
watches timing carefully to write out the correct number of bits per
disk byte. These routines will definitely test out your emulator's cycle
counting ability.
If a long delay occurs between a read (or a write) the routines skips
the correct number of bits to return the correctly formed disk byte.
After a long delay, for efficiency, I always return a full disk byte,
instead of a partial one, even if the timing would put it in the middle
of a disk byte.
The arm stepping is really lame. I will clean it up soon.
Smartport support is sufficient to claim that there are no smartport
devices. This is necessary since the ROM tries to see if there are
smartport devices at power-on.
I tested my 5.25" drive routines on EDD, which could correctly measure
drive speed and other disk factors. I also nibble-copied some disks,
which also worked fine. I tested the 3.5" routines using Copy II+,
which successfully nibble-copied several disks.
Code description:
Most code is in iwm.c, with some defines in iwm.h, and some stuff in
iwm_35_525.h.
Code only supports DOS3.3 ordered 5.25" images now, and ProDOS-ordered 3.5"
images. Well, the code supports ProDOS-order 5.25" also, but has no
mechanism to tell it an image is prodos-order yet. :-)
Iwm state is encoded in the Iwm structure.
drive525[2]: Disk structure for each 5.25" disk
drive35[2]: Disk structure for each 3.5" disk
smarport[32]: Disk structure for each "smartport" device emulated
via slot 7 (this code not included)
motor_on: True if IWM motor_on signal (c0e9) is asserted. Some
drive is on.
motor_off: True if motor has been turned off in software, but the
1 second timeout has not expired yet.
motor_on35: True if 3.5" motor is on (controlled differently than
5.25" c0e9).
motor_off_vbl_count: VBL count to turn motor off.
head35, step_direction35: 3.5" controls, useless.
iwm_phase[4]: Has '1' for each 5.25" phase that is on.
iwm_mode: IWM mode register.
drive_select: 0 = drive 1, 1 = drive 2.
q6, q7: IWM q6, q7 registers.
enable2: Smartport /ENABLE2 asserted.
reset: Smartport /RESET asserted.
previous_write_val: Partial write value.
previous_write_bits: How many bits are valid in previous_write_val.
Each disk (3.5" and 5.25") is encoded in the Disk struct:
fd: Unix file descriptor. If < 0, no disk.
name_ptr: Unix file name for this disk.
image_start: offset from beginning of file for this partition.
image_size: size of this partition.
smartport: 1 if this is a smartport image, 0 if it is 5.25" or 3.5"
disk_525: 1 if this is a 5.25" image, 0 if it is 3.5"
drive: 0 = drive 1, 1 = drive 2.
cur_qtr_track: Current qtr track. So track 1 == qtr_track 4.
For 3.5", cur_qtr_track encodes the side also, so track 3
side 1 would be qtr_track 7.
prodos_order: True if Unix image is ProDOS order.
vol_num: DOS3.3 volume number to use. Always 254.
write_prot: True if disk is write protected.
write_through_to_unix: True if writes should be passed through to
the unix image. If this is false, you can write
to the image in memory, but it won't get reflected
into the Unix file. If you create a non-DOS3.3
or ProDOS format image, it automatically sets this
false.
disk_dirty: Some track has dirty data that need to be flushed.
just_ejected: Ejection flag.
dcycs_last_read: Cycle count of last disk data register access.
last_phase: Phase number last accessed.
nib_pos: Nibble offset ptr--points to a byte.
num_tracks: Number of tracks: 140 for 5.25" and 160 for 3.5"
track[MAX_TRACKS]: nibble image of all possible tracks.
Each track is represented by the Track structure:
track_dirty: Contains data that needs to be written back to
the Unix image file.
overflow_size: Count of overflow bits, used in writing.
track_len: Number of nibbles on this track.
dsk: Handy pointer to parent Disk structure.
nib_area[]: ptr to memory containing pairs of [size,data],
encoding disk data bytes.
pad1: If the structure is 32 bytes long, some array
indexing is done better by my compiler.
Externally callable routines:
iwm_init(): Init various data structures at simulation start.
iwm_reset(): Called at Apple //gs reset time.
iwm_vbl_update(): Called every VBL (60 Hz) period. Used to turn motor
off, and flush out dirty data.
g_vbl_count is the count of VBL ticks (so it counts
at 60 times a second).
iwm_read_c0ec(double dcycs): Optimized routine to handle reading $C0EC
faster. Exactly the same as read_iwm(0xc, dcycs);
read_iwm(loc, dcycs):
Read from 0xc0e0 + loc. Loc is between 0x0 and 0xf.
Dcycs is an artifact from my simulator. Dcycs is a
double holding the number of Apple //gs cycles since the
emulator started. Dcycs always counts at 1.024MHz. If
you are running at 2.5MHz, it increments by 0.4 every
"cycle". This is a very convenient timing strategy. It
also allows emulating the delay caused by synchronizing
the fast part of a real Apple //gs with slow memory,
which means my emulator knows that reading softswitches
takes longer than reading fast memory.
write_iwm(int loc, int val, double dcycs):
Write to 0xc0e0 + loc. Just like read_iwm, but write "val" into
loc.
Tricky routines:
IWM_READ_ROUT(): called by read_iwm() if q6,q7 = 0,0.
This is actually in the file iwm_35_525.h. This is so I
write the basic code once for 5.25" and 3.5" disk reads,
but then include the file with some macros set to create
the correct function optimized for 5.25" or 3.5"
accesses. The function for 5.25" is called
iwm_read_data_525, and iwm_read_data_35 for 3.5".
Returns next disk byte.
Takes three arguments: ptr to the Disk structure for
the active drive, fast_disk_emul, and dcycs. dcycs is
so that it can see how many cycles have passed since
the last read (stored in dsk->dcycs_last_read).
16.0 dcycs need to pass for an 8 bit nibble for 3.5"
accesses, and 32.0 dcycs for an 8 bit nibble for 5.25".
Fast_disk_emul == 1 says don't mess around with accuracy,
and always return the next fully-formed nibble.
There is a lot of complexity in this routine. All IWM
routines must skip over nibbles (stored as byte pairs in
dsk->nib_area[]) which have a size of 0 (special padding
trick, described later). It then determines how much
time has passed, and so how many bits are valid.
If too many bits have gone by (11 cycs is almost 3 5.25"
bit times, which is about the nibble valid time in
the Apple //gs IWM hardware latch), it tries to skip
to the correct position.
Handles IWM latch mode for 3.5" or 5.25" accesses. If a
partial read is indicated, it ensures that the high bit
is clear by shifting the nibble to the right
appropriately. Again, nib_area[] is an array of bytes,
which are treated as pairs. Byte 0 = size, byte 1 =
disk nibble.
IWM_WRITE_ROUT(): called by write_iwm() if q6,q7 = 1,1.
Similar to above. Handles async and sync mode writes.
Handles partial writes. Handles the ROM writing
0xff, 0x3f, 0xcf, 0xf3, 0xfc to be four 10-bit nibbles.
Routine disk_nib_out(dsk, val, bits_read) does the
actual work of merging the bits into the track image.
disk_nib_out(): called by IWM_WRITE_ROUTE() and iwm_nibblize_track_*().
Writes byte into nib_area[]. If size > 10, makes it 10.
If high order bit not set, it sets it (makes certain routines
in EDD happy).
overflow_size:
Writing to the disk creates some problems. I need to
maintain 2 things at all times on the track:
1) Constant number of bits for the entire track.
2) know where each synchronized byte starts on
the track.
If the track was just stored as raw bits, then correctly
simulating a delay of 300*4 cycles is tough, since it has to
be done by reading through all 300 bits on the track,
so that we keep in sync with where bytes really start.
But if you just store the bytes themselves, then sync
bytes look like every other byte. And if you now add
the size field, you have a situation where a track could
gain or lose bits when rewritten. Here's the case:
Assume the track contains: 10,ff 10,ff 10,ff 10,ff.
(That is 4 self-sync disk bytes of 10 bits each).
If we rewrite that area of the track with 'D5 AA 96 FF',
where each byte is 8 bits, we would have:
8,D5 8,AA, 8,96, 8,FF.
Looks OK, but we just lost 8 bits! The original 4 nibbles
were using 40 bits of space on the disk. Our new 4 nibbles
are using 32 bits. 8 bits are lost.
Solution: log these missing bits via overflow_size.
When writing, if overflow_size gets > 8, force out a 0,0
nibble. So sync bytes get written as:
10,FF 10,FF 10,FF 10,FF 0,0 10,FF 10,FF 10,FF 10,FF, 0,0.
So when they get re-written with 8,xx, we don't lose any
bytes on the disk.
Unfortunately, it doesn't quite work that easily, and bits
can still be lost when sync fields are partially overwritten.
This happens when all the 0,0's end up in a place on the
track where few overwrites occur, but other sync bytes
are being turned into 8,xx. So overflow_size goes negative,
saying we've got too much on the track.
The code prints an error when it gains more than 64 bits.
If someone can come up with a better scheme, I'd love to
hear it. A partial solution would be to have a routine
re-space the track to spread the needed 0,0's around
a little better when overflow_size gets too negative.
In iwm_nibblize_track_35(), the comments with hex numbers correspond
to the ROM 01 addresses which I disassembled to determine the checksum
algorithm. The code is not well written--it's basically hand-translated
65816 assembly code. I'll clean it up someday.
Much of the code is not well-optimized. I'll get to that someday, but
the speed has been adequate for me so far.

96
src/INTERNALS.overview Normal file
View File

@ -0,0 +1,96 @@
KEGS Internals
--------------
The INTERNALS* files describe the internal structure of KEGS and how
it works. It is meant to be useful to those who would attempt to
port KEGS to non-Unix platforms, or just want to know how KEGS works.
Documentation files:
--------------------
INTERNALS.overview: Provides overview of KEGS's file structure
KEGS SOURCE FILES:
-----------------
adb.c: ADB emulation routines. This includes keyboard, mouse, and
joystick.
adb.h: Defines for ADB routines.
clock.c: Clock, BRAM, and some timing routines.
compile_time.c: Trick file to put the time you compiled in g_compile_time[].
defc.h: Global defines included by all .c files. Useful trick
to avoid complex multi-level include problems.
defs.h: Global defines included by all .s files (assembly language).
defcomm.h: Global defines included by all files (must be assembly and
C safe, such as #defines).
defs_instr.h: C and assembly definitions for various addressing modes
and for some repeated instructions (like LDA, STA, etc).
dis.c: Disassembler and debugger interface. The debugger interface
is similar to the Apple // monitor, but has many
more commands.
disas.h: Tables for disassembling 65816 instructions. Not very
efficient, but it works.
engine_c.c: C main instruction dispatch loop.
engine_s.s: Assembly main instruction dispatch loop.
instable.h: Instruction table. It is C and assembly-safe through
the make_inst script. make_inst turns instable.h into
8inst_c and 16inst_c, which are both valid C code.
iwm.c: IWM routines for 5.25" and 3.5" disks. See INTERNALS.iwm
iwm.h: IWM defines
iwm_35_525.h: File for reading and writing a disk byte, which is included
in iwm.c twice, once for 5.25" and again for 3.5".
Forcing out compile-time constants this way makes it
faster.
moremem.c: Awful name--this file contains the page table change
routines (fixup_*) and io_read() and io_write() to
emulate all $C000 I/O accesses.
op_routs.h: More macros for 65816 emulation.
protos.h: Prototypes for all C functions. Auto-generated through
the "cproto" program (not included).
protos_xdriver.h: Prototypes for functions in xdriver.c.
scc.c: Serial chip emulation.
scc_driver.h: Unix-specific socket routines, stubbed out if you're not
on Linux or HP-UX.
scc.h: Defines for scc.c.
sim65816.c: main() is here along with many other housekeeping
functions, such as events, and interrupts.
The main loop of KEGS is run_prog().
size_tab.h: Used by assembly for a jump table (make_size script
turns it into 8size_s and 16size_s) and by both C and
assembly to get the size of instructions.
smartport.c: Smartport emulation, emulates s7dx devices.
sound.c: Sound emulation. Builds sound samples, but does not
send sound to output device.
sound.h: Header file for sound.c.
sound_driver.c: Sound driver routines. Takes samples generated by sound.c
and sends them to the correct output device. Supports
HP Alib, HP /dev/audio, and Linux /dev/dsp currently.
superhires.h: "macro" routine used by video.c so that I could write
one generic superhires routine, but then include it
multiple times to get optimized 320 vs 640 mode routines.
video.c: Display routines. Builds 8 bit video buffers in a
device independent way. Functions here know nothing
about X windows.
xdriver.c: X windows driver routines. Takes buffers from video.c
and sends them on to X windows. Get keypresses from
X and sends them to adb.c.
Porting Advice:
--------------
To a non-unix platform, disabling scc emulation would be a good start.
Just make sure you get the dummy stub routines in scc_driver.h.
If you don't have gettimeofday(), clock.c will need to modified with
whatever timer facilities are available. A high-resolution clock works
best, but even a low-resolution clock will work.
Modify sound_driver.c to get it to compile, if necessary. Always run with
"-audio 0" to turn audio off. No routines in sound_driver.c will get
called if you run with -audio 0.
Replace xdriver.c with new routines for whatever platform you are porting to.
See INTERNALS.xdriver for more information.

148
src/INTERNALS.xdriver Normal file
View File

@ -0,0 +1,148 @@
xdriver.c contains the routines for interfacing to X windows. The rest
of KEGS interacts with X windows only through xdriver.c routines.
Externally called routines are:
show_xcolor_array(): Debug routine, it does not need to do anything.
dev_video_init(): Called at startup, it should open up the
window and do other initialization.
update_physical_colormap(): Updates the X windows palette with the colors
from xcolor_a2vid_array[], which is maintained by
other xdriver routines.
update_status_line(): Call to update the internal array of chars
representing the status lines at the bottom of
the window. Does not draw the chars to the screen.
xdriver_end(): Shutdown routine
check_input_events(): Called up to 60 times a second (see video_update() in
video.c) to handle any X window events and get
keypresses.
On a mouse press, call update_mouse() with the
new x, y coordinates, and the status of the mouse
button.
If g_warp_pointer is set, constrain mouse within
the window.
On keypress, calls handle_keysym().
handle_keysym(): Takes X keysym, and converts to the appropriate
a2code using the a2_key_to_xsym[] lookup table.
The a2codes are the Apple // ADB keycodes.
Special work is done to handle shift and control
properly since Apple only has one keycode for both
shift and control keys. Then call
adb_physical_key_update() with the a2 keycode and
is_up = 1 if keyup, 0 = if key down.
In addition, this routine handles all the Function
keys doing special actions, which should be easy to
port.
x_refresh_ximage(): Redraws the window using the a2_line_* arrays.
Described in more detail below.
update_color_array(): Interface to the color map. Sets color[col_num]
of the internal colormap array to a2_color.
a2_color is the 12 bit apple color of the form:
(red << 8) + (green << 4) + (blue).
There are 16 palettes of 16 colors each, managed as
one 256-color colormap. See discussion of
g_a2vid_palette below.
x_auto_repeat_on(): The X routines turn off key repeat when the cursor
enters the graphics window automatically, and turn
it back on when the cursor leaves. But if the
debugger gets control due to a breakpoint, keyrepeat
would be left off. So the debugger calls this
routine to make sure key repeat is back on.
redraw_status_lines(): Draw the status lines from the g_status_buf[][] array
to the graphics window.
Externally referenced data:
g_use_shmem: Set by main() to enable/disable MIT-SHM for X.
Also used by sound routines to auto-turn-off sound
if not using MIT-SHM.
Bytes representing screen data:
byte *data_text[2]: Array of bytes for the lores and text pages 1 and 2.
Just 400*640 bytes.
byte *data_hires[2]: Array of bytes for the hires pages 1 and 2.
byte *data_superhires: Array of bytes for superhires screen.
byte *data_border_sides: Array of bytes representing the border sides.
Basically just A2_WINDOW_HEIGHT*EFF_BORDER_WIDTH bytes.
byte *data_border_special: Top and bottom border bytes.
(X_A2_WINDOW_HEIGHT - A2_WINDOW_HEIGHT + 2*8) *
(X_A2_WINDOW_WIDTH) bytes.
Handles used for X windows drawing:
XImage *ximage_hires[2]: Opaque handle to XImage object for hires page 1 and
page 2.
XImage *ximage_text[2]: Text pages 1 and 2.
XImage *ximage_superhires: Superhires graphics XImage
XImage *ximage_border_special: Top and bottom border XImage.
XImage *ximage_border_sides: Left and right sides (only one copy, it is
drawn at two different locations to be both sides).
Basic operation of xdriver:
--------------------------
X windows can push arrays of bytes to the screen through structures
called XImages. An XImage is a structure describing an offscreen bitmap.
For efficiency of page flipping, KEGS maintains separate bitmaps for the
two lores/text screens, the two hires screens, and the superhires screen.
It also maintains bitmaps for the border. For MIT-SHM to work, X
requires a unique XImage for each bitmap, and the bitmap must be allocated
within xdriver.c since it must be obtained through an shmat() call.
The X code also has non-MIT-SHM code which allocates the data_* buffers
just through malloc().
All bitmaps are 8-bits of Pseudo-color. The color arrays are managed
through the update_color_array() and update_physical_colormap() routines.
KEGS manages all 256 colors in the colormap as 16 palettes of 16 colors.
One of the palettes is reserved for the 16 lores colors, and is
indicated by the variable g_a2vid_palette. It defaults to 0xe.
Update_color_array() is called to update superhires colormap entries.
Update_color_array must not update colors corresponding to g_a2vid_palette.
Update_physical_colormap() pushes the color array managed by
update_color_array() to the screen, but first forces the lores colors into
the g_a2vid_palette palette. g_installed_full_superhires_colormap is
always false in KEGS for now. video.c calls update_color_array and changes
g_a2vid_palette. No xdriver routines gets notified when g_a2vid_palette
changes, so update_physical_colormap must handle the case where
g_a2vid_palette might have changed since it was last called.
x_redraw_ximage():
Routines in video.c are free to draw into the corresponding data_*
arrays to change any byte at any time. video.c manages remembering
which lines need to be redrawn and which parts of the screen are in
which video mode via the a2_line_* arrays.
KEGS divides the video screen up into 25 groups, corresponding to each
text line. Each of these groups consists of 16 sublines. 25*8 = 400 lines.
(video.c has already doubled the vertical resolution in all video modes).
KEGS can allow any group to be from any of the five screens it manages:
The two text/lores pages, the two hires pages, and the superhires screen.
For each group, KEGS keeps track of what part of it needs to be redrawn.
g_a2_screen_buffer_changed has a bit set for each group which has changed
since the last call to x_redraw_ximage(). The rightmost bit (bit 0)
corresponds to group 0. If g_a2_screen_buffer_changed == 0, no groups
need to be redrawn. x_redraw_ximage clears out g_a2_screen_buffer_changed
after drawing the screen.
For each group, a2_line_left_edge[] and a2_line_right_edge give the pixel
offsets of what should be redrawn. a2_line_xim[] gives the ximage handle
of what needs to be redrawn. KEGS always redraws 8 verticals of a group.
g_full_refresh_needed also has one bit set in it for each group, which
indicates overriding the a2_line_*_edge functions and redraw from 0 to
640 pixels of each group that needs to be redrawn. x_redraw_ximage()
interprets this information now using a simple algorithm: Skip over
groups which have not changed (using g_a2_screen_buffer_changed).
Save the ximage of this group, the left pixel and the right pixel.
Continue with the next group if it has changed. Widen the pixel region
and keep sucking up new groups to the same ximage. At group 25, or
when the ximage changes, call x_refresh_lines to redraw this large
rectangle from this ximage. x_refresh_lines() knows the ximage
corresponding to the border for the last group has to be handled
specially since the border group is not 640*400 pixels like the others.
Other porting info:
a2_key_to_xsym[][3] contains the mapping function from X keysyms to
a2 keycodes. The first element is the a2 keycode, the second element
is the unshifted X keysym, and the third element is the shifted keysym.
A port must make the conversion to a2 keycodes, and provide up and
down events.

22
src/Info.plist Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>KEGSMAC</string>
<key>CFBundleIconFile</key>
<string>kegsicon.icns</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
</plist>

BIN
src/InfoPlist.strings Normal file

Binary file not shown.

123
src/Makefile Normal file
View File

@ -0,0 +1,123 @@
# $Id: release_makefile_base,v 1.15 2003/11/21 20:00:42 kentd Exp $
OBJECTS1 = adb.o clock.o config.o dis.o engine_c.o scc.o iwm.o \
joystick_driver.o moremem.o paddles.o sim65816.o smartport.o \
sound.o sound_driver.o video.o scc_socket_driver.o scc_windriver.o \
scc_macdriver.o
include vars
.SUFFIXES: .dep .proto
AS = $(CC)
XLIBS = -L/usr/X11R6/lib
PERL = perl
all: $(TARGET)
specials: 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s
specials_clean:
rm -f 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s
# Mac builds:
kegsmac: $(OBJECTS) compile_time.o
$(CC) $(CCOPTS) $(LDOPTS) -arch ppc $(OBJECTS) compile_time.o $(LDFLAGS) -o kegsmac $(EXTRA_LIBS) -prebind -framework Carbon
mkdir -p ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib
mkdir -p ../KEGSMAC.app/Contents/MacOS
mv kegsmac ../KEGSMAC.app/Contents/MacOS/KEGSMAC
echo "APPL????" > ../KEGSMAC.app/Contents/PkgInfo
cp -f Info.plist ../KEGSMAC.app/Contents/
cp -f InfoPlist.strings ../KEGSMAC.app/Contents/Resources/English.lproj/
cp -f info.nib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib
cp -f classes.nib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib
cp -f objects.xib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib
cp -f kegsicon.icns ../KEGSMAC.app/Contents/Resources/
touch '../KEGSMAC.app/Icon?'
# Linux for X builds:
xkegs: $(OBJECTS) compile_time.o
$(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(XLIBS) $(EXTRA_LIBS) -lX11
mv xkegs ..
# Cygwin for X builds:
kegs.exe: $(OBJECTS) compile_time.o
$(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(XLIBS) $(EXTRA_LIBS) -lXext -lX11 -lm
mv kegs.exe ..
# Mingw32 (native windows) builds:
kegswin.exe: $(OBJECTS) compile_time.o
$(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32
mv $(NAME)$(SUFFIX) ..
8inst_c.h: instable.h
$(PERL) make_inst c 8 instable.h > 8inst_c.h
16inst_c.h: instable.h
$(PERL) make_inst c 16 instable.h > 16inst_c.h
size_c.h: size_tab.h
$(PERL) make_size c size_tab.h > size_c.h
engine_c.o: 8inst_c.h 16inst_c.h size_c.h
8inst_s.h: instable.h
$(PERL) make_inst s 8 instable.h > 8inst_s.h
16inst_s.h: instable.h
$(PERL) make_inst s 16 instable.h > 16inst_s.h
size_s.h: size_tab.h
$(PERL) make_size s size_tab.h > size_s.h
8size_s.h: size_tab.h
$(PERL) make_size 8 size_tab.h > 8size_s.h
16size_s.h: size_tab.h
$(PERL) make_size 16 size_tab.h > 16size_s.h
engine_s.o: 8inst_s.h 16inst_s.h 8size_s.h 16size_s.h size_s.h
.s.o:
$(AS) -c $(OPTS) -I. $*.s
.c.o:
$(CC) $(CCOPTS) $(XOPTS) -c $(OPTS) -I. $*.c
partls: partls.c
cc $(CCOPTS) $(XOPTS) $(OPTS) -o partls partls.c
to_pro: prodos.h prodos_protos.h to_pro.c
cc $(CCOPTS) $(XOPTS) $(OPTS) -o to_pro to_pro.c
compile_time.o: $(OBJECTS)
# dependency stuff
adb.o: adb.c adb.h defc.h defcomm.h iwm.h protos.h
engine_c.o: engine_c.c defc.h defcomm.h iwm.h protos.h protos_engine_c.h size_c.h op_routs.h defs_instr.h 8inst_c.h 16inst_c.h
clock.o: clock.c defc.h defcomm.h iwm.h protos.h
compile_time.o: compile_time.c
config.o: config.c defc.h defcomm.h iwm.h protos.h config.h
dis.o: dis.c defc.h defcomm.h iwm.h protos.h disas.h
scc.o: scc.c defc.h defcomm.h iwm.h protos.h scc.h
scc_socket_driver.o: scc_socket_driver.c defc.h defcomm.h iwm.h protos.h scc.h
scc_windriver.o: scc_windriver.c defc.h defcomm.h iwm.h protos.h scc.h
scc_macdriver.o: scc_macdriver.c defc.h defcomm.h iwm.h protos.h scc.h
iwm.o: iwm.c defc.h defcomm.h iwm.h protos.h iwm_35_525.h
joystick_driver.o: joystick_driver.c defc.h defcomm.h iwm.h protos.h
moremem.o: moremem.c defc.h defcomm.h iwm.h protos.h
paddles.o: paddles.c defc.h defcomm.h iwm.h protos.h
sim65816.o: sim65816.c defc.h defcomm.h iwm.h protos.h
smartport.o: smartport.c defc.h defcomm.h iwm.h protos.h
sound.o: sound.c defc.h defcomm.h iwm.h protos.h sound.h
sound_driver.o: sound_driver.c defc.h defcomm.h iwm.h protos.h sound.h
video.o: video.c defc.h defcomm.h iwm.h protos.h superhires.h kegsfont.h
macdriver.o: macdriver.c defc.h defcomm.h iwm.h protos.h protos_macdriver.h
macsnd_driver.o: macsnd_driver.c defc.h defcomm.h iwm.h protos.h sound.h
windriver.o: windriver.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h
win32snd_driver.o: win32snd_driver.c defc.h defcomm.h iwm.h protos.h sound.h

1760
src/adb.c Normal file

File diff suppressed because it is too large Load Diff

160
src/adb.h Normal file
View File

@ -0,0 +1,160 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_adb_h[] = "@(#)$KmKId: adb.h,v 1.9 2002-11-19 03:10:38-05 kadickey Exp $";
#include "defc.h"
/* Format: a2code, ascii if no shift, ascii if shift, ascii if ctl */
const int a2_key_to_ascii[][4] = {
{ 0x00, 'a', 'A', 0x01 },
{ 0x01, 's', 'S', 0x13 },
{ 0x02, 'd', 'D', 0x04 },
{ 0x03, 'f', 'F', 0x06 },
{ 0x04, 'h', 'H', 0x08 },
{ 0x05, 'g', 'G', 0x07 },
{ 0x06, 'z', 'Z', 0x1a },
{ 0x07, 'x', 'X', 0x18 },
{ 0x08, 'c', 'C', 0x03 },
{ 0x09, 'v', 'V', 0x16 },
{ 0x0a, -1, -1, -1 },
{ 0x0b, 'b', 'B', 0x02 },
{ 0x0c, 'q', 'Q', 0x11 },
{ 0x0d, 'w', 'W', 0x17 },
{ 0x0e, 'e', 'E', 0x05 },
{ 0x0f, 'r', 'R', 0x12 },
{ 0x10, 'y', 'Y', 0x19 },
{ 0x11, 't', 'T', 0x14 },
{ 0x12, '1', '!', -1 },
{ 0x13, '2', '@', 0x00 },
{ 0x14, '3', '#', -1 },
{ 0x15, '4', '$', -1 },
{ 0x16, '6', '^', 0x1e },
{ 0x17, '5', '%', -1 },
{ 0x18, '=', '+', -1 },
{ 0x19, '9', '(', -1 },
{ 0x1a, '7', '&', -1 },
{ 0x1b, '-', '_', 0x1f },
{ 0x1c, '8', '*', -1 },
{ 0x1d, '0', ')', -1 },
{ 0x1e, ']', '}', 0x1d },
{ 0x1f, 'o', 'O', 0x0f },
{ 0x20, 'u', 'U', 0x15 },
{ 0x21, '[', '{', 0x1b },
{ 0x22, 'i', 'I', 0x09 },
{ 0x23, 'p', 'P', 0x10 },
{ 0x24, 0x0d, 0x0d, -1 }, /* return */
{ 0x25, 'l', 'L', 0x0c },
{ 0x26, 'j', 'J', 0x0a },
{ 0x27, 0x27, '"', -1 }, /* single quote */
{ 0x28, 'k', 'K', 0x0b },
{ 0x29, ';', ':', -1 },
{ 0x2a, 0x5c, '|', 0x1c }, /* \, | */
{ 0x2b, ',', '<', -1 },
{ 0x2c, '/', '?', 0x7f },
{ 0x2d, 'n', 'N', 0x0e },
{ 0x2e, 'm', 'M', 0x0d },
{ 0x2f, '.', '>', -1 },
{ 0x30, 0x09, 0x09, -1 }, /* tab */
{ 0x31, ' ', ' ', -1 },
{ 0x32, '`', '~', -1 },
{ 0x33, 0x7f, 0x7f, -1 }, /* Delete */
{ 0x34, -1, -1, -1 },
{ 0x35, 0x1b, 0x1b, -1 }, /* Esc */
{ 0x36, 0x0200, 0x0200, -1 }, /* control */
{ 0x37, 0x8000, 0x8000, -1 }, /* Command */
{ 0x38, 0x0100, 0x0100, -1 }, /* shift */
{ 0x39, 0x0400, 0x0400, -1 }, /* caps lock */
{ 0x3a, 0x4000, 0x4000, -1 }, /* Option */
{ 0x3b, 0x08, 0x08, -1 }, /* left */
{ 0x3c, 0x15, 0x15, -1 }, /* right */
{ 0x3d, 0x0a, 0x0a, -1 }, /* down */
{ 0x3e, 0x0b, 0x0b, -1 }, /* up arrow */
{ 0x3f, -1, -1, -1 },
{ 0x40, -1, -1, -1 },
{ 0x41, 0x102e, 0x102e, -1 }, /* keypad . */
{ 0x42, -1, -1, -1 },
{ 0x43, 0x102a, 0x102a, -1 }, /* keypad * */
{ 0x44, -1, -1, -1 },
{ 0x45, 0x102b, 0x102b, -1 }, /* keypad + */
{ 0x46, -1, -1, -1 },
{ 0x47, 0x1018, 0x1018, -1 }, /* keypad Clear */
{ 0x48, -1, -1, -1 },
{ 0x49, -1, -1, -1 },
{ 0x4a, -1, -1, -1 },
{ 0x4b, 0x102f, 0x102f, -1 }, /* keypad / */
{ 0x4c, 0x100d, 0x100d, -1 }, /* keypad enter */
{ 0x4d, -1, -1, -1 },
{ 0x4e, 0x102d, 0x102d, -1 }, /* keypad - */
{ 0x4f, -1, -1, -1 },
{ 0x50, -1, -1, -1 },
{ 0x51, 0x103d, 0x103d, -1 }, /* keypad = */
{ 0x52, 0x1030, 0x1030, -1 }, /* keypad 0 */
{ 0x53, 0x1031, 0x1031, -1 }, /* keypad 1 */
{ 0x54, 0x1032, 0x1032, -1 }, /* keypad 2 */
{ 0x55, 0x1033, 0x1033, -1 }, /* keypad 3 */
{ 0x56, 0x1034, 0x1034, -1 }, /* keypad 4 */
{ 0x57, 0x1035, 0x1035, -1 }, /* keypad 5 */
{ 0x58, 0x1036, 0x1036, -1 }, /* keypad 6 */
{ 0x59, 0x1037, 0x1037, -1 }, /* keypad 7 */
{ 0x5a, -1, -1, -1 },
{ 0x5b, 0x1038, 0x1038, -1 }, /* keypad 8 */
{ 0x5c, 0x1039, 0x1039, -1 }, /* keypad 9 */
{ 0x5d, -1, -1, -1 },
{ 0x5e, -1, -1, -1 },
{ 0x5f, -1, -1, -1 },
{ 0x60, 0x8005, 0x1060, -1 }, /* F5 */
{ 0x61, 0x8006, 0x1061, -1 }, /* F6 */
{ 0x62, 0x8007, 0x1062, -1 }, /* F7 */
{ 0x63, 0x8003, 0x1063, -1 }, /* F3 */
{ 0x64, 0x8008, 0x1064, -1 }, /* F8 */
{ 0x65, 0x8009, 0x1065, -1 }, /* F9 */
{ 0x66, -1, -1, -1 },
{ 0x67, 0x800b, 0x1067, -1 }, /* F11 */
{ 0x68, -1, -1, -1 },
{ 0x69, 0x800d, 0x1069, -1 }, /* F13 */
{ 0x6a, -1, -1, -1 },
{ 0x6b, 0x800e, 0x106b, -1 }, /* F14 */
{ 0x6c, -1, -1, -1 },
{ 0x6d, 0x800a, 0x106d, -1 }, /* F10 */
{ 0x6e, -1, -1, -1 },
{ 0x6f, 0x800c, 0x106f, -1 }, /* F12 */
{ 0x70, -1, -1, -1 },
{ 0x71, 0x800f, 0x1071, -1 }, /* F15 */
{ 0x72, 0x1072, 0x1072, -1 }, /* Help, insert */
{ 0x73, 0x1073, 0x1073, -1 }, /* Home */
{ 0x74, 0x1074, 0x1074, -1 }, /* Page up */
{ 0x75, 0x1075, 0x1075, -1 }, /* keypad delete */
{ 0x76, 0x8004, 0x1076, -1 }, /* F4 */
{ 0x77, 0x1077, 0x1077, -1 }, /* keypad end */
{ 0x78, 0x8002, 0x1078, -1 }, /* F2 */
{ 0x79, 0x1079, 0x1079, -1 }, /* keypad page down */
{ 0x7a, 0x8001, 0x107a, -1 }, /* F1 */
{ 0x7b, 0x08, 0x08, -1 }, /* left */ /* remapped to 0x3b */
{ 0x7c, 0x15, 0x15, -1 }, /* right */ /* remapped to 0x3c */
{ 0x7d, 0x0a, 0x0a, -1 }, /* down */ /* remapped to 0x3d */
{ 0x7e, 0x0b, 0x0b, -1 }, /* up arrow */ /* remapped to 0x3e */
{ 0x7f, -1, -1, -1 }, /* Reset */
};

4
src/classes.nib generated Executable file
View File

@ -0,0 +1,4 @@
{
IBClasses = ();
IBVersion = 1;
}

392
src/clock.c Normal file
View File

@ -0,0 +1,392 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_clock_c[] = "@(#)$KmKId: clock.c,v 1.29 2003-10-17 15:07:35-04 kentd Exp $";
#include "defc.h"
#include <time.h>
#ifdef _WIN32
# include <windows.h>
# include <mmsystem.h>
#else
# include <sys/time.h>
#endif
extern int Verbose;
extern int g_vbl_count;
extern int g_rom_version;
extern int g_config_kegs_update_needed;
#define CLK_IDLE 1
#define CLK_TIME 2
#define CLK_INTERNAL 3
#define CLK_BRAM1 4
#define CLK_BRAM2 5
int g_clk_mode = CLK_IDLE;
int g_clk_read = 0;
int g_clk_reg1 = 0;
word32 c033_data = 0;
word32 c034_val = 0;
byte g_bram[2][256];
byte *g_bram_ptr = &(g_bram[0][0]);
word32 g_clk_cur_time = 0xa0000000;
int g_clk_next_vbl_update = 0;
double
get_dtime()
{
#ifndef _WIN32
struct timeval tp1;
double dsec;
double dusec;
#endif
double dtime;
/* Routine used to return actual system time as a double */
/* No routine cares about the absolute value, only deltas--maybe */
/* take advantage of that in future to increase usec accuracy */
#ifdef _WIN32
dtime = timeGetTime() / 1000.0;
#else
# ifdef SOLARIS
gettimeofday(&tp1, (void *)0);
# else
gettimeofday(&tp1, (struct timezone *)0);
# endif
dsec = (double)tp1.tv_sec;
dusec = (double)tp1.tv_usec;
dtime = dsec + (dusec / (1000.0 * 1000.0));
#endif
return dtime;
}
int
micro_sleep(double dtime)
{
#ifndef _WIN32
struct timeval Timer;
int ret;
#endif
if(dtime <= 0.0) {
return 0;
}
if(dtime >= 1.0) {
halt_printf("micro_sleep called with %f!!\n", dtime);
return -1;
}
#if 0
printf("usleep: %f\n", dtime);
#endif
#ifdef _WIN32
Sleep(dtime * 1000);
#else
Timer.tv_sec = 0;
Timer.tv_usec = (dtime * 1000000.0);
if( (ret = select(0, 0, 0, 0, &Timer)) < 0) {
fprintf(stderr, "micro_sleep (select) ret: %d, errno: %d\n",
ret, errno);
return -1;
}
#endif
return 0;
}
void
clk_bram_zero()
{
int i, j;
/* zero out all bram */
for(i = 0; i < 2; i++) {
for(j = 0; j < 256; j++) {
g_bram[i][j] = 0;
}
}
g_bram_ptr = &(g_bram[0][0]);
}
void
clk_bram_set(int bram_num, int offset, int val)
{
g_bram[bram_num][offset] = val;
}
void
clk_setup_bram_version()
{
if(g_rom_version < 3) {
g_bram_ptr = (&g_bram[0][0]); // ROM 01
} else {
g_bram_ptr = (&g_bram[1][0]); // ROM 03
}
}
void
clk_write_bram(FILE *fconf)
{
int i, j, k;
for(i = 0; i < 2; i++) {
fprintf(fconf, "\n");
for(j = 0; j < 256; j += 16) {
fprintf(fconf, "bram%d[%02x] =", 2*i + 1, j);
for(k = 0; k < 16; k++) {
fprintf(fconf, " %02x", g_bram[i][j+k]);
}
fprintf(fconf, "\n");
}
}
}
void
update_cur_time()
{
struct tm *tm_ptr;
time_t cur_time;
unsigned int secs, secs2;
cur_time = time(0);
/* Figure out the timezone (effectively) by diffing two times. */
/* this is probably not right for a few hours around daylight savings*/
/* time transition */
secs2 = mktime(gmtime(&cur_time));
tm_ptr = localtime(&cur_time);
secs = mktime(tm_ptr);
secs = (unsigned int)cur_time - (secs2 - secs);
if(tm_ptr->tm_isdst) {
/* adjust for daylight savings time */
secs += 3600;
}
/* add in secs to make date based on Apple Jan 1, 1904 instead of */
/* Unix's Jan 1, 1970 */
/* So add in 66 years and 17 leap year days (1904 is a leap year) */
secs += ((66*365) + 17) * (24*3600);
g_clk_cur_time = secs;
clk_printf("Update g_clk_cur_time to %08x\n", g_clk_cur_time);
g_clk_next_vbl_update = g_vbl_count + 5;
}
/* clock_update called by sim65816 every VBL */
void
clock_update()
{
/* Nothing to do */
}
void
clock_update_if_needed()
{
int diff;
diff = g_clk_next_vbl_update - g_vbl_count;
if(diff < 0 || diff > 60) {
/* Been a while, re-read the clock */
update_cur_time();
}
}
word32
clock_read_c033()
{
return c033_data;
}
word32
clock_read_c034()
{
return c034_val;
}
void
clock_write_c033(word32 val)
{
c033_data = val;
}
void
clock_write_c034(word32 val)
{
c034_val = val & 0x7f;
if((val & 0x80) != 0) {
if((val & 0x20) == 0) {
printf("c034 write not last = 1\n");
/* set_halt(1); */
}
do_clock_data();
}
}
void
do_clock_data()
{
word32 mask;
int read;
int op;
clk_printf("In do_clock_data, g_clk_mode: %02x\n", g_clk_mode);
read = c034_val & 0x40;
switch(g_clk_mode) {
case CLK_IDLE:
g_clk_read = (c033_data >> 7) & 1;
g_clk_reg1 = (c033_data >> 2) & 3;
op = (c033_data >> 4) & 7;
if(!read) {
/* write */
switch(op) {
case 0x0: /* Read/write seconds register */
g_clk_mode = CLK_TIME;
clock_update_if_needed();
break;
case 0x3: /* internal registers */
g_clk_mode = CLK_INTERNAL;
if(g_clk_reg1 & 0x2) {
/* extend BRAM read */
g_clk_mode = CLK_BRAM2;
g_clk_reg1 = (c033_data & 7) << 5;
}
break;
case 0x2: /* read/write ram 0x10-0x13 */
g_clk_mode = CLK_BRAM1;
g_clk_reg1 += 0x10;
break;
case 0x4: /* read/write ram 0x00-0x0f */
case 0x5: case 0x6: case 0x7:
g_clk_mode = CLK_BRAM1;
g_clk_reg1 = (c033_data >> 2) & 0xf;
break;
default:
halt_printf("Bad c033_data in CLK_IDLE: %02x\n",
c033_data);
}
} else {
printf("clk read from IDLE mode!\n");
/* set_halt(1); */
g_clk_mode = CLK_IDLE;
}
break;
case CLK_BRAM2:
if(!read) {
/* get more bits of bram addr */
if((c033_data & 0x83) == 0x00) {
/* more address bits */
g_clk_reg1 |= ((c033_data >> 2) & 0x1f);
g_clk_mode = CLK_BRAM1;
} else {
halt_printf("CLK_BRAM2: c033_data: %02x!\n",
c033_data);
g_clk_mode = CLK_IDLE;
}
} else {
halt_printf("CLK_BRAM2: clock read!\n");
g_clk_mode = CLK_IDLE;
}
break;
case CLK_BRAM1:
/* access battery ram addr g_clk_reg1 */
if(read) {
if(g_clk_read) {
/* Yup, read */
c033_data = g_bram_ptr[g_clk_reg1];
clk_printf("Reading BRAM loc %02x: %02x\n",
g_clk_reg1, c033_data);
} else {
halt_printf("CLK_BRAM1: said wr, now read\n");
}
} else {
if(g_clk_read) {
halt_printf("CLK_BRAM1: said rd, now write\n");
} else {
/* Yup, write */
clk_printf("Writing BRAM loc %02x with %02x\n",
g_clk_reg1, c033_data);
g_bram_ptr[g_clk_reg1] = c033_data;
g_config_kegs_update_needed = 1;
}
}
g_clk_mode = CLK_IDLE;
break;
case CLK_TIME:
if(read) {
if(g_clk_read == 0) {
halt_printf("Reading time, but in set mode!\n");
}
c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) & 0xff;
clk_printf("Returning time byte %d: %02x\n",
g_clk_reg1, c033_data);
} else {
/* Write */
if(g_clk_read) {
halt_printf("Write time, but in read mode!\n");
}
clk_printf("Writing TIME loc %d with %02x\n",
g_clk_reg1, c033_data);
mask = 0xff << (8 * g_clk_reg1);
g_clk_cur_time = (g_clk_cur_time & (~mask)) |
((c033_data & 0xff) << (8 *g_clk_reg1));
}
g_clk_mode = CLK_IDLE;
break;
case CLK_INTERNAL:
if(read) {
printf("Attempting to read internal reg %02x!\n",
g_clk_reg1);
} else {
switch(g_clk_reg1) {
case 0x0: /* test register */
if(c033_data & 0xc0) {
printf("Writing test reg: %02x!\n",
c033_data);
/* set_halt(1); */
}
break;
case 0x1: /* write protect reg */
clk_printf("Writing clk wr_protect: %02x\n",
c033_data);
if(c033_data & 0x80) {
printf("Stop, wr clk wr_prot: %02x\n",
c033_data);
/* set_halt(1); */
}
break;
default:
halt_printf("Writing int reg: %02x with %02x\n",
g_clk_reg1, c033_data);
}
}
g_clk_mode = CLK_IDLE;
break;
default:
halt_printf("clk mode: %d unknown!\n", g_clk_mode);
g_clk_mode = CLK_IDLE;
break;
}
}

5
src/compile_time.c Normal file
View File

@ -0,0 +1,5 @@
const char rcsid_compile_time_c[] = "@(#)$KmKId: compile_time.c,v 1.2 2002-11-14 01:02:44-05 kadickey Exp $";
char g_compile_time[] = "Compiled: " __DATE__ " " __TIME__ ;

2560
src/config.c Normal file

File diff suppressed because it is too large Load Diff

34
src/config.h Normal file
View File

@ -0,0 +1,34 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2003 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_config_h[] = "@(#)$KmKId: config.h,v 1.8 2003-10-17 15:09:58-04 kentd Exp $";
#endif
#define CONF_BUF_LEN 1024
#define COPY_BUF_SIZE 4096
#define CFG_PRINTF_BUFSIZE 2048
#define CFG_PATH_MAX 1024
#define CFG_NUM_SHOWENTS 16
#define CFGTYPE_MENU 1
#define CFGTYPE_INT 2
#define CFGTYPE_DISK 3
#define CFGTYPE_FUNC 4
/* CFGTYPE limited to just 4 bits: 0-15 */
/* Cfg_menu, Cfg_dirent and Cfg_listhdr are defined in defc.h */
STRUCT(Cfg_defval) {
Cfg_menu *menuptr;
int intval;
};

265
src/defc.h Normal file
View File

@ -0,0 +1,265 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_defc_h[] = "@(#)$KmKId: defc.h,v 1.91 2003-11-03 01:29:38-05 kentd Exp $";
#endif
#include "defcomm.h"
#define STRUCT(a) typedef struct _ ## a a; struct _ ## a
typedef unsigned char byte;
typedef unsigned short word16;
typedef unsigned int word32;
#if _MSC_VER
typedef unsigned __int64 word64;
#else
typedef unsigned long long word64;
#endif
void U_STACK_TRACE();
/* 28MHz crystal, plus every 65th 1MHz cycle is stretched 140ns */
#define CYCS_28_MHZ (28636360)
#define DCYCS_28_MHZ (1.0*CYCS_28_MHZ)
#define CYCS_3_5_MHZ (CYCS_28_MHZ/8)
#define DCYCS_1_MHZ ((DCYCS_28_MHZ/28.0)*(65.0*7/(65.0*7+1.0)))
#define CYCS_1_MHZ ((int)DCYCS_1_MHZ)
#define DCYCS_IN_16MS_RAW (DCYCS_1_MHZ / 60.0)
#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW))
#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS))
#ifdef KEGS_LITTLE_ENDIAN
# define BIGEND(a) ((((a) >> 24) & 0xff) + \
(((a) >> 8) & 0xff00) + \
(((a) << 8) & 0xff0000) + \
(((a) << 24) & 0xff000000))
# define GET_BE_WORD16(a) ((((a) >> 8) & 0xff) + (((a) << 8) & 0xff00))
# define GET_BE_WORD32(a) (BIGEND(a))
#else
# define BIGEND(a) (a)
# define GET_BE_WORD16(a) (a)
# define GET_BE_WORD32(a) (a)
#endif
#define MAXNUM_HEX_PER_LINE 32
#ifdef __NeXT__
# include <libc.h>
#endif
#ifndef _WIN32
# include <unistd.h>
# include <sys/ioctl.h>
# include <sys/wait.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HPUX
# include <machine/inline.h> /* for GET_ITIMER */
#endif
#ifdef SOLARIS
# include <sys/filio.h>
#endif
#ifndef O_BINARY
/* work around some Windows junk */
# define O_BINARY 0
#endif
STRUCT(Pc_log) {
double dcycs;
word32 dbank_kpc;
word32 instr;
word32 psr_acc;
word32 xreg_yreg;
word32 stack_direct;
word32 pad;
};
STRUCT(Event) {
double dcycs;
int type;
Event *next;
};
STRUCT(Fplus) {
double plus_1;
double plus_2;
double plus_3;
double plus_x_minus_1;
};
STRUCT(Engine_reg) {
double fcycles;
word32 kpc;
word32 acc;
word32 xreg;
word32 yreg;
word32 stack;
word32 dbank;
word32 direct;
word32 psr;
Fplus *fplus_ptr;
};
STRUCT(Kimage) {
void *dev_handle;
void *dev_handle2;
byte *data_ptr;
int width_req;
int width_act;
int height;
int depth;
int mdepth;
int aux_info;
};
typedef byte *Pg_info;
STRUCT(Page_info) {
Pg_info rd_wr;
};
STRUCT(Cfg_menu) {
const char *str;
void *ptr;
const char *name_str;
void *defptr;
int cfgtype;
};
STRUCT(Cfg_dirent) {
char *name;
int is_dir;
int size;
int image_start;
int part_num;
};
STRUCT(Cfg_listhdr) {
Cfg_dirent *direntptr;
int max;
int last;
int invalid;
int curent;
int topent;
int num_to_show;
};
#ifdef __LP64__
# define PTR2WORD(a) ((unsigned long)(a))
#else
# define PTR2WORD(a) ((unsigned int)(a))
#endif
#define ALTZP (statereg & 0x80)
#define PAGE2 (statereg & 0x40)
#define RAMRD (statereg & 0x20)
#define RAMWRT (statereg & 0x10)
#define RDROM (statereg & 0x08)
#define LCBANK2 (statereg & 0x04)
#define ROMB (statereg & 0x02)
#define INTCX (statereg & 0x01)
#define EXTRU(val, pos, len) \
( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \
(((val) >> (31-(pos)) ) & ( (1<<(len) ) - 1) ) )
#define DEP1(val, pos, old_val) \
(((old_val) & ~(1 << (31 - (pos))) ) | \
( ((val) & 1) << (31 - (pos))) )
#define set_halt(val) \
if(val) { set_halt_act(val); }
#define clear_halt() \
clr_halt_act()
#define GET_PAGE_INFO_RD(page) \
(page_info_rd_wr[page].rd_wr)
#define GET_PAGE_INFO_WR(page) \
(page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr)
#define SET_PAGE_INFO_RD(page,val) \
;page_info_rd_wr[page].rd_wr = (Pg_info)val;
#define SET_PAGE_INFO_WR(page,val) \
;page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr = \
(Pg_info)val;
#define VERBOSE_DISK 0x001
#define VERBOSE_IRQ 0x002
#define VERBOSE_CLK 0x004
#define VERBOSE_SHADOW 0x008
#define VERBOSE_IWM 0x010
#define VERBOSE_DOC 0x020
#define VERBOSE_ADB 0x040
#define VERBOSE_SCC 0x080
#define VERBOSE_TEST 0x100
#define VERBOSE_VIDEO 0x200
#define VERBOSE_MAC 0x400
#ifdef NO_VERB
# define DO_VERBOSE 0
#else
# define DO_VERBOSE 1
#endif
#define disk_printf if(DO_VERBOSE && (Verbose & VERBOSE_DISK)) printf
#define irq_printf if(DO_VERBOSE && (Verbose & VERBOSE_IRQ)) printf
#define clk_printf if(DO_VERBOSE && (Verbose & VERBOSE_CLK)) printf
#define shadow_printf if(DO_VERBOSE && (Verbose & VERBOSE_SHADOW)) printf
#define iwm_printf if(DO_VERBOSE && (Verbose & VERBOSE_IWM)) printf
#define doc_printf if(DO_VERBOSE && (Verbose & VERBOSE_DOC)) printf
#define adb_printf if(DO_VERBOSE && (Verbose & VERBOSE_ADB)) printf
#define scc_printf if(DO_VERBOSE && (Verbose & VERBOSE_SCC)) printf
#define test_printf if(DO_VERBOSE && (Verbose & VERBOSE_TEST)) printf
#define vid_printf if(DO_VERBOSE && (Verbose & VERBOSE_VIDEO)) printf
#define mac_printf if(DO_VERBOSE && (Verbose & VERBOSE_MAC)) printf
#define HALT_ON_SCAN_INT 0x001
#define HALT_ON_IRQ 0x002
#define HALT_ON_SHADOW_REG 0x004
#define HALT_ON_C70D_WRITES 0x008
#define HALT_ON(a, msg) \
if(Halt_on & a) { \
halt_printf(msg); \
}
#ifndef MIN
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
# define MAX(a,b) (((a) < (b)) ? (b) : (a))
#endif
#define GET_ITIMER(dest) dest = get_itimer();
#include "iwm.h"
#include "protos.h"

200
src/defcomm.h Normal file
View File

@ -0,0 +1,200 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsdif_defcomm_h[] = "@(#)$KmKId: defcomm.h,v 1.93 2002-11-19 03:10:38-05 kadickey Exp $";
#endif
#define USE_XIMAGE_CHANGED
#if 0
# define CHECK_BREAKPOINTS
#endif
#define SHIFT_PER_CHANGE 3
#define CHANGE_SHIFT (5 + SHIFT_PER_CHANGE)
#define SLOW_MEM_CH_SIZE (0x10000 >> CHANGE_SHIFT)
#define MAXNUM_HEX_PER_LINE 32
/* Different Joystick defines */
#define JOYSTICK_MOUSE 1
#define JOYSTICK_LINUX 2
#define JOYSTICK_KEYPAD 3
#define JOYSTICK_WIN32_1 4
#define JOYSTICK_WIN32_2 5
#define HALT_EVENT 0x10
#define MAX_BREAK_POINTS 0x20
#define MAX_BP_INDEX 0x100
#define MAX_BP_PER_INDEX 3 /* 4 word32s total = 16 bytes */
#define SIZE_BREAKPT_ENTRY_BITS 4 /* 16 bytes = 4 bits */
/* Warning--next defines used by asm! */
#define PAGE_INFO_PAD_SIZE 0x800
#define PAGE_INFO_WR_OFFSET 0x10000+PAGE_INFO_PAD_SIZE
#define BANK_IO_BIT 31
#define BANK_SHADOW_BIT 30
#define BANK_SHADOW2_BIT 29
#define BANK_IO2_BIT 28
#define BANK_BREAK_BIT 27
#define BANK_BREAK (1 << (31 - BANK_BREAK_BIT))
#define BANK_IO2_TMP (1 << (31 - BANK_IO2_BIT))
#define BANK_IO_TMP (1 << (31 - BANK_IO_BIT))
#define BANK_SHADOW (1 << (31 - BANK_SHADOW_BIT))
#define BANK_SHADOW2 (1 << (31 - BANK_SHADOW2_BIT))
#define SET_BANK_IO \
(&g_dummy_memory1_ptr[BANK_IO_TMP | BANK_IO2_TMP])
#define BANK_BAD_MEM (&g_dummy_memory1_ptr[0xff])
#define LEN_FIFO_BUF 160
#define LEN_KBD_BUF 160
#define FIFO_OK 0x1
#define FIFO_INIT 0x2
#define FIFO_END 0x3
#define FIFO_40COLS 0x4
#define FIFO_80COLS 0x5
#define FIFO_SENDCHAR 0x6
#define FIFO_SENDKEY 0x7
#define FIFO_REFRESH 0x8
#define B_OP_SIZE 2
#define B_OP_D_SIZE 5
#define B_OP_DTYPE 12
#define SIZE_OP_DTYPE 7
#define ENGINE_FCYCLES 0x00
#define ENGINE_REG_KPC 0x08
#define ENGINE_REG_ACC 0x0c
#define ENGINE_REG_XREG 0x10
#define ENGINE_REG_YREG 0x14
#define ENGINE_REG_STACK 0x18
#define ENGINE_REG_DBANK 0x1c
#define ENGINE_REG_DIRECT 0x20
#define ENGINE_REG_PSR 0x24
#define ENGINE_FPLUS_PTR 0x28
#define LOG_PC_DCYCS 0x00
#define LOG_PC_DBANK_KPC 0x08
#define LOG_PC_INSTR 0x0c
#define LOG_PC_PSR_ACC 0x10
#define LOG_PC_XREG_YREG 0x14
#define LOG_PC_STACK_DIRECT 0x18
#define LOG_PC_PAD 0x1c
#define LOG_PC_SIZE 0x20
#define FPLUS_PLUS_1 0x00
#define FPLUS_PLUS_2 0x08
#define FPLUS_PLUS_3 0x10
#define FPLUS_PLUS_X_M1 0x18
#define RET_BREAK 0x1
#define RET_COP 0x2
#define RET_WDM 0x3
#define RET_MVP 0x4
#define RET_MVN 0x5
#define RET_WAI 0x6
#define RET_STP 0x7
#define RET_ADD_DEC_8 0x8
#define RET_ADD_DEC_16 0x9
#define RET_C700 0xa
#define RET_C70A 0xb
#define RET_C70D 0xc
#define RET_IRQ 0xd
#define MODE_BORDER 0
#define MODE_TEXT 1
#define MODE_GR 2
#define MODE_HGR 3
#define MODE_SUPER_HIRES 4
#define BIT_ALL_STAT_TEXT 0
#define BIT_ALL_STAT_VID80 1
#define BIT_ALL_STAT_ST80 2
#define BIT_ALL_STAT_COLOR_C021 3
#define BIT_ALL_STAT_MIX_T_GR 4
#define BIT_ALL_STAT_DIS_COLOR_DHIRES 5 /* special val, c029 */
#define BIT_ALL_STAT_PAGE2 6 /* special val, statereg */
#define BIT_ALL_STAT_SUPER_HIRES 7 /* special, c029 */
#define BIT_ALL_STAT_HIRES 8
#define BIT_ALL_STAT_ANNUNC3 9
#define BIT_ALL_STAT_BG_COLOR 10 /* 4 bits */
#define BIT_ALL_STAT_TEXT_COLOR 14 /* 4 bits */
/* Text must be just above */
/* bg to match c022 reg */
#define BIT_ALL_STAT_ALTCHARSET 18
#define BIT_ALL_STAT_FLASH_STATE 19
#define BIT_ALL_STAT_A2VID_PALETTE 20 /* 4 bits */
#define ALL_STAT_SUPER_HIRES (1 << (BIT_ALL_STAT_SUPER_HIRES))
#define ALL_STAT_TEXT (1 << (BIT_ALL_STAT_TEXT))
#define ALL_STAT_VID80 (1 << (BIT_ALL_STAT_VID80))
#define ALL_STAT_PAGE2 (1 << (BIT_ALL_STAT_PAGE2))
#define ALL_STAT_ST80 (1 << (BIT_ALL_STAT_ST80))
#define ALL_STAT_COLOR_C021 (1 << (BIT_ALL_STAT_COLOR_C021))
#define ALL_STAT_DIS_COLOR_DHIRES (1 << (BIT_ALL_STAT_DIS_COLOR_DHIRES))
#define ALL_STAT_MIX_T_GR (1 << (BIT_ALL_STAT_MIX_T_GR))
#define ALL_STAT_HIRES (1 << (BIT_ALL_STAT_HIRES))
#define ALL_STAT_ANNUNC3 (1 << (BIT_ALL_STAT_ANNUNC3))
#define ALL_STAT_TEXT_COLOR (0xf << (BIT_ALL_STAT_TEXT_COLOR))
#define ALL_STAT_BG_COLOR (0xf << (BIT_ALL_STAT_BG_COLOR))
#define ALL_STAT_ALTCHARSET (1 << (BIT_ALL_STAT_ALTCHARSET))
#define ALL_STAT_FLASH_STATE (1 << (BIT_ALL_STAT_FLASH_STATE))
#define ALL_STAT_A2VID_PALETTE (0xf << (BIT_ALL_STAT_A2VID_PALETTE))
#define BORDER_WIDTH 32
#define EFF_BORDER_WIDTH (BORDER_WIDTH + (640-560))
/* BASE_MARGIN_BOTTOM+MARGIN_TOP must equal 62. There are 262 scan lines */
/* at 60Hz (15.7KHz line rate) and so we just make 62 border lines */
#define BASE_MARGIN_TOP 32
#define BASE_MARGIN_BOTTOM 30
#define BASE_MARGIN_LEFT BORDER_WIDTH
#define BASE_MARGIN_RIGHT BORDER_WIDTH
#define A2_WINDOW_WIDTH 640
#define A2_WINDOW_HEIGHT 400
#define X_A2_WINDOW_WIDTH (A2_WINDOW_WIDTH + BASE_MARGIN_LEFT + \
BASE_MARGIN_RIGHT)
#define X_A2_WINDOW_HEIGHT (A2_WINDOW_HEIGHT + BASE_MARGIN_TOP + \
BASE_MARGIN_BOTTOM)
#define MAX_STATUS_LINES 7
#define STATUS_LINE_LENGTH 88
#define BASE_WINDOW_WIDTH (X_A2_WINDOW_WIDTH)
#define A2_BORDER_COLOR_NUM 0xfe
#if 0
#define A2_TEXT_COLOR_ALT_NUM 0x01
#define A2_BG_COLOR_ALT_NUM 0x00
#define A2_TEXT_COLOR_PRIM_NUM 0x02
#define A2_BG_COLOR_PRIM_NUM 0x00
#define A2_TEXT_COLOR_FLASH_NUM 0x0c
#define A2_BG_COLOR_FLASH_NUM 0x08
#endif

63
src/defs.h Normal file
View File

@ -0,0 +1,63 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_S
.data
.export rcsdif_defs_h,data
rcsdif_defs_h
.stringz "@(#)$KmKId: defs.h,v 1.22 2002-11-19 03:10:38-05 kadickey Exp $"
.code
#endif
#include "defcomm.h"
link .reg %r2
acc .reg %r3
xreg .reg %r4
yreg .reg %r5
stack .reg %r6
dbank .reg %r7
direct .reg %r8
neg .reg %r9
zero .reg %r10
psr .reg %r11
kpc .reg %r12
const_fd .reg %r13
instr .reg %r14
#if 0
cycles .reg %r13
kbank .reg %r14
#endif
page_info_ptr .reg %r15
inst_tab_ptr .reg %r16
fcycles_stop_ptr .reg %r17
addr_latch .reg %r18
scratch1 .reg %r19
scratch2 .reg %r20
scratch3 .reg %r21
scratch4 .reg %r22
;instr .reg %r23 ; arg3
fcycles .reg %fr12
fr_plus_1 .reg %fr13
fr_plus_2 .reg %fr14
fr_plus_3 .reg %fr15
fr_plus_x_m1 .reg %fr16
fcycles_stop .reg %fr17
fcycles_last_dcycs .reg %fr18
ftmp1 .reg %fr4
ftmp2 .reg %fr5
fscr1 .reg %fr6
#define LDC(val,reg) ldil L%val,reg ! ldo R%val(reg),reg

1622
src/defs_instr.h Normal file

File diff suppressed because it is too large Load Diff

1342
src/dis.c Normal file

File diff suppressed because it is too large Load Diff

210
src/disas.h Normal file
View File

@ -0,0 +1,210 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_disas_h[] = "@(#)$KmKId: disas.h,v 1.10 2002-11-19 03:10:38-05 kadickey Exp $";
enum {
ABS = 1,
ABSX,
ABSY,
ABSLONG,
ABSIND,
ABSXIND,
IMPLY,
ACCUM,
IMMED,
JUST8,
DLOC,
DLOCX,
DLOCY,
LONG,
LONGX,
DLOCIND,
DLOCINDY,
DLOCXIND,
DLOCBRAK,
DLOCBRAKY,
DISP8,
DISP8S,
DISP8SINDY,
DISP16,
MVPMVN,
REPVAL,
SEPVAL
};
const char * const disas_opcodes[256] = {
"BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", /* 00-07 */
"PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", /* 08-0f */
"BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", /* 10-17 */
"CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", /* 18-1f */
"JSR", "AND", "JSL", "AND", "BIT", "AND", "ROL", "AND", /* 20-27 */
"PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND", /* 28-2f */
"BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", /* 30-37 */
"SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND", /* 38-3f */
"RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", /* 40-47 */
"PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR", /* 48-4f */
"BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", /* 50-57 */
"CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR", /* 58-5f */
"RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", /* 60-67 */
"PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC", /* 68-6f */
"BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", /* 70-77 */
"SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC", /* 78-7f */
"BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", /* 80-87 */
"DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA", /* 88-8f */
"BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", /* 90-97 */
"TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA", /* 98-9f */
"LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", /* a0-a7 */
"TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA", /* a8-af */
"BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", /* b0-b7 */
"CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA", /* b8-bf */
"CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", /* c0-c7 */
"INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", /* c8-cf */
"BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", /* d0-d7 */
"CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", /* d8-df */
"CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", /* e0-e7 */
"INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", /* e8-ef */
"BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", /* f0-f7 */
"SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC", /* f8-ff */
};
const word32 disas_types[256] = {
JUST8+0x100, DLOCXIND+0x100, /* 00-01 */
JUST8+0x100, DISP8S+0x100, /* 02-03 */
DLOC+0x100, DLOC+0x100, /* 04-05 */
DLOC+0x100, DLOCBRAK+0x100, /* 06-07 */
IMPLY+0x000, IMMED+0x400, /* 08-9 */
ACCUM+0x000, IMPLY+0x000, /* 0a-b */
ABS+0x200, ABS+0x200, /* c-d */
ABS+0x200, LONG+0x300, /* e-f */
DISP8+0x100, DLOCINDY+0x100, /* 10-11 */
DLOCIND+0x100, DISP8SINDY+0x100, /* 12-13 */
DLOC+0x100, DLOCX+0x100, /* 14-15 */
DLOCX+0x100, DLOCBRAKY+0x100, /* 16-17 */
IMPLY+0x000, ABSY+0x200, /* 18-19 */
ACCUM+0x000, IMPLY+0x000, /* 1a-1b */
ABS+0x200, ABSX+0x200, /* 1c-1d */
ABSX+0x200, LONGX+0x300, /* 1e-1f */
ABS+0x200, DLOCXIND+0x100, /* 20-21 */
ABSLONG+0x300, DISP8S+0x100, /* 22-23 */
DLOC+0x100, DLOC+0x100, /* 24-25 */
DLOC+0x100, DLOCBRAK+0x100, /* 26-27 */
IMPLY+0x000, IMMED+0x400, /* 28-29 */
ACCUM+0x000, IMPLY+0x000, /* 2a-2b */
ABS+0x200, ABS+0x200, /* 2c-2d */
ABS+0x200, LONG+0x300, /* 2e-2f */
DISP8+0x100, DLOCINDY+0x100, /* 30-31 */
DLOCIND+0x100, DISP8SINDY+0x100, /* 32-33 */
DLOCX+0x100, DLOCX+0x100, /* 34-35 */
DLOCX+0x100, DLOCBRAKY+0x100, /* 36-37 */
IMPLY+0x000, ABSY+0x200, /* 38-39 */
ACCUM+0x000, IMPLY+0x000, /* 3a-3b */
ABSX+0x200, ABSX+0x200, /* 3c-3d */
ABSX+0x200, LONGX+0x300, /* 3e-3f */
IMPLY+0x000, DLOCXIND+0x100, /* 40-41 */
JUST8+0x100, DISP8S+0x100, /* 42-43 */
MVPMVN+0x200, DLOC+0x100, /* 44-45 */
DLOC+0x100, DLOCBRAK+0x100, /* 46-47 */
IMPLY+0x000, IMMED+0x400, /* 48-49 */
ACCUM+0x000, IMPLY+0x000, /* 4a-4b */
ABS+0x200, ABS+0x200, /* 4c-4d */
ABS+0x200, LONG+0x300, /* 4e-4f */
DISP8+0x100, DLOCINDY+0x100, /* 50-51 */
DLOCIND+0x100, DISP8SINDY+0x100, /* 52-53 */
MVPMVN+0x200, DLOCX+0x100, /* 54-55 */
DLOCX+0x100, DLOCBRAKY+0x100, /* 56-57 */
IMPLY+0x000, ABSY+0x200, /* 58-59 */
IMPLY+0x000, IMPLY+0x000, /* 5a-5b */
LONG+0x300, ABSX+0x200, /* 5c-5d */
ABSX+0x200, LONGX+0x300, /* 5e-5f */
IMPLY+0x000, DLOCXIND+0x100, /* 60-61 */
DISP16+0x200, DISP8S+0x100, /* 62-63 */
DLOC+0x100, DLOC+0x100, /* 64-65 */
DLOC+0x100, DLOCBRAK+0x100, /* 66-67 */
IMPLY+0x000, IMMED+0x400, /* 68-69 */
ACCUM+0x000, IMPLY+0x000, /* 6a-6b */
ABSIND+0x200, ABS+0x200, /* 6c-6d */
ABS+0x200, LONG+0x300, /* 6e-6f */
DISP8+0x100, DLOCINDY+0x100, /* 70-71 */
DLOCIND+0x100, DISP8SINDY+0x100, /* 72-73 */
DLOCX+0x100, DLOCX+0x100, /* 74-75 */
DLOCX+0x100, DLOCBRAKY+0x100, /* 76-77 */
IMPLY+0x000, ABSY+0x200, /* 78-79 */
IMPLY+0x000, IMPLY+0x000, /* 7a-7b */
ABSXIND+0x200, ABSX+0x200, /* 7c-7d */
ABSX+0x200, LONGX+0x300, /* 7e-7f */
DISP8+0x100, DLOCXIND+0x100, /* 80-81 */
DISP16+0x200, DISP8S+0x100, /* 82-83 */
DLOC+0x100, DLOC+0x100, /* 84-85 */
DLOC+0x100, DLOCBRAK+0x100, /* 86-87 */
IMPLY+0x000, IMMED+0x400, /* 88-89 */
IMPLY+0x000, IMPLY+0x000, /* 8a-8b */
ABS+0x200, ABS+0x200, /* 8c-8d */
ABS+0x200, LONG+0x300, /* 8e-8f */
DISP8+0x100, DLOCINDY+0x100, /* 90-91 */
DLOCIND+0x100, DISP8SINDY+0x100, /* 92-93 */
DLOCX+0x100, DLOCX+0x100, /* 94-95 */
DLOCY+0x100, DLOCBRAKY+0x100, /* 96-97 */
IMPLY+0x000, ABSY+0x200, /* 98-99 */
IMPLY+0x000, IMPLY+0x000, /* 9a-9b */
ABS+0x200, ABSX+0x200, /* 9c-9d */
ABSX+0x200, LONGX+0x300, /* 9e-9f */
IMMED+0x500, DLOCXIND+0x100, /* a0-a1 */
IMMED+0x500, DISP8S+0x100, /* a2-a3 */
DLOC+0x100, DLOC+0x100, /* a4-a5 */
DLOC+0x100, DLOCBRAK+0x100, /* a6-a7 */
IMPLY+0x000, IMMED+0x400, /* a8-a9 */
IMPLY+0x000, IMPLY+0x000, /* aa-ab */
ABS+0x200, ABS+0x200, /* ac-ad */
ABS+0x200, LONG+0x300, /* ae-af */
DISP8+0x100, DLOCINDY+0x100, /* b0-b1 */
DLOCIND+0x100, DISP8SINDY+0x100, /* b2-b3 */
DLOCX+0x100, DLOCX+0x100, /* b4-b5 */
DLOCY+0x100, DLOCBRAKY+0x100, /* b6-b7 */
IMPLY+0x000, ABSY+0x200, /* b8-b9 */
IMPLY+0x000, IMPLY+0x000, /* ba-bb */
ABSX+0x200, ABSX+0x200, /* bc-bd */
ABSY+0x200, LONGX+0x300, /* be-bf */
IMMED+0x500, DLOCXIND+0x100, /* c0-c1 */
REPVAL+0x100, DISP8S+0x100, /* c2-c3 */
DLOC+0x100, DLOC+0x100, /* c4-c5 */
DLOC+0x100, DLOCBRAK+0x100, /* c6-c7 */
IMPLY+0x000, IMMED+0x400, /* c8-c9 */
IMPLY+0x000, IMPLY+0x000, /* ca-cb */
ABS+0x200, ABS+0x200, /* cc-cd */
ABS+0x200, LONG+0x300, /* ce-cf */
DISP8+0x100, DLOCINDY+0x100, /* d0-d1 */
DLOCIND+0x100, DISP8SINDY+0x100, /* d2-d3 */
DLOC+0x100, DLOCX+0x100, /* d4-d5 */
DLOCX+0x100, DLOCBRAKY+0x100, /* d6-d7 */
IMPLY+0x000, ABSY+0x200, /* d8-d9 */
IMPLY+0x000, IMPLY+0x000, /* da-db */
ABSIND+0x200, ABSX+0x200, /* dc-dd */
ABSX+0x200, LONGX+0x300, /* de-df */
IMMED+0x500, DLOCXIND+0x100, /* e0-e1 */
SEPVAL+0x100, DISP8S+0x100, /* e2-e3 */
DLOC+0x100, DLOC+0x100, /* e4-e5 */
DLOC+0x100, DLOCBRAK+0x100, /* e6-e7 */
IMPLY+0x000, IMMED+0x400, /* e8-e9 */
IMPLY+0x000, IMPLY+0x000, /* ea-eb */
ABS+0x200, ABS+0x200, /* ec-ed */
ABS+0x200, LONG+0x300, /* ee-ef */
DISP8+0x100, DLOCINDY+0x100, /* f0-f1 */
DLOCIND+0x100, DISP8SINDY+0x100, /* f2-f3 */
IMMED+0x200, DLOCX+0x100, /* f4-f5 */
DLOCX+0x100, DLOCBRAKY+0x100, /* f6-f7 */
IMPLY+0x000, ABSY+0x200, /* f8-f9 */
IMPLY+0x000, IMPLY+0x000, /* fa-fb */
ABSXIND+0x200, ABSX+0x200, /* fc-fd */
ABSX+0x200, LONGX+0x300, /* fe-ff */
};

1007
src/engine_c.c Normal file

File diff suppressed because it is too large Load Diff

2491
src/engine_s.s Normal file

File diff suppressed because it is too large Load Diff

19
src/info.nib generated Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>152 85 356 240 0 0 1280 832 </string>
<key>IBEditorPositions</key>
<dict>
<key>29</key>
<string>69 252 182 44 0 0 1280 832 </string>
</dict>
<key>IBFramework Version</key>
<string>291.0</string>
<key>IBSystem Version</key>
<string>6R73</string>
<key>targetFramework</key>
<string>IBCarbonFramework</string>
</dict>
</plist>

2703
src/instable.h Normal file

File diff suppressed because it is too large Load Diff

2329
src/iwm.c Normal file

File diff suppressed because it is too large Load Diff

116
src/iwm.h Normal file
View File

@ -0,0 +1,116 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_iwm_h[] = "@(#)$KmKId: iwm.h,v 1.13 2003-07-08 23:29:48-04 kentd Exp $";
#endif
#define MAX_TRACKS (2*80)
#define MAX_C7_DISKS 32
#define NIB_LEN_525 0x1900 /* 51072 bits per track */
#define NIBS_FROM_ADDR_TO_DATA 20
#define DSK_TYPE_PRODOS 0
#define DSK_TYPE_DOS33 1
#define DSK_TYPE_NIB 2
typedef struct _Disk Disk;
STRUCT(Track) {
Disk *dsk;
byte *nib_area;
int track_dirty;
int overflow_size;
int track_len;
int unix_pos;
int unix_len;
};
struct _Disk {
double dcycs_last_read;
char *name_ptr;
char *partition_name;
int partition_num;
int fd;
int force_size;
int image_start;
int image_size;
int smartport;
int disk_525;
int drive;
int cur_qtr_track;
int image_type;
int vol_num;
int write_prot;
int write_through_to_unix;
int disk_dirty;
int just_ejected;
int last_phase;
int nib_pos;
int num_tracks;
Track tracks[MAX_TRACKS];
};
STRUCT(Iwm) {
Disk drive525[2];
Disk drive35[2];
Disk smartport[MAX_C7_DISKS];
int motor_on;
int motor_off;
int motor_off_vbl_count;
int motor_on35;
int head35;
int step_direction35;
int iwm_phase[4];
int iwm_mode;
int drive_select;
int q6;
int q7;
int enable2;
int reset;
word32 previous_write_val;
int previous_write_bits;
};
STRUCT(Driver_desc) {
word16 sig;
word16 blk_size;
word32 blk_count;
word16 dev_type;
word16 dev_id;
word32 data;
word16 drvr_count;
};
STRUCT(Part_map) {
word16 sig;
word16 sigpad;
word32 map_blk_cnt;
word32 phys_part_start;
word32 part_blk_cnt;
char part_name[32];
char part_type[32];
word32 data_start;
word32 data_cnt;
word32 part_status;
word32 log_boot_start;
word32 boot_size;
word32 boot_load;
word32 boot_load2;
word32 boot_entry;
word32 boot_entry2;
word32 boot_cksum;
char processor[16];
char junk[128];
};

310
src/iwm_35_525.h Normal file
View File

@ -0,0 +1,310 @@
#ifdef INCLUDE_IWM_RCSID_C
const char rcsdif_iwm_35_525_h[] = "@(#)$KmKId: iwm_35_525.h,v 1.9 2002-11-14 01:03:16-05 kadickey Exp $";
#endif
int
IWM_READ_ROUT (Disk *dsk, int fast_disk_emul, double dcycs)
{
Track *trk;
double dcycs_last_read;
int pos;
int pos2;
int size;
int next_size;
int qtr_track;
int skip_nibs;
int track_len;
byte ret;
int shift;
int skip;
int cycs_this_nib;
int cycs_passed;
double dcycs_this_nib;
double dcycs_next_nib;
double dcycs_passed;
double track_dcycs;
double dtmp;
iwm.previous_write_bits = 0;
qtr_track = dsk->cur_qtr_track;
trk = &(dsk->tracks[qtr_track]);
track_len = trk->track_len;
dcycs_last_read = dsk->dcycs_last_read;
dcycs_passed = dcycs - dcycs_last_read;
pos = dsk->nib_pos;
if(pos >= track_len) {
/* Arm may have moved from inner 3.5 track to outer one, */
/* and so must make pos fit on smaller sized track */
pos = 0;
}
cycs_passed = (int)dcycs_passed;
if(track_len == 0) {
return (cycs_passed & 0x7f) + 0x80;
}
size = trk->nib_area[pos];
while(size == 0) {
pos += 2;
if(pos >= track_len) {
pos = 0;
}
size = trk->nib_area[pos];
}
cycs_this_nib = size * (2 * IWM_CYC_MULT);
dcycs_this_nib = (double)cycs_this_nib;
if(fast_disk_emul) {
cycs_passed = cycs_this_nib;
dcycs_passed = dcycs_this_nib;
/* pull a trick to make disk motor-on test pass ($bd34 RWTS) */
/* if this would be a sync byte, and we didn't just do this */
/* then don't return whole byte */
/* BUT, don't do this if g_fast_disk_unnib, since it will */
/* cause the dsk->unix routines to break */
if(size > 8 && !g_fast_disk_unnib && (g_iwm_fake_fast == 0)) {
cycs_passed = cycs_passed >> 1;
dcycs_passed = dcycs_passed * 0.5;
g_iwm_fake_fast = 1;
} else {
g_iwm_fake_fast = 0;
}
}
skip = 0;
if(cycs_passed >= (cycs_this_nib + 11)) {
/* skip some bits? */
skip = 1;
if(iwm.iwm_mode & 1) {
/* latch mode */
pos2 = pos + 2;
if(pos2 >= track_len) {
pos2 = 0;
}
next_size = trk->nib_area[pos2];
while(next_size == 0) {
pos2 += 2;
if(pos2 >= track_len) {
pos2 = 0;
}
next_size = trk->nib_area[pos2];
}
dcycs_next_nib = next_size * (2 * IWM_CYC_MULT);
if(dcycs_passed < (dcycs_this_nib + dcycs_next_nib)) {
skip = 0;
}
}
}
if(skip) {
iwm_printf("skip since cycs_passed: %f, cycs_this_nib: %f\n",
dcycs_passed, dcycs_this_nib);
track_dcycs = IWM_CYC_MULT * (track_len * 8);
if(dcycs_passed >= track_dcycs) {
dtmp = (int)(dcycs_passed / track_dcycs);
dcycs_passed = dcycs_passed -
(dtmp * track_dcycs);
dcycs_last_read += (dtmp * track_dcycs);
}
if(dcycs_passed >= track_dcycs || dcycs_passed < 0.0) {
dcycs_passed = 0.0;
}
cycs_passed = (int)dcycs_passed;
skip_nibs = ((word32)cycs_passed) >> (4 + IWM_DISK_525);
pos += skip_nibs * 2;
while(pos >= track_len) {
pos -= track_len;
}
dcycs_last_read += (skip_nibs * 16 * IWM_CYC_MULT);
dsk->dcycs_last_read = dcycs_last_read;
size = trk->nib_area[pos];
dcycs_passed = dcycs - dcycs_last_read;
if(dcycs_passed < 0.0 || dcycs_passed > 64.0) {
halt_printf("skip, last_read:%f, dcycs:%f, dcyc_p:%f\n",
dcycs_last_read, dcycs, dcycs_passed);
}
while(size == 0) {
pos += 2;
if(pos >= track_len) {
pos = 0;
}
size = trk->nib_area[pos];
}
cycs_this_nib = size * (2 * IWM_CYC_MULT);
cycs_passed = (int)dcycs_passed;
dcycs_this_nib = cycs_this_nib;
}
if(cycs_passed < cycs_this_nib) {
/* partial */
#if 0
iwm_printf("Disk partial, %f < %f, size: %d\n",
dcycs_passed, dcycs_this_nib, size);
#endif
shift = (cycs_passed) >> (1 + IWM_DISK_525);
ret = trk->nib_area[pos+1] >> (size - shift);
if(ret & 0x80) {
halt_printf("Bad shift in partial read: %02x, but "
"c_pass:%f, this_nib:%f, shift: %d, size: %d\n",
ret, dcycs_passed, dcycs_this_nib, shift, size);
}
} else {
/* whole thing */
ret = trk->nib_area[pos+1];
pos += 2;
if(pos >= track_len) {
pos = 0;
}
if(!fast_disk_emul) {
dsk->dcycs_last_read = dcycs_last_read + dcycs_this_nib;
}
}
dsk->nib_pos = pos;
if(pos < 0 || pos > track_len) {
halt_printf("I just set nib_pos: %d!\n", pos);
}
#if 0
iwm_printf("Disk read, returning: %02x\n", ret);
#endif
return ret;
}
void
IWM_WRITE_ROUT (Disk *dsk, word32 val, int fast_disk_emul, double dcycs)
{
double dcycs_last_read;
word32 bits_read;
word32 mask;
word32 prev_val;
double dcycs_this_nib;
double dcycs_passed;
int sdiff;
int prev_bits;
if(dsk->fd < 0) {
halt_printf("Tried to write to type: %d, drive: %d, fd: %d!\n",
IWM_DISK_525, dsk->drive, dsk->fd);
return;
}
dcycs_last_read = dsk->dcycs_last_read;
dcycs_passed = dcycs - dcycs_last_read;
prev_val = iwm.previous_write_val;
prev_bits = iwm.previous_write_bits;
mask = 0x100;
iwm_printf("Iwm write: prev: %x,%d, new:%02x\n", prev_val, prev_bits,
val);
if(IWM_DISK_525) {
/* Activate slow write emulation mode */
g_dcycs_end_emul_wr = dcycs + 64.0;
if(!g_slow_525_emul_wr) {
set_halt(HALT_EVENT);
g_slow_525_emul_wr = 1;
}
} else {
/* disable slow writes on 3.5" drives */
if(g_slow_525_emul_wr) {
set_halt(HALT_EVENT);
printf("HACK3: g_slow_525_emul_wr set to 0\n");
g_slow_525_emul_wr = 0;
}
}
if(iwm.iwm_mode & 2) {
/* async mode = 3.5" default */
bits_read = 8;
} else {
/* sync mode, 5.25" drives */
bits_read = ((int)dcycs_passed) >> (1 + IWM_DISK_525);
if(bits_read < 8) {
bits_read = 8;
}
}
if(fast_disk_emul) {
bits_read = 8;
}
dcycs_this_nib = bits_read * (2 * IWM_CYC_MULT);
if(fast_disk_emul) {
dcycs_passed = dcycs_this_nib;
}
if(prev_bits > 0) {
while((prev_val & 0x80) == 0 && bits_read > 0) {
/* previous byte needs some bits */
mask = mask >> 1;
prev_val = (prev_val << 1) + ((val & mask) !=0);
prev_bits++;
bits_read--;
}
}
val = val & (mask - 1);
if(prev_bits) {
/* force out prev_val if it had many bits before */
/* this prevents writes of 0 from messing us up */
if(((prev_val & 0x80) == 0) && (prev_bits < 10)) {
/* special case: we still don't have enough to go */
iwm_printf("iwm_write: zip2: %02x, %d, left:%02x,%d\n",
prev_val, prev_bits, val,bits_read);
val = prev_val;
bits_read = prev_bits;
} else {
iwm_printf("iwm_write: prev: %02x, %d, left:%02x, %d\n",
prev_val, prev_bits, val, bits_read);
disk_nib_out(dsk, prev_val, prev_bits);
}
} else if(val & 0x80) {
iwm_printf("iwm_write: new: %02x, %d\n", val,bits_read);
disk_nib_out(dsk, val, bits_read);
bits_read = 0;
} else {
iwm_printf("iwm_write: zip: %02x, %d, left:%02x,%d\n",
prev_val, prev_bits, val,bits_read);
}
iwm.previous_write_val = val;
iwm.previous_write_bits = bits_read;
if(bits_read < 0) {
halt_printf("iwm, bits_rd:%d, val:%08x, prev:%02x, prevb:%d\n",
bits_read, val, prev_val, prev_bits);
}
sdiff = dcycs - dcycs_last_read;
if(sdiff < (dcycs_this_nib) || (sdiff > (2*dcycs_this_nib)) ) {
dsk->dcycs_last_read = dcycs;
} else {
dsk->dcycs_last_read = dcycs_last_read + dcycs_this_nib;
}
}

227
src/joystick_driver.c Normal file
View File

@ -0,0 +1,227 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_joystick_driver_c[] = "@(#)$KmKId: joystick_driver.c,v 1.7 2002-11-19 03:09:59-05 kadickey Exp $";
#include "defc.h"
#include <sys/time.h>
#ifdef __linux__
# include <linux/joystick.h>
#endif
#ifdef _WIN32
# include <windows.h>
# include <mmsystem.h>
#endif
extern int g_joystick_type; /* in paddles.c */
extern int g_paddle_button[];
extern int g_paddle_val[];
const char *g_joystick_dev = "/dev/js0"; /* default joystick dev file */
#define MAX_JOY_NAME 128
int g_joystick_fd = -1;
int g_joystick_num_axes = 0;
int g_joystick_num_buttons = 0;
#ifdef __linux__
void
joystick_init()
{
char joy_name[MAX_JOY_NAME];
int version;
int fd;
int i;
fd = open(g_joystick_dev, O_RDONLY | O_NONBLOCK);
if(fd < 0) {
printf("Unable to open joystick dev file: %s, errno: %d\n",
g_joystick_dev, errno);
printf("Defaulting to mouse joystick\n");
return;
}
strcpy(&joy_name[0], "Unknown Joystick");
version = 0x800;
ioctl(fd, JSIOCGNAME(MAX_JOY_NAME), &joy_name[0]);
ioctl(fd, JSIOCGAXES, &g_joystick_num_axes);
ioctl(fd, JSIOCGBUTTONS, &g_joystick_num_buttons);
ioctl(fd, JSIOCGVERSION, &version);
printf("Detected joystick: %s [%d axes, %d buttons vers: %08x]\n",
joy_name, g_joystick_num_axes, g_joystick_num_buttons,
version);
g_joystick_type = JOYSTICK_LINUX;
g_joystick_fd = fd;
for(i = 0; i < 4; i++) {
g_paddle_val[i] = 280;
g_paddle_button[i] = 1;
}
joystick_update();
}
/* joystick_update_linux() called from paddles.c. Update g_paddle_val[] */
/* and g_paddle_button[] arrays with current information */
void
joystick_update()
{
struct js_event js; /* the linux joystick event record */
int val;
int num;
int type;
int ret;
int len;
int i;
/* suck up to 20 events, then give up */
len = sizeof(struct js_event);
for(i = 0; i < 20; i++) {
ret = read(g_joystick_fd, &js, len);
if(ret != len) {
/* just get out */
return;
}
type = js.type & ~JS_EVENT_INIT;
val = js.value;
num = js.number & 3; /* clamp to 0-3 */
switch(type) {
case JS_EVENT_BUTTON:
g_paddle_button[num] = val;
break;
case JS_EVENT_AXIS:
/* val is -32767 to +32767, convert to 0->280 */
/* want just 255, but go a little over for robustness*/
g_paddle_val[num] = ((val + 32767) * 9) >> 11;
break;
}
}
}
void
joystick_update_button()
{
}
#else /* !__linux__ */
# ifdef _WIN32
void
joystick_init()
{
JOYINFO info;
JOYCAPS joycap;
MMRESULT ret1, ret2;
int i;
// Check that there is a joystick device
if(joyGetNumDevs() <= 0) {
printf("--No joystick hardware detected\n");
return;
}
// Check that at least joystick 1 or joystick 2 is available
ret1 = joyGetPos(JOYSTICKID1, &info);
ret2 = joyGetDevCaps(JOYSTICKID1, &joycap, sizeof(joycap));
if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) {
g_joystick_type = JOYSTICK_WIN32_1;
printf("--Joystick #1 = %s\n", joycap.szPname);
} else {
ret1 = joyGetPos(JOYSTICKID2, &info);
ret2 = joyGetDevCaps(JOYSTICKID2, &joycap, sizeof(joycap));
if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) {
g_joystick_type = JOYSTICK_WIN32_2;
printf("--Joystick #2 = %s\n", joycap.szPname);
} else {
printf("No joysticks found...\n");
g_joystick_type = JOYSTICK_MOUSE;
return;
}
}
for(i = 0; i < 4; i++) {
g_paddle_val[i] = 280;
g_paddle_button[i] = 1;
}
joystick_update();
}
void
joystick_update()
{
JOYCAPS joycap;
JOYINFO info;
UINT id;
MMRESULT ret1, ret2;
id = JOYSTICKID1;
if(g_joystick_type == JOYSTICK_WIN32_2) {
id = JOYSTICKID2;
}
ret1 = joyGetDevCaps(id, &joycap, sizeof(joycap));
ret2 = joyGetPos(id, &info);
if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) {
g_paddle_val[0] = (info.wXpos - joycap.wXmin) * 280 /
(joycap.wXmax - joycap.wXmin);
g_paddle_val[1] = (info.wYpos - joycap.wYmin) * 280 /
(joycap.wYmax - joycap.wYmin);
g_paddle_button[0] = ((info.wButtons & JOY_BUTTON1) ? 1 : 0);
g_paddle_button[1] = ((info.wButtons & JOY_BUTTON2) ? 1 : 0);
}
}
void
joystick_update_button()
{
JOYINFOEX info;
UINT id;
id = JOYSTICKID1;
if(g_joystick_type == JOYSTICK_WIN32_2) {
id = JOYSTICKID2;
}
info.dwSize = sizeof(JOYINFOEX);
info.dwFlags = JOY_RETURNBUTTONS;
if(joyGetPosEx(id, &info) == JOYERR_NOERROR) {
g_paddle_button[0] = ((info.dwButtons & JOY_BUTTON1) ? 1 : 0);
g_paddle_button[1] = ((info.dwButtons & JOY_BUTTON2) ? 1 : 0);
}
}
# else
/* stubs for the routines */
void
joystick_init()
{
printf("No joy with joystick\n");
}
void
joystick_update()
{
}
void
joystick_update_button()
{
}
# endif /* !WIN32 */
#endif

514
src/kegsfont.h Normal file
View File

@ -0,0 +1,514 @@
/* $KmKId: kegsfont.h,v 1.1 2002-11-10 03:31:51-05 kadickey Exp $ */
/* char 0x00 (raw 0x40) */
{ 0xc7, 0xbb, 0xab, 0xa3, 0xa7, 0xbf, 0xc3, 0xff },
/* char 0x01 (raw 0x41) */
{ 0xef, 0xd7, 0xbb, 0xbb, 0x83, 0xbb, 0xbb, 0xff },
/* char 0x02 (raw 0x42) */
{ 0x87, 0xbb, 0xbb, 0x87, 0xbb, 0xbb, 0x87, 0xff },
/* char 0x03 (raw 0x43) */
{ 0xc7, 0xbb, 0xbf, 0xbf, 0xbf, 0xbb, 0xc7, 0xff },
/* char 0x04 (raw 0x44) */
{ 0x87, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x87, 0xff },
/* char 0x05 (raw 0x45) */
{ 0x83, 0xbf, 0xbf, 0x87, 0xbf, 0xbf, 0x83, 0xff },
/* char 0x06 (raw 0x46) */
{ 0x83, 0xbf, 0xbf, 0x87, 0xbf, 0xbf, 0xbf, 0xff },
/* char 0x07 (raw 0x47) */
{ 0xc3, 0xbf, 0xbf, 0xbf, 0xb3, 0xbb, 0xc3, 0xff },
/* char 0x08 (raw 0x48) */
{ 0xbb, 0xbb, 0xbb, 0x83, 0xbb, 0xbb, 0xbb, 0xff },
/* char 0x09 (raw 0x49) */
{ 0xc7, 0xef, 0xef, 0xef, 0xef, 0xef, 0xc7, 0xff },
/* char 0x0a (raw 0x4a) */
{ 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xbb, 0xc7, 0xff },
/* char 0x0b (raw 0x4b) */
{ 0xbb, 0xb7, 0xaf, 0x9f, 0xaf, 0xb7, 0xbb, 0xff },
/* char 0x0c (raw 0x4c) */
{ 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x83, 0xff },
/* char 0x0d (raw 0x4d) */
{ 0xbb, 0x93, 0xab, 0xab, 0xbb, 0xbb, 0xbb, 0xff },
/* char 0x0e (raw 0x4e) */
{ 0xbb, 0xbb, 0x9b, 0xab, 0xb3, 0xbb, 0xbb, 0xff },
/* char 0x0f (raw 0x4f) */
{ 0xc7, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xc7, 0xff },
/* char 0x10 (raw 0x50) */
{ 0x87, 0xbb, 0xbb, 0x87, 0xbf, 0xbf, 0xbf, 0xff },
/* char 0x11 (raw 0x51) */
{ 0xc7, 0xbb, 0xbb, 0xbb, 0xab, 0xb7, 0xcb, 0xff },
/* char 0x12 (raw 0x52) */
{ 0x87, 0xbb, 0xbb, 0x87, 0xaf, 0xb7, 0xbb, 0xff },
/* char 0x13 (raw 0x53) */
{ 0xc7, 0xbb, 0xbf, 0xc7, 0xfb, 0xbb, 0xc7, 0xff },
/* char 0x14 (raw 0x54) */
{ 0x83, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xff },
/* char 0x15 (raw 0x55) */
{ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xc7, 0xff },
/* char 0x16 (raw 0x56) */
{ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xd7, 0xef, 0xff },
/* char 0x17 (raw 0x57) */
{ 0xbb, 0xbb, 0xbb, 0xab, 0xab, 0x93, 0xbb, 0xff },
/* char 0x18 (raw 0x58) */
{ 0xbb, 0xbb, 0xd7, 0xef, 0xd7, 0xbb, 0xbb, 0xff },
/* char 0x19 (raw 0x59) */
{ 0xbb, 0xbb, 0xd7, 0xef, 0xef, 0xef, 0xef, 0xff },
/* char 0x1a (raw 0x5a) */
{ 0x83, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x83, 0xff },
/* char 0x1b (raw 0x5b) */
{ 0x83, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x83, 0xff },
/* char 0x1c (raw 0x5c) */
{ 0xff, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xff, 0xff },
/* char 0x1d (raw 0x5d) */
{ 0x83, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0x83, 0xff },
/* char 0x1e (raw 0x5e) */
{ 0xff, 0xff, 0xef, 0xd7, 0xbb, 0xff, 0xff, 0xff },
/* char 0x1f (raw 0x5f) */
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 },
/* char 0x20 (raw 0x20) */
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
/* char 0x21 (raw 0x21) */
{ 0xef, 0xef, 0xef, 0xef, 0xef, 0xff, 0xef, 0xff },
/* char 0x22 (raw 0x22) */
{ 0xd7, 0xd7, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff },
/* char 0x23 (raw 0x23) */
{ 0xd7, 0xd7, 0x83, 0xd7, 0x83, 0xd7, 0xd7, 0xff },
/* char 0x24 (raw 0x24) */
{ 0xef, 0xc3, 0xaf, 0xc7, 0xeb, 0x87, 0xef, 0xff },
/* char 0x25 (raw 0x25) */
{ 0x9f, 0x9b, 0xf7, 0xef, 0xdf, 0xb3, 0xf3, 0xff },
/* char 0x26 (raw 0x26) */
{ 0xdf, 0xaf, 0xaf, 0xdf, 0xab, 0xb7, 0xcb, 0xff },
/* char 0x27 (raw 0x27) */
{ 0xef, 0xef, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff },
/* char 0x28 (raw 0x28) */
{ 0xef, 0xdf, 0xbf, 0xbf, 0xbf, 0xdf, 0xef, 0xff },
/* char 0x29 (raw 0x29) */
{ 0xef, 0xf7, 0xfb, 0xfb, 0xfb, 0xf7, 0xef, 0xff },
/* char 0x2a (raw 0x2a) */
{ 0xef, 0xab, 0xc7, 0xef, 0xc7, 0xab, 0xef, 0xff },
/* char 0x2b (raw 0x2b) */
{ 0xff, 0xef, 0xef, 0x83, 0xef, 0xef, 0xff, 0xff },
/* char 0x2c (raw 0x2c) */
{ 0xff, 0xff, 0xff, 0xff, 0xef, 0xef, 0xdf, 0xff },
/* char 0x2d (raw 0x2d) */
{ 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xff },
/* char 0x2e (raw 0x2e) */
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff },
/* char 0x2f (raw 0x2f) */
{ 0xff, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0xff, 0xff },
/* char 0x30 (raw 0x30) */
{ 0xc7, 0xbb, 0xb3, 0xab, 0x9b, 0xbb, 0xc7, 0xff },
/* char 0x31 (raw 0x31) */
{ 0xef, 0xcf, 0xef, 0xef, 0xef, 0xef, 0xc7, 0xff },
/* char 0x32 (raw 0x32) */
{ 0xc7, 0xbb, 0xfb, 0xe7, 0xdf, 0xbf, 0x83, 0xff },
/* char 0x33 (raw 0x33) */
{ 0x83, 0xfb, 0xf7, 0xe7, 0xfb, 0xbb, 0xc7, 0xff },
/* char 0x34 (raw 0x34) */
{ 0xf7, 0xe7, 0xd7, 0xb7, 0x83, 0xf7, 0xf7, 0xff },
/* char 0x35 (raw 0x35) */
{ 0x83, 0xbf, 0x87, 0xfb, 0xfb, 0xbb, 0xc7, 0xff },
/* char 0x36 (raw 0x36) */
{ 0xe3, 0xdf, 0xbf, 0x87, 0xbb, 0xbb, 0xc7, 0xff },
/* char 0x37 (raw 0x37) */
{ 0x83, 0xfb, 0xf7, 0xef, 0xdf, 0xdf, 0xdf, 0xff },
/* char 0x38 (raw 0x38) */
{ 0xc7, 0xbb, 0xbb, 0xc7, 0xbb, 0xbb, 0xc7, 0xff },
/* char 0x39 (raw 0x39) */
{ 0xc7, 0xbb, 0xbb, 0xc3, 0xfb, 0xf7, 0x8f, 0xff },
/* char 0x3a (raw 0x3a) */
{ 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xff, 0xff },
/* char 0x3b (raw 0x3b) */
{ 0xff, 0xff, 0xef, 0xff, 0xef, 0xef, 0xdf, 0xff },
/* char 0x3c (raw 0x3c) */
{ 0xf7, 0xef, 0xdf, 0xbf, 0xdf, 0xef, 0xf7, 0xff },
/* char 0x3d (raw 0x3d) */
{ 0xff, 0xff, 0x83, 0xff, 0x83, 0xff, 0xff, 0xff },
/* char 0x3e (raw 0x3e) */
{ 0xdf, 0xef, 0xf7, 0xfb, 0xf7, 0xef, 0xdf, 0xff },
/* char 0x3f (raw 0x3f) */
{ 0xc7, 0xbb, 0xf7, 0xef, 0xef, 0xff, 0xef, 0xff },
/* char 0x40 (raw 0x14) */
{ 0x08, 0x10, 0x6c, 0xfe, 0xfc, 0xfc, 0x7e, 0x6c },
/* char 0x41 (raw 0x11) */
{ 0x08, 0x10, 0x6c, 0x82, 0x84, 0x84, 0x52, 0x6c },
/* char 0x42 (raw 0xf5) */
{ 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, 0x6c, 0x42 },
/* char 0x43 (raw 0x82) */
{ 0xfe, 0x44, 0x28, 0x10, 0x10, 0x28, 0x54, 0xfe },
/* char 0x44 (raw 0xeb) */
{ 0x00, 0x02, 0x04, 0x88, 0x50, 0x20, 0x20, 0x00 },
/* char 0x45 (raw 0xe4) */
{ 0xfe, 0xfc, 0xfa, 0x36, 0xae, 0xde, 0xde, 0xfe },
/* char 0x46 (raw 0xec) */
{ 0xfc, 0xfc, 0xfc, 0xdc, 0x9c, 0x00, 0x9e, 0xde },
/* char 0x47 (raw 0xed) */
{ 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0xfe },
/* char 0x48 (raw 0xee) */
{ 0x10, 0x20, 0x40, 0xfe, 0x40, 0x20, 0x10, 0x00 },
/* char 0x49 (raw 0xe9) */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54 },
/* char 0x4a (raw 0xef) */
{ 0x10, 0x10, 0x10, 0x10, 0x92, 0x54, 0x38, 0x10 },
/* char 0x4b (raw 0xf0) */
{ 0x10, 0x38, 0x54, 0x92, 0x10, 0x10, 0x10, 0x10 },
/* char 0x4c (raw 0xf1) */
{ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* char 0x4d (raw 0xf7) */
{ 0x02, 0x02, 0x02, 0x22, 0x62, 0xfe, 0x60, 0x20 },
/* char 0x4e (raw 0xf6) */
{ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc },
/* char 0x4f (raw 0xaf) */
{ 0xc8, 0x18, 0x38, 0x7e, 0x38, 0x18, 0x08, 0xf6 },
/* char 0x50 (raw 0xb8) */
{ 0x26, 0x30, 0x38, 0xfc, 0x38, 0x30, 0x20, 0xde },
/* char 0x51 (raw 0xce) */
{ 0x02, 0x12, 0x10, 0xfe, 0x7c, 0x38, 0x12, 0x02 },
/* char 0x52 (raw 0xe5) */
{ 0x02, 0x12, 0x38, 0x7c, 0xfe, 0x10, 0x12, 0x02 },
/* char 0x53 (raw 0xea) */
{ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00 },
/* char 0x54 (raw 0xe6) */
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xfe },
/* char 0x55 (raw 0xe8) */
{ 0x10, 0x08, 0x04, 0xfe, 0x04, 0x08, 0x10, 0x00 },
/* char 0x56 (raw 0xd7) */
{ 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa },
/* char 0x57 (raw 0xe3) */
{ 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54 },
/* char 0x58 (raw 0xf4) */
{ 0x00, 0x7c, 0x82, 0x80, 0x80, 0x80, 0xfe, 0x00 },
/* char 0x59 (raw 0xe7) */
{ 0x00, 0x00, 0xfc, 0x02, 0x02, 0x02, 0xfe, 0x00 },
/* char 0x5a (raw 0xf3) */
{ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
/* char 0x5b (raw 0xd2) */
{ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00 },
/* char 0x5c (raw 0xc7) */
{ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe },
/* char 0x5d (raw 0xd4) */
{ 0x28, 0x28, 0xee, 0x00, 0xee, 0x28, 0x28, 0x00 },
/* char 0x5e (raw 0xdf) */
{ 0xfe, 0x02, 0x02, 0x32, 0x32, 0x02, 0x02, 0xfe },
/* char 0x5f (raw 0xd1) */
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
/* char 0x60 (raw 0x60) */
{ 0xdf, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff },
/* char 0x61 (raw 0x61) */
{ 0xff, 0xff, 0xc7, 0xfb, 0xc3, 0xbb, 0xc3, 0xff },
/* char 0x62 (raw 0x62) */
{ 0xbf, 0xbf, 0x87, 0xbb, 0xbb, 0xbb, 0x87, 0xff },
/* char 0x63 (raw 0x63) */
{ 0xff, 0xff, 0xc3, 0xbf, 0xbf, 0xbf, 0xc3, 0xff },
/* char 0x64 (raw 0x64) */
{ 0xfb, 0xfb, 0xc3, 0xbb, 0xbb, 0xbb, 0xc3, 0xff },
/* char 0x65 (raw 0x65) */
{ 0xff, 0xff, 0xc7, 0xbb, 0x83, 0xbf, 0xc3, 0xff },
/* char 0x66 (raw 0x66) */
{ 0xe7, 0xdb, 0xdf, 0x87, 0xdf, 0xdf, 0xdf, 0xff },
/* char 0x67 (raw 0x67) */
{ 0xff, 0xff, 0xc7, 0xbb, 0xbb, 0xc3, 0xfb, 0xc7 },
/* char 0x68 (raw 0x68) */
{ 0xbf, 0xbf, 0x87, 0xbb, 0xbb, 0xbb, 0xbb, 0xff },
/* char 0x69 (raw 0x69) */
{ 0xef, 0xff, 0xcf, 0xef, 0xef, 0xef, 0xc7, 0xff },
/* char 0x6a (raw 0x6a) */
{ 0xf7, 0xff, 0xe7, 0xf7, 0xf7, 0xf7, 0xb7, 0xcf },
/* char 0x6b (raw 0x6b) */
{ 0xbf, 0xbf, 0xbb, 0xb7, 0x8f, 0xb7, 0xbb, 0xff },
/* char 0x6c (raw 0x6c) */
{ 0xcf, 0xef, 0xef, 0xef, 0xef, 0xef, 0xc7, 0xff },
/* char 0x6d (raw 0x6d) */
{ 0xff, 0xff, 0x93, 0xab, 0xab, 0xab, 0xbb, 0xff },
/* char 0x6e (raw 0x6e) */
{ 0xff, 0xff, 0x87, 0xbb, 0xbb, 0xbb, 0xbb, 0xff },
/* char 0x6f (raw 0x6f) */
{ 0xff, 0xff, 0xc7, 0xbb, 0xbb, 0xbb, 0xc7, 0xff },
/* char 0x70 (raw 0x70) */
{ 0xff, 0xff, 0x87, 0xbb, 0xbb, 0x87, 0xbf, 0xbf },
/* char 0x71 (raw 0x71) */
{ 0xff, 0xff, 0xc3, 0xbb, 0xbb, 0xc3, 0xfb, 0xfb },
/* char 0x72 (raw 0x72) */
{ 0xff, 0xff, 0xa3, 0x9f, 0xbf, 0xbf, 0xbf, 0xff },
/* char 0x73 (raw 0x73) */
{ 0xff, 0xff, 0xc3, 0xbf, 0xc7, 0xfb, 0x87, 0xff },
/* char 0x74 (raw 0x74) */
{ 0xdf, 0xdf, 0x87, 0xdf, 0xdf, 0xdb, 0xe7, 0xff },
/* char 0x75 (raw 0x75) */
{ 0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xb3, 0xcb, 0xff },
/* char 0x76 (raw 0x76) */
{ 0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xd7, 0xef, 0xff },
/* char 0x77 (raw 0x77) */
{ 0xff, 0xff, 0xbb, 0xbb, 0xab, 0xab, 0x93, 0xff },
/* char 0x78 (raw 0x78) */
{ 0xff, 0xff, 0xbb, 0xd7, 0xef, 0xd7, 0xbb, 0xff },
/* char 0x79 (raw 0x79) */
{ 0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xc3, 0xfb, 0xc7 },
/* char 0x7a (raw 0x7a) */
{ 0xff, 0xff, 0x83, 0xf7, 0xef, 0xdf, 0x83, 0xff },
/* char 0x7b (raw 0x7b) */
{ 0xe3, 0xcf, 0xcf, 0x9f, 0xcf, 0xcf, 0xe3, 0xff },
/* char 0x7c (raw 0x7c) */
{ 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef },
/* char 0x7d (raw 0x7d) */
{ 0x8f, 0xe7, 0xe7, 0xf3, 0xe7, 0xe7, 0x8f, 0xff },
/* char 0x7e (raw 0x7e) */
{ 0xcb, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
/* char 0x7f (raw 0x7f) */
{ 0xff, 0xab, 0xd7, 0xab, 0xd7, 0xab, 0xff, 0xff },
/* char 0x80 (raw 0x40) */
{ 0x38, 0x44, 0x54, 0x5c, 0x58, 0x40, 0x3c, 0x00 },
/* char 0x81 (raw 0x41) */
{ 0x10, 0x28, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x00 },
/* char 0x82 (raw 0x42) */
{ 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00 },
/* char 0x83 (raw 0x43) */
{ 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00 },
/* char 0x84 (raw 0x44) */
{ 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00 },
/* char 0x85 (raw 0x45) */
{ 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x00 },
/* char 0x86 (raw 0x46) */
{ 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00 },
/* char 0x87 (raw 0x47) */
{ 0x3c, 0x40, 0x40, 0x40, 0x4c, 0x44, 0x3c, 0x00 },
/* char 0x88 (raw 0x48) */
{ 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x00 },
/* char 0x89 (raw 0x49) */
{ 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 },
/* char 0x8a (raw 0x4a) */
{ 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00 },
/* char 0x8b (raw 0x4b) */
{ 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00 },
/* char 0x8c (raw 0x4c) */
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00 },
/* char 0x8d (raw 0x4d) */
{ 0x44, 0x6c, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00 },
/* char 0x8e (raw 0x4e) */
{ 0x44, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x00 },
/* char 0x8f (raw 0x4f) */
{ 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 },
/* char 0x90 (raw 0x50) */
{ 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00 },
/* char 0x91 (raw 0x51) */
{ 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00 },
/* char 0x92 (raw 0x52) */
{ 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00 },
/* char 0x93 (raw 0x53) */
{ 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00 },
/* char 0x94 (raw 0x54) */
{ 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 },
/* char 0x95 (raw 0x55) */
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 },
/* char 0x96 (raw 0x56) */
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 },
/* char 0x97 (raw 0x57) */
{ 0x44, 0x44, 0x44, 0x54, 0x54, 0x6c, 0x44, 0x00 },
/* char 0x98 (raw 0x58) */
{ 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00 },
/* char 0x99 (raw 0x59) */
{ 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00 },
/* char 0x9a (raw 0x5a) */
{ 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00 },
/* char 0x9b (raw 0x5b) */
{ 0x7c, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7c, 0x00 },
/* char 0x9c (raw 0x5c) */
{ 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00 },
/* char 0x9d (raw 0x5d) */
{ 0x7c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x7c, 0x00 },
/* char 0x9e (raw 0x5e) */
{ 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00 },
/* char 0x9f (raw 0x5f) */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe },
/* char 0xa0 (raw 0x20) */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* char 0xa1 (raw 0x21) */
{ 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00 },
/* char 0xa2 (raw 0x22) */
{ 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* char 0xa3 (raw 0x23) */
{ 0x28, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x28, 0x00 },
/* char 0xa4 (raw 0x24) */
{ 0x10, 0x3c, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00 },
/* char 0xa5 (raw 0x25) */
{ 0x60, 0x64, 0x08, 0x10, 0x20, 0x4c, 0x0c, 0x00 },
/* char 0xa6 (raw 0x26) */
{ 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00 },
/* char 0xa7 (raw 0x27) */
{ 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* char 0xa8 (raw 0x28) */
{ 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00 },
/* char 0xa9 (raw 0x29) */
{ 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00 },
/* char 0xaa (raw 0x2a) */
{ 0x10, 0x54, 0x38, 0x10, 0x38, 0x54, 0x10, 0x00 },
/* char 0xab (raw 0x2b) */
{ 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00 },
/* char 0xac (raw 0x2c) */
{ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00 },
/* char 0xad (raw 0x2d) */
{ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00 },
/* char 0xae (raw 0x2e) */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00 },
/* char 0xaf (raw 0x2f) */
{ 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00 },
/* char 0xb0 (raw 0x30) */
{ 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, 0x00 },
/* char 0xb1 (raw 0x31) */
{ 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 },
/* char 0xb2 (raw 0x32) */
{ 0x38, 0x44, 0x04, 0x18, 0x20, 0x40, 0x7c, 0x00 },
/* char 0xb3 (raw 0x33) */
{ 0x7c, 0x04, 0x08, 0x18, 0x04, 0x44, 0x38, 0x00 },
/* char 0xb4 (raw 0x34) */
{ 0x08, 0x18, 0x28, 0x48, 0x7c, 0x08, 0x08, 0x00 },
/* char 0xb5 (raw 0x35) */
{ 0x7c, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00 },
/* char 0xb6 (raw 0x36) */
{ 0x1c, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00 },
/* char 0xb7 (raw 0x37) */
{ 0x7c, 0x04, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00 },
/* char 0xb8 (raw 0x38) */
{ 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00 },
/* char 0xb9 (raw 0x39) */
{ 0x38, 0x44, 0x44, 0x3c, 0x04, 0x08, 0x70, 0x00 },
/* char 0xba (raw 0x3a) */
{ 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00 },
/* char 0xbb (raw 0x3b) */
{ 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x20, 0x00 },
/* char 0xbc (raw 0x3c) */
{ 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00 },
/* char 0xbd (raw 0x3d) */
{ 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, 0x00 },
/* char 0xbe (raw 0x3e) */
{ 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00 },
/* char 0xbf (raw 0x3f) */
{ 0x38, 0x44, 0x08, 0x10, 0x10, 0x00, 0x10, 0x00 },
/* char 0xc0 (raw 0x40) */
{ 0x38, 0x44, 0x54, 0x5c, 0x58, 0x40, 0x3c, 0x00 },
/* char 0xc1 (raw 0x41) */
{ 0x10, 0x28, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x00 },
/* char 0xc2 (raw 0x42) */
{ 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00 },
/* char 0xc3 (raw 0x43) */
{ 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00 },
/* char 0xc4 (raw 0x44) */
{ 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00 },
/* char 0xc5 (raw 0x45) */
{ 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x00 },
/* char 0xc6 (raw 0x46) */
{ 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00 },
/* char 0xc7 (raw 0x47) */
{ 0x3c, 0x40, 0x40, 0x40, 0x4c, 0x44, 0x3c, 0x00 },
/* char 0xc8 (raw 0x48) */
{ 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x00 },
/* char 0xc9 (raw 0x49) */
{ 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 },
/* char 0xca (raw 0x4a) */
{ 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00 },
/* char 0xcb (raw 0x4b) */
{ 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00 },
/* char 0xcc (raw 0x4c) */
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00 },
/* char 0xcd (raw 0x4d) */
{ 0x44, 0x6c, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00 },
/* char 0xce (raw 0x4e) */
{ 0x44, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x00 },
/* char 0xcf (raw 0x4f) */
{ 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 },
/* char 0xd0 (raw 0x50) */
{ 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00 },
/* char 0xd1 (raw 0x51) */
{ 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00 },
/* char 0xd2 (raw 0x52) */
{ 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00 },
/* char 0xd3 (raw 0x53) */
{ 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00 },
/* char 0xd4 (raw 0x54) */
{ 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 },
/* char 0xd5 (raw 0x55) */
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 },
/* char 0xd6 (raw 0x56) */
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 },
/* char 0xd7 (raw 0x57) */
{ 0x44, 0x44, 0x44, 0x54, 0x54, 0x6c, 0x44, 0x00 },
/* char 0xd8 (raw 0x58) */
{ 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00 },
/* char 0xd9 (raw 0x59) */
{ 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00 },
/* char 0xda (raw 0x5a) */
{ 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00 },
/* char 0xdb (raw 0x5b) */
{ 0x7c, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7c, 0x00 },
/* char 0xdc (raw 0x5c) */
{ 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00 },
/* char 0xdd (raw 0x5d) */
{ 0x7c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x7c, 0x00 },
/* char 0xde (raw 0x5e) */
{ 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00 },
/* char 0xdf (raw 0x5f) */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe },
/* char 0xe0 (raw 0x60) */
{ 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* char 0xe1 (raw 0x61) */
{ 0x00, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00 },
/* char 0xe2 (raw 0x62) */
{ 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00 },
/* char 0xe3 (raw 0x63) */
{ 0x00, 0x00, 0x3c, 0x40, 0x40, 0x40, 0x3c, 0x00 },
/* char 0xe4 (raw 0x64) */
{ 0x04, 0x04, 0x3c, 0x44, 0x44, 0x44, 0x3c, 0x00 },
/* char 0xe5 (raw 0x65) */
{ 0x00, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00 },
/* char 0xe6 (raw 0x66) */
{ 0x18, 0x24, 0x20, 0x78, 0x20, 0x20, 0x20, 0x00 },
/* char 0xe7 (raw 0x67) */
{ 0x00, 0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x38 },
/* char 0xe8 (raw 0x68) */
{ 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00 },
/* char 0xe9 (raw 0x69) */
{ 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00 },
/* char 0xea (raw 0x6a) */
{ 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x48, 0x30 },
/* char 0xeb (raw 0x6b) */
{ 0x40, 0x40, 0x44, 0x48, 0x70, 0x48, 0x44, 0x00 },
/* char 0xec (raw 0x6c) */
{ 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 },
/* char 0xed (raw 0x6d) */
{ 0x00, 0x00, 0x6c, 0x54, 0x54, 0x54, 0x44, 0x00 },
/* char 0xee (raw 0x6e) */
{ 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00 },
/* char 0xef (raw 0x6f) */
{ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 },
/* char 0xf0 (raw 0x70) */
{ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40 },
/* char 0xf1 (raw 0x71) */
{ 0x00, 0x00, 0x3c, 0x44, 0x44, 0x3c, 0x04, 0x04 },
/* char 0xf2 (raw 0x72) */
{ 0x00, 0x00, 0x5c, 0x60, 0x40, 0x40, 0x40, 0x00 },
/* char 0xf3 (raw 0x73) */
{ 0x00, 0x00, 0x3c, 0x40, 0x38, 0x04, 0x78, 0x00 },
/* char 0xf4 (raw 0x74) */
{ 0x20, 0x20, 0x78, 0x20, 0x20, 0x24, 0x18, 0x00 },
/* char 0xf5 (raw 0x75) */
{ 0x00, 0x00, 0x44, 0x44, 0x44, 0x4c, 0x34, 0x00 },
/* char 0xf6 (raw 0x76) */
{ 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 },
/* char 0xf7 (raw 0x77) */
{ 0x00, 0x00, 0x44, 0x44, 0x54, 0x54, 0x6c, 0x00 },
/* char 0xf8 (raw 0x78) */
{ 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 },
/* char 0xf9 (raw 0x79) */
{ 0x00, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x38 },
/* char 0xfa (raw 0x7a) */
{ 0x00, 0x00, 0x7c, 0x08, 0x10, 0x20, 0x7c, 0x00 },
/* char 0xfb (raw 0x7b) */
{ 0x1c, 0x30, 0x30, 0x60, 0x30, 0x30, 0x1c, 0x00 },
/* char 0xfc (raw 0x7c) */
{ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
/* char 0xfd (raw 0x7d) */
{ 0x70, 0x18, 0x18, 0x0c, 0x18, 0x18, 0x70, 0x00 },
/* char 0xfe (raw 0x7e) */
{ 0x34, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* char 0xff (raw 0x7f) */
{ 0x00, 0x54, 0x28, 0x54, 0x28, 0x54, 0x00, 0x00 },

BIN
src/kegsicon.icns Normal file

Binary file not shown.

955
src/macdriver.c Normal file
View File

@ -0,0 +1,955 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_macdriver_c[] = "@(#)$KmKId: macdriver.c,v 1.19 2004-03-23 17:27:56-05 kentd Exp $";
// Quartz: CreateCGContextForPort vs QDBeginCGContext
// Use CGDisplayMoveCursorToPoint(kCGDirectMainDisplay) to warp pointer
// Use CGPointMake to get a point
#include <Carbon/Carbon.h>
#include "defc.h"
#include "protos_macdriver.h"
#define MAX_STATUS_LINES 7
#define X_LINE_LENGTH 88
#define MAX_MAC_ARGS 128
WindowRef g_main_window;
int g_quit_seen = 0;
EventHandlerUPP g_quit_handler_UPP;
EventHandlerUPP g_dummy_event_handler_UPP;
RgnHandle g_event_rgnhandle = 0;
int g_ignore_next_click = 0;
int g_mainwin_active = 0;
GDHandle g_gdhandle = 0;
int g_mac_mouse_x = 0;
int g_mac_mouse_y = 0;
FMFontFamily g_status_font_family;
extern Kimage g_mainwin_kimage;
int g_mac_argc = 0;
char *g_mac_argv[MAX_MAC_ARGS];
word32 g_mac_shift_control_state = 0;
extern char g_argv0_path[];
extern word32 g_red_mask;
extern word32 g_green_mask;
extern word32 g_blue_mask;
extern int g_red_left_shift;
extern int g_green_left_shift;
extern int g_blue_left_shift;
extern int g_red_right_shift;
extern int g_green_right_shift;
extern int g_blue_right_shift;
int g_use_shmem = 0;
extern int Verbose;
extern int g_warp_pointer;
extern int g_screen_depth;
extern int g_force_depth;
int g_screen_mdepth = 0;
extern int g_send_sound_to_file;
extern int g_quit_sim_now;
extern int g_config_control_panel;
int g_auto_repeat_on = -1;
int g_x_shift_control_state = 0;
extern int Max_color_size;
extern word32 g_palette_8to1624[256];
extern word32 g_a2palette_8to1624[256];
int g_alt_left_up = 1;
int g_alt_right_up = 1;
extern word32 g_full_refresh_needed;
extern int g_border_sides_refresh_needed;
extern int g_border_special_refresh_needed;
extern int g_status_refresh_needed;
extern int g_lores_colors[];
extern int g_a2vid_palette;
extern int g_installed_full_superhires_colormap;
extern int g_screen_redraw_skip_amt;
extern word32 g_a2_screen_buffer_changed;
extern char *g_status_ptrs[MAX_STATUS_LINES];
extern const char g_kegs_version_str[];
#if 0
char g_printf_buf[4096];
int g_debug_file_fd = -1;
/* HACK to debug startup issues when launched from Finder */
int
printf(const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vsnprintf(g_printf_buf, 4090, fmt, ap);
if(g_debug_file_fd < 0) {
g_debug_file_fd = open("/tmp/kegs.out",
O_CREAT | O_WRONLY | O_TRUNC, 0x1b6);
fprintf(stdout, "g_debug_file_fd = %d, %d\n", g_debug_file_fd,
errno);
}
write(1, g_printf_buf, strlen(g_printf_buf));
write(g_debug_file_fd, g_printf_buf, strlen(g_printf_buf));
va_end(ap);
return ret;
}
#endif
pascal OSStatus
quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore)
{
OSStatus err;
err = CallNextEventHandler(call_ref, event);
if(err == noErr) {
g_quit_seen = 1;
}
return err;
}
void
show_alert(const char *str1, const char *str2, const char *str3, int num)
{
char buf[256];
DialogRef alert;
DialogItemIndex out_item_hit;
CFStringRef cfstrref;
if(num != 0) {
snprintf(buf, 250, "%s%s%s: %d", str1, str2, str3, num);
} else {
snprintf(buf, 250, "%s%s%s", str1, str2, str3);
}
cfstrref = CFStringCreateWithCString(NULL, buf,
kCFStringEncodingMacRoman);
CreateStandardAlert(kAlertStopAlert, cfstrref, CFSTR("Click OK"),
NULL, &alert);
RunStandardAlert(alert, NULL, &out_item_hit);
}
pascal OSStatus
my_cmd_handler( EventHandlerCallRef handlerRef, EventRef event, void *userdata)
{
OSStatus osresult;
HICommand command;
word32 command_id;
osresult = eventNotHandledErr;
GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL,
sizeof(HICommand), NULL, &command);
command_id = (word32)command.commandID;
switch(command_id) {
case 'Kbep':
SysBeep(10);
osresult = noErr;
break;
case 'abou':
show_alert("KEGSMAC v", g_kegs_version_str,
", Copyright 2004 Kent Dickey\n"
"Latest version at http://kegs.sourceforge.net/\n", 0);
osresult = noErr;
break;
case 'KCFG':
g_config_control_panel = !g_config_control_panel;
osresult = noErr;
break;
case 'quit':
break;
case 'swin':
/* not sure what this is, but Panther sends it */
break;
default:
printf("commandID %08x unknown\n", command_id);
SysBeep(90);
break;
}
return osresult;
}
int g_upd_count = 0;
void
update_window(void)
{
SetPortWindowPort(g_main_window);
PenNormal();
g_full_refresh_needed = -1;
g_a2_screen_buffer_changed = -1;
g_status_refresh_needed = 1;
g_border_sides_refresh_needed = 1;
g_border_special_refresh_needed = 1;
g_upd_count++;
if(g_upd_count > 250) {
g_upd_count = 0;
}
}
struct char_int_un {
union {
char c[4];
UInt32 uint;
} u;
char c2[2];
};
typedef struct char_int_un Char_int;
int g_event_count = 0;
void
show_event(UInt32 event_class, UInt32 event_kind, int handled)
{
Char_int char_int;
if(handled == 0 && event_class != 'cgs ') {
char_int.c2[0] = 0;
char_int.u.uint = event_class;
printf("Event %d: %08x = %s, %d\n", g_event_count,
(int)event_class, &(char_int.u.c[0]), (int)event_kind);
}
g_event_count++;
}
pascal OSStatus
my_win_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata)
{
OSStatus os_result;
UInt32 event_kind;
os_result = eventNotHandledErr;
// SysBeep(1);
event_kind = GetEventKind(event);
// show_alert("win handler", event_kind);
if(event_kind == kEventWindowDrawContent) {
update_window();
} if(event_kind == kEventWindowClose) {
g_quit_sim_now = 1;
g_quit_seen = 1;
my_exit(0);
} else {
show_event(GetEventClass(event), event_kind, 0);
update_window();
}
return os_result;
}
pascal OSStatus
dummy_event_handler(EventHandlerCallRef call_ref, EventRef in_event,
void *ignore)
{
OSStatus err;
EventHandlerRef installed_handler;
EventTypeSpec event_spec = { kEventClassApplication, kEventAppQuit };
// From http://developer.apple.com/qa/qa2001/qa1061.html
// Trick to move main event queue to use ReceiveNextEvent in an event
// handler called by RunApplicationEventLoop
err = InstallApplicationEventHandler(g_quit_handler_UPP, 1, &event_spec,
NULL, &installed_handler);
kegsmain(g_mac_argc, g_mac_argv);
return noErr;
}
void
mac_update_modifiers(word32 state)
{
word32 state_xor;
int is_up;
state = state & (cmdKey | shiftKey | alphaLock | optionKey |
controlKey);
state_xor = g_mac_shift_control_state ^ state;
is_up = 0;
if(state_xor & controlKey) {
is_up = ((state & controlKey) == 0);
adb_physical_key_update(0x36, is_up);
}
if(state_xor & alphaLock) {
is_up = ((state & alphaLock) == 0);
adb_physical_key_update(0x39, is_up);
}
if(state_xor & shiftKey) {
is_up = ((state & shiftKey) == 0);
adb_physical_key_update(0x38, is_up);
}
if(state_xor & cmdKey) {
is_up = ((state & cmdKey) == 0);
adb_physical_key_update(0x37, is_up);
}
if(state_xor & optionKey) {
is_up = ((state & optionKey) == 0);
adb_physical_key_update(0x3a, is_up);
}
g_mac_shift_control_state = state;
}
void
mac_warp_mouse()
{
Rect port_rect;
Point win_origin_pt;
CGPoint cgpoint;
CGDisplayErr cg_err;
GetPortBounds(GetWindowPort(g_main_window), &port_rect);
SetPt(&win_origin_pt, port_rect.left, port_rect.top);
LocalToGlobal(&win_origin_pt);
cgpoint = CGPointMake( (float)(win_origin_pt.h + X_A2_WINDOW_WIDTH/2),
(float)(win_origin_pt.v + X_A2_WINDOW_HEIGHT/2));
cg_err = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
}
void
check_input_events()
{
OSStatus err;
EventTargetRef target;
EventRef event;
UInt32 event_class, event_kind;
byte mac_keycode;
UInt32 keycode;
UInt32 modifiers;
Point mouse_point, mouse_delta_point;
WindowRef window_ref;
int button, button_state;
EventMouseButton mouse_button;
int handled;
int mouse_events;
int is_up;
int in_win;
int ignore;
if(g_quit_seen) {
exit(0);
}
SetPortWindowPort(g_main_window);
mouse_events = 0;
target = GetEventDispatcherTarget();
while(1) {
err = ReceiveNextEvent(0, NULL, kEventDurationNoWait,
true, &event);
if(err == eventLoopTimedOutErr) {
break;
}
if(err != noErr) {
printf("err: %d\n", (int)err);
break;
}
event_class = GetEventClass(event);
event_kind = GetEventKind(event);
handled = 0;
switch(event_class) {
case kEventClassKeyboard:
handled = 1;
keycode = 0;
modifiers = 0;
GetEventParameter(event, kEventParamKeyMacCharCodes,
typeChar, NULL, sizeof(byte), NULL,
&mac_keycode);
GetEventParameter(event, kEventParamKeyCode,
typeUInt32, NULL, sizeof(UInt32), NULL,
&keycode);
GetEventParameter(event, kEventParamKeyModifiers,
typeUInt32, NULL, sizeof(UInt32), NULL,
&modifiers);
mac_update_modifiers((word32)modifiers);
// Key up/down event
is_up = -1;
switch(event_kind) {
case kEventRawKeyDown:
is_up = 0;
//printf("key down: %02x, %08x\n",
// (int)mac_keycode, (int)keycode);
break;
case kEventRawKeyUp:
is_up = 1;
//printf("key up: %02x, %08x\n",
// (int)mac_keycode, (int)keycode);
break;
case kEventRawKeyModifiersChanged:
is_up = -1;
//printf("key xxx: %08x\n", (int)modifiers);
break;
}
if(is_up >= 0) {
adb_physical_key_update((int)keycode, is_up);
}
break;
case kEventClassMouse:
handled = 2;
mouse_events++;
GetEventParameter(event, kEventParamMouseLocation,
typeQDPoint, NULL, sizeof(Point), NULL,
&mouse_point);
GetWindowRegion(g_main_window, kWindowContentRgn,
g_event_rgnhandle);
in_win = PtInRgn(mouse_point, g_event_rgnhandle);
// in_win = 1 if it was in the contect region of window
err = GetEventParameter(event, kEventParamMouseDelta,
typeQDPoint, NULL, sizeof(Point), NULL,
&mouse_delta_point);
button = 0;
button_state = -1;
switch(event_kind) {
case kEventMouseDown:
button_state = 7;
handled = 3;
break;
case kEventMouseUp:
button_state = 0;
handled = 3;
break;
}
if(button_state >= 0) {
GetEventParameter(event, kEventParamMouseButton,
typeMouseButton, NULL,
sizeof(EventMouseButton), NULL,
&mouse_button);
button = mouse_button;
if(button > 1) {
button = 4 - button;
button = 1 << button;
}
ignore = (button_state != 0) &&
(!in_win || g_ignore_next_click);
ignore = ignore || !g_mainwin_active;
if(ignore) {
// Outside of A2 window, ignore clicks
button = 0;
}
if(button_state == 0) {
g_ignore_next_click = 0;
}
}
GlobalToLocal(&mouse_point);
if(g_warp_pointer) {
if(err == 0) {
g_mac_mouse_x += mouse_delta_point.h;
g_mac_mouse_y += mouse_delta_point.v;
}
mac_warp_mouse();
} else {
g_mac_mouse_x = mouse_point.h -BASE_MARGIN_LEFT;
g_mac_mouse_y = mouse_point.v -BASE_MARGIN_TOP;
}
#if 0
printf("Mouse %d at: %d,%d button:%d, button_st:%d\n",
mouse_events, g_mac_mouse_x, g_mac_mouse_y,
button, button_state);
printf("Mouse deltas: err:%d, %d,%d\n", (int)err,
mouse_delta_point.h, mouse_delta_point.v);
#endif
update_mouse(g_mac_mouse_x, g_mac_mouse_y,
button_state, button & 7);
if(g_warp_pointer) {
g_mac_mouse_x = A2_WINDOW_WIDTH/2;
g_mac_mouse_y = A2_WINDOW_HEIGHT/2;
update_mouse(g_mac_mouse_x, g_mac_mouse_y,0,-1);
}
break;
case kEventClassApplication:
switch(event_kind) {
case kEventAppActivated:
handled = 1;
g_mainwin_active = 1;
window_ref = 0;
GetEventParameter(event, kEventParamWindowRef,
typeWindowRef, NULL, sizeof(WindowRef),
NULL, &window_ref);
if(window_ref == g_main_window) {
g_ignore_next_click = 1;
}
break;
case kEventAppDeactivated:
handled = 1;
g_mainwin_active = 0;
g_ignore_next_click = 1;
break;
}
break;
}
show_event(event_class, event_kind, handled);
if(handled != 1) {
(void)SendEventToEventTarget(event, target);
}
ReleaseEvent(event);
}
return;
}
void
temp_run_application_event_loop(void)
{
OSStatus err;
EventRef dummy_event;
EventHandlerRef install_handler;
EventTypeSpec event_spec = { 'KWIN', 'KWIN' };
// Create UPP for dummy_event_handler and for quit_event_handler
err = noErr;
dummy_event = 0;
g_dummy_event_handler_UPP = NewEventHandlerUPP(dummy_event_handler);
g_quit_handler_UPP = NewEventHandlerUPP(quit_event_handler);
if((g_dummy_event_handler_UPP == 0) || (g_quit_handler_UPP == 0)) {
err = memFullErr;
}
if(err == noErr) {
err = InstallApplicationEventHandler(g_dummy_event_handler_UPP,
1, &event_spec, 0, &install_handler);
if(err == noErr) {
err = MacCreateEvent(NULL, 'KWIN', 'KWIN',
GetCurrentEventTime(), kEventAttributeNone,
&dummy_event);
if(err == noErr) {
err = PostEventToQueue(GetMainEventQueue(),
dummy_event, kEventPriorityHigh);
}
if(err == noErr) {
RunApplicationEventLoop();
}
(void)RemoveEventHandler(install_handler);
}
}
if(dummy_event != NULL) {
ReleaseEvent(dummy_event);
}
}
int
main(int argc, char* argv[])
{
ProcessSerialNumber my_psn;
IBNibRef nibRef;
EventHandlerUPP handlerUPP;
EventTypeSpec cmd_event[3];
#if 0
MenuBarHandle mbar_handle;
MenuRef menu_ref;
#endif
Rect win_rect;
OSStatus err;
char *argptr;
int slash_cnt;
int i;
/* Prepare argv0 */
slash_cnt = 0;
argptr = argv[0];
for(i = strlen(argptr); i >= 0; i--) {
if(argptr[i] == '/') {
slash_cnt++;
if(slash_cnt == 3) {
strncpy(&(g_argv0_path[0]), argptr, i);
g_argv0_path[i] = 0;
}
}
}
printf("g_argv0_path is %s\n", g_argv0_path);
g_mac_argv[0] = argv[0];
g_mac_argc = 1;
i = 1;
while((i < argc) && (g_mac_argc < MAX_MAC_ARGS)) {
if(!strncmp(argv[i], "-psn", 4)) {
/* skip this argument */
} else {
g_mac_argv[g_mac_argc++] = argv[i];
}
i++;
}
InitCursor();
g_event_rgnhandle = NewRgn();
g_status_font_family = FMGetFontFamilyFromName("\pCourier");
SetRect(&win_rect, 0, 0, X_A2_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT +
MAX_STATUS_LINES*16 + 8);
OffsetRect(&win_rect, 64, 50);
// Create a Nib reference passing the name of the nib file
// CreateNibReference only searches into the application bundle.
err = CreateNibReference(CFSTR("main"), &nibRef);
require_noerr( err, CantGetNibRef );
// Once the nib reference is created, set the menu bar.
err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
require_noerr( err, CantSetMenuBar );
#if 0
mbar_handle = GetMenuBar();
SetMenuBar(mbar_handle);
printf("mbar_handle: %p\n", mbar_handle);
menu_ref = NewMenu(1, "\pTest");
printf("menu_ref: %p\n", menu_ref);
AppendMenu(menu_ref, "\pTest item 1");
InsertMenu(menu_ref, 0);
// ShowMenuBar(); // Don't call ShowMenuBar: it prevents menubar update!
DrawMenuBar();
InvalMenuBar();
#endif
err = CreateNewWindow(kDocumentWindowClass,
kWindowStandardDocumentAttributes |
kWindowStandardHandlerAttribute,
&win_rect, &g_main_window);
//printf("CreateNewWindow ret: %d, g_main_window: %p\n", (int)err,
// g_main_window);
err = SetWindowTitleWithCFString(g_main_window, CFSTR("KEGSMAC"));
// We don't need the nib reference anymore.
DisposeNibReference(nibRef);
SysBeep(120);
handlerUPP = NewEventHandlerUPP( my_cmd_handler );
cmd_event[0].eventClass = kEventClassCommand;
cmd_event[0].eventKind = kEventProcessCommand;
InstallWindowEventHandler(g_main_window, handlerUPP, 1, &cmd_event[0],
(void *)g_main_window, NULL);
handlerUPP = NewEventHandlerUPP(my_win_handler);
cmd_event[0].eventClass = kEventClassWindow;
cmd_event[0].eventKind = kEventWindowDrawContent;
cmd_event[1].eventClass = kEventClassWindow;
cmd_event[1].eventKind = kEventWindowUpdate;
cmd_event[2].eventClass = kEventClassWindow;
cmd_event[2].eventKind = kEventWindowClose;
err = InstallWindowEventHandler(g_main_window, handlerUPP, 3,
&cmd_event[0], (void *)g_main_window, NULL);
require_noerr(err, CantCreateWindow);
// Get screen depth
g_gdhandle = GetGDevice();
g_screen_mdepth = (**((**g_gdhandle).gdPMap)).pixelSize;
g_screen_depth = g_screen_mdepth;
//printf("g_screen_depth = %d, depth: %d, bytes: %d\n", g_screen_depth,
// (**g_gdhandle).gdCCDepth, (**g_gdhandle).gdCCBytes);
if(g_screen_depth > 16) {
/* 32-bit display */
g_red_mask = 0xff;
g_green_mask = 0xff;
g_blue_mask = 0xff;
g_red_left_shift = 16;
g_green_left_shift = 8;
g_blue_left_shift = 0;
g_red_right_shift = 0;
g_green_right_shift = 0;
g_blue_right_shift = 0;
} else if(g_screen_depth > 8) {
/* 16-bit display */
g_red_mask = 0x1f;
g_green_mask = 0x1f;
g_blue_mask = 0x1f;
g_red_left_shift = 10;
g_green_left_shift = 5;
g_blue_left_shift = 0;
g_red_right_shift = 3;
g_green_right_shift = 3;
g_blue_right_shift = 3;
}
// show_alert("About to show window", (int)g_main_window);
update_window();
// The window was created hidden so show it.
ShowWindow( g_main_window );
BringToFront( g_main_window );
update_window();
// Make us pop to the front a different way
err = GetCurrentProcess(&my_psn);
if(err == noErr) {
(void)SetFrontProcess(&my_psn);
}
// Call the event loop
temp_run_application_event_loop();
CantCreateWindow:
CantSetMenuBar:
CantGetNibRef:
show_alert("ending", "", "error code", err);
return err;
}
void
x_update_color(int col_num, int red, int green, int blue, word32 rgb)
{
}
void
x_update_physical_colormap()
{
}
void
show_xcolor_array()
{
int i;
for(i = 0; i < 256; i++) {
printf("%02x: %08x\n", i, g_palette_8to1624[i]);
}
}
void
xdriver_end()
{
printf("xdriver_end\n");
}
void
x_get_kimage(Kimage *kimage_ptr)
{
PixMapHandle pixmap_handle;
GWorldPtr world;
Rect world_rect;
OSStatus err;
word32 *wptr;
byte *ptr;
int row_bytes;
int width;
int height;
int depth, mdepth;
int size;
width = kimage_ptr->width_req;
height = kimage_ptr->height;
depth = kimage_ptr->depth;
mdepth = kimage_ptr->mdepth;
size = 0;
if(depth == g_screen_depth) {
SetRect(&world_rect, 0, 0, width, height);
err = NewGWorld( &world, 0, &world_rect, NULL, NULL, 0);
pixmap_handle = GetGWorldPixMap(world);
err = LockPixels(pixmap_handle);
ptr = (byte *)GetPixBaseAddr(pixmap_handle);
row_bytes = ((*pixmap_handle)->rowBytes & 0x3fff);
kimage_ptr->width_act = row_bytes / (mdepth >> 3);
mac_printf("Got depth: %d, bitmap_ptr: %p, width: %d\n", depth,
ptr, kimage_ptr->width_act);
mac_printf("pixmap->base: %08x, rowbytes: %08x, pixType:%08x\n",
(int)(*pixmap_handle)->baseAddr,
(*pixmap_handle)->rowBytes,
(*pixmap_handle)->pixelType);
wptr = (word32 *)(*pixmap_handle);
mac_printf("wptr: %p=%08x %08x %08x %08x %08x %08x %08x %08x\n",
wptr,
wptr[0], wptr[1], wptr[2], wptr[3],
wptr[4], wptr[5], wptr[6], wptr[7]);
kimage_ptr->dev_handle = pixmap_handle;
kimage_ptr->data_ptr = ptr;
} else {
/* allocate buffers for video.c to draw into */
size = (width*height*mdepth) >> 3;
ptr = (byte *)malloc(size);
if(ptr == 0) {
mac_printf("malloc for data fail, mdepth:%d\n", mdepth);
exit(2);
}
kimage_ptr->data_ptr = ptr;
kimage_ptr->dev_handle = (void *)-1;
}
mac_printf("kim: %p, dev:%p data: %p, size: %08x\n", kimage_ptr,
kimage_ptr->dev_handle, kimage_ptr->data_ptr, size);
}
void
dev_video_init()
{
int lores_col;
int i;
printf("Preparing graphics system\n");
video_get_kimages();
if(g_screen_depth != 8) {
// Get g_mainwin_kimage
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,
g_screen_mdepth);
}
for(i = 0; i < 256; i++) {
lores_col = g_lores_colors[i & 0xf];
video_update_color_raw(i, lores_col);
g_a2palette_8to1624[i] = g_palette_8to1624[i];
}
g_installed_full_superhires_colormap = 1;
fflush(stdout);
}
void
x_redraw_status_lines()
{
Rect rect;
Pattern white_pattern;
char tmp_buf[256];
char *buf;
int len;
int line;
int height;
int margin;
SetPortWindowPort(g_main_window);
PenNormal();
height = 16;
margin = 0;
TextFont(g_status_font_family);
TextFace(normal);
TextSize(12);
SetRect(&rect, 0, X_A2_WINDOW_HEIGHT + margin, X_A2_WINDOW_WIDTH,
X_A2_WINDOW_HEIGHT + margin + MAX_STATUS_LINES*height);
GetQDGlobalsWhite(&white_pattern);
FillRect(&rect, &white_pattern);
for(line = 0; line < MAX_STATUS_LINES; line++) {
buf = g_status_ptrs[line];
if(buf == 0) {
/* skip it */
continue;
}
MoveTo(10, X_A2_WINDOW_HEIGHT + height*line + margin + height);
len = MIN(250, strlen(buf));
strncpy(&tmp_buf[1], buf, len);
tmp_buf[0] = len;
DrawString(&tmp_buf[0]);
}
}
void
x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy,
int width, int height)
{
PixMapHandle pixmap_handle;
Rect src_rect, dest_rect;
CGrafPtr window_port;
SetPortWindowPort(g_main_window);
pixmap_handle = kimage_ptr->dev_handle;
window_port = GetWindowPort(g_main_window);
SetRect(&src_rect, srcx, srcy, srcx + width, srcy + height);
SetRect(&dest_rect, destx, desty, destx + width, desty + height);
CopyBits( (BitMap *)(*pixmap_handle),
GetPortBitMapForCopyBits(window_port), &src_rect, &dest_rect,
srcCopy, NULL);
}
void
x_push_done()
{
}
void
x_auto_repeat_on(int must)
{
}
void
x_auto_repeat_off(int must)
{
}
void
x_hide_pointer(int do_hide)
{
if(do_hide) {
HideCursor();
} else {
ShowCursor();
}
}

154
src/macsnd_driver.c Normal file
View File

@ -0,0 +1,154 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_macsnd_driver_c[] = "@(#)$KmKId: macsnd_driver.c,v 1.4 2003-10-17 15:57:40-04 kentd Exp $";
#include "defc.h"
#include "sound.h"
#include <Carbon/Carbon.h>
#include <unistd.h>
#define MACSND_REBUF_SIZE (64*1024)
#define MACSND_QUANTA 512
/* MACSND_QUANTA must be >= 128 and a power of 2 */
word32 g_macsnd_rebuf[MACSND_REBUF_SIZE];
volatile word32 *g_macsnd_rebuf_ptr;
volatile word32 *g_macsnd_rebuf_cur;
volatile int g_macsnd_playing = 0;
extern int Verbose;
extern int g_audio_rate;
extern word32 *g_sound_shm_addr;
extern int g_sound_size;
SndChannelPtr g_snd_channel_ptr;
ExtSoundHeader g_snd_hdr;
SndCommand g_snd_cmd;
void
mac_snd_callback(SndChannelPtr snd_chan_ptr, SndCommand *in_sndcmd)
{
OSStatus err;
int samps;
// This is an interrupt routine--no printf, etc!
samps = g_macsnd_rebuf_ptr - g_macsnd_rebuf_cur;
if(samps < 0) {
samps += MACSND_REBUF_SIZE;
}
samps = samps & -(MACSND_QUANTA); // quantize to 1024 samples
if(g_macsnd_rebuf_cur + samps > &(g_macsnd_rebuf[MACSND_REBUF_SIZE])) {
samps = &(g_macsnd_rebuf[MACSND_REBUF_SIZE]) -
g_macsnd_rebuf_cur;
}
if(samps > 0) {
g_macsnd_playing = 1;
g_snd_hdr.numFrames = samps;
g_snd_hdr.loopEnd = samps;
g_snd_hdr.samplePtr = (byte *)g_macsnd_rebuf_cur;
g_snd_cmd.cmd = bufferCmd;
g_snd_cmd.param1 = 0;
g_snd_cmd.param2 = (long) &g_snd_hdr;
g_macsnd_rebuf_cur += samps;
if(g_macsnd_rebuf_cur >= &(g_macsnd_rebuf[MACSND_REBUF_SIZE])) {
g_macsnd_rebuf_cur -= MACSND_REBUF_SIZE;
}
err = SndDoImmediate(g_snd_channel_ptr, &g_snd_cmd);
// And set-up callback
g_snd_cmd.cmd = callBackCmd;
g_snd_cmd.param1 = 0;
g_snd_cmd.param2 = 0;
err = SndDoCommand(g_snd_channel_ptr, &g_snd_cmd, TRUE);
} else {
g_macsnd_playing = 0;
}
}
int
mac_send_audio(byte *ptr, int in_size)
{
SndCommand snd_cmd = {0};
word32 *wptr, *macptr;
word32 *eptr;
int samps;
int i;
samps = in_size / 4;
wptr = (word32 *)ptr;
macptr = (word32 *)g_macsnd_rebuf_ptr;
eptr = &g_macsnd_rebuf[MACSND_REBUF_SIZE];
for(i = 0; i < samps; i++) {
*macptr++ = *wptr++;
if(macptr >= eptr) {
macptr = &g_macsnd_rebuf[0];
}
}
g_macsnd_rebuf_ptr = macptr;
if(!g_macsnd_playing) {
mac_snd_callback(g_snd_channel_ptr, &snd_cmd);
}
return in_size;
}
void
child_sound_init_mac()
{
OSStatus err;
mac_printf("In mac child\n");
fflush(stdout);
mac_printf("pid: %d\n", getpid());
fflush(stdout);
//return;
//g_snd_channel_ptr = 0;
err = SndNewChannel(&g_snd_channel_ptr, sampledSynth, initStereo,
NewSndCallBackUPP(mac_snd_callback));
mac_printf("SndNewChannel ret: %d\n", (int)err);
fflush(stdout);
memset(&g_snd_hdr, 0, sizeof(g_snd_hdr));
g_snd_hdr.sampleSize = 16;
g_snd_hdr.numChannels = 2;
g_audio_rate = 44100;
g_snd_hdr.sampleRate = g_audio_rate << 16;
g_snd_hdr.numFrames = 0; // will be set in mac_send_audio
g_snd_hdr.encode = extSH;
g_snd_hdr.baseFrequency = 0;
g_snd_hdr.samplePtr = 0;
set_audio_rate(g_audio_rate);
mac_printf("End of child_sound_init_mac\n");
fflush(stdout);
}
void
macsnd_init(word32 *shmaddr)
{
g_macsnd_rebuf_cur = &g_macsnd_rebuf[0];
g_macsnd_rebuf_ptr = &g_macsnd_rebuf[0];
mac_printf("macsnd_init called\n");
child_sound_loop(-1, -1, shmaddr);
}

31
src/make_inst Executable file
View File

@ -0,0 +1,31 @@
#!/usr/local/bin/perl -w
# $KmKId: make_inst,v 1.5 2002-11-07 08:18:16-08 kadickey Exp $
$is_c = shift;
$repl = shift;
$count = 0;
while(<>) {
$line = $_;
if(/^inst(..)_SYM(.*)$/) {
if($is_c eq "c") {
if($count > 0) {
printf("\tbreak;\n");
}
print "case 0x$1: $2\n";
$count++;
} else {
print "\t.align\t8\n";
print "inst" . "$1" . "_$repl" . "$2\n";
}
} elsif(/^(.*)_SYM(.*)$/) {
print "$1" . "_$repl" . "$2\n";
} else {
print $line;
}
}
# if(/^inst(..)_SYM (.*)$/) {
# print "OPCODE($1) /* $2 */\n";
# } else if(/^(

30
src/make_size Executable file
View File

@ -0,0 +1,30 @@
#!/usr/local/bin/perl -w
# $KmKId: make_size,v 1.3 2002-11-07 08:18:16-08 kadickey Exp $
$repl = shift;
while(<>) {
$line = $_;
if(/\.word inst(..)_SYM\+(.)(.*)$/) {
if($repl eq "c") {
print "\t0x$2, /* $1 */ $3\n";
} elsif($repl eq "s") {
print "\t.byte 0x$2, /* $1 */ $3\n";
} else {
print "\t.word\tinst$1" . "_$repl" . "\t/*$2*/ $3\n";
}
} elsif (/\.block.*$/) {
if($repl eq "c") {
print "\n";
} elsif($repl eq "s") {
print "\n";
} else {
print $line;
}
} else {
print $line;
}
}
# if(/^inst(..)_SYM (.*)$/) {
# print "OPCODE($1) /* $2 */\n";
# } else if(/^(

4
src/make_win Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
export PATH="/mingw/bin:${PATH}"
make

2353
src/moremem.c Normal file

File diff suppressed because it is too large Load Diff

169
src/objects.xib Normal file
View File

@ -0,0 +1,169 @@
<?xml version="1.0" standalone="yes"?>
<object class="NSIBObjectData">
<string name="targetFramework">IBCarbonFramework</string>
<object name="rootObject" class="NSCustomObject" id="1">
<string name="customClass">NSApplication</string>
</object>
<array count="18" name="allObjects">
<object class="IBCarbonMenu" id="29">
<string name="title">main</string>
<array count="3" name="items">
<object class="IBCarbonMenuItem" id="185">
<string name="title">KEGSMAC</string>
<object name="submenu" class="IBCarbonMenu" id="184">
<string name="title">KEGSMAC</string>
<array count="3" name="items">
<object class="IBCarbonMenuItem" id="187">
<string name="title">About KEGSMAC</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">abou</ostype>
</object>
<object class="IBCarbonMenuItem" id="199">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem" id="198">
<string name="title">Quit</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">quit</ostype>
</object>
</array>
<string name="name">_NSAppleMenu</string>
</object>
</object>
<object class="IBCarbonMenuItem" id="127">
<string name="title">File</string>
<object name="submenu" class="IBCarbonMenu" id="131">
<string name="title">File</string>
<array count="1" name="items">
<object class="IBCarbonMenuItem" id="200">
<string name="title">Configuration F4</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">KCFG</ostype>
<string name="helpTagText">Enter KEGS Configuration Panel</string>
</object>
</array>
</object>
</object>
<object class="IBCarbonMenuItem" id="192">
<string name="title">Window</string>
<object name="submenu" class="IBCarbonMenu" id="195">
<string name="title">Window</string>
<array count="6" name="items">
<object class="IBCarbonMenuItem" id="197">
<string name="title">Zoom Window</string>
<ostype name="command">zoom</ostype>
</object>
<object class="IBCarbonMenuItem" id="190">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize Window</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">mini</ostype>
</object>
<object class="IBCarbonMenuItem" id="191">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize All Windows</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">mina</ostype>
</object>
<object class="IBCarbonMenuItem" id="194">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem" id="196">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Bring All to Front</string>
<ostype name="command">bfrt</ostype>
</object>
<object class="IBCarbonMenuItem" id="193">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Arrange in Front</string>
<int name="keyEquivalentModifier">1572864</int>
<ostype name="command">frnt</ostype>
</object>
</array>
<string name="name">_NSWindowsMenu</string>
</object>
</object>
</array>
<string name="name">_NSMainMenu</string>
</object>
<reference idRef="127"/>
<reference idRef="131"/>
<object class="IBCarbonMenuItem" id="153">
<string name="title">Window</string>
<object name="submenu" class="IBCarbonMenu">
<string name="title">Window</string>
<array count="5" name="items">
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize Window</string>
<string name="keyEquivalent">m</string>
<ostype name="command">mini</ostype>
</object>
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Minimize All Windows</string>
<string name="keyEquivalent">m</string>
<int name="keyEquivalentModifier">1572864</int>
<ostype name="command">mini</ostype>
</object>
<object class="IBCarbonMenuItem">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Bring All to Front</string>
<ostype name="command">frnt</ostype>
</object>
<object class="IBCarbonMenuItem">
<boolean name="dynamic">TRUE</boolean>
<string name="title">Bring in Front</string>
<int name="keyEquivalentModifier">1572864</int>
<ostype name="command">frnt</ostype>
</object>
</array>
<string name="name">_NSWindowsMenu</string>
</object>
</object>
<reference idRef="184"/>
<reference idRef="185"/>
<reference idRef="187"/>
<reference idRef="190"/>
<reference idRef="191"/>
<reference idRef="192"/>
<reference idRef="193"/>
<reference idRef="194"/>
<reference idRef="195"/>
<reference idRef="196"/>
<reference idRef="197"/>
<reference idRef="198"/>
<reference idRef="199"/>
<reference idRef="200"/>
</array>
<array count="18" name="allParents">
<reference idRef="1"/>
<reference idRef="29"/>
<reference idRef="127"/>
<reference idRef="29"/>
<reference idRef="185"/>
<reference idRef="29"/>
<reference idRef="184"/>
<reference idRef="195"/>
<reference idRef="195"/>
<reference idRef="29"/>
<reference idRef="195"/>
<reference idRef="195"/>
<reference idRef="192"/>
<reference idRef="195"/>
<reference idRef="195"/>
<reference idRef="184"/>
<reference idRef="184"/>
<reference idRef="131"/>
</array>
<dictionary count="2" name="nameTable">
<string>Files Owner</string>
<reference idRef="1"/>
<string>MenuBar</string>
<reference idRef="29"/>
</dictionary>
<unsigned_int name="nextObjectID">201</unsigned_int>
</object>

466
src/op_routs.h Normal file
View File

@ -0,0 +1,466 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef ASM
# ifdef INCLUDE_RCSID_S
.data
.export rcsdif_op_routs_h,data
rcsdif_op_routs_h
.stringz "@(#)$KmKId: op_routs.h,v 1.40 2004-01-10 15:49:46-05 kentd Exp $"
.code
# endif
.import get_mem_b0_16,code
.import get_mem_b0_8,code
.export op_routs_start,data
op_routs_start .word 0
#endif /* ASM */
#ifdef ASM
# define CMP_INDEX_REG_MEAT8(index_reg) \
extru ret0,31,8,ret0 ! \
ldi 0xff,scratch3 ! \
subi 0x100,ret0,ret0 ! \
add index_reg,ret0,ret0 ! \
extru ret0,23,1,scratch1 ! \
and ret0,scratch3,zero ! \
extru ret0,24,1,neg ! \
b dispatch ! \
dep scratch1,31,1,psr
# define CMP_INDEX_REG_MEAT16(index_reg) \
extru ret0,31,16,ret0 ! \
ldil l%0x10000,scratch2 ! \
zdepi -1,31,16,scratch3 ! \
sub scratch2,ret0,ret0 ! \
add index_reg,ret0,ret0 ! \
extru ret0,15,1,scratch1 ! \
and ret0,scratch3,zero ! \
extru ret0,16,1,neg ! \
b dispatch ! \
dep scratch1,31,1,psr
# define CMP_INDEX_REG_LOAD(new_label, index_reg) \
bb,>=,n psr,27,new_label ! \
bl get_mem_long_8,link ! \
nop ! \
CMP_INDEX_REG_MEAT8(index_reg) ! \
.label new_label ! \
bl get_mem_long_16,link ! \
nop ! \
CMP_INDEX_REG_MEAT16(index_reg)
#endif
#ifdef ASM
#define GET_DLOC_X_IND_WR() \
CYCLES_PLUS_1 ! \
add xreg,direct,scratch2 ! \
INC_KPC_2 ! \
add scratch2,arg0,arg0 ! \
bl get_mem_b0_direct_page_16,link ! \
extru arg0,31,16,arg0 ! \
copy ret0,arg0 ! \
extru,= direct,31,8,0 ! \
CYCLES_PLUS_1 ! \
dep dbank,15,8,arg0
#else /* C */
# define GET_DLOC_X_IND_WR() \
CYCLES_PLUS_1; \
INC_KPC_2; \
if(direct & 0xff) { \
CYCLES_PLUS_1; \
} \
arg = arg + xreg + direct; \
GET_MEMORY_DIRECT_PAGE16(arg & 0xffff, arg); \
arg = (dbank << 16) + arg;
#endif
#ifdef ASM
# define GET_DLOC_X_IND_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DLOC_X_IND_WR()
#else /* C */
# define GET_DLOC_X_IND_ADDR() \
GET_1BYTE_ARG; \
GET_DLOC_X_IND_WR()
#endif
#ifdef ASM
# define GET_DISP8_S_WR() \
CYCLES_PLUS_1 ! \
add stack,arg0,arg0 ! \
INC_KPC_2 ! \
extru arg0,31,16,arg0
#else /* C */
#define GET_DISP8_S_WR() \
CYCLES_PLUS_1; \
arg = (arg + stack) & 0xffff; \
INC_KPC_2;
#endif
#ifdef ASM
# define GET_DISP8_S_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DISP8_S_WR()
#else /* C */
# define GET_DISP8_S_ADDR() \
GET_1BYTE_ARG; \
GET_DISP8_S_WR()
#endif
#ifdef ASM
# define GET_DLOC_WR() \
INC_KPC_2 ! \
extru,= direct,31,8,0 ! \
CYCLES_PLUS_1 ! \
add direct,arg0,arg0 ! \
extru arg0,31,16,arg0
#else /* C */
# define GET_DLOC_WR() \
arg = (arg + direct) & 0xffff; \
if(direct & 0xff) { \
CYCLES_PLUS_1; \
} \
INC_KPC_2;
#endif
#ifdef ASM
# define GET_DLOC_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DLOC_WR()
#else /* C */
# define GET_DLOC_ADDR() \
GET_1BYTE_ARG; \
GET_DLOC_WR()
#endif
#ifdef ASM
# define GET_DLOC_L_IND_WR() \
INC_KPC_2 ! \
extru,= direct,31,8,0 ! \
CYCLES_PLUS_1 ! \
add direct,arg0,arg0 ! \
bl get_mem_b0_24,link ! \
extru arg0,31,16,arg0 ! \
copy ret0,arg0
#else /* C */
# define GET_DLOC_L_IND_WR() \
arg = (arg + direct) & 0xffff; \
if(direct & 0xff) { \
CYCLES_PLUS_1; \
} \
INC_KPC_2; \
GET_MEMORY24(arg, arg, 1);
#endif
#ifdef ASM
# define GET_DLOC_L_IND_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DLOC_L_IND_WR()
#else /* C */
# define GET_DLOC_L_IND_ADDR() \
GET_1BYTE_ARG; \
GET_DLOC_L_IND_WR()
#endif
#ifdef ASM
# define GET_DLOC_IND_Y_ADDR_FOR_WR() \
ldb 1(scratch1),arg0 ! \
CYCLES_PLUS_1 ! \
GET_DLOC_IND_Y_WR_SPECIAL()
#else /* C */
# define GET_DLOC_IND_Y_ADDR_FOR_WR() \
GET_1BYTE_ARG; \
if(direct & 0xff) { \
CYCLES_PLUS_1; \
} \
GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, tmp1); \
tmp1 += (dbank << 16); \
arg = tmp1 + yreg; \
CYCLES_PLUS_1; \
INC_KPC_2;
#endif
#ifdef ASM
# define GET_DLOC_IND_WR() \
extru,= direct,31,8,0 ! \
CYCLES_PLUS_1 ! \
INC_KPC_2 ! \
add direct,arg0,arg0 ! \
bl get_mem_b0_direct_page_16,link ! \
extru arg0,31,16,arg0 ! \
copy ret0,arg0 ! \
dep dbank,15,16,arg0
#else /* C */
# define GET_DLOC_IND_WR() \
INC_KPC_2; \
if(direct & 0xff) { \
CYCLES_PLUS_1; \
} \
GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, arg); \
arg = (dbank << 16) + arg;
#endif
#ifdef ASM
# define GET_DLOC_IND_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DLOC_IND_WR()
#else
# define GET_DLOC_IND_ADDR() \
GET_1BYTE_ARG; \
GET_DLOC_IND_WR();
#endif
#ifdef ASM
#define GET_DLOC_INDEX_WR(index_reg) \
GET_DLOC_INDEX_WR_A(index_reg) ! GET_DLOC_INDEX_WR_B(index_reg)
#define GET_DLOC_INDEX_WR_A(index_reg) \
CYCLES_PLUS_1 ! \
add index_reg,direct,scratch2 ! \
extru direct,23,8,scratch1 ! \
INC_KPC_2 ! \
extru,= direct,31,8,0 ! \
CYCLES_PLUS_1 ! \
bb,>= psr,23,.+16 ! \
/* 4*/ add scratch2,arg0,arg0 ! \
/* 8*/ extru,<> direct,31,8,0 ! \
/*12*/ dep scratch1,23,8,arg0
/* GET_DLOC_INDeX_WR_B must be exactly one instruction! */
#define GET_DLOC_INDEX_WR_B(index_reg) \
/*16*/ extru arg0,31,16,arg0
#define GET_DLOC_Y_WR() \
GET_DLOC_INDEX_WR(yreg)
#define GET_DLOC_X_WR() \
GET_DLOC_INDEX_WR(xreg)
#define GET_DLOC_Y_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DLOC_Y_WR()
# define GET_DLOC_X_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DLOC_X_WR()
#else
# define GET_DLOC_INDEX_WR(index_reg) \
CYCLES_PLUS_1; \
arg = (arg & 0xff) + index_reg; \
INC_KPC_2; \
if(direct & 0xff) { \
CYCLES_PLUS_1; \
} \
if((psr & 0x100) && ((direct & 0xff) == 0)) { \
arg = (arg & 0xff); \
} \
arg = (arg + direct) & 0xffff;
# define GET_DLOC_X_WR() \
GET_DLOC_INDEX_WR(xreg)
# define GET_DLOC_Y_WR() \
GET_DLOC_INDEX_WR(yreg)
# define GET_DLOC_X_ADDR() \
GET_1BYTE_ARG; \
GET_DLOC_INDEX_WR(xreg)
# define GET_DLOC_Y_ADDR() \
GET_1BYTE_ARG; \
GET_DLOC_INDEX_WR(yreg)
#endif
#ifdef ASM
# define GET_DISP8_S_IND_Y_WR() \
add stack,arg0,arg0 ! \
bl get_mem_b0_16,link ! \
extru arg0,31,16,arg0 ! \
dep dbank,15,16,ret0 ! \
CYCLES_PLUS_2 ! \
add ret0,yreg,arg0 ! \
INC_KPC_2 ! \
extru arg0,31,24,arg0
# define GET_DISP8_S_IND_Y_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DISP8_S_IND_Y_WR()
#else /* C */
# define GET_DISP8_S_IND_Y_WR() \
arg = (stack + arg) & 0xffff; \
GET_MEMORY16(arg,arg,1); \
CYCLES_PLUS_2; \
arg += (dbank << 16); \
INC_KPC_2; \
arg = (arg + yreg) & 0xffffff;
# define GET_DISP8_S_IND_Y_ADDR() \
GET_1BYTE_ARG; \
GET_DISP8_S_IND_Y_WR()
#endif
#ifdef ASM
# define GET_DLOC_L_IND_Y_WR() \
extru,= direct,31,8,0 ! \
CYCLES_PLUS_1 ! \
INC_KPC_2 ! \
add direct,arg0,arg0 ! \
bl get_mem_b0_24,link ! \
extru arg0,31,16,arg0 ! \
add ret0,yreg,arg0 ! \
extru arg0,31,24,arg0
# define GET_DLOC_L_IND_Y_ADDR() \
ldb 1(scratch1),arg0 ! \
GET_DLOC_L_IND_Y_WR()
#else /* C */
# define GET_DLOC_L_IND_Y_WR() \
arg = (direct + arg) & 0xffff; \
if(direct & 0xff) { \
CYCLES_PLUS_1; \
} \
GET_MEMORY24(arg,arg,1); \
INC_KPC_2; \
arg = (arg + yreg) & 0xffffff;
# define GET_DLOC_L_IND_Y_ADDR() \
GET_1BYTE_ARG; \
GET_DLOC_L_IND_Y_WR()
#endif
#ifdef ASM
# define GET_ABS_ADDR() \
ldb 1(scratch1),arg0 ! \
ldb 2(scratch1),scratch1 ! \
CYCLES_PLUS_1 ! \
dep dbank,15,8,arg0 ! \
INC_KPC_3 ! \
dep scratch1,23,8,arg0
# define GET_LONG_ADDR() \
ldb 1(scratch1),arg0 ! \
ldb 2(scratch1),scratch2 ! \
CYCLES_PLUS_2 ! \
ldb 3(scratch1),scratch1 ! \
INC_KPC_4 ! \
dep scratch2,23,8,arg0 ! \
dep scratch1,15,8,arg0
#else /* C */
# define GET_ABS_ADDR() \
GET_2BYTE_ARG; \
CYCLES_PLUS_1; \
arg = arg + (dbank << 16); \
INC_KPC_3;
# define GET_LONG_ADDR() \
GET_3BYTE_ARG; \
CYCLES_PLUS_2; \
INC_KPC_4;
#endif
#ifdef ASM
#define GET_ABS_INDEX_ADDR_FOR_WR(index_reg) \
ldb 1(scratch1),arg0 ! \
copy index_reg,scratch3 ! \
ldb 2(scratch1),scratch2 ! \
dep dbank,15,8,scratch3 ! \
INC_KPC_3 ! \
dep scratch2,23,8,arg0 ! \
CYCLES_PLUS_2 ! \
add arg0,scratch3,arg0 ! \
extru arg0,31,24,arg0
#define GET_LONG_X_ADDR_FOR_WR() \
ldb 3(scratch1),scratch2 ! \
copy xreg,scratch3 ! \
ldb 1(scratch1),arg0 ! \
ldb 2(scratch1),scratch1 ! \
CYCLES_PLUS_2 ! \
dep scratch2,15,8,scratch3 ! \
INC_KPC_4 ! \
dep scratch1,23,8,arg0 ! \
add arg0,scratch3,arg0 ! \
extru arg0,31,24,arg0
#else /* C */
#define GET_ABS_INDEX_ADDR_FOR_WR(index_reg) \
GET_2BYTE_ARG; \
arg = arg + (dbank << 16); \
INC_KPC_3; \
CYCLES_PLUS_2; \
arg = (arg + index_reg) & 0xffffff;
#define GET_LONG_X_ADDR_FOR_WR() \
GET_3BYTE_ARG; \
INC_KPC_4; \
arg = (arg + xreg) & 0xffffff; \
CYCLES_PLUS_2;
#endif /* ASM */
#ifdef ASM
.export op_routs_end,data
op_routs_end .word 0
#define GET_DLOC_IND_Y_WR_SPECIAL() \
add direct,arg0,arg0 ! \
extru,= direct,31,8,0 ! \
CYCLES_PLUS_1 ! \
bl get_mem_b0_direct_page_16,link ! \
extru arg0,31,16,arg0 ! \
dep dbank,15,8,ret0 ! \
INC_KPC_2 ! \
add yreg,ret0,arg0 /* don't change this instr */
/* or add any after */
/* to preserve ret0 & arg0 */
/* cycle calc: if yreg is 16bit or carry into 2nd byte, inc cycle */
/* So, if y==16bit, add 1. If x==8bit, add 1 if carry */
get_dloc_ind_y_rd_8
stw link,STACK_SAVE_OP_LINK(sp)
GET_DLOC_IND_Y_WR_SPECIAL()
xor arg0,ret0,scratch1
extru,= psr,27,1,0
extru,= scratch1,23,8,0
CYCLES_PLUS_1
b get_mem_long_8
ldw STACK_SAVE_OP_LINK(sp),link
get_dloc_ind_y_rd_16
stw link,STACK_SAVE_OP_LINK(sp)
GET_DLOC_IND_Y_WR_SPECIAL()
xor arg0,ret0,scratch1
extru,= psr,27,1,0
extru,= scratch1,23,8,0
CYCLES_PLUS_1
b get_mem_long_16
ldw STACK_SAVE_OP_LINK(sp),link
#endif /* ASM */

114
src/paddles.c Normal file
View File

@ -0,0 +1,114 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_paddles_c[] = "@(#)$KmKId: paddles.c,v 1.7 2004-03-23 17:28:06-05 kentd Exp $";
#include "defc.h"
extern int g_mouse_fifo_x[]; /* from adb.c */
extern int g_mouse_fifo_y[];
double g_paddle_trig_dcycs = 0.0;
int g_swap_paddles = 0;
int g_invert_paddles = 0;
int g_joystick_type = JOYSTICK_MOUSE;
int g_paddle_button[4] = { 0, 0, 0, 0 };
/* g_paddle_button[0] = button 0, etc */
int g_paddle_val[4] = { 0, 0, 0, 0 };
/* g_paddle_val[0]: Joystick X coord, [1]:Y coord */
void
paddle_trigger(double dcycs)
{
/* Called by read/write to $c070 */
g_paddle_trig_dcycs = dcycs;
/* Determine what all the paddle values are right now */
switch(g_joystick_type) {
case JOYSTICK_MOUSE:
paddle_trigger_mouse(dcycs);
break;
case JOYSTICK_LINUX:
case JOYSTICK_WIN32_1:
case JOYSTICK_WIN32_2:
joystick_update();
}
}
void
paddle_trigger_mouse(double dcycs)
{
int val_x;
int val_y;
val_x = 0;
/* mous_phys_x is 0->560, convert that to 0-255 cyc */
/* so, mult by 117 then divide by 256 */
if(g_mouse_fifo_x[0] > BASE_MARGIN_LEFT) {
val_x = (g_mouse_fifo_x[0] - BASE_MARGIN_LEFT) * 117;
val_x = val_x >> 8;
}
/* mous_phys_y is 0->384, convert that to 0-255 cyc */
/* so, mult by 170 then divide by 256 (shift right by 8) */
val_y = 0;
if(g_mouse_fifo_y[0] > BASE_MARGIN_TOP) {
val_y = ((g_mouse_fifo_y[0] - BASE_MARGIN_TOP) * 170) >> 8;
}
if(val_x > 280) {
val_x = 280;
}
if(val_y > 280) {
val_y = 280;
}
g_paddle_val[0] = val_x;
g_paddle_val[1] = val_y;
g_paddle_val[2] = 255;
g_paddle_val[3] = 255;
g_paddle_button[2] = 1;
g_paddle_button[3] = 1;
}
int
read_paddles(int paddle, double dcycs)
{
double trig_dcycs;
int val;
/* This routine is called by any read to $c064-$c067 */
if(g_swap_paddles) {
paddle = paddle ^ 1;
}
paddle = paddle & 3;
val = g_paddle_val[paddle];
if(g_invert_paddles) {
val = 255 - val;
}
/* convert 0->255 into 0->2816.0 cycles (the paddle delay const) */
trig_dcycs = g_paddle_trig_dcycs + (val * 11.0);
if(dcycs < trig_dcycs) {
return 0x80;
} else {
return 0x00;
}
}

135
src/partls.c Executable file
View File

@ -0,0 +1,135 @@
#include "defc.h"
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#define BUF_SIZE 65536
char buf[BUF_SIZE];
void
read_block(int fd, char *buf, int blk, int blk_size)
{
int ret;
ret = lseek(fd, blk * blk_size, SEEK_SET);
if(ret != blk * blk_size) {
printf("lseek: %d, errno: %d\n", ret, errno);
exit(1);
}
ret = read(fd, buf, blk_size);
if(ret != blk_size) {
printf("ret: %d, errno: %d\n", ret, errno);
exit(1);
}
}
int
main(int argc, char **argv)
{
Driver_desc *driver_desc_ptr;
Part_map *part_map_ptr;
double dsize;
int fd;
int block_size;
word32 sig;
word32 map_blk_cnt;
word32 phys_part_start;
word32 part_blk_cnt;
word32 data_start;
word32 data_cnt;
int map_blocks;
int cur;
int long_form;
int last_arg;
int i;
/* parse args */
long_form = 0;
last_arg = 1;
for(i = 1; i < argc; i++) {
if(!strcmp("-l", argv[i])) {
long_form = 1;
} else {
last_arg = i;
break;
}
}
fd = open(argv[last_arg], O_RDONLY | O_BINARY, 0x1b6);
if(fd < 0) {
printf("open %s, ret: %d, errno:%d\n", argv[last_arg],fd,errno);
exit(1);
}
if(long_form) {
printf("fd: %d\n", fd);
}
block_size = 512;
read_block(fd, buf, 0, block_size);
driver_desc_ptr = (Driver_desc *)buf;
sig = GET_BE_WORD16(driver_desc_ptr->sig);
block_size = GET_BE_WORD16(driver_desc_ptr->blk_size);
if(long_form) {
printf("sig: %04x, blksize: %04x\n", sig, block_size);
}
if(block_size == 0) {
block_size = 512;
}
if(sig == 0x4552 && block_size >= 0x200) {
if(long_form) {
printf("good!\n");
}
} else {
printf("bad sig:%04x or block_size:%04x!\n", sig, block_size);
exit(1);
}
map_blocks = 1;
cur = 0;
while(cur < map_blocks) {
read_block(fd, buf, cur + 1, block_size);
part_map_ptr = (Part_map *)buf;
sig = GET_BE_WORD16(part_map_ptr->sig);
map_blk_cnt = GET_BE_WORD32(part_map_ptr->map_blk_cnt);
phys_part_start = GET_BE_WORD32(part_map_ptr->phys_part_start);
part_blk_cnt = GET_BE_WORD32(part_map_ptr->part_blk_cnt);
data_start = GET_BE_WORD32(part_map_ptr->data_start);
data_cnt = GET_BE_WORD32(part_map_ptr->data_cnt);
if(cur == 0) {
map_blocks = MIN(100, map_blk_cnt);
}
if(long_form) {
printf("%2d: sig: %04x, map_blk_cnt: %d, "
"phys_part_start: %08x, part_blk_cnt: %08x\n",
cur, sig, map_blk_cnt, phys_part_start,
part_blk_cnt);
printf(" part_name: %s, part_type: %s\n",
part_map_ptr->part_name,
part_map_ptr->part_type);
printf(" data_start:%08x, data_cnt:%08x status:%08x\n",
GET_BE_WORD32(part_map_ptr->data_start),
GET_BE_WORD32(part_map_ptr->data_cnt),
GET_BE_WORD32(part_map_ptr->part_status));
printf(" processor: %s\n", part_map_ptr->processor);
} else {
dsize = (double)GET_BE_WORD32(part_map_ptr->data_cnt);
printf("%2d:%-20s size=%6.2fMB type=%s\n", cur,
part_map_ptr->part_name,
(dsize/(1024.0*2.0)),
part_map_ptr->part_type);
}
cur++;
}
close(fd);
return 0;
}

116
src/prodos.h Executable file
View File

@ -0,0 +1,116 @@
/****************************************************************/
/* Apple //gs emulator */
/* Copyright 1996 Kent Dickey */
/* */
/* This code may not be used in a commercial product */
/* without prior written permission of the author. */
/* */
/* You may freely distribute this code. */
/* */
/* You can contact the author at kentd@cup.hp.com. */
/* HP has nothing to do with this software. */
/****************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_defc_h[] = "@(#)$Id: prodos.h,v 1.4 2002/11/19 07:49:31 kadickey Exp $";
#endif
typedef struct l2byte_st L2byte;
struct l2byte_st {
byte low;
byte hi;
};
typedef struct l3byte_st L3byte;
struct l3byte_st {
byte low;
byte hi;
byte higher;
};
typedef L2byte Block;
typedef struct pro_time_st Pro_time;
struct pro_time_st {
byte times[4];
};
typedef struct file_entry_st File_entry;
struct file_entry_st {
byte storage_type_name_len;
byte file_name[15];
/* 0x10 */
byte file_type;
Block key_pointer;
/* 0x13 */
L2byte blocks_used;
/* 0x15 */
L3byte eof;
/* 0x18 */
Pro_time creation_time;
/* 0x1c */
byte version;
byte min_version;
/* 0x1e */
byte access;
/* 0x1f */
L2byte aux_type;
/* 0x21 */
Pro_time last_mod;
/* 0x25 */
Block header_pointer;
};
STRUCT(Vol_hdr) {
/* 0x4 */
byte storage_type_name_len;
/* 0x5 */
byte vol_name[15];
/* 0x14 */
byte res1[8];
/* 0x1c */
Pro_time creation_time;
/* 0x20 */
byte version;
byte min_version;
byte access;
byte entry_length;
/* 0x24 */
byte entries_per_block;
L2byte file_count;
/* 0x27 */
Block bit_map;
/* 0x29 */
L2byte total_blocks;
};
typedef struct directory_st Directory;
struct directory_st {
Block prev_blk;
Block next_blk;
File_entry file_entries[13];
};
STRUCT(ProDisk) {
int fd;
int total_blocks;
int size_bitmap_blocks;
int disk_bytes_left;
int bitmap_bytes;
int bitmap_cur_pos;
byte *bitmap_ptr;
int file_open;
File_entry *file_ptr;
int dir_blk_num;
int ind_blk_num;
int master_ind_blk_num;
byte dir_blk_data[512];
byte ind_blk_data[512];
byte master_ind_blk_data[512];
};
#include "prodos_protos.h"

46
src/prodos_protos.h Executable file
View File

@ -0,0 +1,46 @@
/****************************************************************/
/* Apple //gs emulator */
/* Copyright 1996 Kent Dickey */
/* */
/* This code may not be used in a commercial product */
/* without prior written permission of the author. */
/* */
/* You may freely distribute this code. */
/* */
/* You can contact the author at kentd@cup.hp.com. */
/* HP has nothing to do with this software. */
/****************************************************************/
const char rcsid_prodos_protos_h[] = "@(#)$Id: prodos_protos.h,v 1.4 2002/11/19 07:49:31 kadickey Exp $";
/* to_pro.c */
void flush_disk(ProDisk *disk);
void close_file(ProDisk *disk);
ProDisk *allocate_memdisk(char *out_name, int size);
void format_memdisk(ProDisk *ptr, char *name);
void disk_write_data(ProDisk *disk, int blk_num, byte *buf, int size);
void disk_read_data(ProDisk *disk, int blk_num, byte *buf, int size);
Directory *disk_read_dir(ProDisk *disk, int blk_num);
void disk_write_dir(ProDisk *disk, int blk_num);
void create_new_file(ProDisk *disk, int dir_block, int storage_type,
char *name, int file_type, word32 creation_time, int version,
int min_version, int access, int aux_type, word32 last_mod, word32 eof);
int pro_write_file(ProDisk *disk, byte *in_buf, int pos, int size);
int get_disk_block(ProDisk *disk, int pos, int create);
void get_new_ind_block(ProDisk *disk);
void write_ind_block(ProDisk *disk);
void get_new_master_ind_block(ProDisk *disk);
void write_master_ind_block(ProDisk *disk);
int find_next_free_block(ProDisk *disk);
void set_bitmap_used(byte *ptr, int i);
void set_bitmap_free(byte *ptr, int i);
void set_file_entry(File_entry *entry, int storage_type_name_len,
char *file_name, int file_type, int key_pointer, int blocks_used,
int eof, word32 creation, int version, int min_version, int access,
int aux_type, word32 last_mod, int header_pointer);
void set_l2byte(L2byte *ptr, int val);
void set_l3byte(L3byte *ptr, int val);
void set_pro_time(Pro_time *ptr, word32 val);
int get_l2byte(L2byte *ptr);
int get_l3byte(L3byte *ptr);
void inc_l2byte(L2byte *ptr);

495
src/protos.h Normal file
View File

@ -0,0 +1,495 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_protos_h[] = "@(#)$KmKId: protos.h,v 1.173 2004-03-23 17:26:19-05 kentd Exp $";
#endif
/* xdriver.c and macdriver.c and windriver.c */
void update_color_array(int col_num, int a2_color);
void set_border_color(int val);
void x_update_physical_colormap(void);
void show_xcolor_array(void);
void x_auto_repeat_on(int must);
void install_text_colormap(void);
void set_border_color(int val);
void draw_status(int line_num, const char *string1);
void xdriver_end(void);
void dev_video_init(void);
void x_update_color(int col_num, int red, int green, int blue, word32 rgb);
void redraw_border(void);
void check_input_events(void);
void x_redraw_status_lines(void);
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height);
void x_push_done();
void x_hide_pointer(int);
void x_get_kimage(Kimage *kimage_ptr);
/* test65.c */
void do_gen_test(int got_num, int base_seed);
/* engine.s and engine_c.c */
void fixed_memory_ptrs_init();
word32 get_itimer(void);
word32 get_memory_c(word32 addr, int cycs);
word32 get_memory16_c(word32 addr, int cycs);
word32 get_memory24_c(word32 addr, int cycs);
int get_memory_asm(word32 addr, int cycs);
int get_memory16_asm(word32 addr, int cycs);
int get_memory16_asm_fail(word32 addr, int cycs);
int get_memory_act_stub_asm(word32 addr, int cycs);
int get_memory16_act_stub_asm(word32 addr, int cycs);
void set_memory_c(word32 addr, word32 val, int cycs);
void set_memory16_c(word32 addr, word32 val, int cycs);
int enter_engine(Engine_reg *ptr);
void clr_halt_act(void);
void set_halt_act(int val);
/* special scc_macdriver.c prototypes */
int scc_serial_mac_init(int port);
void scc_serial_mac_change_params(int port);
void scc_serial_mac_fill_readbuf(int port, double dcycs);
void scc_serial_mac_empty_writebuf(int port);
/* special scc_windriver.c prototypes */
int scc_serial_win_init(int port);
void scc_serial_win_change_params(int port);
void scc_serial_win_fill_readbuf(int port, double dcycs);
void scc_serial_win_empty_writebuf(int port);
/* special joystick_driver.c prototypes */
void joystick_init(void);
void joystick_update(void);
void joystick_update_button(void);
/* END_HDR */
/* adb.c */
void adb_init(void);
void adb_reset(void);
void adb_log(word32 addr, int val);
void show_adb_log(void);
void adb_error(void);
void adb_add_kbd_srq(void);
void adb_clear_kbd_srq(void);
void adb_add_data_int(void);
void adb_add_mouse_int(void);
void adb_clear_data_int(void);
void adb_clear_mouse_int(void);
void adb_send_bytes(int num_bytes, word32 val0, word32 val1, word32 val2);
void adb_send_1byte(word32 val);
void adb_response_packet(int num_bytes, word32 val);
void adb_kbd_reg0_data(int a2code, int is_up);
void adb_kbd_talk_reg0(void);
void adb_set_config(word32 val0, word32 val1, word32 val2);
void adb_set_new_mode(word32 val);
int adb_read_c026(void);
void adb_write_c026(int val);
void do_adb_cmd(void);
int adb_read_c027(void);
void adb_write_c027(int val);
int read_adb_ram(word32 addr);
void write_adb_ram(word32 addr, int val);
int update_mouse(int x, int y, int button_states, int buttons_valid);
int mouse_read_c024(double dcycs);
void adb_key_event(int a2code, int is_up);
word32 adb_read_c000(void);
word32 adb_access_c010(void);
word32 adb_read_c025(void);
int adb_is_cmd_key_down(void);
int adb_is_option_key_down(void);
void adb_increment_speed(void);
void adb_physical_key_update(int a2code, int is_up);
void adb_virtual_key_update(int a2code, int is_up);
void adb_kbd_repeat_off(void);
/* clock.c */
double get_dtime(void);
int micro_sleep(double dtime);
void clk_bram_zero(void);
void clk_bram_set(int bram_num, int offset, int val);
void clk_setup_bram_version(void);
void clk_write_bram(FILE *fconf);
void update_cur_time(void);
void clock_update(void);
void clock_update_if_needed(void);
word32 clock_read_c033(void);
word32 clock_read_c034(void);
void clock_write_c033(word32 val);
void clock_write_c034(word32 val);
void do_clock_data(void);
/* compile_time.c */
/* config.c */
void config_init_menus(Cfg_menu *menuptr);
void config_init(void);
void cfg_exit(void);
void cfg_text_screen_dump(void);
void config_vbl_update(int doit_3_persec);
void config_parse_option(char *buf, int pos, int len, int line);
void config_parse_bram(char *buf, int pos, int len);
void config_parse_config_kegs_file(void);
Disk *cfg_get_dsk_from_slot_drive(int slot, int drive);
void config_generate_config_kegs_name(char *outstr, int maxlen, Disk *dsk, int with_extras);
void config_write_config_kegs_file(void);
void insert_disk(int slot, int drive, const char *name, int ejected, int force_size, const char *partition_name, int part_num);
void eject_named_disk(Disk *dsk, const char *name, const char *partition_name);
void eject_disk_by_num(int slot, int drive);
void eject_disk(Disk *dsk);
int cfg_get_fd_size(int fd);
int cfg_partition_read_block(int fd, void *buf, int blk, int blk_size);
int cfg_partition_find_by_name_or_num(int fd, const char *partnamestr, int part_num, Disk *dsk);
int cfg_partition_make_list(int fd);
int cfg_maybe_insert_disk(int slot, int drive, const char *namestr);
int cfg_stat(char *path, struct stat *sb);
void cfg_htab_vtab(int x, int y);
void cfg_home(void);
void cfg_cleol(void);
void cfg_putchar(int c);
void cfg_printf(const char *fmt, ...);
void cfg_print_num(int num, int max_len);
void cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras);
void cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change);
void cfg_get_base_path(char *pathptr, const char *inptr, int go_up);
void cfg_file_init(void);
void cfg_free_alldirents(Cfg_listhdr *listhdrptr);
void cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, int size, int image_start, int part_num);
int cfg_dirent_sortfn(const void *obj1, const void *obj2);
int cfg_str_match(const char *str1, const char *str2, int len);
void cfg_file_readdir(const char *pathptr);
char *cfg_shorten_filename(const char *in_ptr, int maxlen);
void cfg_fix_topent(Cfg_listhdr *listhdrptr);
void cfg_file_draw(void);
void cfg_partition_selected(void);
void cfg_file_selected(void);
void cfg_file_handle_key(int key);
void config_control_panel(void);
/* dis.c */
int get_num(void);
void debugger_help(void);
void do_debug_intfc(void);
word32 dis_get_memory_ptr(word32 addr);
void show_one_toolset(FILE *toolfile, int toolnum, word32 addr);
void show_toolset_tables(word32 a2bank, word32 addr);
void set_bp(word32 addr);
void show_bp(void);
void delete_bp(word32 addr);
void do_blank(void);
void do_go(void);
void do_step(void);
void xam_mem(int count);
void show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count);
int read_line(char *buf, int len);
void do_debug_list(void);
void load_roms(void);
void do_debug_unix(void);
void do_debug_load(void);
int do_dis(FILE *outfile, word32 kpc, int accsize, int xsize, int op_provided, word32 instr);
void show_line(FILE *outfile, word32 kaddr, word32 operand, int size, char *string);
void halt_printf(const char *fmt, ...);
void halt2_printf(const char *fmt, ...);
/* scc.c */
void scc_init(void);
void scc_reset(void);
void scc_hard_reset_port(int port);
void scc_reset_port(int port);
void scc_regen_clocks(int port);
void scc_port_init(int port);
void scc_try_to_empty_writebuf(int port);
void scc_try_fill_readbuf(int port, double dcycs);
void scc_update(double dcycs);
void do_scc_event(int type, double dcycs);
void show_scc_state(void);
void scc_log(int regnum, word32 val, double dcycs);
void show_scc_log(void);
word32 scc_read_reg(int port, double dcycs);
void scc_write_reg(int port, word32 val, double dcycs);
void scc_maybe_br_event(int port, double dcycs);
void scc_evaluate_ints(int port);
void scc_maybe_rx_event(int port, double dcycs);
void scc_maybe_rx_int(int port, double dcycs);
void scc_clr_rx_int(int port);
void scc_handle_tx_event(int port, double dcycs);
void scc_maybe_tx_event(int port, double dcycs);
void scc_clr_tx_int(int port);
void scc_set_zerocnt_int(int port);
void scc_clr_zerocnt_int(int port);
void scc_add_to_readbuf(int port, word32 val, double dcycs);
void scc_add_to_writebuf(int port, word32 val, double dcycs);
word32 scc_read_data(int port, double dcycs);
void scc_write_data(int port, word32 val, double dcycs);
/* scc_socket_driver.c */
void scc_socket_init(int port);
void scc_socket_change_params(int port);
void scc_accept_socket(int port);
void scc_socket_fill_readbuf(int port, double dcycs);
void scc_socket_empty_writebuf(int port);
/* scc_windriver.c */
/* scc_macdriver.c */
/* iwm.c */
void iwm_init_drive(Disk *dsk, int smartport, int drive, int disk_525);
void iwm_init(void);
void iwm_reset(void);
void draw_iwm_status(int line, char *buf);
void iwm_flush_disk_to_unix(Disk *dsk);
void iwm_vbl_update(int doit_3_persec);
void iwm_show_stats(void);
void iwm_touch_switches(int loc, double dcycs);
void iwm_move_to_track(Disk *dsk, int new_track);
void iwm525_phase_change(int drive, int phase);
int iwm_read_status35(double dcycs);
void iwm_do_action35(double dcycs);
void iwm_set_apple35_sel(int newval);
int iwm_read_c0ec(double dcycs);
int read_iwm(int loc, double dcycs);
void write_iwm(int loc, int val, double dcycs);
int iwm_read_enable2(double dcycs);
int iwm_read_enable2_handshake(double dcycs);
void iwm_write_enable2(int val, double dcycs);
int iwm_read_data(Disk *dsk, int fast_disk_emul, double dcycs);
void iwm_write_data(Disk *dsk, word32 val, int fast_disk_emul, double dcycs);
void sector_to_partial_nib(byte *in, byte *nib_ptr);
int disk_unnib_4x4(Disk *dsk);
int iwm_denib_track525(Disk *dsk, Track *trk, int qtr_track, byte *outbuf);
int iwm_denib_track35(Disk *dsk, Track *trk, int qtr_track, byte *outbuf);
int disk_track_to_unix(Disk *dsk, int qtr_track, byte *outbuf);
void show_hex_data(byte *buf, int count);
void disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size);
void disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len, int nib_len);
void iwm_nibblize_track_nib525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track);
void iwm_nibblize_track_525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track);
void iwm_nibblize_track_35(Disk *dsk, Track *trk, byte *track_buf, int qtr_track);
void disk_4x4_nib_out(Disk *dsk, word32 val);
void disk_nib_out(Disk *dsk, byte val, int size);
void disk_nib_end_track(Disk *dsk);
void iwm_show_track(int slot_drive, int track);
void iwm_show_a_track(Track *trk);
/* joystick_driver.c */
/* moremem.c */
void fixup_brks(void);
void fixup_hires_on(void);
void fixup_bank0_2000_4000(void);
void fixup_bank0_0400_0800(void);
void fixup_any_bank_any_page(int start_page, int num_pages, byte *mem0rd, byte *mem0wr);
void fixup_intcx(void);
void fixup_wrdefram(int new_wrdefram);
void fixup_st80col(double dcycs);
void fixup_altzp(void);
void fixup_page2(double dcycs);
void fixup_ramrd(void);
void fixup_ramwrt(void);
void fixup_lcbank2(void);
void fixup_rdrom(void);
void set_statereg(double dcycs, int val);
void fixup_shadow_txt1(void);
void fixup_shadow_txt2(void);
void fixup_shadow_hires1(void);
void fixup_shadow_hires2(void);
void fixup_shadow_shr(void);
void fixup_shadow_iolc(void);
void update_shadow_reg(int val);
void fixup_shadow_all_banks(void);
void setup_pageinfo(void);
void show_bankptrs_bank0rdwr(void);
void show_bankptrs(int bnk);
void show_addr(byte *ptr);
int io_read(word32 loc, double *cyc_ptr);
void io_write(word32 loc, int val, double *cyc_ptr);
word32 get_lines_since_vbl(double dcycs);
int in_vblank(double dcycs);
int read_vid_counters(int loc, double dcycs);
/* paddles.c */
void paddle_trigger(double dcycs);
void paddle_trigger_mouse(double dcycs);
int read_paddles(int paddle, double dcycs);
/* sim65816.c */
void show_pc_log(void);
word32 toolbox_debug_4byte(word32 addr);
void toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr);
void show_toolbox_log(void);
word32 get_memory_io(word32 loc, double *cyc_ptr);
void set_memory_io(word32 loc, int val, double *cyc_ptr);
void show_regs_act(Engine_reg *eptr);
void show_regs(void);
void my_exit(int ret);
void do_reset(void);
void check_engine_asm_defines(void);
byte *memalloc_align(int size, int skip_amt);
void memory_ptr_init(void);
int kegsmain(int argc, char **argv);
void kegs_expand_path(char *out_ptr, const char *in_ptr, int maxlen);
void setup_kegs_file(char *outname, int maxlen, int ok_if_missing, const char **name_ptr);
void initialize_events(void);
void check_for_one_event_type(int type);
void add_event_entry(double dcycs, int type);
double remove_event_entry(int type);
void add_event_stop(double dcycs);
void add_event_doc(double dcycs, int osc);
void add_event_scc(double dcycs, int type);
void add_event_vbl(void);
void add_event_vid_upd(int line);
double remove_event_doc(int osc);
double remove_event_scc(int type);
void show_all_events(void);
void show_pmhz(void);
void setup_zip_speeds(void);
void run_prog(void);
void add_irq(void);
void remove_irq(void);
void take_irq(int is_it_brk);
void show_dtime_array(void);
void update_60hz(double dcycs, double dtime_now);
void do_vbl_int(void);
void do_scan_int(double dcycs, int line);
void check_scan_line_int(double dcycs, int cur_video_line);
void check_for_new_scan_int(double dcycs);
void init_reg(void);
void handle_action(word32 ret);
void do_break(word32 ret);
void do_cop(word32 ret);
void do_wdm(word32 arg);
void do_wai(void);
void do_stp(void);
void size_fail(int val, word32 v1, word32 v2);
/* smartport.c */
void smartport_error(void);
void smartport_log(word32 start_addr, int cmd, int rts_addr, int cmd_list);
void do_c70d(word32 arg0);
void do_c70a(word32 arg0);
int do_read_c7(int unit_num, word32 buf, int blk);
int do_write_c7(int unit_num, word32 buf, int blk);
int do_format_c7(int unit_num);
void do_c700(word32 ret);
/* sound.c */
void doc_log_rout(char *msg, int osc, double dsamps, int etc);
void show_doc_log(void);
void sound_init(void);
void sound_init_general(void);
void parent_sound_get_sample_rate(int read_fd);
void set_audio_rate(int rate);
void sound_reset(double dcycs);
void sound_shutdown(void);
void sound_update(double dcycs);
void open_sound_file(void);
void close_sound_file(void);
void check_for_range(word32 *addr, int num_samps, int offset);
void send_sound_to_file(word32 *addr, int shm_pos, int num_samps);
void send_sound(int real_samps, int size);
void show_c030_state(void);
void show_c030_samps(int *outptr, int num);
void sound_play(double dsamps);
void doc_handle_event(int osc, double dcycs);
void doc_sound_end(int osc, int can_repeat, double eff_dsamps, double dsamps);
void add_sound_irq(int osc);
void remove_sound_irq(int osc, int must);
void start_sound(int osc, double eff_dsamps, double dsamps);
void wave_end_estimate(int osc, double eff_dsamps, double dsamps);
void remove_sound_event(int osc);
void doc_write_ctl_reg(int osc, int val, double dsamps);
void doc_recalc_sound_parms(int osc, double eff_dcycs, double dsamps);
int doc_read_c030(double dcycs);
int doc_read_c03c(double dcycs);
int doc_read_c03d(double dcycs);
void doc_write_c03c(int val, double dcycs);
void doc_write_c03d(int val, double dcycs);
void doc_write_c03e(int val);
void doc_write_c03f(int val);
void doc_show_ensoniq_state(int osc);
/* sound_driver.c */
void reliable_buf_write(word32 *shm_addr, int pos, int size);
void reliable_zero_write(int amt);
void child_sound_loop(int read_fd, int write_fd, word32 *shm_addr);
void child_sound_playit(word32 tmp);
/* video.c */
void video_init(void);
void show_a2_line_stuff(void);
void video_reset(void);
void video_update(void);
int video_all_stat_to_line_stat(int line, int new_all_stat);
int *video_update_kimage_ptr(int line, int new_stat);
void change_a2vid_palette(int new_palette);
void check_a2vid_palette(void);
void change_display_mode(double dcycs);
void video_update_all_stat_through_line(int line);
void change_border_color(double dcycs, int val);
void update_border_info(void);
void update_border_line(int st_line_offset, int end_line_offset, int color);
void video_border_pixel_write(Kimage *kimage_ptr, int starty, int num_lines, word32 val, int st_off, int end_off);
void redraw_changed_text_40(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, int pixels_per_line);
void redraw_changed_text_80(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, int pixels_per_line);
void redraw_changed_gr(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line);
void redraw_changed_dbl_gr(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line);
void redraw_changed_hires(int start_offset, int start_line, int num_lines, int color, int reparse, byte *screen_data, int pixels_per_line);
void redraw_changed_hires_bw(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line);
void redraw_changed_hires_color(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line);
void redraw_changed_dbl_hires(int start_offset, int start_line, int num_lines, int color, int reparse, byte *screen_data, int pixels_per_line);
void redraw_changed_dbl_hires_bw(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line);
void redraw_changed_dbl_hires_color(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line);
int video_rebuild_super_hires_palette(word32 scan_info, int line, int reparse);
void redraw_changed_super_hires(int start_offset, int start_line, int num_lines, int in_reparse, byte *screen_data);
void display_screen(void);
void video_update_event_line(int line);
void video_update_through_line(int line);
void video_refresh_lines(int st_line, int num_lines, int must_reparse);
void refresh_border(void);
void end_screen(void);
void read_a2_font(void);
void video_get_kimage(Kimage *kimage_ptr, int extend_info, int depth, int mdepth);
void video_get_kimages(void);
void video_convert_kimage_depth(Kimage *kim_in, Kimage *kim_out, int startx, int starty, int width, int height);
void video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, int right_pix);
void video_push_border_sides_lines(int src_x, int dest_x, int width, int start_line, int end_line);
void video_push_border_sides(void);
void video_push_border_special(void);
void video_push_kimages(void);
void video_update_color_raw(int col_num, int a2_color);
void video_update_color_array(int col_num, int a2_color);
void video_update_colormap(void);
void video_update_status_line(int line, const char *string);
void video_show_debug_info(void);

39
src/protos_engine_c.h Normal file
View File

@ -0,0 +1,39 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_protos_engine_c_h[] = "@(#)$KmKId: protos_engine_c.h,v 1.10 2004-01-10 15:50:02-05 kentd Exp $";
#endif
/* END_HDR */
/* engine_c.c */
void check_breakpoints(word32 addr);
word32 get_memory8_io_stub(word32 addr, byte *stat, double *fcycs_ptr, double fplus_x_m1);
word32 get_memory16_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank);
word32 get_memory24_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank);
void set_memory8_io_stub(word32 addr, word32 val, byte *stat, double *fcycs_ptr, double fplus_x_m1);
void set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank);
void set_memory24_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank);
word32 get_memory_c(word32 addr, int cycs);
word32 get_memory16_c(word32 addr, int cycs);
word32 get_memory24_c(word32 addr, int cycs);
void set_memory_c(word32 addr, word32 val, int cycs);
void set_memory16_c(word32 addr, word32 val, int cycs);
void set_memory24_c(word32 addr, word32 val, int cycs);
word32 do_adc_sbc8(word32 in1, word32 in2, word32 psr, int sub);
word32 do_adc_sbc16(word32 in1, word32 in2, word32 psr, int sub);
void fixed_memory_ptrs_init(void);
word32 get_itimer(void);
void set_halt_act(int val);
void clr_halt_act(void);
word32 get_remaining_operands(word32 addr, word32 opcode, word32 psr, Fplus *fplus_ptr);
int enter_engine(Engine_reg *engine_ptr);

40
src/protos_macdriver.h Normal file
View File

@ -0,0 +1,40 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_protos_mac_h[] = "@(#)$KmKId: protos_macdriver.h,v 1.6 2004-03-23 17:27:31-05 kentd Exp $";
/* END_HDR */
/* macdriver.c */
pascal OSStatus quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore);
void show_alert(const char *str1, const char *str2, const char *str3, int num);
pascal OSStatus my_cmd_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata);
void update_window(void);
void show_event(UInt32 event_class, UInt32 event_kind, int handled);
pascal OSStatus my_win_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata);
pascal OSStatus dummy_event_handler(EventHandlerCallRef call_ref, EventRef in_event, void *ignore);
void mac_update_modifiers(word32 state);
void mac_warp_mouse(void);
void check_input_events(void);
void temp_run_application_event_loop(void);
int main(int argc, char *argv[]);
void x_update_color(int col_num, int red, int green, int blue, word32 rgb);
void x_update_physical_colormap(void);
void show_xcolor_array(void);
void xdriver_end(void);
void x_get_kimage(Kimage *kimage_ptr);
void dev_video_init(void);
void x_redraw_status_lines(void);
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height);
void x_push_done(void);
void x_auto_repeat_on(int must);
void x_auto_repeat_off(int must);
void x_hide_pointer(int do_hide);

View File

@ -0,0 +1,20 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2003 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_protos_macsnd_driver_h[] = "@(#)$KmKId: protos_macsnd_driver.h,v 1.2 2003-11-19 19:57:02-05 kentd Exp $";
/* END_HDR */
/* macsnd_driver.c */
void mac_snd_callback(SndChannelPtr snd_chan_ptr, SndCommand *in_sndcmd);
int mac_send_audio(byte *ptr, int in_size);
void child_sound_init_mac(void);
void macsnd_init(word32 *shmaddr);

36
src/protos_windriver.h Normal file
View File

@ -0,0 +1,36 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
// $KmKId: protos_windriver.h,v 1.4 2004-03-23 17:27:26-05 kentd Exp $
/* END_HDR */
/* windriver.c */
int win_update_mouse(int x, int y, int button_states, int buttons_valid);
void win_event_mouse(WPARAM wParam, LPARAM lParam);
void win_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags);
void win_event_quit(HWND hwnd);
void win_event_redraw(void);
LRESULT CALLBACK win_event_handler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam);
int main(int argc, char **argv);
void check_input_events(void);
void x_update_color(int col_num, int red, int green, int blue, word32 rgb);
void x_update_physical_colormap(void);
void show_xcolor_array(void);
void xdriver_end(void);
void x_get_kimage(Kimage *kimage_ptr);
void dev_video_init(void);
void x_redraw_status_lines(void);
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height);
void x_push_done(void);
void x_auto_repeat_on(int must);
void x_auto_repeat_off(int must);
void x_hide_pointer(int do_hide);

36
src/protos_xdriver.h Normal file
View File

@ -0,0 +1,36 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_protos_x_h[] = "@(#)$KmKId: protos_xdriver.h,v 1.18 2002-11-19 03:10:38-05 kadickey Exp $";
/* END_HDR */
/* xdriver.c */
int main(int argc, char **argv);
void x_update_physical_colormap(void);
void show_xcolor_array(void);
int my_error_handler(Display *display, XErrorEvent *ev);
void xdriver_end(void);
void show_colormap(char *str, Colormap cmap, int index1, int index2, int index3);
void dev_video_init(void);
Visual *x_try_find_visual(int depth, int screen_num, XVisualInfo **visual_list_ptr);
void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr);
int xhandle_shm_error(Display *display, XErrorEvent *event);
int get_shm(Kimage *kimage_ptr);
void get_ximage(Kimage *kimage_ptr);
void update_status_line(int line, const char *string);
void redraw_status_lines(void);
void check_input_events(void);
void handle_keysym(XEvent *xev_in);
int x_keysym_to_a2code(int keysym, int is_up);
void x_update_modifier_state(int state);
void x_auto_repeat_on(int must);
void x_auto_repeat_off(int must);

1153
src/scc.c Normal file

File diff suppressed because it is too large Load Diff

78
src/scc.h Normal file
View File

@ -0,0 +1,78 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_scc_h[] = "@(#)$KmKId: scc.h,v 1.12 2003-11-21 00:27:00-05 kentd Exp $";
#endif
#ifdef _WIN32
# include <winsock.h>
#else
# include <sys/socket.h>
# include <netinet/in.h>
#endif
#if defined(HPUX) || defined(__linux__) || defined(SOLARIS) || defined(MAC) || defined(__MACH__)
# define SCC_SOCKETS
#endif
/* my scc port 0 == channel A, port 1 = channel B */
#define SCC_INBUF_SIZE 4096 /* must be a power of 2 */
#define SCC_OUTBUF_SIZE 4096 /* must be a power of 2 */
STRUCT(Scc) {
int port;
int state;
int accfd;
int rdwrfd;
void *host_handle;
void *host_handle2;
int host_aux1;
int read_called_this_vbl;
int write_called_this_vbl;
int mode;
int reg_ptr;
int reg[16];
int rx_queue_depth;
byte rx_queue[4];
int in_rdptr;
int in_wrptr;
byte in_buf[SCC_INBUF_SIZE];
int out_rdptr;
int out_wrptr;
byte out_buf[SCC_OUTBUF_SIZE];
int br_is_zero;
int tx_buf_empty;
int wantint_rx;
int wantint_tx;
int wantint_zerocnt;
int int_pending_rx;
int int_pending_tx;
int int_pending_zerocnt;
double br_dcycs;
double tx_dcycs;
double rx_dcycs;
int br_event_pending;
int rx_event_pending;
int tx_event_pending;
int char_size;
int baud_rate;
};

211
src/scc_macdriver.c Normal file
View File

@ -0,0 +1,211 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_scc_macdriver_c[] = "@(#)$KmKId: scc_macdriver.c,v 1.3 2003-11-03 01:52:49-05 kentd Exp $";
/* This file contains the Mac serial calls */
#include "defc.h"
#include "scc.h"
#ifndef _WIN32
# include <termios.h>
#endif
extern Scc scc_stat[2];
extern word32 g_c025_val;
#ifdef MAC
int
scc_serial_mac_init(int port)
{
char str_buf[1024];
Scc *scc_ptr;
int state;
int fd;
scc_ptr = &(scc_stat[port]);
scc_ptr->state = 0; /* mark as uninitialized */
sprintf(&str_buf[0], "/dev/tty.USA19QW11P1.1");
/* HACK: fix this... */
fd = open(&str_buf[0], O_RDWR | O_NONBLOCK);
scc_ptr->host_handle = (void *)fd;
scc_ptr->host_handle2 = 0;
printf("scc_serial_mac_init %d called, fd: %d\n", port, fd);
if(fd < 0) {
scc_ptr->host_handle = (void *)-1;
return -1;
}
scc_serial_mac_change_params(port);
state = 2; /* raw serial */
scc_ptr->state = state;
return state;
}
void
scc_serial_mac_change_params(int port)
{
struct termios termios_buf;
Scc *scc_ptr;
int fd;
int csz;
int ret;
scc_ptr = &(scc_stat[port]);
fd = (int)scc_ptr->host_handle;
printf("scc_serial_mac_change_parms port: %d, fd: %d\n", port, fd);
if(fd <= 0) {
return;
}
ret = tcgetattr(fd, &termios_buf);
if(ret != 0) {
printf("tcgetattr port%d ret: %d\n", port, ret);
}
#if 1
printf("baudrate: %d, iflag:%x, oflag:%x, cflag:%x, lflag:%x\n",
(int)termios_buf.c_ispeed, (int)termios_buf.c_iflag,
(int)termios_buf.c_oflag, (int)termios_buf.c_cflag,
(int)termios_buf.c_lflag);
#endif
memset(&termios_buf, 0, sizeof(struct termios));
cfmakeraw(&termios_buf);
cfsetspeed(&termios_buf, scc_ptr->baud_rate);
csz = scc_ptr->char_size;
termios_buf.c_cflag = CREAD | CLOCAL;
termios_buf.c_cflag |= (csz == 5) ? CS5 :
(csz == 6) ? CS6 :
(csz == 7) ? CS7 :
CS8;
switch((scc_ptr->reg[4] >> 2) & 0x3) {
case 2: // 1.5 stop bits
termios_buf.c_cflag |= CSTOPB; /* no 1.5 stop bit setting.*/
break;
case 3: // 2 stop bits
termios_buf.c_cflag |= CSTOPB;
break;
}
switch((scc_ptr->reg[4]) & 0x3) {
case 1: // Odd parity
termios_buf.c_cflag |= (PARENB | PARODD);
break;
case 3: // Even parity
termios_buf.c_cflag |= PARENB;
break;
}
/* always enabled DTR and RTS control */
termios_buf.c_cflag |= CDTR_IFLOW | CRTS_IFLOW;
printf("fd: %d, baudrate: %d, iflag:%x, oflag:%x, cflag:%x, lflag:%x\n",
fd, (int)termios_buf.c_ispeed, (int)termios_buf.c_iflag,
(int)termios_buf.c_oflag, (int)termios_buf.c_cflag,
(int)termios_buf.c_lflag);
ret = tcsetattr(fd, TCSANOW, &termios_buf);
if(ret != 0) {
printf("tcsetattr ret: %d\n", ret);
}
}
void
scc_serial_mac_fill_readbuf(int port, double dcycs)
{
byte tmp_buf[256];
Scc *scc_ptr;
int fd;
int i;
int ret;
scc_ptr = &(scc_stat[port]);
fd = (int)scc_ptr->host_handle;
if(fd <= 0) {
return;
}
/* Try reading some bytes */
ret = read(fd, tmp_buf, 256);
if(ret > 0) {
for(i = 0; i < ret; i++) {
scc_add_to_readbuf(port, tmp_buf[i], dcycs);
}
}
}
void
scc_serial_mac_empty_writebuf(int port)
{
Scc *scc_ptr;
int fd;
int rdptr;
int wrptr;
int done;
int ret;
int len;
scc_ptr = &(scc_stat[port]);
fd = (int)scc_ptr->host_handle;
if(fd <= 0) {
return;
}
/* Try writing some bytes */
done = 0;
while(!done) {
rdptr = scc_ptr->out_rdptr;
wrptr = scc_ptr->out_wrptr;
if(rdptr == wrptr) {
//printf("...rdptr == wrptr\n");
done = 1;
break;
}
len = wrptr - rdptr;
if(len < 0) {
len = SCC_OUTBUF_SIZE - rdptr;
}
if(len > 32) {
len = 32;
}
if(len <= 0) {
done = 1;
break;
}
ret = write(fd, &(scc_ptr->out_buf[rdptr]), len);
if(ret <= 0) {
done = 1;
break;
} else {
rdptr = rdptr + ret;
if(rdptr >= SCC_OUTBUF_SIZE) {
rdptr = rdptr - SCC_OUTBUF_SIZE;
}
scc_ptr->out_rdptr = rdptr;
}
}
}
#endif /* MAC */

255
src/scc_socket_driver.c Normal file
View File

@ -0,0 +1,255 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_scc_socket_driver_c[] = "@(#)$KmKId: scc_socket_driver.c,v 1.4 2003-11-20 23:43:41-05 kentd Exp $";
/* This file contains the Unix socket calls */
#include "defc.h"
#include "scc.h"
#include <signal.h>
extern Scc scc_stat[2];
void
scc_socket_init(int port)
{
#ifdef SCC_SOCKETS
Scc *scc_ptr;
struct sockaddr_in sa_in;
int on;
int flags;
int ret;
int sockfd;
int inc;
inc = 0;
scc_ptr = &(scc_stat[port]);
scc_ptr->state = -1; /* mark as failed for now */
scc_ptr->host_aux1 = sizeof(struct sockaddr_in);
scc_ptr->host_handle = malloc(scc_ptr->host_aux1);
memset(scc_ptr->host_handle, 0, scc_ptr->host_aux1);
while(1) {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) {
printf("socket ret: %d, errno: %d\n", sockfd, errno);
return;
}
/* printf("socket ret: %d\n", sockfd); */
on = 1;
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if(ret < 0) {
printf("setsockopt REUSEADDR ret: %d, err:%d\n",
ret, errno);
return;
}
memset(&sa_in, 0, sizeof(sa_in));
sa_in.sin_family = AF_INET;
sa_in.sin_port = htons(6501 + port + inc);
sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in));
if(ret < 0) {
printf("bind ret: %d, errno: %d\n", ret, errno);
inc++;
close(sockfd);
printf("Trying next port: %d\n", 6501 + port + inc);
if(inc >= 10) {
printf("Too many retries, quitting\n");
return;
}
} else {
break;
}
}
printf("SCC port %d is at unix port %d\n", port, 6501 + port + inc);
ret = listen(sockfd, 1);
flags = fcntl(sockfd, F_GETFL, 0);
if(flags == -1) {
printf("fcntl GETFL ret: %d, errno: %d\n", flags, errno);
return;
}
ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
if(ret == -1) {
printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno);
return;
}
scc_ptr->accfd = sockfd;
scc_ptr->state = 1; /* successful socket */
#endif /* SCC_SOCKETS */
}
void
scc_socket_change_params(int port)
{
#ifdef SCC_SOCKETS
#endif
}
void
scc_accept_socket(int port)
{
#ifdef SCC_SOCKETS
Scc *scc_ptr;
int flags;
int rdwrfd;
int ret;
scc_ptr = &(scc_stat[port]);
if(scc_ptr->rdwrfd <= 0) {
rdwrfd = accept(scc_ptr->accfd, scc_ptr->host_handle,
&(scc_ptr->host_aux1));
if(rdwrfd < 0) {
return;
}
/* For Linux, we need to set O_NONBLOCK on the rdwrfd */
flags = fcntl(rdwrfd, F_GETFL, 0);
if(flags == -1) {
printf("fcntl GETFL ret: %d, errno: %d\n", flags,errno);
return;
}
ret = fcntl(rdwrfd, F_SETFL, flags | O_NONBLOCK);
if(ret == -1) {
printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno);
return;
}
scc_ptr->rdwrfd = rdwrfd;
}
#endif
}
void
scc_socket_fill_readbuf(int port, double dcycs)
{
#ifdef SCC_SOCKETS
byte tmp_buf[256];
Scc *scc_ptr;
int rdwrfd;
int i;
int ret;
scc_ptr = &(scc_stat[port]);
/* Accept socket if not already open */
scc_accept_socket(port);
rdwrfd = scc_ptr->rdwrfd;
if(rdwrfd < 0) {
return;
}
/* Try reading some bytes */
ret = read(rdwrfd, tmp_buf, 256);
if(ret > 0) {
for(i = 0; i < ret; i++) {
if(tmp_buf[i] == 0) {
/* Skip null chars */
continue;
}
scc_add_to_readbuf(port, tmp_buf[i], dcycs);
}
} else if(ret == 0) {
/* assume socket close */
close(rdwrfd);
scc_ptr->rdwrfd = -1;
}
#endif
}
void
scc_socket_empty_writebuf(int port)
{
#ifdef SCC_SOCKETS
struct sigaction newact, oldact;
Scc *scc_ptr;
int rdptr;
int wrptr;
int rdwrfd;
int done;
int ret;
int len;
scc_ptr = &(scc_stat[port]);
scc_accept_socket(port);
rdwrfd = scc_ptr->rdwrfd;
if(rdwrfd < 0) {
return;
}
/* Try writing some bytes */
done = 0;
while(!done) {
rdptr = scc_ptr->out_rdptr;
wrptr = scc_ptr->out_wrptr;
if(rdptr == wrptr) {
done = 1;
break;
}
len = wrptr - rdptr;
if(len < 0) {
len = SCC_OUTBUF_SIZE - rdptr;
}
if(len > 32) {
len = 32;
}
if(len <= 0) {
done = 1;
break;
}
/* ignore SIGPIPE around writes to the socket, so we can */
/* catch a closed socket and prepare to re-accept a new */
/* connection. Otherwise, SIGPIPE kills KEGS */
sigemptyset(&newact.sa_mask);
newact.sa_handler = SIG_IGN;
newact.sa_flags = 0;
sigaction(SIGPIPE, &newact, &oldact);
ret = write(rdwrfd, &(scc_ptr->out_buf[rdptr]), len);
sigaction(SIGPIPE, &oldact, 0);
/* restore previous SIGPIPE behavior */
if(ret == 0) {
done = 1; /* give up for now */
break;
} else if(ret < 0) {
/* assume socket is dead */
close(rdwrfd);
scc_ptr->rdwrfd = -1;
done = 1;
break;
} else {
rdptr = rdptr + ret;
if(rdptr >= SCC_OUTBUF_SIZE) {
rdptr = rdptr - SCC_OUTBUF_SIZE;
}
scc_ptr->out_rdptr = rdptr;
}
}
#endif
}

252
src/scc_windriver.c Normal file
View File

@ -0,0 +1,252 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_scc_windriver_c[] = "@(#)$KmKId: scc_windriver.c,v 1.3 2003-09-20 15:05:15-04 kentd Exp $";
/* This file contains the Win32 COM1/COM2 calls */
#include "defc.h"
#include "scc.h"
extern Scc scc_stat[2];
extern word32 g_c025_val;
#ifdef _WIN32
int
scc_serial_win_init(int port)
{
COMMTIMEOUTS commtimeouts;
char str_buf[8];
Scc *scc_ptr;
HANDLE host_handle;
int state;
int ret;
scc_ptr = &(scc_stat[port]);
scc_ptr->state = 0; /* mark as failed */
sprintf(&str_buf[0], "COM%d", port+1);
host_handle = CreateFile(&str_buf[0], GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
scc_ptr->host_handle = host_handle;
scc_ptr->host_handle2 = malloc(sizeof(DCB));
printf("scc_socket_init %d called, host_handle: %p\n", port,
host_handle);
if(host_handle == INVALID_HANDLE_VALUE) {
scc_ptr->host_handle = 0;
return 0;
}
scc_serial_win_change_params(port);
commtimeouts.ReadIntervalTimeout = MAXDWORD;
commtimeouts.ReadTotalTimeoutMultiplier = 0;
commtimeouts.ReadTotalTimeoutConstant = 0;
commtimeouts.WriteTotalTimeoutMultiplier = 0;
commtimeouts.WriteTotalTimeoutConstant = 10;
ret = SetCommTimeouts(host_handle, &commtimeouts);
if(ret == 0) {
printf("setcommtimeout ret: %d\n", ret);
}
state = 2; /* raw serial */
scc_ptr->state = state;
return state;
}
void
scc_serial_win_change_params(int port)
{
DCB *dcbptr;
HANDLE host_handle;
Scc *scc_ptr;
int ret;
scc_ptr = &(scc_stat[port]);
host_handle = scc_ptr->host_handle;
dcbptr = scc_ptr->host_handle2;
if(host_handle == 0) {
return;
}
ret = GetCommState(host_handle, dcbptr);
if(ret == 0) {
printf("getcomm port%d ret: %d\n", port, ret);
}
#if 1
printf("dcb.baudrate: %d, bytesize:%d, stops:%d, parity:%d\n",
(int)dcbptr->BaudRate, (int)dcbptr->ByteSize,
(int)dcbptr->StopBits, (int)dcbptr->Parity);
printf("dcb.binary: %d, ctsflow: %d, dsrflow: %d, dtr: %d, dsr: %d\n",
(int)dcbptr->fBinary,
(int)dcbptr->fOutxCtsFlow,
(int)dcbptr->fOutxDsrFlow,
(int)dcbptr->fDtrControl,
(int)dcbptr->fDsrSensitivity);
printf("dcb.txonxoff:%d, outx:%d, inx: %d, null: %d, rts: %d\n",
(int)dcbptr->fTXContinueOnXoff,
(int)dcbptr->fOutX,
(int)dcbptr->fInX,
(int)dcbptr->fNull,
(int)dcbptr->fRtsControl);
printf("dcb.fAbortOnErr:%d, fParity:%d\n", (int)dcbptr->fAbortOnError,
(int)dcbptr->fParity);
#endif
dcbptr->fAbortOnError = 0;
dcbptr->BaudRate = scc_ptr->baud_rate;
dcbptr->ByteSize = scc_ptr->char_size;
dcbptr->StopBits = ONESTOPBIT;
switch((scc_ptr->reg[4] >> 2) & 0x3) {
case 2: // 1.5 stop bits
dcbptr->StopBits = ONE5STOPBITS;
break;
case 3: // 2 stop bits
dcbptr->StopBits = TWOSTOPBITS;
break;
}
dcbptr->Parity = NOPARITY;
switch((scc_ptr->reg[4]) & 0x3) {
case 1: // Odd parity
dcbptr->Parity = ODDPARITY;
break;
case 3: // Even parity
dcbptr->Parity = EVENPARITY;
break;
}
dcbptr->fNull = 0;
dcbptr->fDtrControl = DTR_CONTROL_ENABLE;
dcbptr->fDsrSensitivity = 0;
dcbptr->fOutxCtsFlow = 0;
dcbptr->fOutxDsrFlow = 0;
dcbptr->fParity = 0;
dcbptr->fInX = 0;
dcbptr->fOutX = 0;
dcbptr->fRtsControl = RTS_CONTROL_ENABLE;
ret = SetCommState(host_handle, dcbptr);
if(ret == 0) {
printf("SetCommState ret: %d, new baud: %d\n", ret,
(int)dcbptr->BaudRate);
}
}
void
scc_serial_win_fill_readbuf(int port, double dcycs)
{
byte tmp_buf[256];
Scc *scc_ptr;
HANDLE host_handle;
DWORD bytes_read;
int i;
int ret;
scc_ptr = &(scc_stat[port]);
host_handle = scc_ptr->host_handle;
if(host_handle == 0) {
return;
}
/* Try reading some bytes */
ret = ReadFile(host_handle, tmp_buf, 256, &bytes_read, NULL);
if(ret == 0) {
printf("ReadFile ret 0\n");
}
if(ret && (bytes_read > 0)) {
for(i = 0; i < bytes_read; i++) {
scc_add_to_readbuf(port, tmp_buf[i], dcycs);
}
}
}
void
scc_serial_win_empty_writebuf(int port)
{
Scc *scc_ptr;
HANDLE host_handle;
int rdptr;
int wrptr;
int done;
word32 err_code;
DWORD bytes_written;
int ret;
int len;
scc_ptr = &(scc_stat[port]);
//printf("win_empty_writebuf, host_handle: %d\n", scc_ptr->host_handle);
host_handle = scc_ptr->host_handle;
if(host_handle == 0) {
return;
}
/* Try writing some bytes */
done = 0;
while(!done) {
rdptr = scc_ptr->out_rdptr;
wrptr = scc_ptr->out_wrptr;
if(rdptr == wrptr) {
//printf("...rdptr == wrptr\n");
done = 1;
break;
}
len = wrptr - rdptr;
if(len < 0) {
len = SCC_OUTBUF_SIZE - rdptr;
}
if(len > 32) {
len = 32;
}
if(len <= 0) {
done = 1;
break;
}
bytes_written = 1;
ret = WriteFile(host_handle, &(scc_ptr->out_buf[rdptr]), len,
&bytes_written, NULL);
printf("WriteFile ret: %d, bytes_written:%d, len:%d\n", ret,
(int)bytes_written, len);
err_code = (word32)-1;
if(ret == 0) {
err_code = (word32)GetLastError();
printf("WriteFile ret:0, err_code: %08x\n", err_code);
}
if(ret == 0 || (bytes_written == 0)) {
done = 1;
break;
} else {
rdptr = rdptr + bytes_written;
if(rdptr >= SCC_OUTBUF_SIZE) {
rdptr = rdptr - SCC_OUTBUF_SIZE;
}
scc_ptr->out_rdptr = rdptr;
}
}
}
#endif

2285
src/sim65816.c Normal file

File diff suppressed because it is too large Load Diff

274
src/size_tab.h Normal file
View File

@ -0,0 +1,274 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_S
.stringz "@(#)$KmKId: size_tab.h,v 1.13 2002-11-19 03:10:38-05 kadickey Exp $"
#else
.word inst00_SYM+1 /* brk */
.word inst01_SYM+1 /* ORA (Dloc,X) */
.word inst02_SYM+1 /* COP */
.word inst03_SYM+1 /* ORA Disp8,S */
.word inst04_SYM+1 /* TSB Dloc */
.word inst05_SYM+1 /* ORA Dloc */
.word inst06_SYM+1 /* ASL Dloc */
.word inst07_SYM+1 /* ORA [Dloc] */
.word inst08_SYM+0 /* PHP */
.word inst09_SYM+4 /* ORA #imm */
.word inst0a_SYM+0 /* ASL a */
.word inst0b_SYM+0 /* PHD */
.word inst0c_SYM+2 /* TSB abs */
.word inst0d_SYM+2 /* ORA abs */
.word inst0e_SYM+2 /* ASL abs */
.word inst0f_SYM+3 /* ORA long */
.word inst10_SYM+1 /* BPL disp8 */
.word inst11_SYM+1 /* ORA (),y */
.word inst12_SYM+1 /* ORA () */
.word inst13_SYM+1 /* ORA (disp8,s),y */
.word inst14_SYM+1 /* TRB Dloc */
.word inst15_SYM+1 /* ORA Dloc,x */
.word inst16_SYM+1 /* ASL Dloc,x */
.word inst17_SYM+1 /* ORA [],y */
.word inst18_SYM+0 /* clc */
.word inst19_SYM+2 /* ORA abs,y */
.word inst1a_SYM+0 /* INC a */
.word inst1b_SYM+0 /* TCS */
.word inst1c_SYM+2 /* TRB Abs */
.word inst1d_SYM+2 /* ORA Abs,X */
.word inst1e_SYM+2 /* ASL abs,x */
.word inst1f_SYM+3 /* ORA Long,x */
.word inst20_SYM+2 /* JSR abs */
.word inst21_SYM+1 /* AND (Dloc,X) */
.word inst22_SYM+3 /* JSL Abslong */
.word inst23_SYM+1 /* AND Disp8,S */
.word inst24_SYM+1 /* BIT Dloc */
.word inst25_SYM+1 /* AND Dloc */
.word inst26_SYM+1 /* ROL Dloc */
.word inst27_SYM+1 /* AND [Dloc] */
.word inst28_SYM+0 /* PLP */
.word inst29_SYM+4 /* AND #imm */
.word inst2a_SYM+0 /* ROL a */
.word inst2b_SYM+0 /* PLD */
.word inst2c_SYM+2 /* BIT abs */
.word inst2d_SYM+2 /* AND abs */
.word inst2e_SYM+2 /* ROL abs */
.word inst2f_SYM+3 /* AND long */
.word inst30_SYM+1 /* BMI disp8 */
.word inst31_SYM+1 /* AND (),y */
.word inst32_SYM+1 /* AND () */
.word inst33_SYM+1 /* AND (disp8,s),y */
.word inst34_SYM+1 /* BIT Dloc,X */
.word inst35_SYM+1 /* AND Dloc,x */
.word inst36_SYM+1 /* ROL Dloc,x */
.word inst37_SYM+1 /* AND [],y */
.word inst38_SYM+0 /* SEC */
.word inst39_SYM+2 /* AND abs,y */
.word inst3a_SYM+0 /* DEC a */
.word inst3b_SYM+0 /* TSC */
.word inst3c_SYM+2 /* BIT Abs,X */
.word inst3d_SYM+2 /* AND Abs,X */
.word inst3e_SYM+2 /* ROL abs,x */
.word inst3f_SYM+3 /* AND Long,x */
.word inst40_SYM+0 /* RTI */
.word inst41_SYM+1 /* EOR (Dloc,X) */
.word inst42_SYM+1 /* WDM */
.word inst43_SYM+1 /* EOR Disp8,S */
.word inst44_SYM+2 /* MVP I,J */
.word inst45_SYM+1 /* EOR Dloc */
.word inst46_SYM+1 /* LSR Dloc */
.word inst47_SYM+1 /* EOR [Dloc] */
.word inst48_SYM+0 /* PHA */
.word inst49_SYM+4 /* EOR #imm */
.word inst4a_SYM+0 /* LSR a */
.word inst4b_SYM+0 /* PHK */
.word inst4c_SYM+2 /* JMP abs */
.word inst4d_SYM+2 /* EOR abs */
.word inst4e_SYM+2 /* LSR abs */
.word inst4f_SYM+3 /* EOR long */
.word inst50_SYM+1 /* BVC disp8 */
.word inst51_SYM+1 /* EOR (),y */
.word inst52_SYM+1 /* EOR () */
.word inst53_SYM+1 /* EOR (disp8,s),y */
.word inst54_SYM+2 /* MVN I,J */
.word inst55_SYM+1 /* EOR Dloc,x */
.word inst56_SYM+1 /* LSR Dloc,x */
.word inst57_SYM+1 /* EOR [],y */
.word inst58_SYM+0 /* CLI */
.word inst59_SYM+2 /* EOR abs,y */
.word inst5a_SYM+0 /* PHY */
.word inst5b_SYM+0 /* TCD */
.word inst5c_SYM+3 /* JMP Long */
.word inst5d_SYM+2 /* EOR Abs,X */
.word inst5e_SYM+2 /* LSR abs,x */
.word inst5f_SYM+3 /* EOR Long,x */
.word inst60_SYM+0 /* RTS */
.word inst61_SYM+1 /* ADC (Dloc,X) */
.word inst62_SYM+2 /* PER DISP16 */
.word inst63_SYM+1 /* ADC Disp8,S */
.word inst64_SYM+1 /* STZ Dloc */
.word inst65_SYM+1 /* ADC Dloc */
.word inst66_SYM+1 /* ROR Dloc */
.word inst67_SYM+1 /* ADC [Dloc] */
.word inst68_SYM+0 /* PLA */
.word inst69_SYM+4 /* ADC #imm */
.word inst6a_SYM+0 /* ROR a */
.word inst6b_SYM+0 /* RTL */
.word inst6c_SYM+2 /* JMP (abs) */
.word inst6d_SYM+2 /* ADC abs */
.word inst6e_SYM+2 /* ROR abs */
.word inst6f_SYM+3 /* ADC long */
.word inst70_SYM+1 /* BVS disp8 */
.word inst71_SYM+1 /* ADC (),y */
.word inst72_SYM+1 /* ADC () */
.word inst73_SYM+1 /* ADC (disp8,s),y */
.word inst74_SYM+1 /* STZ Dloc,X */
.word inst75_SYM+1 /* ADC Dloc,x */
.word inst76_SYM+1 /* ROR Dloc,x */
.word inst77_SYM+1 /* ADC [],y */
.word inst78_SYM+0 /* SEI */
.word inst79_SYM+2 /* ADC abs,y */
.word inst7a_SYM+0 /* PLY */
.word inst7b_SYM+0 /* TDC */
.word inst7c_SYM+2 /* JMP (abs,x) */
.word inst7d_SYM+2 /* ADC Abs,X */
.word inst7e_SYM+2 /* ROR abs,x */
.word inst7f_SYM+3 /* ADC Long,x */
.word inst80_SYM+1 /* BRA Disp8 */
.word inst81_SYM+1 /* STA (Dloc,X) */
.word inst82_SYM+2 /* BRL DISP16 */
.word inst83_SYM+1 /* STA Disp8,S */
.word inst84_SYM+1 /* STY Dloc */
.word inst85_SYM+1 /* STA Dloc */
.word inst86_SYM+1 /* STX Dloc */
.word inst87_SYM+1 /* STA [Dloc] */
.word inst88_SYM+0 /* DEY */
.word inst89_SYM+4 /* BIT #imm */
.word inst8a_SYM+0 /* TXA */
.word inst8b_SYM+0 /* PHB */
.word inst8c_SYM+2 /* STY abs */
.word inst8d_SYM+2 /* STA abs */
.word inst8e_SYM+2 /* STX abs */
.word inst8f_SYM+3 /* STA long */
.word inst90_SYM+1 /* BCC disp8 */
.word inst91_SYM+1 /* STA (),y */
.word inst92_SYM+1 /* STA () */
.word inst93_SYM+1 /* STA (disp8,s),y */
.word inst94_SYM+1 /* STY Dloc,X */
.word inst95_SYM+1 /* STA Dloc,x */
.word inst96_SYM+1 /* STX Dloc,y */
.word inst97_SYM+1 /* STA [],y */
.word inst98_SYM+0 /* TYA */
.word inst99_SYM+2 /* STA abs,y */
.word inst9a_SYM+0 /* TXS */
.word inst9b_SYM+0 /* TXY */
.word inst9c_SYM+2 /* STX abs */
.word inst9d_SYM+2 /* STA Abs,X */
.word inst9e_SYM+2 /* STZ abs,x */
.word inst9f_SYM+3 /* STA Long,x */
.word insta0_SYM+5 /* LDY #imm */
.word insta1_SYM+1 /* LDA (Dloc,X) */
.word insta2_SYM+5 /* LDX #imm */
.word insta3_SYM+1 /* LDA Disp8,S */
.word insta4_SYM+1 /* LDY Dloc */
.word insta5_SYM+1 /* LDA Dloc */
.word insta6_SYM+1 /* LDX Dloc */
.word insta7_SYM+1 /* LDA [Dloc] */
.word insta8_SYM+0 /* TAY */
.word insta9_SYM+4 /* LDA #imm */
.word instaa_SYM+0 /* TAX */
.word instab_SYM+0 /* PLB */
.word instac_SYM+2 /* LDY abs */
.word instad_SYM+2 /* LDA abs */
.word instae_SYM+2 /* LDX abs */
.word instaf_SYM+3 /* LDA long */
.word instb0_SYM+1 /* BCS disp8 */
.word instb1_SYM+1 /* LDA (),y */
.word instb2_SYM+1 /* LDA () */
.word instb3_SYM+1 /* LDA (disp8,s),y */
.word instb4_SYM+1 /* LDY Dloc,X */
.word instb5_SYM+1 /* LDA Dloc,x */
.word instb6_SYM+1 /* LDX Dloc,y */
.word instb7_SYM+1 /* LDA [],y */
.word instb8_SYM+0 /* CLV */
.word instb9_SYM+2 /* LDA abs,y */
.word instba_SYM+0 /* TSX */
.word instbb_SYM+0 /* TYX */
.word instbc_SYM+2 /* LDY abs,x */
.word instbd_SYM+2 /* LDA Abs,X */
.word instbe_SYM+2 /* LDX abs,y */
.word instbf_SYM+3 /* LDA Long,x */
.word instc0_SYM+5 /* CPY #Imm */
.word instc1_SYM+1 /* CMP (Dloc,X) */
.word instc2_SYM+1 /* REP #8bit */
.word instc3_SYM+1 /* CMP Disp8,S */
.word instc4_SYM+1 /* CPY Dloc */
.word instc5_SYM+1 /* CMP Dloc */
.word instc6_SYM+1 /* DEC Dloc */
.word instc7_SYM+1 /* CMP [Dloc] */
.word instc8_SYM+0 /* INY */
.word instc9_SYM+4 /* CMP #imm */
.word instca_SYM+0 /* DEX */
.word instcb_SYM+0 /* WAI */
.word instcc_SYM+2 /* CPY abs */
.word instcd_SYM+2 /* CMP abs */
.word instce_SYM+2 /* DEC abs */
.word instcf_SYM+3 /* CMP long */
.word instd0_SYM+1 /* BNE disp8 */
.word instd1_SYM+1 /* CMP (),y */
.word instd2_SYM+1 /* CMP () */
.word instd3_SYM+1 /* CMP (disp8,s),y */
.word instd4_SYM+1 /* PEI Dloc */
.word instd5_SYM+1 /* CMP Dloc,x */
.word instd6_SYM+1 /* DEC Dloc,x */
.word instd7_SYM+1 /* CMP [],y */
.word instd8_SYM+0 /* CLD */
.word instd9_SYM+2 /* CMP abs,y */
.word instda_SYM+0 /* PHX */
.word instdb_SYM+0 /* STP */
.word instdc_SYM+2 /* JML (Abs) */
.word instdd_SYM+2 /* CMP Abs,X */
.word instde_SYM+2 /* DEC abs,x */
.word instdf_SYM+3 /* CMP Long,x */
.word inste0_SYM+5 /* CPX #Imm */
.word inste1_SYM+1 /* SBC (Dloc,X) */
.word inste2_SYM+1 /* SEP #8bit */
.word inste3_SYM+1 /* SBC Disp8,S */
.word inste4_SYM+1 /* CPX Dloc */
.word inste5_SYM+1 /* SBC Dloc */
.word inste6_SYM+1 /* INC Dloc */
.word inste7_SYM+1 /* SBC [Dloc] */
.word inste8_SYM+0 /* INX */
.word inste9_SYM+4 /* SBC #imm */
.word instea_SYM+0 /* NOP */
.word insteb_SYM+0 /* XBA */
.word instec_SYM+2 /* CPX abs */
.word insted_SYM+2 /* SBC abs */
.word instee_SYM+2 /* INC abs */
.word instef_SYM+3 /* SBC long */
.word instf0_SYM+1 /* BEQ disp8 */
.word instf1_SYM+1 /* SBC (),y */
.word instf2_SYM+1 /* SBC () */
.word instf3_SYM+1 /* SBC (disp8,s),y */
.word instf4_SYM+2 /* PEA Imm */
.word instf5_SYM+1 /* SBC Dloc,x */
.word instf6_SYM+1 /* INC Dloc,x */
.word instf7_SYM+1 /* SBC [],y */
.word instf8_SYM+0 /* SED */
.word instf9_SYM+2 /* SBC abs,y */
.word instfa_SYM+0 /* PLX */
.word instfb_SYM+0 /* XCE */
.word instfc_SYM+2 /* JSR (Abs,x) */
.word instfd_SYM+2 /* SBC Abs,X */
.word instfe_SYM+2 /* INC abs,x */
.word instff_SYM+3 /* SBC Long,x */
.block 4*16
#endif

783
src/smartport.c Normal file
View File

@ -0,0 +1,783 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_smartport_c[] = "@(#)$KmKId: smartport.c,v 1.29 2003-11-17 15:44:44-05 kentd Exp $";
#include "defc.h"
extern int Verbose;
extern int Halt_on;
extern int g_rom_version;
extern int g_io_amt;
extern int g_highest_smartport_unit;
int g_cycs_in_io_read = 0;
extern Engine_reg engine;
extern Iwm iwm;
#define LEN_SMPT_LOG 16
STRUCT(Smpt_log) {
word32 start_addr;
int cmd;
int rts_addr;
int cmd_list;
int extras;
int unit;
int buf;
int blk;
};
Smpt_log g_smpt_log[LEN_SMPT_LOG];
int g_smpt_log_pos = 0;
void
smartport_error(void)
{
int pos;
int i;
pos = g_smpt_log_pos;
printf("Smartport log pos: %d\n", pos);
for(i = 0; i < LEN_SMPT_LOG; i++) {
pos--;
if(pos < 0) {
pos = LEN_SMPT_LOG - 1;
}
printf("%d:%d: t:%04x, cmd:%02x, rts:%04x, "
"cmd_l:%04x, x:%d, unit:%d, buf:%04x, blk:%04x\n",
i, pos,
g_smpt_log[pos].start_addr,
g_smpt_log[pos].cmd,
g_smpt_log[pos].rts_addr,
g_smpt_log[pos].cmd_list,
g_smpt_log[pos].extras,
g_smpt_log[pos].unit,
g_smpt_log[pos].buf,
g_smpt_log[pos].blk);
}
}
void
smartport_log(word32 start_addr, int cmd, int rts_addr, int cmd_list)
{
int pos;
pos = g_smpt_log_pos;
if(start_addr != 0) {
g_smpt_log[pos].start_addr = start_addr;
g_smpt_log[pos].cmd = cmd;
g_smpt_log[pos].rts_addr = rts_addr;
g_smpt_log[pos].cmd_list = cmd_list;
g_smpt_log[pos].extras = 0;
g_smpt_log[pos].unit = 0;
g_smpt_log[pos].buf = 0;
g_smpt_log[pos].blk = 0;
} else {
pos--;
if(pos < 0) {
pos = LEN_SMPT_LOG - 1;
}
g_smpt_log[pos].extras = 1;
g_smpt_log[pos].unit = cmd;
g_smpt_log[pos].buf = rts_addr;
g_smpt_log[pos].blk = cmd_list;
}
pos++;
if(pos >= LEN_SMPT_LOG) {
pos = 0;
}
g_smpt_log_pos = pos;
}
void
do_c70d(word32 arg0)
{
int cmd;
int cmd_list_lo, cmd_list_mid, cmd_list_hi;
int rts_lo, rts_hi;
word32 rts_addr;
word32 cmd_list;
int unit;
int param_cnt;
int status_ptr_lo, status_ptr_mid, status_ptr_hi;
int buf_ptr_lo, buf_ptr_hi;
int buf_ptr;
int block_lo, block_mid, block_hi;
int block;
word32 status_ptr;
int status_code;
int ctl_ptr_lo, ctl_ptr_hi;
int ctl_ptr;
int ctl_code;
int mask;
int stat_val;
int size;
int ret;
int ext;
int i;
set_memory_c(0x7f8, 0xc7, 0);
if((engine.psr & 0x100) == 0) {
disk_printf("c70d called in native mode!\n");
if((engine.psr & 0x30) != 0x30) {
halt_printf("c70d called native, psr: %03x!\n",
engine.psr);
}
}
engine.stack = ((engine.stack + 1) & 0xff) + 0x100;
rts_lo = get_memory_c(engine.stack, 0);
engine.stack = ((engine.stack + 1) & 0xff) + 0x100;
rts_hi = get_memory_c(engine.stack, 0);
rts_addr = (rts_lo + (256*rts_hi) + 1) & 0xffff;
disk_printf("rts_addr: %04x\n", rts_addr);
cmd = get_memory_c(rts_addr, 0);
cmd_list_lo = get_memory_c((rts_addr + 1) & 0xffff, 0);
cmd_list_mid = get_memory_c((rts_addr + 2) & 0xffff, 0);
cmd_list_hi = 0;
mask = 0xffff;
if(cmd & 0x40) {
/* extended */
mask = 0xffffff;
cmd_list_hi = get_memory_c((rts_addr + 3) & 0xffff, 0);
}
cmd_list = cmd_list_lo + (256*cmd_list_mid) + (65536*cmd_list_hi);
disk_printf("cmd: %02x, cmd_list: %06x\n", cmd, cmd_list);
param_cnt = get_memory_c(cmd_list, 0);
ext = 0;
if(cmd & 0x40) {
ext = 2;
}
smartport_log(0xc70d, cmd, rts_addr, cmd_list);
switch(cmd & 0x3f) {
case 0x00: /* Status == 0x00 and 0x40 */
if(param_cnt != 3) {
disk_printf("param_cnt %d is != 3!\n", param_cnt);
exit(8);
}
unit = get_memory_c((cmd_list+1) & mask, 0);
status_ptr_lo = get_memory_c((cmd_list+2) & mask, 0);
status_ptr_mid = get_memory_c((cmd_list+3) & mask, 0);
status_ptr_hi = 0;
if(cmd & 0x40) {
status_ptr_hi = get_memory_c((cmd_list+4) & mask, 0);
}
status_ptr = status_ptr_lo + (256*status_ptr_mid) +
(65536*status_ptr_hi);
if(cmd & 0x40) {
status_code = get_memory_c((cmd_list+6) & mask, 0);
} else {
status_code = get_memory_c((cmd_list+4) & mask, 0);
}
smartport_log(0, unit, status_ptr, status_code);
disk_printf("unit: %02x, status_ptr: %06x, code: %02x\n",
unit, status_ptr, status_code);
if(unit == 0 && status_code == 0) {
/* Smartport driver status */
/* see technotes/smpt/tn-smpt-002 */
set_memory_c(status_ptr, g_highest_smartport_unit+1, 0);
set_memory_c(status_ptr+1, 0xff, 0); /* interrupt stat*/
set_memory_c(status_ptr+2, 0x02, 0); /* vendor id */
set_memory_c(status_ptr+3, 0x00, 0); /* vendor id */
set_memory_c(status_ptr+4, 0x00, 0); /* version lo */
set_memory_c(status_ptr+5, 0x10, 0); /* version hi */
set_memory_c(status_ptr+6, 0x00, 0);
set_memory_c(status_ptr+7, 0x00, 0);
engine.xreg = 8;
engine.yreg = 0;
engine.acc &= 0xff00;
engine.psr &= ~1;
engine.kpc = (rts_addr + 3 + ext) & mask;
return;
} else if(unit > 0 && status_code == 0) {
/* status for unit x */
if(unit > MAX_C7_DISKS || iwm.smartport[unit-1].fd < 0){
stat_val = 0x80;
size = 0;
} else {
stat_val = 0xf8;
size = iwm.smartport[unit-1].image_size;
size = (size+511) / 512;
}
set_memory_c(status_ptr, stat_val, 0);
set_memory_c(status_ptr +1, size & 0xff, 0);
set_memory_c(status_ptr +2, (size >> 8) & 0xff, 0);
set_memory_c(status_ptr +3, (size >> 16) & 0xff, 0);
engine.xreg = 4;
if(cmd & 0x40) {
set_memory_c(status_ptr + 4,
(size >> 16) & 0xff, 0);
engine.xreg = 5;
}
engine.yreg = 0;
engine.acc &= 0xff00;
engine.psr &= ~1;
engine.kpc = (rts_addr + 3 + ext) & mask;
disk_printf("just finished unit %d, stat 0\n", unit);
return;
} else if(status_code == 3) {
if(unit > MAX_C7_DISKS || iwm.smartport[unit-1].fd < 0){
stat_val = 0x80;
size = 0;
} else {
stat_val = 0xf8;
size = iwm.smartport[unit-1].image_size;
size = (size+511) / 512;
}
if(cmd & 0x40) {
disk_printf("extended for stat_code 3!\n");
}
/* DIB for unit 1 */
set_memory_c(status_ptr, stat_val, 0);
set_memory_c(status_ptr +1, size & 0xff, 0);
set_memory_c(status_ptr +2, (size >> 8) & 0xff, 0);
set_memory_c(status_ptr +3, (size >> 16) & 0xff, 0);
if(cmd & 0x40) {
set_memory_c(status_ptr + 4,
(size >> 24) & 0xff, 0);
status_ptr++;
}
set_memory_c(status_ptr +4, 4, 0);
for(i = 5; i < 21; i++) {
set_memory_c(status_ptr +i, 0x20, 0);
}
set_memory_c(status_ptr +5, 'K', 0);
set_memory_c(status_ptr +6, 'E', 0);
set_memory_c(status_ptr +7, 'G', 0);
set_memory_c(status_ptr +8, 'S', 0);
/* hard disk supporting extended calls */
set_memory_c(status_ptr + 21, 0x02, 0);
set_memory_c(status_ptr + 22, 0xa0, 0);
set_memory_c(status_ptr + 23, 0x00, 0);
set_memory_c(status_ptr + 24, 0x00, 0);
if(cmd & 0x40) {
engine.xreg = 26;
} else {
engine.xreg = 25;
}
engine.yreg = 0;
engine.acc &= 0xff00;
engine.psr &= ~1;
engine.kpc = (rts_addr + 3 + ext) & 0xffff;
disk_printf("Just finished unit %d, stat 3\n", unit);
if(unit == 0 || unit > MAX_C7_DISKS) {
engine.acc |= 0x28;
engine.psr |= 1;
}
return;
}
printf("cmd: 00, unknown unit/status code!\n");
break;
case 0x01: /* Read Block == 0x01 and 0x41 */
if(param_cnt != 3) {
halt_printf("param_cnt %d is != 3!\n", param_cnt);
return;
}
unit = get_memory_c((cmd_list+1) & mask, 0);
buf_ptr_lo = get_memory_c((cmd_list+2) & mask, 0);
buf_ptr_hi = get_memory_c((cmd_list+3) & mask, 0);
buf_ptr = buf_ptr_lo + (256*buf_ptr_hi);
if(cmd & 0x40) {
buf_ptr_lo = get_memory_c((cmd_list+4) & mask, 0);
buf_ptr_hi = get_memory_c((cmd_list+5) & mask, 0);
buf_ptr += ((buf_ptr_hi*256) + buf_ptr_lo)*65536;
cmd_list += 2;
}
block_lo = get_memory_c((cmd_list+4) & mask, 0);
block_mid = get_memory_c((cmd_list+5) & mask, 0);
block_hi = get_memory_c((cmd_list+6) & mask, 0);
block = ((block_hi*256) + block_mid)*256 + block_lo;
disk_printf("smartport read unit %d of block %04x into %04x\n",
unit, block, buf_ptr);
if(unit < 1 || unit > MAX_C7_DISKS) {
halt_printf("Unknown unit #: %d\n", unit);
}
smartport_log(0, unit - 1, buf_ptr, block);
ret = do_read_c7(unit - 1, buf_ptr, block);
engine.xreg = 0;
engine.yreg = 2;
engine.acc = (engine.acc & 0xff00) | (ret & 0xff);
engine.psr &= ~1;
if(ret != 0) {
engine.psr |= 1;
}
engine.kpc = (rts_addr + 3 + ext) & 0xffff;
return;
break;
case 0x02: /* Write Block == 0x02 and 0x42 */
if(param_cnt != 3) {
halt_printf("param_cnt %d is != 3!\n", param_cnt);
return;
}
unit = get_memory_c((cmd_list+1) & mask, 0);
buf_ptr_lo = get_memory_c((cmd_list+2) & mask, 0);
buf_ptr_hi = get_memory_c((cmd_list+3) & mask, 0);
buf_ptr = buf_ptr_lo + (256*buf_ptr_hi);
if(cmd & 0x40) {
buf_ptr_lo = get_memory_c((cmd_list+4) & mask, 0);
buf_ptr_hi = get_memory_c((cmd_list+5) & mask, 0);
buf_ptr += ((buf_ptr_hi*256) + buf_ptr_lo)*65536;
cmd_list += 2;
}
block_lo = get_memory_c((cmd_list+4) & mask, 0);
block_mid = get_memory_c((cmd_list+5) & mask, 0);
block_hi = get_memory_c((cmd_list+6) & mask, 0);
block = ((block_hi*256) + block_mid)*256 + block_lo;
disk_printf("smartport write unit %d of block %04x from %04x\n",
unit, block, buf_ptr);
if(unit < 1 || unit > MAX_C7_DISKS) {
halt_printf("Unknown unit #: %d\n", unit);
}
smartport_log(0, unit - 1, buf_ptr, block);
ret = do_write_c7(unit - 1, buf_ptr, block);
engine.xreg = 0;
engine.yreg = 2;
engine.acc = (engine.acc & 0xff00) | (ret & 0xff);
engine.psr &= ~1;
if(ret != 0) {
engine.psr |= 1;
}
engine.kpc = (rts_addr + 3 + ext) & 0xffff;
HALT_ON(HALT_ON_C70D_WRITES, "c70d Write done\n");
return;
break;
case 0x03: /* Format == 0x03 and 0x43 */
if(param_cnt != 1) {
halt_printf("param_cnt %d is != 1!\n", param_cnt);
return;
}
unit = get_memory_c((cmd_list+1) & mask, 0);
if(unit < 1 || unit > MAX_C7_DISKS) {
halt_printf("Unknown unit #: %d\n", unit);
}
smartport_log(0, unit - 1, 0, 0);
ret = do_format_c7(unit - 1);
engine.xreg = 0;
engine.yreg = 2;
engine.acc = (engine.acc & 0xff00) | (ret & 0xff);
engine.psr &= ~1;
if(ret != 0) {
engine.psr |= 1;
}
engine.kpc = (rts_addr + 3 + ext) & 0xffff;
HALT_ON(HALT_ON_C70D_WRITES, "c70d Format done\n");
return;
break;
case 0x04: /* Control == 0x04 and 0x44 */
if(cmd == 0x44) {
halt_printf("smartport code 0x44 not supported\n");
}
if(param_cnt != 3) {
halt_printf("param_cnt %d is != 3!\n", param_cnt);
return;
}
unit = get_memory_c((cmd_list+1) & mask, 0);
ctl_ptr_lo = get_memory_c((cmd_list+2) & mask, 0);
ctl_ptr_hi = get_memory_c((cmd_list+3) & mask, 0);
ctl_ptr = (ctl_ptr_hi << 8) + ctl_ptr_lo;
if(cmd & 0x40) {
ctl_ptr_lo = get_memory_c((cmd_list+4) & mask, 0);
ctl_ptr_hi = get_memory_c((cmd_list+5) & mask, 0);
ctl_ptr += ((ctl_ptr_hi << 8) + ctl_ptr_lo) << 16;
cmd_list += 2;
}
ctl_code = get_memory_c((cmd_list +4) & mask, 0);
switch(ctl_code) {
case 0x00:
printf("Performing a reset on unit %d\n", unit);
break;
default:
halt_printf("control code: %02x unknown!\n", ctl_code);
}
engine.xreg = 0;
engine.yreg = 2;
engine.acc &= 0xff00;
engine.psr &= ~1;
engine.kpc = (rts_addr + 3 + ext) & 0xffff;
return;
break;
default: /* Unknown command! */
/* set acc = 1, and set carry, and set kpc */
engine.xreg = (rts_addr) & 0xff;
engine.yreg = (rts_addr >> 8) & 0xff;
engine.acc = (engine.acc & 0xff00) + 0x01;
engine.psr |= 0x01; /* set carry */
engine.kpc = (rts_addr + 3 + ext) & 0xffff;
if(cmd != 0x4a && cmd != 0x48) {
/* Finder does 0x4a call before formatting disk */
/* Many things do 0x48 call to see online drives */
halt_printf("Just did smtport cmd:%02x rts_addr:%04x, "
"cmdlst:%06x\n", cmd, rts_addr, cmd_list);
}
return;
}
halt_printf("Unknown smtport cmd:%02x, cmd_list:%06x, rts_addr:%06x\n",
cmd, cmd_list, rts_addr);
}
void
do_c70a(word32 arg0)
{
int cmd, unit;
int buf_lo, buf_hi;
int blk_lo, blk_hi;
int blk, buf;
int prodos_unit;
int size;
int ret;
set_memory_c(0x7f8, 0xc7, 0);
cmd = get_memory_c((engine.direct + 0x42) & 0xffff, 0);
prodos_unit = get_memory_c((engine.direct + 0x43) & 0xffff, 0);
buf_lo = get_memory_c((engine.direct + 0x44) & 0xffff, 0);
buf_hi = get_memory_c((engine.direct + 0x45) & 0xffff, 0);
blk_lo = get_memory_c((engine.direct + 0x46) & 0xffff, 0);
blk_hi = get_memory_c((engine.direct + 0x47) & 0xffff, 0);
blk = (blk_hi << 8) + blk_lo;
buf = (buf_hi << 8) + buf_lo;
disk_printf("cmd: %02x, pro_unit: %02x, buf: %04x, blk: %04x\n",
cmd, prodos_unit, buf, blk);
if((prodos_unit & 0x7f) == 0x70) {
unit = 0 + (prodos_unit >> 7);
} else if((prodos_unit & 0x7f) == 0x40) {
unit = 2 + (prodos_unit >> 7);
} else {
halt_printf("Unknown prodos_unit: %d\n", prodos_unit);
return;
}
smartport_log(0xc70a, cmd, blk, buf);
engine.psr &= ~1; /* clear carry */
if(g_rom_version >= 3) {
engine.kpc = 0xc764;
} else {
engine.kpc = 0xc765;
}
ret = 0x27; /* I/O error */
if(cmd == 0x00) {
size = iwm.smartport[unit].image_size;
size = (size+511) / 512;
smartport_log(0, unit, size, 0);
ret = 0;
engine.xreg = size & 0xff;
engine.yreg = size >> 8;
} else if(cmd == 0x01) {
smartport_log(0, unit, buf, blk);
ret = do_read_c7(unit, buf, blk);
} else if(cmd == 0x02) {
smartport_log(0, unit, buf, blk);
ret = do_write_c7(unit, buf, blk);
} else if(cmd == 0x03) { /* format */
smartport_log(0, unit, buf, blk);
ret = do_format_c7(unit);
}
engine.acc = (engine.acc & 0xff00) | (ret & 0xff);
if(ret != 0) {
engine.psr |= 1;
}
return;
}
int
do_read_c7(int unit_num, word32 buf, int blk)
{
byte local_buf[0x200];
register word32 start_time;
register word32 end_time;
word32 val;
int len;
int fd;
int image_start;
int image_size;
int ret;
int i;
if(unit_num < 0 || unit_num > MAX_C7_DISKS) {
halt_printf("do_read_c7: unit_num: %d\n", unit_num);
smartport_error();
return 0x28;
}
fd = iwm.smartport[unit_num].fd;
image_start = iwm.smartport[unit_num].image_start;
image_size = iwm.smartport[unit_num].image_size;
if(fd < 0) {
printf("c7_fd == %d!\n", fd);
#if 0
if(blk != 2 && blk != 0) {
/* don't print error if only reading directory */
smartport_error();
halt_printf("Read unit:%02x blk:%04x\n", unit_num, blk);
}
#endif
return 0x2f;
}
ret = lseek(fd, image_start + blk*0x200, SEEK_SET);
if(ret != image_start + blk*0x200) {
halt_printf("lseek returned %08x, errno: %d\n", ret, errno);
smartport_error();
return 0x27;
}
if(ret >= image_start + image_size) {
halt_printf("Tried to read from pos %08x on disk, (blk:%04x)\n",
ret, blk);
smartport_error();
return 0x27;
}
len = read(fd, &local_buf[0], 0x200);
if(len != 0x200) {
printf("read returned %08x, errno:%d, blk:%04x, unit: %02x\n",
len, errno, blk, unit_num);
halt_printf("name: %s\n", iwm.smartport[unit_num].name_ptr);
smartport_error();
return 0x27;
}
g_io_amt += 0x200;
if(buf >= 0xfc0000) {
disk_printf("reading into ROM, just returning\n");
return 0;
}
GET_ITIMER(start_time);
for(i = 0; i < 0x200; i += 2) {
val = (local_buf[i+1] << 8) + local_buf[i];
set_memory16_c(buf + i, val, 0);
}
GET_ITIMER(end_time);
g_cycs_in_io_read += (end_time - start_time);
return 0;
}
int
do_write_c7(int unit_num, word32 buf, int blk)
{
word32 local_buf[0x200/4];
Disk *dsk;
word32 *ptr;
word32 val1, val2;
word32 val;
int len;
int ret;
int fd;
int image_start;
int image_size;
int i;
if(unit_num < 0 || unit_num > MAX_C7_DISKS) {
halt_printf("do_write_c7: unit_num: %d\n", unit_num);
smartport_error();
return 0x28;
}
dsk = &(iwm.smartport[unit_num]);
fd = dsk->fd;
image_start = dsk->image_start;
image_size = dsk->image_size;
if(fd < 0) {
halt_printf("c7_fd == %d!\n", fd);
smartport_error();
return 0x28;
}
ptr = &(local_buf[0]);
for(i = 0; i < 0x200; i += 4) {
val1 = get_memory16_c(buf + i, 0);
val2 = get_memory16_c(buf + i + 2, 0);
/* reorder the little-endian bytes to be big-endian */
#ifdef KEGS_LITTLE_ENDIAN
val = (val2 << 16) + val1;
#else
val = (val1 << 24) + ((val1 << 8) & 0xff0000) +
((val2 << 8) & 0xff00) + (val2 >> 8);
#endif
*ptr++ = val;
}
ret = lseek(fd, image_start + blk*0x200, SEEK_SET);
if(ret != image_start + blk*0x200) {
halt_printf("lseek returned %08x, errno: %d\n", ret, errno);
smartport_error();
return 0x27;
}
if(ret >= image_start + image_size) {
halt_printf("Tried to write to %08x\n", ret);
smartport_error();
return 0x27;
}
if(dsk->write_prot) {
printf("Write, but %s is write protected!\n", dsk->name_ptr);
return 0x2b;
}
if(dsk->write_through_to_unix == 0) {
halt_printf("Write to %s, but not wr_thru!\n", dsk->name_ptr);
return 0x00;
}
len = write(fd, (byte *)&local_buf[0], 0x200);
if(len != 0x200) {
halt_printf("write ret %08x bytes, errno: %d\n", len, errno);
smartport_error();
return 0x27;
}
g_io_amt += 0x200;
return 0;
}
int
do_format_c7(int unit_num)
{
byte local_buf[0x1000];
Disk *dsk;
int len;
int ret;
int sum;
int total;
int max;
int image_start;
int image_size;
int fd;
int i;
if(unit_num < 0 || unit_num > MAX_C7_DISKS) {
halt_printf("do_format_c7: unit_num: %d\n", unit_num);
smartport_error();
return 0x28;
}
dsk = &(iwm.smartport[unit_num]);
fd = dsk->fd;
image_start = dsk->image_start;
image_size = dsk->image_size;
if(fd < 0) {
halt_printf("c7_fd == %d!\n", fd);
smartport_error();
return 0x28;
}
for(i = 0; i < 0x1000; i++) {
local_buf[i] = 0;
}
ret = lseek(fd, image_start, SEEK_SET);
if(ret != image_start) {
halt_printf("lseek returned %08x, errno: %d\n", ret, errno);
smartport_error();
return 0x27;
}
if(dsk->write_prot) {
printf("Format, but %s is write protected!\n", dsk->name_ptr);
return 0x2b;
}
if(dsk->write_through_to_unix == 0) {
printf("Format of %s ignored\n", dsk->name_ptr);
return 0x00;
}
sum = 0;
total = image_size;
while(sum < total) {
max = MIN(0x1000, total-sum);
len = write(fd, &local_buf[0], max);
if(len != max) {
halt_printf("write ret %08x, errno:%d\n", len, errno);
smartport_error();
return 0x27;
}
sum += len;
}
return 0;
}
void
do_c700(word32 ret)
{
disk_printf("do_c700 called, ret: %08x\n", ret);
ret = do_read_c7(0, 0x800, 0);
set_memory_c(0x7f8, 7, 0);
set_memory_c(0x42, 0x01, 0);
set_memory_c(0x43, 0x70, 0);
set_memory_c(0x44, 0x0, 0);
set_memory_c(0x45, 0x8, 0);
set_memory_c(0x46, 0x0, 0);
set_memory_c(0x47, 0x0, 0);
engine.xreg = 0x70;
engine.kpc = 0x801;
if(ret != 0) {
printf("Failure reading boot disk in s7d1!\n");
engine.kpc = 0xe000;
}
}

2031
src/sound.c Normal file

File diff suppressed because it is too large Load Diff

60
src/sound.h Normal file
View File

@ -0,0 +1,60 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
#ifdef INCLUDE_RCSID_C
const char rcsid_sound_h[] = "@(#)$KmKId: sound.h,v 1.17 2003-11-21 15:15:57-05 kentd Exp $";
#endif
#if !defined(_WIN32) && !defined(__CYGWIN__)
# include <sys/ipc.h>
# include <sys/shm.h>
#endif
#define SOUND_SHM_SAMP_SIZE (32*1024)
#define SAMPLE_SIZE 2
#define NUM_CHANNELS 2
#define SAMPLE_CHAN_SIZE (SAMPLE_SIZE * NUM_CHANNELS)
STRUCT(Doc_reg) {
double dsamp_ev;
double dsamp_ev2;
double complete_dsamp;
int samps_left;
word32 cur_acc;
word32 cur_inc;
word32 cur_start;
word32 cur_end;
word32 cur_mask;
int size_bytes;
int event;
int running;
int has_irq_pending;
word32 freq;
word32 vol;
word32 waveptr;
word32 ctl;
word32 wavesize;
word32 last_samp_val;
};
/* prototypes for win32snd_driver.c functions */
void win32snd_init(word32 *);
void win32snd_shutdown();
void win32snd_shutdown();
void child_sound_init_win32();
int win32_send_audio(byte *ptr, int size);
/* Prototypes for macsnd_driver.c functions */
int mac_send_audio(byte *ptr, int in_size);
void child_sound_init_mac();
void macsnd_init(word32 *shmaddr);

469
src/sound_driver.c Normal file
View File

@ -0,0 +1,469 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_sound_driver_c[] = "@(#)$KmKId: sound_driver.c,v 1.16 2004-03-22 19:08:08-05 kentd Exp $";
#include "defc.h"
#include "sound.h"
#ifdef HPUX
# include <sys/audio.h>
#endif
#ifdef SOLARIS
# include <sys/audioio.h>
#endif
#if defined(__linux__) || defined(OSS)
# include <sys/soundcard.h>
#endif
#ifndef _WIN32
# include <sys/socket.h>
# include <netinet/in.h>
#endif
#include <errno.h>
extern int Verbose;
extern int g_use_alib;
extern int g_audio_rate;
int g_preferred_rate = 48000;
int g_audio_socket = -1;
int g_bytes_written = 0;
#define ZERO_BUF_SIZE 2048
word32 g_snd_zero_buf[ZERO_BUF_SIZE];
#define ZERO_PAUSE_SAFETY_SAMPS (g_audio_rate >> 5)
#define ZERO_PAUSE_NUM_SAMPS (4*g_audio_rate)
int g_zeroes_buffered = 0;
int g_zeroes_seen = 0;
int g_sound_paused = 0;
int g_childsnd_vbl = 0;
int g_childsnd_pos = 0;
word32 *g_childsnd_shm_addr = 0;
void child_sound_init_linux();
void child_sound_init_hpdev();
void child_sound_init_solaris();
void child_sound_init_win32();
void child_sound_init_mac();
void
reliable_buf_write(word32 *shm_addr, int pos, int size)
{
byte *ptr;
int ret;
if(size < 1 || pos < 0 || pos > SOUND_SHM_SAMP_SIZE ||
size > SOUND_SHM_SAMP_SIZE ||
(pos + size) > SOUND_SHM_SAMP_SIZE) {
printf("reliable_buf_write: pos: %04x, size: %04x\n",
pos, size);
exit(1);
}
ptr = (byte *)&(shm_addr[pos]);
size = size * 4;
while(size > 0) {
#ifdef _WIN32
ret = win32_send_audio(ptr, size);
#else
# ifdef MAC
ret = mac_send_audio(ptr, size);
# else
ret = write(g_audio_socket, ptr, size);
# endif
#endif
if(ret < 0) {
printf("audio write, errno: %d\n", errno);
exit(1);
}
size = size - ret;
ptr += ret;
g_bytes_written += ret;
}
}
void
reliable_zero_write(int amt)
{
int len;
while(amt > 0) {
len = MIN(amt, ZERO_BUF_SIZE);
reliable_buf_write(g_snd_zero_buf, 0, len);
amt -= len;
}
}
void
child_sound_loop(int read_fd, int write_fd, word32 *shm_addr)
{
#ifdef HPUX
long status_return;
#endif
word32 tmp;
int ret;
doc_printf("Child pipe fd: %d\n", read_fd);
g_audio_rate = g_preferred_rate;
g_zeroes_buffered = 0;
g_zeroes_seen = 0;
g_sound_paused = 0;
g_childsnd_pos = 0;
g_childsnd_vbl = 0;
g_childsnd_shm_addr = shm_addr;
#ifdef HPUX
child_sound_init_hpdev();
#endif
#ifdef SOLARIS
child_sound_init_solaris();
#endif
#if defined(__linux__) || defined(OSS)
child_sound_init_linux();
#endif
#ifdef _WIN32
child_sound_init_win32();
return;
#endif
#ifdef MAC
child_sound_init_mac();
return;
#endif
tmp = g_audio_rate;
ret = write(write_fd, &tmp, 4);
if(ret != 4) {
printf("Unable to send back audio rate to parent\n");
printf("ret: %d fd: %d, errno: %d\n", ret, write_fd, errno);
exit(1);
}
printf("Wrote to fd %d the audio rate\n", write_fd);
close(write_fd);
while(1) {
errno = 0;
ret = read(read_fd, &tmp, 4);
if(ret <= 0) {
printf("child dying from ret: %d, errno: %d\n",
ret, errno);
break;
}
child_sound_playit(tmp);
}
#ifdef HPUX
ioctl(g_audio_socket, AUDIO_DRAIN, 0);
#endif
close(g_audio_socket);
exit(0);
}
void
child_sound_playit(word32 tmp)
{
int size;
size = tmp & 0xffffff;
//printf("child_sound_playit: %08x\n", tmp);
if((tmp >> 24) == 0xa2) {
/* play sound here */
#if 0
g_childsnd_pos += g_zeroes_buffered;
while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) {
g_childsnd_pos -= SOUND_SHM_SAMP_SIZE;
}
#endif
if(g_zeroes_buffered) {
reliable_zero_write(g_zeroes_buffered);
}
g_zeroes_buffered = 0;
g_zeroes_seen = 0;
if((size + g_childsnd_pos) > SOUND_SHM_SAMP_SIZE) {
reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos,
SOUND_SHM_SAMP_SIZE - g_childsnd_pos);
size = (g_childsnd_pos + size) - SOUND_SHM_SAMP_SIZE;
g_childsnd_pos = 0;
}
reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, size);
if(g_sound_paused) {
printf("Unpausing sound, zb: %d\n", g_zeroes_buffered);
g_sound_paused = 0;
}
} else if((tmp >> 24) == 0xa1) {
if(g_sound_paused) {
if(g_zeroes_buffered < ZERO_PAUSE_SAFETY_SAMPS) {
g_zeroes_buffered += size;
}
} else {
/* not paused, send it through */
g_zeroes_seen += size;
reliable_zero_write(size);
if(g_zeroes_seen >= ZERO_PAUSE_NUM_SAMPS) {
printf("Pausing sound\n");
g_sound_paused = 1;
}
}
} else {
printf("tmp received bad: %08x\n", tmp);
exit(3);
}
g_childsnd_pos += size;
while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) {
g_childsnd_pos -= SOUND_SHM_SAMP_SIZE;
}
g_childsnd_vbl++;
if(g_childsnd_vbl >= 60) {
g_childsnd_vbl = 0;
#if 0
printf("sound bytes written: %06x\n", g_bytes_written);
printf("Sample samples[0]: %08x %08x %08x %08x\n",
g_childsnd_shm_addr[0], g_childsnd_shm_addr[1],
g_childsnd_shm_addr[2], g_childsnd_shm_addr[3]);
printf("Sample samples[100]: %08x %08x %08x %08x\n",
g_childsnd_shm_addr[100], g_childsnd_shm_addr[101],
g_childsnd_shm_addr[102], g_childsnd_shm_addr[103]);
#endif
g_bytes_written = 0;
}
}
#ifdef HPUX
void
child_sound_init_hpdev()
{
struct audio_describe audio_descr;
int output_channel;
char *str;
int speaker;
int ret;
int i;
g_audio_socket = open("/dev/audio", O_WRONLY, 0);
if(g_audio_socket < 0) {
printf("open /dev/audio failed, ret: %d, errno:%d\n",
g_audio_socket, errno);
exit(1);
}
ret = ioctl(g_audio_socket, AUDIO_DESCRIBE, &audio_descr);
if(ret < 0) {
printf("ioctl AUDIO_DESCRIBE failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
for(i = 0; i < audio_descr.nrates; i++) {
printf("Audio rate[%d] = %d\n", i,
audio_descr.sample_rate[i]);
}
ret = ioctl(g_audio_socket, AUDIO_SET_DATA_FORMAT,
AUDIO_FORMAT_LINEAR16BIT);
if(ret < 0) {
printf("ioctl AUDIO_SET_DATA_FORMAT failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
ret = ioctl(g_audio_socket, AUDIO_SET_CHANNELS, NUM_CHANNELS);
if(ret < 0) {
printf("ioctl AUDIO_SET_CHANNELS failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
ret = ioctl(g_audio_socket, AUDIO_SET_TXBUFSIZE, 16*1024);
if(ret < 0) {
printf("ioctl AUDIO_SET_TXBUFSIZE failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
ret = ioctl(g_audio_socket, AUDIO_SET_SAMPLE_RATE, g_audio_rate);
if(ret < 0) {
printf("ioctl AUDIO_SET_SAMPLE_RATE failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
ret = ioctl(g_audio_socket, AUDIO_GET_OUTPUT, &output_channel);
if(ret < 0) {
printf("ioctl AUDIO_GET_OUTPUT failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
speaker = 1;
str = getenv("SPEAKER");
if(str) {
if(str[0] != 'i' && str[0] != 'I') {
speaker = 0;
}
}
if(speaker) {
printf("Sending sound to internal speaker\n");
output_channel |= AUDIO_OUT_SPEAKER;
} else {
printf("Sending sound to external jack\n");
output_channel &= (~AUDIO_OUT_SPEAKER);
output_channel |= AUDIO_OUT_HEADPHONE;
}
ret = ioctl(g_audio_socket, AUDIO_SET_OUTPUT, output_channel);
if(ret < 0) {
printf("ioctl AUDIO_SET_OUTPUT failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
}
#endif /* HPUX */
#ifdef SOLARIS
void
child_sound_init_solaris()
{
struct audio_info audioi;
int ret;
g_audio_socket = open("/dev/audio", O_WRONLY, 0);
if(g_audio_socket < 0) {
printf("open /dev/audio failed, ret: %d, errno:%d\n",
g_audio_socket, errno);
exit(1);
}
ret = ioctl(g_audio_socket, AUDIO_GETINFO, &audioi);
if(ret < 0) {
printf("ioctl audio getinfo ret: %d, errno:%d\n", ret, errno);
exit(1);
}
audioi.play.sample_rate = g_preferred_rate;
audioi.play.encoding = AUDIO_ENCODING_LINEAR;
audioi.play.precision = 16;
audioi.play.channels = 2;
ret = ioctl(g_audio_socket, AUDIO_SETINFO, &audioi);
if(ret < 0) {
printf("ioctl audio setinfo ret: %d, errno:%d\n", ret, errno);
exit(1);
}
}
#endif /* SOLARIS */
#if defined(__linux__) || defined(OSS)
void
child_sound_init_linux()
{
int stereo;
int sample_size;
int rate;
int fragment;
int fmt;
int ret;
g_audio_socket = open("/dev/dsp", O_WRONLY, 0);
if(g_audio_socket < 0) {
printf("open /dev/dsp failed, ret: %d, errno:%d\n",
g_audio_socket, errno);
exit(1);
}
fragment = 0x00200009;
#if 0
ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFRAGMENT, &fragment);
if(ret < 0) {
printf("ioctl SETFRAGEMNT failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
#endif
sample_size = 16;
ret = ioctl(g_audio_socket, SNDCTL_DSP_SAMPLESIZE, &sample_size);
if(ret < 0) {
printf("ioctl SNDCTL_DSP_SAMPLESIZE failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
#ifdef KEGS_LITTLE_ENDIAN
fmt = AFMT_S16_LE;
#else
fmt = AFMT_S16_BE;
#endif
ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFMT, &fmt);
if(ret < 0) {
printf("ioctl SNDCTL_DSP_SETFMT failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
stereo = 1;
ret = ioctl(g_audio_socket, SNDCTL_DSP_STEREO, &stereo);
if(ret < 0) {
printf("ioctl SNDCTL_DSP_STEREO failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
rate = g_audio_rate;
ret = ioctl(g_audio_socket, SNDCTL_DSP_SPEED, &rate);
if(ret < 0) {
printf("ioctl SNDCTL_DSP_SPEED failed, ret:%d, errno:%d\n",
ret, errno);
exit(1);
}
if(ret > 0) {
rate = ret; /* rate is returned value */
}
if(rate < 8000) {
printf("Audio rate of %d which is < 8000!\n", rate);
exit(1);
}
g_audio_rate = rate;
printf("Sound initialized\n");
}
#endif

204
src/superhires.h Normal file
View File

@ -0,0 +1,204 @@
/* This file is included by video.c */
#ifndef SUPERHIRES_INCLUDED
const char rcsid_superhires_h[] = "@(#)$KmKId: superhires.h,v 1.9 2003-10-29 02:02:59-05 kentd Exp $";
# define SUPERHIRES_INCLUDED
#endif
void
SUPER_TYPE(byte *screen_data, int pixels_per_line, int y, int scan,
word32 ch_mask, int use_a2vid_palette, int mode_640)
{
word32 *palptr;
word32 mem_ptr;
byte val0;
int x1, x2;
byte *b_ptr;
word32 *img_ptr, *img_ptr2;
word32 tmp, tmp2;
word32 ch_tmp;
byte *slow_mem_ptr;
int shift_per;
word32 pal;
word32 pal_word;
word32 pix0, pix1, pix2, pix3;
word32 save_pix;
int offset, next_line_offset;
int dopr;
mem_ptr = 0xa0 * y + 0x12000;
tmp2 = 0;
tmp = 0;
shift_per = (1 << SHIFT_PER_CHANGE);
if(use_a2vid_palette) {
pal = (g_a2vid_palette & 0xf);
} else {
pal = (scan & 0xf);
}
if(SUPER_FILL) {
ch_mask = -1;
save_pix = 0;
}
if(use_a2vid_palette) {
palptr = &(g_a2vid_palette_remap[0]);
} else {
palptr = &(g_palette_8to1624[pal * 16]);
}
dopr = 0;
#if 0
if(y == 1) {
dopr = 1;
printf("superhires line %d has ch_mask: %08x\n", y, ch_mask);
}
#endif
for(x1 = 0; x1 < 0xa0; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
pal_word = (pal << 28) + (pal << 20) + (pal << 12) +
(pal << 4);
if(mode_640 && !use_a2vid_palette) {
#ifdef KEGS_LITTLE_ENDIAN
pal_word += 0x04000c08;
#else
pal_word += 0x080c0004;
#endif
}
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
offset = y*2*pixels_per_line + x1*4;
next_line_offset = pixels_per_line;
#if SUPER_PIXEL_SIZE == 16
offset *= 2;
next_line_offset *= 2;
#elif SUPER_PIXEL_SIZE == 32
offset *= 4;
next_line_offset *= 4;
#endif
b_ptr = &screen_data[offset];
img_ptr = (word32 *)b_ptr;
img_ptr2 = (word32 *)(b_ptr + next_line_offset);
if(mode_640) {
for(x2 = 0; x2 < shift_per; x2++) {
val0 = *slow_mem_ptr++;
pix0 = (val0 >> 6) & 0x3;
pix1 = (val0 >> 4) & 0x3;
pix2 = (val0 >> 2) & 0x3;
pix3 = val0 & 0x3;
if(use_a2vid_palette || (SUPER_PIXEL_SIZE > 8)){
pix0 = palptr[pix0+8];
pix1 = palptr[pix1+12];
pix2 = palptr[pix2+0];
pix3 = palptr[pix3+4];
}
#if SUPER_PIXEL_SIZE == 8
# ifdef KEGS_LITTLE_ENDIAN
tmp = (pix3 << 24) + (pix2 << 16) +
(pix1 << 8) + pix0 + pal_word;
# else
tmp = (pix0 << 24) + (pix1 << 16) +
(pix2 << 8) + pix3 + pal_word;
# endif
*img_ptr++ = tmp; *img_ptr2++ = tmp;
#elif SUPER_PIXEL_SIZE == 16
# ifdef KEGS_LITTLE_ENDIAN
tmp = (pix1 << 16) + pix0;
tmp2 = (pix3 << 16) + pix2;
# else
tmp = (pix0 << 16) + pix1;
tmp2 = (pix2 << 16) + pix3;
# endif
*img_ptr++ = tmp;
*img_ptr++ = tmp2;
*img_ptr2++ = tmp;
*img_ptr2++ = tmp2;
#else /* SUPER_PIXEL_SIZE == 32 */
*img_ptr++ = pix0;
*img_ptr++ = pix1;
*img_ptr++ = pix2;
*img_ptr++ = pix3;
*img_ptr2++ = pix0;
*img_ptr2++ = pix1;
*img_ptr2++ = pix2;
*img_ptr2++ = pix3;
#endif
#if 0
if(y == 1 && x1 == 0 && x2 == 0) {
printf("y==1,x1,x2=0, %02x = %08x %08x "
"%08x %08x, pal: %04x\n", val0,
pix0, pix1, pix2, pix3, pal);
printf("offset: %04x, nlo:%04x, ppl:"
"%04x, %d\n", offset,
next_line_offset,
pixels_per_line, SUPER_PIXEL_SIZE);
}
#endif
}
} else { /* 320 mode */
for(x2 = 0; x2 < shift_per; x2++) {
val0 = *slow_mem_ptr++;
pix0 = (val0 >> 4);
if(SUPER_FILL) {
if(pix0) {
save_pix = pix0;
} else {
pix0 = save_pix;
}
}
pix1 = (val0 & 0xf);
if(SUPER_FILL) {
if(pix1) {
save_pix = pix1;
} else {
pix1 = save_pix;
}
}
if(use_a2vid_palette || (SUPER_PIXEL_SIZE > 8)){
pix0 = palptr[pix0];
pix1 = palptr[pix1];
}
if(dopr && x1 == 0) {
printf("y:%d, x2:%d, val:%02x = %08x %08x\n", y, x2, val0, pix0, pix1);
}
#if SUPER_PIXEL_SIZE == 8
# ifdef KEGS_LITTLE_ENDIAN
tmp = (pix1 << 24) + (pix1 << 16) +
(pix0 << 8) + pix0 + pal_word;
# else
tmp = (pix0 << 24) + (pix0 << 16) +
(pix1 << 8) + pix1 + pal_word;
# endif
*img_ptr++ = tmp; *img_ptr2++ = tmp;
#elif SUPER_PIXEL_SIZE == 16
tmp = (pix0 << 16) + pix0;
tmp2 = (pix1 << 16) + pix1;
*img_ptr++ = tmp;
*img_ptr++ = tmp2;
*img_ptr2++ = tmp;
*img_ptr2++ = tmp2;
#else /* SUPER_PIXEL_SIZE == 32 */
*img_ptr++ = pix0;
*img_ptr++ = pix0;
*img_ptr++ = pix1;
*img_ptr++ = pix1;
*img_ptr2++ = pix0;
*img_ptr2++ = pix0;
*img_ptr2++ = pix1;
*img_ptr2++ = pix1;
#endif
}
}
}
}

897
src/to_pro.c Executable file
View File

@ -0,0 +1,897 @@
/****************************************************************/
/* Apple //gs emulator */
/* Copyright 1996 Kent Dickey */
/* */
/* This code may not be used in a commercial product */
/* without prior written permission of the author. */
/* */
/* You may freely distribute this code. */
/* */
/* You can contact the author at kentd@cup.hp.com. */
/* HP has nothing to do with this software. */
/****************************************************************/
#include "defc.h"
#include <ctype.h>
#include "prodos.h"
#include <errno.h>
#define DEF_DISK_SIZE (800*1024)
#define MAX_FILE_NAMES 51
char out_name[] = "POOF1";
int g_def_file_type = -1;
int g_def_aux_type = -1;
void make_legal_prodos_name(char *new_name, char *old_name);
int
main(int argc, char **argv)
{
char *files[MAX_FILE_NAMES];
char *name;
char *new_name_end;
int new_name_len;
struct stat stat_buf;
int in;
int in_size;
int ret;
ProDisk *disk;
char new_name[128];
byte in_buf[1024];
int disk_size;
int i;
int done;
int pos;
int size;
int num_files;
int file_type;
int aux_type;
disk_size = DEF_DISK_SIZE;
if(argc < 2) {
fprintf(stderr, "%s: {-[size in K]} {unix_files}\n",
argv[0]);
exit(1);
}
num_files = 0;
for(i = 1; i < argc; i++) {
if(argv[i][0] == '-') {
/* I smell a -size_in_K */
disk_size = strtoul(&(argv[i][1]), 0, 10) * 1024;
printf("disk_size: %d, 0x%x\n", disk_size, disk_size);
if(disk_size < 40*1024) {
printf("Too small!\n");
exit(1);
}
} else {
files[num_files] = argv[i];
num_files++;
if(num_files >= MAX_FILE_NAMES) {
printf("Too many filenames: %d\n", num_files);
exit(2);
}
}
}
disk = allocate_memdisk(out_name, disk_size);
format_memdisk(disk, out_name);
for(i = 0; i < num_files; i++) {
name = files[i];
in = open(name, O_RDONLY | O_BINARY);
if(in < 0) {
fprintf(stderr, "opening %s returned %d, errno: %d\n",
name, in, errno);
exit(1);
}
ret = fstat(in, &stat_buf);
if(ret != 0) {
fprintf(stderr, "fstat returned %d, errno: %d\n",
ret, errno);
}
in_size = stat_buf.st_size;
printf("in size: %d\n", in_size);
if(in_size > disk->disk_bytes_left) {
printf("File bigger than %d, too big!\n", disk_size);
exit(2);
}
make_legal_prodos_name(new_name, name);
new_name_len = strlen(new_name);
new_name_end = new_name + new_name_len;
file_type = g_def_file_type;
aux_type = g_def_aux_type;
while(g_def_file_type < 0) {
/* choose file type */
if(new_name_len >= 5) {
if(strcmp(new_name_end - 4, ".SHK") == 0) {
file_type = 0xe0;
aux_type = 0x8002;
break;
}
if(strcmp(new_name_end - 4, ".SDK") == 0) {
file_type = 0xe0;
aux_type = 0x8002;
break;
}
}
file_type = 0x04; /* TXT */
aux_type = 0;
break;
}
create_new_file(disk, 2, 1, new_name, file_type,
0, 0, 0, 0xc3, aux_type, 0, in_size);
done = 0;
pos = 0;
while(pos < in_size) {
size = 512;
if(pos + size > in_size) {
size = in_size - pos;
}
ret = read(in, in_buf, size);
if(ret != size || ret <= 0) {
fprintf(stderr, "read returned %d, errno: %d\n",
ret, errno);
exit(2);
}
ret = pro_write_file(disk, in_buf, pos, size);
if(ret != 0) {
printf("pro_write returned %d!\n", ret);
exit(3);
}
pos += size;
}
close_file(disk);
close(in);
}
flush_disk(disk);
return 0;
}
void
make_legal_prodos_name(char *new_name, char *old_name)
{
char *ptr;
int start_len, start_char;
int len;
int pos;
int c;
int j;
for(j = 0; j < 16; j++) {
/* make sure it ends with null == 15 + 1 */
new_name[j] = 0;
}
start_char = 0;
start_len = strlen(old_name);
len = 0;
ptr = &old_name[start_len - 1];
for(j = start_len - 1; j >= 0; j--) {
if(*ptr == '/' || *ptr == ':') {
break;
}
ptr--;
len++;
}
ptr++;
if(len <= 0) {
printf("Filename: %s has len: %d!\n", old_name, len);
exit(1);
}
printf("mid_name: %s, len:%d\n", ptr, len);
pos = 0;
for(j = 0; j < 15; j++) {
c = ptr[pos];
if(isalnum(c)) {
c = toupper(c);
} else if(c != 0) {
c = '.';
}
if(j == 0 && !isalpha(c)) {
c = 'A';
}
new_name[j] = c;
pos++;
if(pos == 7 && len > 15) {
pos = len - 8;
}
}
printf("new_name: %s\n", new_name);
}
void
flush_disk(ProDisk *disk)
{
disk_write_data(disk, 6, disk->bitmap_ptr,
disk->size_bitmap_blocks * 512);
close(disk->fd);
disk->fd = -1;
}
void
close_file(ProDisk *disk)
{
write_ind_block(disk);
write_master_ind_block(disk);
disk_write_data(disk, disk->dir_blk_num, &(disk->dir_blk_data[0]), 512);
disk->file_ptr = 0;
}
ProDisk *
allocate_memdisk(char *out_name, int size)
{
ProDisk *disk;
int out;
out = open(out_name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0x1b6);
if(out < 0) {
fprintf(stderr, "opening %s returned %d, errno: %d\n",
out_name, out, errno);
exit(1);
}
disk = (ProDisk *)malloc(sizeof(ProDisk));
if(disk == 0) {
printf("allocate_memdisk failed, errno: %d\n", errno);
}
disk->fd = out;
disk->total_blocks = (size + 511) / 512;
disk->bitmap_ptr = 0;
disk->disk_bytes_left = 0;
disk->size_bitmap_blocks = 0;
disk->dir_blk_num = -1;
disk->ind_blk_num = -1;
disk->master_ind_blk_num = -1;
return disk;
}
void
format_memdisk(ProDisk *disk, char *name)
{
byte zero_buf[1024];
int total_blocks;
byte *bitmap_ptr;
Vol_hdr *vol_hdr;
Directory *dir;
int size_bitmap_bytes;
int size_bitmap_blocks;
int disk_blocks_left;
int i, j;
total_blocks = disk->total_blocks;
/* Zero out blocks 0 and 1 */
for(i = 0; i < 2*512; i++) {
zero_buf[i] = 0;
}
disk_write_data(disk, 0x00000, zero_buf, 2*512);
/* and make the image the right size */
disk_write_data(disk, total_blocks - 1, zero_buf, 512);
dir = disk_read_dir(disk, 2);
set_l2byte(&(dir->prev_blk), 0);
set_l2byte(&(dir->next_blk), 3);
vol_hdr = (Vol_hdr *)&(dir->file_entries[0]);
vol_hdr->storage_type_name_len = 0xf0 + strlen(name);
strncpy((char *)vol_hdr->vol_name, name, strlen(name));
vol_hdr->version = 0;
vol_hdr->min_version = 0;
vol_hdr->access = 0xc3;
vol_hdr->entry_length = 0x27;
vol_hdr->entries_per_block = 0x0d;
set_l2byte(&(vol_hdr->file_count), 0);
vol_hdr->entries_per_block = 0x0d;
set_l2byte(&(vol_hdr->bit_map), 6);
set_l2byte(&(vol_hdr->total_blocks), total_blocks);
for(i = 1; i < 13; i++) {
set_file_entry(&(dir->file_entries[i]), 0, "", 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0);
}
disk_write_dir(disk, 2);
for(i = 3; i < 6; i++) {
dir = disk_read_dir(disk, i);
set_l2byte(&(dir->prev_blk), i - 1);
set_l2byte(&(dir->next_blk), i + 1);
if(i == 5) {
set_l2byte(&(dir->next_blk), 0);
}
for(j = 0; j < 13; j++) {
set_file_entry(&(dir->file_entries[j]), 0, "", 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0);
}
disk_write_dir(disk, i);
}
size_bitmap_bytes = (total_blocks + 7)/ 8;
size_bitmap_blocks = (size_bitmap_bytes + 511)/ 512;
bitmap_ptr = (byte *)malloc(size_bitmap_blocks * 512);
for(i = 0; i < 6+size_bitmap_blocks; i++) {
set_bitmap_used(bitmap_ptr, i);
}
for(i = 6+size_bitmap_blocks; i < total_blocks; i++) {
set_bitmap_free(bitmap_ptr, i);
}
for(i = total_blocks; i < size_bitmap_blocks*512*8; i++) {
set_bitmap_used(bitmap_ptr, i);
}
disk_write_data(disk, 6, bitmap_ptr, size_bitmap_blocks * 512);
disk->bitmap_ptr = bitmap_ptr;
disk->size_bitmap_blocks = size_bitmap_blocks;
disk->bitmap_bytes = size_bitmap_blocks * 512;
disk->bitmap_cur_pos = 0;
disk_blocks_left = total_blocks - 6 - size_bitmap_blocks;
disk->disk_bytes_left = disk_blocks_left * 512;
}
void
disk_write_data(ProDisk *disk, int blk_num, byte *buf, int size)
{
int size_in_blocks;
int ret;
#if 0
printf("Writing blk %04x from buf: %08x, %03x\n", blk_num, buf, size);
#endif
size_in_blocks = size >> 9;
if(size_in_blocks * 512 != size) {
printf("disk_write: blk: %04x, buf: %08x, size: %08x\n",
blk_num, (word32)buf, size);
exit(1);
}
ret = lseek(disk->fd, 512*blk_num, SEEK_SET);
if(ret != 512*blk_num) {
printf("disk_write: seek: %d, errno: %d, blk: %04x, buf: "
"%08x, sz: %08x\n", ret, errno, blk_num,
(word32)buf, size);
exit(1);
}
ret = write(disk->fd, buf, size);
if(ret != size) {
printf("disk_write: write: %d, errno: %d, blk: %04x, buf: "
"%08x, sz: %08x\n", ret, errno, blk_num,
(word32)buf, size);
exit(1);
}
}
void
disk_read_data(ProDisk *disk, int blk_num, byte *buf, int size)
{
int size_in_blocks;
int ret;
int i;
size_in_blocks = size >> 9;
if(size_in_blocks * 512 != size) {
printf("disk_read: blk: %04x, buf: %08x, size: %08x\n",
blk_num, (word32)buf, size);
exit(1);
}
ret = lseek(disk->fd, 512*blk_num, SEEK_SET);
if(ret != 512*blk_num) {
printf("disk_read: seek: %d, errno: %d, blk: %04x, buf: "
"%08x, sz: %08x\n", ret, errno, blk_num,
(word32)buf, size);
exit(1);
}
ret = read(disk->fd, buf, size);
if(ret != size) {
printf("disk_read: read: %d, errno: %d, blk: %04x, buf: "
"%08x, sz: %08x\n", ret, errno, blk_num,
(word32)buf, size);
for(i = 0; i < size; i++) {
buf[i] = 0;
}
}
}
Directory *
disk_read_dir(ProDisk *disk, int blk_num)
{
disk_write_dir(disk, blk_num);
disk->dir_blk_num = blk_num;
disk_read_data(disk, blk_num, &(disk->dir_blk_data[0]), 512);
return (Directory *)&(disk->dir_blk_data[0]);
}
void
disk_write_dir(ProDisk *disk, int blk_num)
{
if(disk->dir_blk_num >= 0) {
if(disk->dir_blk_num != blk_num) {
printf("disk_write_dir: %04x != %04x\n",
disk->dir_blk_num, blk_num);
}
disk_write_data(disk, disk->dir_blk_num,
&(disk->dir_blk_data[0]), 512);
disk->dir_blk_num = -1;
}
}
void
create_new_file(ProDisk *disk, int dir_block, int storage_type, char *name,
int file_type, word32 creation_time, int version, int min_version,
int access, int aux_type, word32 last_mod, word32 eof)
{
Vol_hdr *vol_ptr;
int val;
Directory *dir_ptr;
File_entry *file_ptr;
int file_count;
int pos;
int last_pos;
int done;
int next_blk;
int name_len;
name_len = strlen(name);
dir_ptr = disk_read_dir(disk, dir_block);
next_blk = dir_block;
val = dir_ptr->file_entries[0].storage_type_name_len;
last_pos = 13;
pos = 0;
if(((val & 0xf0) == 0xf0) || ((val & 0xf0) == 0xe0)) {
/* vol dir or subdir header */
vol_ptr = (Vol_hdr *)&(dir_ptr->file_entries[0]);
file_count = get_l2byte(&(vol_ptr->file_count));
pos = 1;
last_pos = vol_ptr->entries_per_block;
} else {
printf("dir_block: %04x not subdir or voldir\n", dir_block);
exit(6);
}
vol_ptr = 0;
done = 0;
while(!done) {
file_ptr = &(dir_ptr->file_entries[pos]);
if(((file_ptr->storage_type_name_len) & 0xf0) == 0) {
/* Got it! */
file_ptr->storage_type_name_len =
(storage_type << 4) | name_len;
strncpy((char *)file_ptr->file_name, name, 15);
file_ptr->file_type = file_type;
set_l2byte(&(file_ptr->key_pointer),
find_next_free_block(disk));
set_l2byte(&(file_ptr->blocks_used), 0);
set_pro_time(&(file_ptr->creation_time),
creation_time);
file_ptr->version = version;
file_ptr->min_version = min_version;
file_ptr->access = access;
set_l2byte(&(file_ptr->aux_type), aux_type);
set_pro_time(&(file_ptr->last_mod), last_mod);
set_l2byte(&(file_ptr->header_pointer),
dir_block);
set_l3byte(&(file_ptr->eof), eof);
disk_write_dir(disk, next_blk);
dir_ptr = disk_read_dir(disk, dir_block);
vol_ptr = (Vol_hdr *)&(dir_ptr->file_entries[0]);
set_l2byte(&(vol_ptr->file_count), file_count+1);
disk_write_dir(disk, dir_block);
disk_read_dir(disk, next_blk);
/* re-read dir so that ptrs are set up right */
disk->file_ptr = file_ptr;
disk->file_open = 1;
disk->ind_blk_num = -1;
disk->master_ind_blk_num = -1;
done = 1;
break;
} else {
/* check to make sure name is unique */
if((file_ptr->storage_type_name_len & 0x0f)== name_len){
if(!memcmp(file_ptr->file_name, name,name_len)){
printf("Name %s already on disk!\n",
name);
exit(8);
}
}
pos++;
if(pos >= last_pos) {
/* Go to next block */
next_blk = get_l2byte(&(dir_ptr->next_blk));
if(next_blk) {
dir_ptr = disk_read_dir(disk, next_blk);
pos = 0;
} else {
printf("Top directory full!\n");
exit(2);
}
}
}
}
}
int
pro_write_file(ProDisk *disk, byte *in_buf, int pos, int size)
{
int block;
int i;
block = get_disk_block(disk, pos, 1);
if(block < 7) {
printf("pro_write_file, get_disk_block: %d\n", block);
exit(3);
}
if(size < 512) {
for(i = size; i < 512; i++) {
in_buf[i] = 0;
}
} else if(size > 512) {
printf("error, pro_write_file size: %d too big\n", size);
exit(4);
}
disk_write_data(disk, block, in_buf, 512);
return 0;
}
int
get_disk_block(ProDisk *disk, int pos, int create)
{
File_entry *file_ptr;
int storage_type;
word32 eof;
int lo, hi;
int offset;
int master_ind_block, ind_block;
int ret_block;
int key_block;
if(pos >= 128*256*512) {
printf("offset too big\n");
exit(3);
}
file_ptr = disk->file_ptr;
eof = get_l3byte(&(file_ptr->eof));
storage_type = (file_ptr->storage_type_name_len) >> 4;
key_block = get_l2byte(&(file_ptr->key_pointer));
if(storage_type == 1 && pos >= 512) {
/* make it sapling */
get_new_ind_block(disk);
inc_l2byte(&(file_ptr->blocks_used));
disk->ind_blk_data[0] = key_block & 0xff;
disk->ind_blk_data[0x100] = key_block >> 8;
key_block = disk->ind_blk_num;
set_l2byte(&(file_ptr->key_pointer), key_block);
file_ptr->storage_type_name_len += 0x10;
storage_type++;
}
if(storage_type == 2 && pos >= 256*512) {
/* make it tree */
get_new_master_ind_block(disk);
inc_l2byte(&(file_ptr->blocks_used));
disk->master_ind_blk_data[0] = key_block & 0xff;
disk->master_ind_blk_data[0x100] = key_block >> 8;
key_block = disk->master_ind_blk_num;
set_l2byte(&(file_ptr->key_pointer), key_block);
file_ptr->storage_type_name_len += 0x10;
storage_type++;
}
switch(storage_type) {
case 1:
if(pos >= 512) {
printf("Error1!\n");
exit(3);
}
ret_block = key_block;
if(ret_block == 0) {
ret_block = find_next_free_block(disk);
inc_l2byte(&(file_ptr->blocks_used));
set_l2byte(&(file_ptr->key_pointer), ret_block);
}
return ret_block;
case 2:
ind_block = key_block;
if(ind_block <= 0) {
printf("write failure, ind_block: %d!\n", ind_block);
exit(3);
}
offset = pos >> 9;
if(offset >= 256) {
printf("pos too big!\n");
exit(3);
}
lo = disk->ind_blk_data[offset];
hi = disk->ind_blk_data[offset + 0x100];
ret_block = hi*256 + lo;
if(ret_block == 0) {
/* Need to alloc a block for this guy */
ret_block = find_next_free_block(disk);
inc_l2byte(&(file_ptr->blocks_used));
disk->ind_blk_data[offset] = ret_block & 0xff;
disk->ind_blk_data[offset + 0x100] =
((ret_block >> 8) & 0xff);
}
return ret_block;
case 3:
/* tree */
master_ind_block = key_block;
if(master_ind_block <= 0) {
printf("write failure, master_ind_block: %d!\n",
master_ind_block);
exit(3);
}
offset = pos >> 17;
if(offset >= 128) {
printf("master too big!\n");
exit(4);
}
lo = disk->master_ind_blk_data[offset];
hi = disk->master_ind_blk_data[offset + 0x100];
ind_block = hi*256 + lo;
if(ind_block == 0) {
/* Need to alloc an ind block */
get_new_ind_block(disk);
ind_block = disk->ind_blk_num;
inc_l2byte(&(file_ptr->blocks_used));
disk->master_ind_blk_data[offset] = ind_block & 0xff;
disk->master_ind_blk_data[offset + 0x100] =
((ind_block >> 8) & 0xff);
}
offset = (pos >> 9) & 0xff;
lo = disk->ind_blk_data[offset];
hi = disk->ind_blk_data[offset + 0x100];
ret_block = hi*256 + lo;
if(ret_block == 0) {
/* Need to alloc a block for this guy */
ret_block = find_next_free_block(disk);
inc_l2byte(&(file_ptr->blocks_used));
disk->ind_blk_data[offset] = ret_block & 0xff;
disk->ind_blk_data[offset + 0x100] =
((ret_block >> 8) & 0xff);
}
return ret_block;
default:
printf("unknown storage type: %d\n", storage_type);
exit(4);
}
printf("Can't get here!\n");
exit(5);
}
void
get_new_ind_block(ProDisk *disk)
{
int ind_blk_num;
int i;
write_ind_block(disk);
ind_blk_num = find_next_free_block(disk);
for(i = 0; i < 512; i++) {
disk->ind_blk_data[i] = 0;
}
disk->ind_blk_num = ind_blk_num;
}
void
write_ind_block(ProDisk *disk)
{
int ind_blk_num;
ind_blk_num = disk->ind_blk_num;
if(ind_blk_num > 0) {
printf("Write ind block: %04x\n", ind_blk_num);
disk_write_data(disk, ind_blk_num, &(disk->ind_blk_data[0]),
512);
disk->ind_blk_num = -1;
}
}
void
get_new_master_ind_block(ProDisk *disk)
{
int master_ind_blk_num;
int i;
write_master_ind_block(disk);
master_ind_blk_num = find_next_free_block(disk);
for(i = 0; i < 512; i++) {
disk->master_ind_blk_data[i] = 0;
}
disk->master_ind_blk_num = master_ind_blk_num;
}
void
write_master_ind_block(ProDisk *disk)
{
int master_ind_blk_num;
master_ind_blk_num = disk->master_ind_blk_num;
if(master_ind_blk_num > 0) {
printf("Write master_ind block: %04x\n", master_ind_blk_num);
disk_write_data(disk, master_ind_blk_num,
&(disk->master_ind_blk_data[0]), 512);
disk->master_ind_blk_num = -1;
}
}
int
find_next_free_block(ProDisk *disk)
{
byte *bitmap_ptr;
int pos;
int bitmap_bytes;
int i, j;
word32 val;
bitmap_ptr = disk->bitmap_ptr;
bitmap_bytes = disk->bitmap_bytes;
pos = disk->bitmap_cur_pos;
for(i = pos; i < bitmap_bytes; i++) {
val = bitmap_ptr[i];
if(val == 0) {
continue;
}
for(j = 0; j < 8; j++) {
if(val & (0x80 >> j)) {
set_bitmap_used(bitmap_ptr, 8*i+j);
disk->bitmap_cur_pos = i;
return 8*i + j;
}
}
return -1;
}
return -1;
}
void
set_bitmap_used(byte *ptr, int i)
{
word32 offset, bit;
word32 val;
offset = i >> 3;
bit = i & 7;
val = ~(0x80 >> bit);
ptr[offset] &= val;
}
void
set_bitmap_free(byte *ptr, int i)
{
int offset, bit;
int val;
offset = i >> 3;
bit = i & 7;
val = (0x80 >> bit);
ptr[offset] |= val;
}
void
set_file_entry(File_entry *entry, int storage_type_name_len, char *file_name,
int file_type, int key_pointer, int blocks_used, int eof,
word32 creation_time, int version, int min_version, int access,
int aux_type, word32 last_mod, int header_pointer)
{
entry->storage_type_name_len = storage_type_name_len;
strncpy((char *)entry->file_name, file_name, 15);
entry->file_type = file_type;
set_l2byte(&(entry->key_pointer), key_pointer);
set_l2byte(&(entry->blocks_used), blocks_used);
set_l3byte(&(entry->eof), eof);
set_pro_time(&(entry->creation_time), creation_time);
entry->version = version;
entry->min_version = min_version;
entry->access = access;
set_l2byte(&(entry->aux_type), aux_type);
set_pro_time(&(entry->last_mod), last_mod);
set_l2byte(&(entry->aux_type), header_pointer);
}
void
set_l2byte(L2byte *ptr, int val)
{
ptr->low = (val & 0xff);
ptr->hi = ((val >> 8) & 0xff);
}
void
set_l3byte(L3byte *ptr, int val)
{
ptr->low = (val & 0xff);
ptr->hi = ((val >> 8) & 0xff);
ptr->higher = ((val >> 16) & 0xff);
}
void
set_pro_time(Pro_time *ptr, word32 val)
{
ptr->times[0] = ((val >> 24) & 0xff);
ptr->times[1] = ((val >> 16) & 0xff);
ptr->times[2] = ((val >> 8) & 0xff);
ptr->times[3] = ((val) & 0xff);
}
int
get_l2byte(L2byte *ptr)
{
int val;
val = ((ptr->hi) * 256) + ptr->low;
return val;
}
int
get_l3byte(L3byte *ptr)
{
int val;
val = ((ptr->higher) * 65536) + ((ptr->hi) * 256) + ptr->low;
return val;
}
void
inc_l2byte(L2byte *ptr)
{
set_l2byte(ptr, get_l2byte(ptr) + 1);
}

1
src/vars Symbolic link
View File

@ -0,0 +1 @@
vars_mac

20
src/vars_c Normal file
View File

@ -0,0 +1,20 @@
TARGET = xkegs
OBJECTS = $(OBJECTS1) xdriver.o
CC = gcc
CCOPTS = -O
OPTS = -DNDEBUG
SUFFIX =
NAME = xkegs
LDFLAGS =
LDOPTS = -z
LD = $(CC)
EXTRA_LIBS = -lXext -lX11 -lcl -lc
EXTRA_SPECIALS = Alib.h
AS = cc -Ae
PERL = perl
XOPTS = -DHPUX -I/usr/include/X11R5
XLIBS = -L/usr/lib/X11R5 -L/opt/audio/lib

20
src/vars_hp Normal file
View File

@ -0,0 +1,20 @@
TARGET = xkegs
OBJECTS = engine_s.o $(OBJECTS1) sound_driver.o xdriver.o
CC = cc -Ae +DA1.1
CCOPTS = -O
OPTS = -DNDEBUG
SUFFIX =
NAME = xkegs
LDFLAGS =
LDOPTS = -z
LD = $(CC)
EXTRA_LIBS = -lXext -lX11 -lcl -lc
EXTRA_SPECIALS = 8inst_s 16inst_s 8size 16size size_s Alib.h
AS = cc -Ae
PERL = perl
XOPTS = -DHPUX -I/usr/include/X11R5
XLIBS = -L/usr/lib/X11R5 -L/opt/audio/lib

20
src/vars_linuxppc Normal file
View File

@ -0,0 +1,20 @@
TARGET = xkegs
OBJECTS = $(OBJECTS1) xdriver.o
CC = cc
CCOPTS = -O
OPTS = -DNDEBUG
SUFFIX =
NAME = xkegs
LDFLAGS =
LDOPTS =
LD = $(CC)
EXTRA_LIBS = -lXext -lX11 -lc
EXTRA_SPECIALS =
AS = cc
PERL = perl
XOPTS = -I/usr/X11R6/include
XLIBS = -L/usr/X11R6/lib

10
src/vars_mac Normal file
View File

@ -0,0 +1,10 @@
TARGET = kegsmac
OBJECTS = $(OBJECTS1) macsnd_driver.o macdriver.o
CCOPTS = -O2 -DMAC
SUFFIX =
NAME = kegsmac
XOPTS = -Wall -fpascal-strings -mdynamic-no-pic -arch ppc
XLIBS =

20
src/vars_solaris Normal file
View File

@ -0,0 +1,20 @@
TARGET = xkegs
OBJECTS = $(OBJECTS1) xdriver.o
CC = cc
CCOPTS = -O
OPTS = -DNDEBUG -DSOLARIS
SUFFIX =
NAME = xkegs
LDFLAGS =
LDOPTS =
LD = $(CC)
EXTRA_LIBS = -lXext -lX11 -lsocket -lnsl
EXTRA_SPECIALS =
AS = cc
PERL = perl
XOPTS = -I/usr/X/include
XLIBS = -L/usr/X/lib

10
src/vars_win32 Normal file
View File

@ -0,0 +1,10 @@
TARGET = kegswin.exe
OBJECTS = $(OBJECTS1) win32snd_driver.o windriver.o
CCOPTS = -O2 -DKEGS_LITTLE_ENDIAN
SUFFIX = ".exe"
NAME = kegswin
XOPTS = -Wall -fomit-frame-pointer -march=pentium
XLIBS =

19
src/vars_x86linux Normal file
View File

@ -0,0 +1,19 @@
TARGET = xkegs
OBJECTS = $(OBJECTS1) xdriver.o
CC = cc
CCOPTS = -O2 -Wall -fomit-frame-pointer -march=pentium
OPTS = -DKEGS_LITTLE_ENDIAN
SUFFIX =
NAME = xkegs
LDFLAGS =
LDOPTS =
LD = $(CC)
EXTRA_LIBS = -lXext
EXTRA_SPECIALS =
AS = cc
PERL = perl
XOPTS = -I/usr/X11R6/include

20
src/vars_x86solaris Normal file
View File

@ -0,0 +1,20 @@
TARGET = xkegs
OBJECTS = $(OBJECTS1) xdriver.o
CC = gcc
CCOPTS = -O
OPTS = -DNDEBUG -DSOLARIS -DKEGS_LITTLE_ENDIAN -DOSS
SUFFIX =
NAME = xkegs
LDFLAGS =
LDOPTS =
LD = $(CC)
EXTRA_LIBS = -lXext -lX11 -lsocket -lnsl
EXTRA_SPECIALS =
AS = cc
PERL = perl
XOPTS = -I/usr/X/include
XLIBS = -L/usr/X/lib

3354
src/video.c Normal file

File diff suppressed because it is too large Load Diff

109
src/win32.rc Normal file
View File

@ -0,0 +1,109 @@
#include <windows.h>
#include "winresource.h"
// $Id: $
#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif
IDD_DLG_DISKCONF DIALOGEX 0, 0, 268, 182
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Disk Configuration"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,150,161,50,14
PUSHBUTTON "Cancel",IDCANCEL,203,161,50,14
LTEXT "S5D1",IDC_STATIC,19,46,19,8
EDITTEXT IDC_EDIT_S5D1,43,42,156,14,ES_AUTOHSCROLL,
WS_EX_ACCEPTFILES
PUSHBUTTON "Browse",IDC_BTN_S5D1,203,42,50,14
LTEXT "S5D2",IDC_STATIC,19,62,19,8
EDITTEXT IDC_EDIT_S5D2,43,60,155,14,ES_AUTOHSCROLL
PUSHBUTTON "Browse",IDC_BTN_S5D2,203,60,50,14
LTEXT "S6D1",IDC_STATIC,19,80,19,8
EDITTEXT IDC_EDIT_S6D1,43,77,156,14,ES_AUTOHSCROLL
PUSHBUTTON "Browse",IDC_BTN_S6D1,203,77,50,14
LTEXT "S6D2",IDC_STATIC,19,98,19,8
EDITTEXT IDC_EDIT_S6D2,43,95,156,14,ES_AUTOHSCROLL
PUSHBUTTON "Browse",IDC_BTN_S6D2,203,96,50,14
LTEXT "S7D1",IDC_STATIC,19,118,19,8
EDITTEXT IDC_EDIT_S7D1,43,115,155,14,ES_AUTOHSCROLL
PUSHBUTTON "Browse",IDC_BTN_S7D1,203,115,50,14
LTEXT "S7D2",IDC_STATIC,19,137,19,8
EDITTEXT IDC_EDIT_S7D2,43,135,155,14,ES_AUTOHSCROLL
PUSHBUTTON "Browse",IDC_BTN_S7D2,203,135,50,14
GROUPBOX "Disk settings",IDC_STATIC,7,7,254,148
LTEXT "Configure your disk images for each drive. Disk image formats supported\nare *.2MG,*.PO and *.DSK. ",
IDC_STATIC,19,20,234,16
END
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDC_KEGS32 MENU DISCARDABLE
BEGIN
POPUP "&Emulator"
BEGIN
MENUITEM "&Set Disk Configuration\tALT-F1", ID_FILE_DISK
MENUITEM "Send CTRL Open-Apple Reset\tCTRL-ALT-BREAK",
ID_FILE_SENDRESET
MENUITEM "Toggle &Joystick", ID_FILE_JOYSTICK
MENUITEM "Toggle Debug Statistics", ID_FILE_DEBUGSTAT
MENUITEM SEPARATOR
MENUITEM "E&xit\tALT-F4", ID_FILE_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About", ID_HELP_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDR_TOOLBAR BITMAP DISCARDABLE "wintoolbar.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_ACCEL ACCELERATORS DISCARDABLE
BEGIN
VK_F1, ID_FILE_DISK, VIRTKEY, ALT, NOINVERT
VK_F4, ID_FILE_EXIT, VIRTKEY, ALT, NOINVERT
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDC_KEGS32 ICON DISCARDABLE "win32.ico"
KEGS32_ICON ICON DISCARDABLE "win32.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUT_DIALOG DIALOG DISCARDABLE 0, 0, 207, 82
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,78,61,50,14
LTEXT "KEGS32: GS Emulator.\nBased on KEGS by Kent Dickey\nWindows Port by Chea Chee Keong\n\nThis software is free for non-commercial use.",
IDC_STATIC,38,7,162,45,NOT WS_GROUP
ICON "KEGS32_ICON",IDC_STATIC,7,7,21,20,0
END

215
src/win32snd_driver.c Normal file
View File

@ -0,0 +1,215 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_win32snd_driver_c[] = "@(#)$KmKId: win32snd_driver.c,v 1.5 2002-11-19 03:09:59-05 kadickey Exp $";
#include "defc.h"
#include "sound.h"
#ifndef __CYGWIN__
# include <windows.h>
# include <mmsystem.h>
#endif
#include <unistd.h>
extern int Verbose;
extern int g_audio_rate;
unsigned int __stdcall child_sound_loop_win32(void *param);
void check_wave_error(int res, char *str);
#define NUM_WAVE_HEADERS 8
#ifndef __CYGWIN__
HWAVEOUT g_wave_handle;
WAVEHDR g_wavehdr[NUM_WAVE_HEADERS];
#endif
extern int g_audio_enable;
extern word32 *g_sound_shm_addr;
extern int g_preferred_rate;
int g_win32snd_buflen = 0x1000;
void
win32snd_init(word32 *shmaddr)
{
printf("win32snd_init\n");
child_sound_loop(-1, -1, shmaddr);
return;
}
void
win32snd_shutdown()
{
/* hmm */
}
#ifndef __CYGWIN__
void CALLBACK
handle_wav_snd(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
DWORD dwParam2)
{
LPWAVEHDR lpwavehdr;
/* Only service "buffer done playing messages */
if(uMsg == WOM_DONE) {
lpwavehdr = (LPWAVEHDR)dwParam1;
if(lpwavehdr->dwFlags == (WHDR_DONE | WHDR_PREPARED)) {
lpwavehdr->dwUser = FALSE;
}
}
return;
}
void
check_wave_error(int res, char *str)
{
char buf[256];
if(res == MMSYSERR_NOERROR) {
return;
}
waveOutGetErrorText(res, &buf[0], sizeof(buf));
printf("%s: %s\n", str, buf);
exit(1);
}
void
child_sound_init_win32()
{
WAVEFORMATEX wavefmt;
WAVEOUTCAPS caps;
byte *bptr;
int bits_per_sample, channels, block_align;
int blen;
int res;
int i;
memset(&wavefmt, 0, sizeof(WAVEFORMATEX));
wavefmt.wFormatTag = WAVE_FORMAT_PCM;
bits_per_sample = 16;
channels = 2;
wavefmt.wBitsPerSample = bits_per_sample;
wavefmt.nChannels = channels;
wavefmt.nSamplesPerSec = g_audio_rate;
block_align = channels * (bits_per_sample / 8);
wavefmt.nBlockAlign = block_align;
wavefmt.nAvgBytesPerSec = block_align * g_audio_rate;
res = waveOutOpen(&g_wave_handle, WAVE_MAPPER, &wavefmt, 0, 0,
WAVE_FORMAT_QUERY);
if(res != MMSYSERR_NOERROR) {
printf("Cannot open audio device\n");
g_audio_enable = 0;
return;
}
res = waveOutOpen(&g_wave_handle, WAVE_MAPPER, &wavefmt,
(DWORD)handle_wav_snd, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC);
if(res != MMSYSERR_NOERROR) {
printf("Cannot register audio\n");
g_audio_enable = 0;
return;
}
g_audio_rate = wavefmt.nSamplesPerSec;
blen = (SOUND_SHM_SAMP_SIZE * 4 * 2) / NUM_WAVE_HEADERS;
g_win32snd_buflen = blen;
bptr = malloc(blen * NUM_WAVE_HEADERS);
if(bptr == NULL) {
printf("Unabled to allocate sound buffer\n");
exit(1);
}
for(i = 0; i < NUM_WAVE_HEADERS; i++) {
memset(&g_wavehdr[i], 0, sizeof(WAVEHDR));
g_wavehdr[i].dwUser = FALSE;
g_wavehdr[i].lpData = &(bptr[i*blen]);
g_wavehdr[i].dwBufferLength = blen;
g_wavehdr[i].dwFlags = 0;
g_wavehdr[i].dwLoops = 0;
res = waveOutPrepareHeader(g_wave_handle, &g_wavehdr[i],
sizeof(WAVEHDR));
check_wave_error(res, "waveOutPrepareHeader");
}
res = waveOutGetDevCaps((UINT)g_wave_handle, &caps, sizeof(caps));
check_wave_error(res, "waveOutGetDevCaps");
printf("Using %s\n", caps.szPname);
printf(" Bits per Sample = %d. Channels = %d\n",
wavefmt.wBitsPerSample, wavefmt.nChannels);
printf(" Sampling rate = %d, avg_bytes_per_sec = %d\n",
(int)wavefmt.nSamplesPerSec, (int)wavefmt.nAvgBytesPerSec);
set_audio_rate(g_audio_rate);
}
void
win32_send_audio2(byte *ptr, int size)
{
int found;
int res;
int i;
found = 0;
for(i = 0; i < NUM_WAVE_HEADERS; i++) {
if(g_wavehdr[i].dwUser == FALSE) {
found = 1;
break;
}
}
if(!found) {
/* all audio buffers busy, just get out */
return;
}
memcpy(g_wavehdr[i].lpData, ptr, size);
g_wavehdr[i].dwBufferLength = size;
g_wavehdr[i].dwUser = TRUE;
res = waveOutWrite(g_wave_handle, &g_wavehdr[i], sizeof(g_wavehdr));
check_wave_error(res, "waveOutWrite");
return;
}
int
win32_send_audio(byte *ptr, int in_size)
{
int size;
int tmpsize;
size = in_size;
while(size > 0) {
tmpsize = size;
if(size > g_win32snd_buflen) {
tmpsize = g_win32snd_buflen;
}
win32_send_audio2(ptr, tmpsize);
ptr += tmpsize;
size = size - tmpsize;
}
return in_size;
}
#endif /* __CYGWIN */

637
src/windriver.c Normal file
View File

@ -0,0 +1,637 @@
/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_windriver_c[] = "@(#)$KmKId: windriver.c,v 1.8 2004-03-23 17:25:37-05 kentd Exp $";
#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */
#define STRICT /* Tell Windows we want compile type checks */
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <winsock.h>
#include <commctrl.h>
#include "defc.h"
#include "protos_windriver.h"
extern int Verbose;
extern int g_warp_pointer;
extern int g_screen_depth;
extern int g_force_depth;
int g_screen_mdepth = 0;
extern int g_quit_sim_now;
int g_use_shmem = 1;
int g_has_focus = 0;
int g_auto_repeat_on = -1;
extern Kimage g_mainwin_kimage;
HDC g_main_dc;
HDC g_main_cdc;
int g_main_height = 0;
int g_win_capslock_down = 0;
extern word32 g_palette_8to1624[256];
extern word32 g_a2palette_8to1624[256];
extern word32 g_full_refresh_needed;
extern int g_border_sides_refresh_needed;
extern int g_border_special_refresh_needed;
extern int g_status_refresh_needed;
extern int g_lores_colors[];
extern int g_cur_a2_stat;
extern int g_a2vid_palette;
extern int g_installed_full_superhires_colormap;
extern int g_screen_redraw_skip_amt;
extern word32 g_a2_screen_buffer_changed;
HWND g_hwnd_main;
BITMAPINFO *g_bmapinfo_ptr = 0;
volatile BITMAPINFOHEADER *g_bmaphdr_ptr = 0;
int g_num_a2_keycodes = 0;
extern char *g_status_ptrs[MAX_STATUS_LINES];
int g_win_button_states = 0;
/* this table is used to search for the Windows VK_* in col 1 or 2 */
/* flags bit 8 is or'ed into the VK, so we can distinguish keypad keys */
/* regardless of numlock */
int g_a2_key_to_wsym[][3] = {
{ 0x35, VK_ESCAPE, 0 },
{ 0x7a, VK_F1, 0 },
{ 0x7b, VK_F2, 0 },
{ 0x63, VK_F3, 0 },
{ 0x76, VK_F4, 0 },
{ 0x60, VK_F5, 0 },
{ 0x61, VK_F6, 0 },
{ 0x62, VK_F7, 0 },
{ 0x64, VK_F8, 0 },
{ 0x65, VK_F9, 0 },
{ 0x6d, VK_F10, 0 },
{ 0x67, VK_F11, 0 },
{ 0x6f, VK_F12, 0 },
{ 0x69, VK_F13, 0 },
{ 0x6b, VK_F14, 0 },
{ 0x71, VK_F15, 0 },
{ 0x7f, VK_PAUSE, VK_CANCEL+0x100 },
{ 0x32, 0xc0, 0 }, /* '`' */
{ 0x12, '1', 0 },
{ 0x13, '2', 0 },
{ 0x14, '3', 0 },
{ 0x15, '4', 0 },
{ 0x17, '5', 0 },
{ 0x16, '6', 0 },
{ 0x1a, '7', 0 },
{ 0x1c, '8', 0 },
{ 0x19, '9', 0 },
{ 0x1d, '0', 0 },
{ 0x1b, 0xbd, 0 }, /* '-' */
{ 0x18, 0xbb, 0 }, /* '=' */
{ 0x33, VK_BACK, 0 }, /* backspace */
{ 0x72, VK_INSERT+0x100, 0 }, /* Insert key */
/* { 0x73, XK_Home, 0 }, alias VK_HOME to be KP_Equal! */
{ 0x74, VK_PRIOR+0x100, 0 }, /* pageup */
{ 0x47, VK_NUMLOCK, VK_NUMLOCK+0x100 }, /* clear */
{ 0x51, VK_HOME+0x100, 0 }, /* KP_equal is HOME key */
{ 0x4b, VK_DIVIDE, VK_DIVIDE+0x100 },
{ 0x43, VK_MULTIPLY, VK_MULTIPLY+0x100 },
{ 0x30, VK_TAB, 0 },
{ 0x0c, 'Q', 0 },
{ 0x0d, 'W', 0 },
{ 0x0e, 'E', 0 },
{ 0x0f, 'R', 0 },
{ 0x11, 'T', 0 },
{ 0x10, 'Y', 0 },
{ 0x20, 'U', 0 },
{ 0x22, 'I', 0 },
{ 0x1f, 'O', 0 },
{ 0x23, 'P', 0 },
{ 0x21, 0xdb, 0 }, /* [ */
{ 0x1e, 0xdd, 0 }, /* ] */
{ 0x2a, 0xdc, 0 }, /* backslash, bar */
{ 0x75, VK_DELETE+0x100, 0 },
{ 0x77, VK_END+0x100, VK_END },
{ 0x79, VK_NEXT+0x100, 0 },
{ 0x59, VK_NUMPAD7, VK_HOME },
{ 0x5b, VK_NUMPAD8, VK_UP },
{ 0x5c, VK_NUMPAD9, VK_PRIOR },
{ 0x4e, VK_SUBTRACT, VK_SUBTRACT+0x100 },
// { 0x39, VK_CAPITAL, 0 }, // Handled specially!
{ 0x00, 'A', 0 },
{ 0x01, 'S', 0 },
{ 0x02, 'D', 0 },
{ 0x03, 'F', 0 },
{ 0x05, 'G', 0 },
{ 0x04, 'H', 0 },
{ 0x26, 'J', 0 },
{ 0x28, 'K', 0 },
{ 0x25, 'L', 0 },
{ 0x29, 0xba, 0 }, /* ; */
{ 0x27, 0xde, 0 }, /* single quote */
{ 0x24, VK_RETURN, 0 },
{ 0x56, VK_NUMPAD4, VK_LEFT },
{ 0x57, VK_NUMPAD5, VK_CLEAR },
{ 0x58, VK_NUMPAD6, VK_RIGHT },
{ 0x45, VK_ADD, 0 },
{ 0x38, VK_SHIFT, 0 },
{ 0x06, 'Z', 0 },
{ 0x07, 'X', 0 },
{ 0x08, 'C', 0 },
{ 0x09, 'V', 0 },
{ 0x0b, 'B', 0 },
{ 0x2d, 'N', 0 },
{ 0x2e, 'M', 0 },
{ 0x2b, 0xbc, 0 }, /* , */
{ 0x2f, 0xbe, 0 }, /* . */
{ 0x2c, 0xbf, 0 }, /* / */
{ 0x3e, VK_UP+0x100, 0 },
{ 0x53, VK_NUMPAD1, VK_END },
{ 0x54, VK_NUMPAD2, VK_DOWN },
{ 0x55, VK_NUMPAD3, VK_NEXT },
{ 0x36, VK_CONTROL, VK_CONTROL+0x100 },
{ 0x3a, VK_SNAPSHOT+0x100, VK_MENU+0x100 },/* Opt=prntscrn or alt-r */
{ 0x37, VK_SCROLL, VK_MENU }, /* Command=scr_lock or alt-l */
{ 0x31, ' ', 0 },
{ 0x3b, VK_LEFT+0x100, 0 },
{ 0x3d, VK_DOWN+0x100, 0 },
{ 0x3c, VK_RIGHT+0x100, 0 },
{ 0x52, VK_NUMPAD0, VK_INSERT },
{ 0x41, VK_DECIMAL, VK_DECIMAL },
{ 0x4c, VK_RETURN+0x100, 0 },
{ -1, -1, -1 }
};
int
win_update_mouse(int x, int y, int button_states, int buttons_valid)
{
int buttons_changed;
buttons_changed = ((g_win_button_states & buttons_valid) !=
button_states);
g_win_button_states = (g_win_button_states & ~buttons_valid) |
(button_states & buttons_valid);
if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) &&
(y == A2_WINDOW_HEIGHT/2) && (!buttons_changed) ) {
/* tell adb routs to recenter but ignore this motion */
update_mouse(x, y, 0, -1);
return 0;
}
return update_mouse(x, y, button_states, buttons_valid & 7);
}
void
win_event_mouse(WPARAM wParam, LPARAM lParam)
{
POINT pt;
word32 flags;
int buttons;
int x, y;
int motion;
flags = wParam;
x = LOWORD(lParam) - BASE_MARGIN_LEFT;
y = HIWORD(lParam) - BASE_MARGIN_TOP;
buttons = (flags & 1) +
(((flags >> 1) & 1) << 2) +
(((flags >> 4) & 1) << 1);
#if 0
printf("Mouse at %d, %d fl: %08x, but: %d\n", x, y, flags, buttons);
#endif
motion = win_update_mouse(x, y, buttons, 7);
if(motion && g_warp_pointer) {
/* move mouse to center of screen */
pt.x = BASE_MARGIN_LEFT + A2_WINDOW_WIDTH/2;
pt.y = BASE_MARGIN_TOP + A2_WINDOW_HEIGHT/2;
ClientToScreen(g_hwnd_main, &pt);
SetCursorPos(pt.x, pt.y);
}
}
void
win_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags)
{
word32 vk;
int a2code;
int is_up;
int capslock_down;
int i;
if((flags & 0x4000) && down) {
/* auto-repeating, just ignore it */
return;
}
vk = raw_vk + (flags & 0x100);
#if 0
printf("Key event, vk=%04x, down:%d, repeat: %d, flags: %08x\n",
vk, down, repeat, flags);
#endif
/* remap a few keys here.. sigh */
if((vk & 0xff) == VK_APPS) {
/* remap to command */
vk = VK_MENU;
}
if((vk & 0xff) == VK_CAPITAL) {
// Windows gives us up-and-down events of the actual key
// Use GetKeyState to get the true toggle state, and pass
// that on to the adb interface
capslock_down = GetKeyState(VK_CAPITAL) & 0x01;
if(capslock_down != g_win_capslock_down) {
g_win_capslock_down = capslock_down;
adb_physical_key_update(0x39, !capslock_down);
}
return; // Do no more processing!
}
/* search a2key_to_wsym to find wsym in col 1 or 2 */
i = 0;
is_up = !down;
for(i = g_num_a2_keycodes-1; i >= 0; i--) {
a2code = g_a2_key_to_wsym[i][0];
if((vk == g_a2_key_to_wsym[i][1]) ||
(vk == g_a2_key_to_wsym[i][2])) {
vid_printf("Found vk:%04x = %02x\n", vk, a2code);
adb_physical_key_update(a2code, is_up);
return;
}
}
printf("VK: %04x unknown\n", vk);
}
void
win_event_quit(HWND hwnd)
{
g_quit_sim_now = 1;
my_exit(0);
}
void
win_event_redraw()
{
g_full_refresh_needed = -1;
g_a2_screen_buffer_changed = -1;
g_status_refresh_needed = 1;
g_border_sides_refresh_needed = 1;
g_border_special_refresh_needed = 1;
}
LRESULT CALLBACK
win_event_handler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
switch(umsg) {
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
win_event_mouse(wParam, lParam);
return 0;
case WM_PAINT:
win_event_redraw();
break;
}
switch(umsg) {
HANDLE_MSG(hwnd, WM_KEYUP, win_event_key);
HANDLE_MSG(hwnd, WM_KEYDOWN, win_event_key);
HANDLE_MSG(hwnd, WM_SYSKEYUP, win_event_key);
HANDLE_MSG(hwnd, WM_SYSKEYDOWN, win_event_key);
HANDLE_MSG(hwnd, WM_DESTROY, win_event_quit);
}
#if 0
switch(umsg) {
case WM_NCACTIVATE:
case WM_NCHITTEST:
case WM_NCMOUSEMOVE:
case WM_SETCURSOR:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_PAINT:
break;
default:
printf("Got umsg2: %d\n", umsg);
}
#endif
return DefWindowProc(hwnd, umsg, wParam, lParam);
}
int
main(int argc, char **argv)
{
WNDCLASS wndclass;
RECT rect;
int height;
InitCommonControls();
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)win_event_handler;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = GetModuleHandle(NULL);
wndclass.hIcon = LoadIcon((HINSTANCE)NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "kegswin";
// Register the window
if(!RegisterClass(&wndclass)) {
printf("Registering window failed\n");
exit(1);
}
height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES * 16) + 32;
g_main_height = height;
g_hwnd_main = CreateWindow("kegswin", "KEGSWIN - Apple //gs Emulator",
WS_TILED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
X_A2_WINDOW_WIDTH, height,
NULL, NULL, GetModuleHandle(NULL), NULL);
printf("g_hwnd_main = %p, height = %d\n", g_hwnd_main, height);
GetWindowRect(g_hwnd_main, &rect);
printf("...rect is: %ld, %ld, %ld, %ld\n", rect.left, rect.top,
rect.right, rect.bottom);
g_main_dc = GetDC(g_hwnd_main);
SetTextColor(g_main_dc, 0);
SetBkColor(g_main_dc, 0xffffff);
g_main_cdc = CreateCompatibleDC(g_main_dc);
g_screen_depth = 24;
g_screen_mdepth = 32;
// Call kegsmain
return kegsmain(argc, argv);
}
void
check_input_events()
{
MSG msg;
while(PeekMessage(&msg, g_hwnd_main, 0, 0, PM_NOREMOVE)) {
if(GetMessage(&msg, g_hwnd_main, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
printf("GetMessage returned <= 0\n");
my_exit(2);
}
}
return;
}
void
x_update_color(int col_num, int red, int green, int blue, word32 rgb)
{
}
void
x_update_physical_colormap()
{
}
void
show_xcolor_array()
{
int i;
for(i = 0; i < 256; i++) {
printf("%02x: %08x\n", i, g_palette_8to1624[i]);
}
}
void
xdriver_end()
{
printf("xdriver_end\n");
}
void
x_get_kimage(Kimage *kimage_ptr)
{
byte *ptr;
int width;
int height;
int depth, mdepth;
int size;
width = kimage_ptr->width_req;
height = kimage_ptr->height;
depth = kimage_ptr->depth;
mdepth = kimage_ptr->mdepth;
size = 0;
if(depth == g_screen_depth) {
/* Use g_bmapinfo_ptr, adjusting width, height */
g_bmaphdr_ptr->biWidth = width;
g_bmaphdr_ptr->biHeight = -height;
kimage_ptr->dev_handle = CreateDIBSection(g_main_dc,
g_bmapinfo_ptr, DIB_RGB_COLORS,
(VOID **)&(kimage_ptr->data_ptr), NULL, 0);
} else {
/* allocate buffers for video.c to draw into */
size = (width*height*mdepth) >> 3;
ptr = (byte *)malloc(size);
if(ptr == 0) {
printf("malloc for data failed, mdepth: %d\n", mdepth);
exit(2);
}
kimage_ptr->data_ptr = ptr;
kimage_ptr->dev_handle = (void *)-1;
}
printf("kim: %p, dev:%p data: %p, size: %08x\n", kimage_ptr,
kimage_ptr->dev_handle, kimage_ptr->data_ptr, size);
return;
}
void
dev_video_init()
{
int extra_size;
int lores_col;
int a2code;
int i;
printf("Preparing graphics system\n");
g_num_a2_keycodes = 0;
for(i = 0; i < 0x7f; i++) {
a2code = g_a2_key_to_wsym[i][0];
if(a2code < 0) {
g_num_a2_keycodes = i;
}
}
g_screen_depth = 24;
g_screen_mdepth = 32;
extra_size = sizeof(RGBQUAD);
if(g_screen_depth == 8) {
extra_size = 256 * sizeof(RGBQUAD);
}
g_bmapinfo_ptr = (BITMAPINFO *)GlobalAlloc(GPTR,
sizeof(BITMAPINFOHEADER) + extra_size);
g_bmaphdr_ptr = (BITMAPINFOHEADER *)g_bmapinfo_ptr;
g_bmaphdr_ptr->biSize = sizeof(BITMAPINFOHEADER);
g_bmaphdr_ptr->biWidth = A2_WINDOW_WIDTH;
g_bmaphdr_ptr->biHeight = -A2_WINDOW_HEIGHT;
g_bmaphdr_ptr->biPlanes = 1;
g_bmaphdr_ptr->biBitCount = g_screen_mdepth;
g_bmaphdr_ptr->biCompression = BI_RGB;
g_bmaphdr_ptr->biClrUsed = 0;
video_get_kimages();
if(g_screen_depth != 8) {
// Allocate g_mainwin_kimage
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,
g_screen_mdepth);
}
for(i = 0; i < 256; i++) {
lores_col = g_lores_colors[i & 0xf];
video_update_color_raw(i, lores_col);
g_a2palette_8to1624[i] = g_palette_8to1624[i];
}
g_installed_full_superhires_colormap = 1;
ShowWindow(g_hwnd_main, SW_SHOWDEFAULT);
UpdateWindow(g_hwnd_main);
printf("Done with dev_video_init\n");
fflush(stdout);
}
void
x_redraw_status_lines()
{
COLORREF oldtextcolor, oldbkcolor;
char *buf;
int line;
int len;
int height;
int margin;
height = 16;
margin = 0;
oldtextcolor = SetTextColor(g_main_dc, 0);
oldbkcolor = SetBkColor(g_main_dc, 0xffffff);
for(line = 0; line < MAX_STATUS_LINES; line++) {
buf = g_status_ptrs[line];
if(buf != 0) {
len = strlen(buf);
TextOut(g_main_dc, 10, X_A2_WINDOW_HEIGHT +
height*line + margin, buf, len);
}
}
SetTextColor(g_main_dc, oldtextcolor);
SetBkColor(g_main_dc, oldbkcolor);
}
void
x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy,
int width, int height)
{
void *bitm_old;
POINT point;
point.x = 0;
point.y = 0;
ClientToScreen(g_hwnd_main, &point);
bitm_old = SelectObject(g_main_cdc, kimage_ptr->dev_handle);
BitBlt(g_main_dc, destx, desty, width, height,
g_main_cdc, srcx, srcy, SRCCOPY);
SelectObject(g_main_cdc, bitm_old);
}
void
x_push_done()
{
}
void
x_auto_repeat_on(int must)
{
}
void
x_auto_repeat_off(int must)
{
}
void
x_hide_pointer(int do_hide)
{
if(do_hide) {
ShowCursor(0);
} else {
ShowCursor(1);
}
}

42
src/winresource.h Normal file
View File

@ -0,0 +1,42 @@
//{{NO_DEPENDENCIES}}
// $Id: $
// Microsoft Developer Studio generated include file.
// Used by win32.rc
//
#define IDD_ABOUT_DIALOG 101
#define IDC_KEGS32 102
#define IDR_TOOLBAR 103
#define IDD_DLG_DISKCONF 104
#define IDR_ACCEL 105
#define ID_TOOLBAR 5000
#define ID_STATUSBAR 5001
#define IDC_EDIT_S5D1 10051
#define IDC_EDIT_S5D2 10052
#define IDC_EDIT_S6D1 10061
#define IDC_EDIT_S6D2 10062
#define IDC_EDIT_S7D1 10071
#define IDC_EDIT_S7D2 10072
#define IDC_BTN_S5D1 11051
#define IDC_BTN_S5D2 11052
#define IDC_BTN_S6D1 11061
#define IDC_BTN_S6D2 11062
#define IDC_BTN_S7D1 11071
#define IDC_BTN_S7D2 11072
#define ID_HELP_ABOUT 40001
#define ID_FILE_EXIT 40002
#define ID_FILE_DISK 40003
#define ID_FILE_SENDRESET 40004
#define ID_FILE_JOYSTICK 40005
#define ID_FILE_DEBUGSTAT 40006
#define ID_FILE_FULLSCREEN 40012
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 111
#define _APS_NEXT_COMMAND_VALUE 40013
#define _APS_NEXT_CONTROL_VALUE 1003
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

1306
src/xdriver.c Normal file

File diff suppressed because it is too large Load Diff