Merge branch 'master' into master

This commit is contained in:
Dagen Brock 2018-08-24 05:12:46 -05:00 committed by GitHub
commit 26ac5bc51a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
173 changed files with 42422 additions and 32124 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*.c eol=lf
*.h eol=lf

16
.gitignore vendored
View File

@ -10,3 +10,19 @@ src/16inst_c.h
src/8inst_c.h
src/size_c.h
gsplus
gsportx
gsport
*.exe
*.gsp
# Storage for many disk images for testing the emulator.
# Games, demos, apps, etc. Not part of the project.
images/
# Screenshot dir
screens/
# build tools that are often kept/tested locally as well as on the ci machines
yoursway-create-dmg/

View File

@ -1,7 +1,12 @@
stages:
- build
- package
- deploy
- updatewebsite
# TARGET SYSTEM: UBUNTU X
build-ubuntu-x:
tags:
- ubuntu
@ -11,29 +16,119 @@ build-ubuntu-x:
- cd src
- ln -s vars_x86linux_x11 vars
- make clean ; make
artifacts:
paths:
- gsplusx
expire_in: 10 minutes
only:
- master
package-ubuntu-x:
tags:
- ubuntu
stage: package
script:
- cp src/config.txt .
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> config.txt'
- cp LICENSE.txt doc/
artifacts:
paths:
- gsplusx
- config.txt
- doc/gsplusmanual.pdf
- doc/LICENSE.txt
expire_in: 10 minutes
only:
- master
# TARGET SYSTEM: DEPRECATED, UBUNTU SDL
build-ubuntu-sdl:
tags:
- ubuntu
stage: build
script:
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev libsdl2-image-dev
- cd src
- ln -s vars_x86linux_sdl vars
- make clean ; make
only:
- master
# TARGET SYSTEM: REALLY ANY LINUX, BUT UBUNTU W SDL2
build-ubuntu-sdl2:
tags:
- ubuntu
stage: build
script:
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev libsdl2-image-dev
- cd src
- ln -s vars_x86linux_sdl2 vars
- make clean ; make
- mv ../gsplus ../gsplus-ubuntu-sdl.bin
artifacts:
paths:
- gsplus-ubuntu-sdl.bin
expire_in: 10 minutes
package-ubuntu-sdl2:
tags:
- ubuntu
stage: package
variables:
GIT_STRATEGY: fetch
PACKAGE_DIR: gsplus-ubuntu-sdl
script:
- mkdir $PACKAGE_DIR
- mkdir $PACKAGE_DIR/doc
- cp gsplus-ubuntu-sdl.bin $PACKAGE_DIR/gsplus
- cp src/config.txt $PACKAGE_DIR
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> $PACKAGE_DIR/config.txt'
- cp src/parallel.rom %PACKAGE_DIR%
- cp LICENSE.txt $PACKAGE_DIR/doc/
- cp doc/gsplusmanual.pdf %PACKAGE_DIR%
- cp doc/README.txt %PACKAGE_DIR%
- tar -cvjf gsplus-ubuntu-sdl.tar.bz2 $PACKAGE_DIR
artifacts:
paths:
- gsplus-ubuntu-sdl.tar.bz2
expire_in: 10 minutes
package-ubuntu-sdl2-deb:
tags:
- ubuntu
stage: package
variables:
GIT_STRATEGY: fetch
PACKAGE_NAME: gsplus_$CI_VERSION-0
script:
- mkdir -p $PACKAGE_NAME/usr/local/bin
- mkdir -p $PACKAGE_NAME/DEBIAN
- cp gsplus-ubuntu-sdl.bin $PACKAGE_NAME/usr/local/bin/gsplus
- cp assets/control $PACKAGE_NAME/DEBIAN
- dpkg-deb --build $PACKAGE_NAME
artifacts:
paths:
- $PACKAGE_NAME.deb
expire_in: 10 minutes
deploy-ubuntu:
tags:
- ubuntu
stage: deploy
variables:
GIT_STRATEGY: none
PACKAGE_NAME: gsplus_$CI_VERSION-0
script:
- aws s3 cp gsplus-ubuntu-sdl.tar.bz2 s3://$AWS_BUCKET/$CI_TAG/$CI_VERSION/$CI_PIPELINE_ID/ubuntu-sdl/$CI_BUILD_ID/ --acl public-read
- aws s3 cp $PACKAGE_NAME.deb s3://$AWS_BUCKET/$CI_TAG/$CI_VERSION/$CI_PIPELINE_ID/ubuntu-sdl-deb/$CI_BUILD_ID/ --acl public-read
# TARGET SYSTEM: OSX 10.SOMETHING
build-osx:
tags:
- osx
@ -42,14 +137,166 @@ build-osx:
- cd src
- ln -s vars_osx_sdl2 vars
- make clean ; make
- mv ../gsplus ../gsplus-osx
artifacts:
paths:
- gsplus-osx
expire_in: 10 minutes
package-osx:
tags:
- osx
stage: package
script:
- mv gsplus-osx gsplus
- cp src/config.txt .
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> config.txt'
- chmod +x make_dist_mac.sh
- ./make_dist_mac.sh
- chmod +x make_dmg_mac.sh
- ./make_dmg_mac.sh
artifacts:
paths:
- GSplus-Install.dmg
expire_in: 10 minutes
deploy-osx:
tags:
- osx
stage: deploy
variables:
GIT_STRATEGY: none
script:
- aws s3 cp GSplus-Install.dmg s3://$AWS_BUCKET/$CI_TAG/$CI_VERSION/$CI_PIPELINE_ID/osx/$CI_BUILD_ID/ --acl public-read
# TARGET SYSTEM: WIN32 WIN API UNDER CYGWIN
build-win32:
tags:
- windows
stage: build
script:
- bash -c "cd src; ln -s vars_win32 vars; make clean ; make"
artifacts:
paths:
- gsplus32.exe
expire_in: 10 minutes
only:
- master
- /^win.*/
package-win32:
tags:
- windows
stage: package
script:
- cp src/config.txt .
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> config.txt'
- cp LICENSE.txt doc/
- cp /bin/cyggcc_s-1.dll .
- cp /bin/cygstdc++-6.dll .
- cp /bin/cygwin1.dll .
- cp /bin/cygfreetype-6.dll .
variables:
GIT_STRATEGY: fetch
PACKAGE_DIR: gsplus-win32
script:
- mkdir %PACKAGE_DIR%
- cp gsplus32.exe %PACKAGE_DIR%
- cp LICENSE.txt %PACKAGE_DIR%
- cp src/config.txt %PACKAGE_DIR%
- cp src/parallel.rom %PACKAGE_DIR%
- cp doc/gsplusmanual.pdf %PACKAGE_DIR%
- cp doc/README.txt %PACKAGE_DIR%
- cp /bin/cyggcc_s-1.dll %PACKAGE_DIR%
- cp /bin/cygstdc++-6.dll %PACKAGE_DIR%
- cp /bin/cygwin1.dll %PACKAGE_DIR%
- cp /bin/cygfreetype-6.dll %PACKAGE_DIR%
- zip gsplus-win32.zip -r %PACKAGE_DIR%
artifacts:
paths:
- gsplus-win32.zip
expire_in: 10 minutes
only:
- master
- /^win.*/
deploy-win32:
tags:
- windows
stage: deploy
variables:
GIT_STRATEGY: none
script:
- aws s3 cp gsplus-win32.zip s3://%AWS_BUCKET%/%CI_TAG%/%CI_VERSION%/%CI_PIPELINE_ID%/win32/%CI_BUILD_ID%/ --acl public-read
only:
- master
- /^win.*/
# TARGET SYSTEM: WIN32 SDL2 UNDER CYGWIN W MINGW64 SDL2 LIBS
build-win-sdl2:
tags:
- windows
stage: build
script:
- cd src
- ln -s vars_win32 vars
- make clean ; make
- ln -s vars_win32_sdl2 vars
- make clean
- make
artifacts:
paths:
- gsplus.exe
expire_in: 10 minutes
package-win-sdl2:
tags:
- windows
stage: package
variables:
GIT_STRATEGY: fetch
PACKAGE_DIR: gsplus-win-sdl
script:
- mkdir %PACKAGE_DIR%
- cp gsplus.exe %PACKAGE_DIR%
- cp LICENSE.txt %PACKAGE_DIR%
- cp src/config.txt %PACKAGE_DIR%
- cp src/parallel.rom %PACKAGE_DIR%
- cp doc/gsplusmanual.pdf %PACKAGE_DIR%
- cp doc/README.txt %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygbz2-1.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygfreetype-6.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cyggcc_s-1.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygjpeg-8.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygpng16-16.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygjpeg-8.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygstdc++-6.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygwin1.dll %PACKAGE_DIR%
- cp /cygdrive/c/cygwin/bin/cygz.dll %PACKAGE_DIR%
- cp /cygdrive/c/mingw/i686-w64-mingw32/bin/SDL2.dll %PACKAGE_DIR%
- cp /cygdrive/c/mingw/i686-w64-mingw32/bin/SDL2_image.dll %PACKAGE_DIR%
- zip gsplus-win-sdl.zip -r %PACKAGE_DIR%
artifacts:
paths:
- gsplus-win-sdl.zip
expire_in: 10 minutes
deploy-win-sdl2:
tags:
- windows
stage: deploy
variables:
GIT_STRATEGY: none
script:
- aws s3 cp gsplus-win-sdl.zip s3://%AWS_BUCKET%/%CI_TAG%/%CI_VERSION%/%CI_PIPELINE_ID%/win-sdl/%CI_BUILD_ID%/ --acl public-read
update-website-universal:
tags:
- osx
stage: updatewebsite
variables:
GIT_STRATEGY: none
script:
- aws s3 ls gsplus-artifacts/ --recursive > s3artifacts.txt
- php assets/updatewebsite.php s3artifacts.txt public > index.html
- php assets/updatewebsite.php s3artifacts.txt auto > index_auto.html
- aws s3 cp index.html s3://$AWS_BUCKET/ --acl public-read
- aws s3 cp index_auto.html s3://$AWS_BUCKET/ --acl public-read

19
COPYRIGHT.txt Normal file
View File

@ -0,0 +1,19 @@
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
Copyright (C) 2016 - 2018 Dagen Brock
Copyright (C) 2010 - 2014 GSport contributors
Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

22
README.md Normal file
View File

@ -0,0 +1,22 @@
# GSplus
An Apple IIgs emulator for Mac OSX, Windows, and Linux.
![Screenshot of starting the program](doc/web/Screenshot.png "Screenshot of starting the program")
# About
This is an early release of an experimental project to modernize the
KEGS/GSport emulator platform and eventually extend it.
# Install
Go to https://apple2.gs/plus to get the latest downloads for your system.
# Usage Notes
You need to provide the ROM file and disk images and a config file. I'd
recommend you just drop it in your current GSport or KEGS folder and run it
from there.
See the doc/gsplusmanual.pdf file for much more complete documentation.
# Build Instructions
See the /doc/ directory for "Developer-Quickstart" docs which cover building
for the various platforms.

View File

@ -1,55 +0,0 @@
GSPLUS ALPHA
============
This is an early release of an experimental project to modernize the
KEGS/GSport emulator platform and eventually extend it.
The first steps are represented here. This release features a new SDL2 driver.
SDL or "Simple DirectMedia Layer" allows me to write one driver to handle input
and output (video, mouse, keyboard, audio, joystick). The hope is that I can
leverage the multi-platform nature of SDL to provide first-class support for
the major plaforms supported by SDL, which includes Mac OSX, Windows and Linux.
I'm not a huge fan of OSX, but I keep a MacBook Pro nearby for work, so the
first version to be release is this OSX build. I'll try to have builds for
other platforms available in a few weeks.
Some notes:
You need to provide the ROM file and disk images and a config file. I'd
recommend you just drop it in your current GSport or KEGS folder and run it
from there.
I took out the "middle-click to enter debug" because it's stupid. No one wants
to use their mouse wheel to enter a debugger. *smacks forehead*
If you want to enter debug, it's shift-F6. F6 is speed up, same as right and
middle mouse.
The big feature is FULLSCREEN SUPPORT! Yaya! Hit F11 for full-screen. My Mac
has some stupid expose feature mapped over this, so I basically hit
control-fn-F11 and it works. Stupid Macs. :P
I haven't changed much else at this point. This is an experimental driver and
a very early release, so I'm not looking for feedback. Please don't tell me
about it rendering weird, making funny noises, crashing your computer, stealing
your car, or blowing up your house.
Please be aware that this is based on KEGS original source by Kent Dickey, so
I must provide the source as per the original license.
I'd recommend you not really try building it at this time, but if you want, go
for it.
https://github.com/digarok/gsplus
I'll keep a page for this at http://apple2.gs/plus
Dagen Brock
Saturday, January 30, 2016 1:18PM
--------------------------------------------------------------------------------
Build Instructions
==========================
See the /doc/ directory for "Developer-Quickstart" docs which cover building
for the various platforms. (as fast as I can write them :P )

33
assets/Info.plist Normal file
View File

@ -0,0 +1,33 @@
<?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>gsplus</string>
<key>CFBundleGetInfoString</key>
<string>0.14, Copyright 2018 Dagen Brock</string>
<key>CFBundleIconFile</key>
<string>gsp-icons.icns</string>
<key>CFBundleIdentifier</key>
<string>com.dagenbrock.gsplus</string>
<key>CFBundleDocumentTypes</key>
<array>
</array>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.14</string>
<key>CFBundleSignature</key>
<string>gsplus</string>
<key>CFBundleVersion</key>
<string>0.14</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright 2018 Dagen Brock</string>
<key>LSMinimumSystemVersion</key>
<string>10.3</string>
</dict>
</plist>

10
assets/control Normal file
View File

@ -0,0 +1,10 @@
Package: gsplus
Version: 0.14-0
Section: base
Priority: optional
Architecture: amd64
Depends: libsdl2-2.0-0, libfreetype6, libsdl2-image-2.0-0
Maintainer: Dagen Brock <dagenbrock@gmail.com>
Description: GSplus
An Apple IIgs emulator for multiple platforms,
based on KEGS

26
assets/dump_icon.py Normal file
View File

@ -0,0 +1,26 @@
# need pil/pillow
# sudo pip install pillow
# ^^ on mac osx
from PIL import Image
#im = Image.open("gsp_icon_128.png") #Can be many different formats.
im = Image.open("gsp_icon_256.png") #Can be many different formats.
pix = im.load()
print im.size #Get the width and hight of the image for iterating over
width = im.size[0]
height = im.size[1]
count = 0
for y in range(0,width):
for x in range(0,height):
# print pix[x,y]
print("0x%02x%02x%02x%02x, " % pix[x,y]),
# RRGGBBAA
count = count + 1
if count == 32:
count = 0
print
#print pix[x,y] #Get the RGBA Value of the a pixel of an image
#pix[x,y] = value # Set the RGBA Value of the image (tuple)

BIN
assets/gsback.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
assets/gsback.psd Normal file

Binary file not shown.

BIN
assets/gsp-dmg-icons.icns Normal file

Binary file not shown.

BIN
assets/gsp-icons.icns Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

BIN
assets/gsp_dmg_icon_128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
assets/gsp_dmg_icon_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets/gsp_dmg_icon_256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
assets/gsp_dmg_icon_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
assets/gsp_dmg_icon_512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

BIN
assets/gsp_dmg_icon_64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
assets/gsp_icon.psd Normal file

Binary file not shown.

BIN
assets/gsp_icon_1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

BIN
assets/gsp_icon_128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/gsp_icon_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/gsp_icon_256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
assets/gsp_icon_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/gsp_icon_512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
assets/gsp_icon_64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
assets/gsp_icon_dmg.psd Normal file

Binary file not shown.

88
assets/make_ico.pl Normal file
View File

@ -0,0 +1,88 @@
#!/usr/bin/perl -w
use strict;
use constant SIZEOF_HEADER => 6;
use constant SIZEOF_ENTRY => 16;
use Getopt::Long;
sub load_png {
my ($file, $width, $height) = @_;
print "Opening $file\n";
open(my $io, "<", $file) or return "";
binmode $io;
local $/;
my $data = <$io>;
my @header = unpack("C[8] NN NNC[5] N", $data);
close($io);
# png header
return "" unless $header[0] == 0x89;
return "" unless $header[1] == 0x50;
return "" unless $header[2] == 0x4e;
return "" unless $header[3] == 0x47;
return "" unless $header[4] == 0x0d;
return "" unless $header[5] == 0x0a;
return "" unless $header[6] == 0x1a;
return "" unless $header[7] == 0x0a;
# ihdr
return "" unless $header[8] == 0x0d;
return "" unless $header[9] == 0x49484452;
$$width = $header[10];
$$height = $header[11];
# bit depth, color type, compression method, filter method, interface method
# crc
return $data;
}
GetOptions();
my $count = scalar @ARGV;
die "Usage: make_ico file.png ..." unless $count;
open(my $ico, ">", "icon.ico") or die "unable to open icon.ico";
binmode $ico;
my $height = 0;
my $width = 0;
my $size = 0;
my $offset = SIZEOF_HEADER + SIZEOF_ENTRY * $count;
my $header = pack("vvv", 0, 1, $count);
my $entry = "";
seek $ico, $offset, 0;
foreach my $file (@ARGV) {
my $data = load_png($file, \$height, \$width);
my $size = length($data);
die "Icon too large ($file)" if ($height > 256 || $width > 256);
$height = 0 if ($height == 256);
$width = 0 if ($width == 256);
$entry = $entry . pack("CCCCvvVV", $width, $height, 0, 0, 0, 0, $size, $offset);
$offset += $size;
print $ico $data;
}
seek $ico, 0, 0;
print $ico $header;
print $ico $entry;
close($ico);
exit 0;

19
assets/uncrustify.cfg Normal file
View File

@ -0,0 +1,19 @@
output_tab_size = 2 # new tab size
indent_columns = output_tab_size
indent_switch_case = output_tab_size
indent_with_tabs = 0
pp_indent_if = 0 # number
pp_if_indent_code = false # false/true
pp_define_at_level = false # false/true
nl_assign_leave_one_liners = true # false/true
nl_class_leave_one_liners = true # false/true
nl_enum_leave_one_liners = true # false/true
nl_getset_leave_one_liners = true # false/true
nl_func_leave_one_liners = true # false/true
nl_if_leave_one_liners = true # false/true
nl_while_leave_one_liners = true # false/true
nl_func_type_name = remove
nl_fdef_brace = remove
sp_fparen_brace = add

65
assets/updatewebsite.php Normal file
View File

@ -0,0 +1,65 @@
<?php
$d = file_get_contents($argv[1]);
$filter = (isset($argv[2])) ? $argv[2] : false;
$builds = [];
foreach(explode("\n", $d) as $line) {
if (!stristr($line, 'gsplus')) { continue; } // only gsplus files
$data = explode(" ", $line);
$data = preg_split('/\s+/', $line);
if (!$data || empty($data) || !isset($data[1])) { continue; } // one more check for validity
$b = explode("/", $data[3]);
$time = $data[0] . ' ' . $data[1];
$date = $data[0];
$bytes = $data[2];
$k = $b[0].$b[1].$b[2]; // lookup key
if (!$k) { continue; } // something isn't right, skip
$row = array('k' => $k, 'bytes' => $bytes, 'tag' => $b[0], 'version' => $b[1],
'pipeline' => $b[2], 'platform' => $b[3], 'job' => $b[4],
'time' => $time, 'date' => $date,
'filename' => $b[5], 's3url' => 'https://s3.amazonaws.com/gsplus-artifacts/'.$data[3]
);
if (!$filter || ($filter && $b[0] == $filter)) {
$builds[] = $row;
}
}
$pipeline = array_column($builds, 'pipeline');
$platform = array_column($builds, 'platform');
array_multisort($pipeline, SORT_DESC, $platform, SORT_ASC, $builds);
$style = <<<EOF
.builddiv {
width: 80%;
-moz-border-radius: 1em 4em 1em 4em;
border-radius: 1em 4em 1em 4em;
padding: 2em;
background-color: #fff;
color: #000;
margin: auto;
}
body { font-family: verdana, sans-serif; font-size: 12px; color: #000; background-color: #18BC9C; font-style: normal; font-weight: normal; font-variant: normal; text-align: left; letter-spacing: 0px; line-height: 20px; }
EOF;
print("<html><head><title>GS+ builds page</title><style>$style</style></head><body>\n");
$lastk = null;
foreach ($builds as $l) {
$k = $l['k'];
if ($k != $lastk) {
if ($lastk != null) {
print("</div><br/><br/>"); // close last build if not first pass
}
print("<div class='builddiv'>\n");
print("<h1>GSPLUS V".$l['version']." - Pipeline #".$l['pipeline']." @ ".$l['date']." <span style='font-size:0.r68em'>(".$l['tag'].")</span></H1><hr/>\n");
$lastk = $k;
}
print("<h2>Platform: ".$l['platform']."</h2>\n");
print("<ul><li>Build Job: ".$l['job']." &nbsp; Date: ".$l['time']." &nbsp; Size(Bytes): ".$l['bytes']."</li>\n");
print("<li>Download: <a href='".$l['s3url']."'>".$l['filename']."</a></li></ul>\n");
}
print("</div></body></html>\n");
#2018-08-07 14:33:11 256833 auto/0.14rc/260/ubuntu-sdl/2481/gsplus-ubuntu-sdl.tar.bz2

Binary file not shown.

View File

@ -1,9 +0,0 @@
# GSport configuration file
s5d1 =
s5d2 =
s6d1 =
s6d2 =
s7d1 = NoBoot.po

View File

@ -1,4 +1,10 @@
# ubuntu - X11 version
# This is basically what you need to install to build this yourself,
# or the pre-requisites of what you need to do to set up a build
# machine as a gitlab ci runner.
#
# All instructions based on a Debian/Ubuntu OS, but should be
# relatively straightforward to modify for something like yum
# system prep
sudo apt-get -y update
@ -6,16 +12,23 @@ sudo apt-get -y upgrade
sudo apt-get -y install git
sudo apt-get -y install g++
sudo apt-get -y install libpcap0.8-dev
sudo apt-get -y install libfreetype6-dev
# X11 version
sudo apt-get -y install libx11-dev
sudo apt-get -y install libxext-dev
# build
git clone git@github.com:digarok/gsplus.git
# SDL version
sudo apt-get -y install libsdl1.2-dev
sudo apt-get -y install libsdl-image1.2-dev
# SDL2 version
sudo apt-get -y install libsdl2-dev
sudo apt-get -y install libsdl2-image-dev
# Example build to test out our system
cd gsplus/src
ln -s vars_x86linux_x11 vars
ln -s vars_x86linux_sdl2 vars
make clean ; make

View File

@ -1,27 +1,25 @@
# Mac OSX - SDL2 version
# Install 'brew' if you don't already have it installed.
#
# This should build a `gsplus` executable and copy it to the project root dir.
# You can run it, though as always you need to supply an Apple IIgs ROM file.
# Have fun, and please note any errors on the issues page of the project.
# system prep
# Prerequisite: You must install Xcode on your system from the App Store
# Also, install Xcode cli tools.
xcode-select --install
# Install 'brew'.
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
# Use brew to install dependencies.
brew install sdl2
brew install sdl2_image
brew install freetype
# build
# Build.
git clone git@github.com:digarok/gsplus.git
cd gsplus/src
ln -s vars_osx_sdl2 vars
make clean ; make
#Note that installing freetype via brew will install the library, but I think
# maybe you have to install the source and build it to link it in properly.
# You could use /usr/local/src instead of /tmp
cd /tmp
curl --remote-name --location http://sourceforge.net/projects/freetype/files/freetype2/2.6.2/freetype-2.6.2.tar.gz
tar -xzvf freetype-2.6.2.tar.gz
cd freetype-2.6.2
./configure --prefix=/usr/local/freetype-2.6.2
make
make install
ln -s freetype-2.6.2 /usr/local/freetype

View File

@ -0,0 +1,40 @@
# Win32 - SDL2 version
#
# This should build a `gsplus.exe` executable and copy it to the project root dir.
# You can run it, though as always you need to supply an Apple IIgs ROM file.
# Have fun, and please note any errors on the issues page of the project.
# Prerequisites: You must install Cygwin on your system.
# I install Cygwin with all "Devel" and "Perl" packages.
# I also search for and add any FreeType libs.
# If you want to deploy to s3 (gitlabci) then also add pip for python.
# If you are deploying the packages then you also need zip.
# You will not use the Cygwin SDL2/image libraries as they are deprecated.
# Instead you must download the mingw64-w64 libraries and link against those.
wget https://www.libsdl.org/release/SDL2-devel-2.0.8-mingw.tar.gz
tar -xvzf SDL2-devel-2.0.8-mingw.tar.gz
cd SDL2-2.0.8
mkdir /cygdrive/c/mingw
mv i686-w64-mingw32/ /cygdrive/c/mingw/
cd ..
wget https://www.libsdl.org/projects/SDL_image/release/SDL2_image-devel-2.0.3-mingw.tar.gz
tar -xvzf SDL2_image-devel-2.0.3-mingw.tar.gz
rsync -a SDL2_image-2.0.3/i686-w64-mingw32/ /cygdrive/c/mingw/i686-w64-mingw32/
# Build.
git clone git@github.com:digarok/gsplus.git
cd gsplus/src
ln -s vars_win32_sdl2 vars
make clean ; make
# if you want to make a machine that can also deploy to s3 (gitlabci):
pip2.7 install awscli
# aws creds are to be passed via CI environment variables
# also, you have to fix the behavior for windows to run this.
# open an Administrator CMD prompt and run:
assoc .py=pyautofile
ftype pyautofile="c:\cygwin\bin\python" "%1" %*

View File

@ -1,6 +1,4 @@
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON LINUX/UBUNTU
# Based on: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/linux-repository.md
## STEP 1 - Install Gitlab Runner
sudo apt-get install -y curl
@ -9,6 +7,14 @@ sudo apt-get install -y gitlab-ci-multi-runner
## STEP 2 - Register it with your server
sudo gitlab-ci-multi-runner register -n \
--url http://centralserv.gotgeeks.com/ci \
--registration-token UqGC2qvJmvU1QBK3mx4b \
--executor shell \
--description "LinBuild" \
--tag-list "ubuntu"
# or manually
sudo gitlab-ci-multi-runner register
# "Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/ci )"
# https://centralserv.gotgeeks.com/ci

View File

@ -1,5 +1,4 @@
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON LINUX/UBUNTU
# Based on: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/osx.md
## STEP 1 - Install Gitlab Runner
sudo curl --output /usr/local/bin/gitlab-ci-multi-runner https://gitlab-ci-multi-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-ci-multi-runner-darwin-amd64
@ -16,3 +15,18 @@ gitlab-ci-multi-runner register -n \
--registration-token a1f60647cf7fe3eb5c7fa87e59bf7 \
--executor shell \
--description "My-Mac"
# this one is better - adds tags simultaneously
gitlab-ci-multi-runner register -n \
--url http://yourgitlab.com/ci \
--registration-token 5b2f60647cf7fe3eb5c7fa87e59bf7 \
--executor shell \
--description "MBP" \
--tag-list "osx"
# maybe also needs
gitlab-ci-multi-runner install
# to run correctly
# you can always check with
gitlab-ci-multi-runner status

View File

@ -0,0 +1,66 @@
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON WIN32 FOR SDL2 BUILDS
## PREREQUISITE AKA SETTING UP A FRESH VM OR DEV COMPUTER
#
# Install your Win7/Win10 VM
# Install VirtualBox additions in your VM
#
# (optional, but seems to help) add build user
# Make user an admin, give it service privs
# ... Local Security Policy -> Local Policies -> User Rights Assignment -> Log on as a service
#
# install Cygwin & SDL2 Libraries according to the steps in the Quickstart doc
# add cygwin bin dir to env path
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON WINDOWS
## STEP 1 - Install Gitlab Runner
# https://docs.gitlab.com/runner/install/windows.html
# Download from page above, run CMD prompt as Administrator and then run the runner exe in there
## STEP 2 - Register it with your server
# First open Administrator CMD prompt then run the following commands.
# REGISTER: Enter your Gitlab CI details - (Token is in Gitlab->Admin-Runners)
gitlab-ci-multi-runner-windows-386.exe register
# enter gitlab url
# enter gitlab runner token
# enter tag of "windows"
gitlab-runner-windows-386.exe register -n \
--url http://yourgitlab.com/ci \
--registration-token UqGC2qvJmU1QBK3mx4b \
--executor shell \
--description "WinBuild"
--tag-list "windows"
## STEP 3 - Install Service
# Note the use of ".\builder" to indicate local account!
gitlab-runner-windows-386.exe install --user .\builder --password builder
## STEP 4 - Start service
gitlab-runner-windows-386.exe start
## STEP 4.5 - if you get a "failed due to logon" message above, you may need to grant "logon as a service" privs
#To add the "Log on as a service" right to an account on your local computer
#To open Local Security Policy, click Start, point to Control Panel, point to Administrative Tools, and then double-click Local Security Policy.
#In the console tree, double-click Local Policies, and then click User Rights Assignment.
#In the details pane, double-click Log on as a service.
#Click Add User or Group, and then add the appropriate account to the list of accounts that possess the Log on as a service right.
# If you have any other problems with the service not starting due to:
# "Failed to start gitlab-runner: The service did not start due to a logon failure."
# Try going to Services and edit the properties of the gitlab-runner service.
# Go to the "Log On" tab and re-enter the password/credentials and see if
# that helps.
## STEP 5 - Make sure gitlab-runner is using the correct shell
# It defaults to CMD, go to the directory where the gitlab-runner
# commands were run and edit the "config.toml" file. Under the line
# that says: executor = "shell"
# add: shell = "bash"
#
# Also, make sure that if you type "bash" <enter> from a CMD prompt,
# that it runs the Cygwin shell. If it can't find the bash command,
# go to the Environment Variables Control Panel for your computer and
# add "c:\cygwin\bin" to your PATH variable.

View File

@ -1,50 +0,0 @@
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON WINDOWS
# Based on: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/windows.md
## STEP 1 - Install Gitlab Runner
# Download from page above, run CMD prompt as Administrator and then run the runner exe in there
## STEP 2 - Register it with your server
# First open Administrator CMD prompt then run the following commands.
# REGISTER: Enter your Gitlab CI details
gitlab-ci-multi-runner-windows-386.exe register
## STEP 3 - Install Service
# Note the use of ".\IEUser" to indicate local account!
gitlab-ci-multi-runner-windows-386.exe install --user .\IEUser --password Passw0rd!
## STEP 4 - Start service
gitlab-ci-multi-runner-windows-386.exe start
# If you have any problems with the service not starting due to:
# "Failed to start gitlab-runner: The service did not start due to a
# logon failure."
# Try going to Services and edit the properties of the gitlab-runner service.
# Go to the "Log On" tab and re-enter the password/credentials and see if
# that helps.
## STEP 5 - Make sure gitlab-runner is using the correct shell
# It defaults to CMD, go to the directory where the gitlab-runner
# commands were run and edit the "config.toml" file. Under the line
# that says: executor = "shell"
# add: shell = "bash"
#
# Also, make sure that if you type "bash" <enter> from a CMD prompt,
# that it runs the Cygwin shell. If it can't find the bash command,
# go to the Environment Variables Control Panel for your computer and
# add "c:\cygwin\bin" to your PATH variable.
## PREREQUISITE
# The project is currently being build in Cygwin.
# I install Cygwin with all "Devel" and "Perl" packages.
# I also search for and add any SDL2 or FreeType libs just in case.
# You'll also need git installed for cmdline usage on Windows.
# Add your ~/.ssh/id_rsa using git bash (or cygwin) so that
# gitlab runner can check out your project

50
doc/README.txt Normal file
View File

@ -0,0 +1,50 @@
Getting started
===============
1. Download the emulator package from https://apple2.gs/plus and put it in a folder.
Yes, you can drag it into your Applications on a Mac, but be aware that it is
meant to be launched from a command line. If you put it in Applications, you
should be able to run it with the terminal command:
/Applications/GSplus.app/Contents/MacOS/gsplus
2. Download the Apple IIgs Firmware ROMs, for either a ROM01 or ROM03 machine.
(If you have a real IIgs, there are ways to save it from your machine too.)
Try: ftp://ftp.apple.asimov.net/pub/apple_II/emulators/rom_images/
a. Put the ROM image in the same folder where you run the emulator from.
It will search for: "ROM", "ROM.01", "ROM.03"
If your ROM file has some other name, launch gsplus and hit F4 to go to
the config menu to choose your ROM under "ROM File Selection"
... or ...
3. Edit your config:
You can manually edit the config.txt file (or use the F4 menu.)
You can set disks using a slot/number syntax like:
s5d1 = images/ArkanoidII.po
s6d1 = images/ProDOS_2_4_1.dsk
s7d1 = images/gsos.2mg
You can also manually set your ROM path like:
g_cfg_rom_path = ../roms/gsrom03
3. Get some Apple IIgs software.
I recommend the excellent Apple IIgs dedicated site:
http://www.whatisthe2gs.apple2.org.za/
If you have a real IIgs, you can transfer your disks using ADTPro
http://adtpro.sourceforge.net/
5. Boot the Apple IIgs by running the emulator
Windows: gsplus32.exe
Mac/Ubuntu: ./gsplus
Mac (if in Apps) /Applications/GSplus.app/Contents/MacOS/gsplus
If the config file cant be found, it will try to create a config.txt file for you,
with all of the defaults.
Note: You can also specify a config file. This is very useful as you can have specific
disks/setting pre-set in a config file and launch directly into your favorite game with
that config. They can be named anything you want, though the officially recognized
extensions are .txt and .gsp.
Examples:
Windows: gsplus32.exe -config arkanoid.gsp
Mac/Ubuntu: ./gsplus -config choplifter_config.txt

BIN
doc/gsplusmanual.pdf Normal file

Binary file not shown.

BIN
doc/web/Screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

0
lib/arch/mac/setfileicon Executable file → Normal file
View File

20
make_dist_mac.sh Executable file
View File

@ -0,0 +1,20 @@
DEXTRAS=gsplus-osx/
DDIR=$DEXTRAS/GSplus.app
ADIR=assets
mkdir -p $DEXTRAS/license
mkdir -p $DDIR/Contents/MacOS
mkdir -p $DDIR/Contents/Resources
cp gsplus $DDIR/Contents/MacOS
cp config.txt $DDIR/Contents/MacOS
cp $ADIR/Info.plist $DDIR/Contents
cp $ADIR/gsp-icons.icns $DDIR/Contents/Resources
dylibbundler -od -b -x $DDIR/Contents/MacOS/gsplus -d $DDIR/Contents/libs/
# files to include in dmg
cp doc/gsplusmanual.pdf $DEXTRAS
cp doc/README.txt $DEXTRAS
cp LICENSE.txt $DEXTRAS/license
cp COPYRIGHT.txt $DEXTRAS/license
# packaging now in DMG script

21
make_dmg_mac.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
git clone https://github.com/andreyvit/yoursway-create-dmg.git
cd yoursway-create-dmg
test -f GSplus-Install.dmg && rm GSplus-Install.dmg
./create-dmg \
--volname "GSplus" \
--volicon "../assets/gsp-dmg-icons.icns" \
--background "../assets/gsback.png" \
--window-pos 200 120 \
--window-size 710 600 \
--icon-size 64 \
--icon GSplus.app 250 210 \
--hide-extension GSplus.app \
--app-drop-link 440 210 \
--icon README.txt 225 350 \
--icon gsplusmanual.pdf 350 350 \
--icon license 470 350 \
GSplus-Install.dmg \
../gsplus-osx/
cp GSplus-Install.dmg ..

View File

@ -1,13 +1,14 @@
# GSport central makefile - you need a 'vars' file linked/copied from a 'vars_xxx' template to build.
# GSplus central makefile - you need a 'vars' file linked/copied from a 'vars_xxx' template to build.
#@todo: check for vars file and do something useful if missing :P
OBJECTS1 = adb.o clock.o config.o dis.o engine_c.o scc.o iwm.o \
joystick_driver.o moremem.o paddles.o parallel.o printer.o \
sim65816.o smartport.o sound.o sound_driver.o video.o \
scc_socket_driver.o imagewriter.o scc_imagewriter.o scc_llap.o
ATOBJ = atbridge/aarp.o atbridge/atbridge.o atbridge/elap.o atbridge/llap.o atbridge/port.o
#@todo: remove all packaging junk and move to packaging scripts in CI
OBJECTS1 = adb.o clock.o config.o debug.o dis.o engine_c.o scc.o iwm.o \
joystick_driver.o moremem.o paddles.o parallel.o printer.o sim65816.o \
smartport.o sound.o sound_driver.o video.o scc_socket_driver.o glog.o \
imagewriter.o scc_imagewriter.o scc_llap.o options.o
ATOBJ = atbridge/aarp.o atbridge/atbridge.o atbridge/elap.o atbridge/llap.o atbridge/port.o
PCAPOBJ = atbridge/pcap_delay.o
TFEOBJ = tfe/tfe.o tfe/tfearch.o tfe/tfesupp.o
FSTOBJ = host_common.o host_fst.o host_mli.o
include vars
@ -32,12 +33,11 @@ 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
# Linux/OSX SDL builds
# Linux/OSX/RPi SDL builds
gsplus: $(OBJECTS) compile_time.o
$(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS)
$(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS)
echo $(OBJECTS)
cp gsplus ..
cp gsplus ../bin/osx
# Linux/OSX XWindows builds
gsplusx: $(OBJECTS) compile_time.o
@ -45,28 +45,35 @@ gsplusx: $(OBJECTS) compile_time.o
echo $(OBJECTS)
mv gsplusx ..
# NOT CURRENTLY SUPPORTED
# NOT CURRENTLY SUPPORTED
# Linux framebuffer builds:
gsplusfb: $(OBJECTS) compile_time.o
$(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS)
echo $(OBJECTS)
mv gsplusfb ..
cp -f ../config.template ../config.txt
# Mingw32 (native windows) / Cygwin builds:
gsplus.exe: $(OBJECTS) compile_time.o
# Mingw32 / Cygwin builds: The Win32 API version
gsplus32.exe: $(OBJECTS) compile_time.o
g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32
mkdir -p ../GSplus.app/lib
cp -f gsplus.exe ../GSplus.app/GSplus.exe
cp -f ../config.template ../GSplus.app/config.txt
cp -f ../lib/*.ttf ../GSplus.app/lib
cp -f ../lib/arch/win32/*.dll ../GSplus.app
cp -f ../lib/NoBoot.po ../GSplus.app
cp -f GSplus.bat ../GSplus.app/GSplus.bat
cp -f parallel.rom ../GSplus.app
cp -f ../COPYING.txt ../GSplus.app
#mkdir -p ../GSplus.app/lib
#cp -f gsplus.exe ../GSplus.app/GSplus.exe
#cp -f ../config.template ../GSplus.app/config.txt
#cp -f ../lib/*.ttf ../GSplus.app/lib
#cp -f ../lib/arch/win32/*.dll ../GSplus.app
#cp -f ../lib/NoBoot.po ../GSplus.app
#cp -f GSplus.bat ../GSplus.app/GSplus.bat
#cp -f parallel.rom ../GSplus.app
#cp -f ../COPYING.txt ../GSplus.app
cp gsplus32.exe ..
# NOT CURRENTLY SUPPORTED
# Mingw32 / Cygwin builds: The SDL version (builds, but non-functioning)
gsplus.exe: $(OBJECTS) compile_time.o
#g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32
#g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -mwindows
g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32
cp gsplus.exe ..
# NOT CURRENTLY SUPPORTED
# Mac build - old style (deprecated)
gsportmac: $(OBJECTS) compile_time.o
$(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o gsport $(EXTRA_LIBS)
@ -139,8 +146,8 @@ partls: partls.c
to_pro: prodos.h prodos_protos.h to_pro.c
cc $(CCOPTS) $(XOPTS) $(OPTS) -o to_pro to_pro.c
gsport32.o: win32.rc winresource.h
windres win32.rc -o gsport32.o
gsplus32.o: win32.rc winresource.h
windres win32.rc -o gsplus32.o
compile_time.o: $(OBJECTS)
@ -183,7 +190,7 @@ macdriver.o: macdriver.c defc.h defcomm.h iwm.h protos.h protos_macdriver.h
macdriver_console.o: macdriver_console.c defc.h defcomm.h iwm.h protos.h protos_macdriver.h
macdriver_generic.o: macdriver_generic.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 gsport32.o
windriver.o: windriver.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h gsplus32.o
win_console.o: win_console.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h
win_generic.o: win_generic.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

3026
src/adb.c

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include "defc.h"

0
src/arch/mac/classes.nib generated Executable file → Normal file
View File

0
src/arch/mac/makedmg.sh Executable file → Normal file
View File

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/*

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include <os2.h>

View File

@ -1,24 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2010 by GSport contributors
Copyright (C) 2016 - Dagen Brock
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include "../../defc.h"
#include "../../protos.h"
@ -30,13 +15,13 @@
#include <string.h>
#include "gsportos2.h" /* Resource symbolic identifiers*/
HAB g_hab; /* PM anchor block handle */
PSZ pszErrMsg;
HAB g_hab; /* PM anchor block handle */
PSZ pszErrMsg;
QMSG qmsg; /* Message from message queue */
HWND g_hwnd_frame = NULLHANDLE; /* Frame window handle */
HWND g_hwnd_client = NULLHANDLE; /* Client area window handle */
HMQ g_hmq; /* Message queue handle */
HMQ g_hmq; /* Message queue handle */
extern int Verbose;
@ -47,15 +32,15 @@ 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;
int g_use_shmem = 1;
int g_has_focus = 0;
int g_auto_repeat_on = -1;
extern Kimage g_mainwin_kimage;
int g_main_height = 0;
int g_main_height = 0;
int g_win_capslock_down = 0;
int g_win_capslock_down = 0;
extern int g_border_sides_refresh_needed;
extern int g_border_special_refresh_needed;
@ -83,87 +68,79 @@ extern char *g_status_ptrs[MAX_STATUS_LINES];
VOID DispErrorMessage();
int
win_nonblock_read_stdin(int fd, char *bufptr, int len)
{
int win_nonblock_read_stdin(int fd, char *bufptr, int len) {
return 0;
}
void
x_dialog_create_gsport_conf(const char *str)
{
void x_dialog_create_gsport_conf(const char *str) {
}
int
x_show_alert(int is_fatal, const char *str)
{
return 0;
int x_show_alert(int is_fatal, const char *str) {
return 0;
}
int
main(int argc, char **argv)
{
DEVOPENSTRUC pszData;
ULONG flCreate; /* Window creation control flags*/
int height;
SIZEL sizel;
int main(int argc, char **argv) {
DEVOPENSTRUC pszData;
ULONG flCreate; /* Window creation control flags*/
int height;
SIZEL sizel;
if ((g_hab = WinInitialize(0)) == 0L) /* Initialize PM */
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
if ((g_hab = WinInitialize(0)) == 0L) /* Initialize PM */
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
if ((g_hmq = WinCreateMsgQueue( g_hab, 0 )) == 0L)/* Create a msg queue */
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
if ((g_hmq = WinCreateMsgQueue( g_hab, 0 )) == 0L) /* Create a msg queue */
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
if (!WinRegisterClass( /* Register window class */
g_hab, /* Anchor block handle */
(PSZ)"MyWindow", /* Window class name */
(PFNWP)MyWindowProc, /* Address of window procedure */
CS_SIZEREDRAW, /* Class style */
0 /* No extra window words */
))
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
if (!WinRegisterClass( /* Register window class */
g_hab, /* Anchor block handle */
(PSZ)"MyWindow", /* Window class name */
(PFNWP)MyWindowProc, /* Address of window procedure */
CS_SIZEREDRAW, /* Class style */
0 /* No extra window words */
))
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES*16);
g_main_height = height;
height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES*16);
g_main_height = height;
flCreate = FCF_STANDARD & /* Set frame control flags to */
~FCF_SHELLPOSITION; /* standard except for shell */
/* positioning. */
flCreate = FCF_STANDARD & /* Set frame control flags to */
~FCF_SHELLPOSITION; /* standard except for shell */
/* positioning. */
if ((g_hwnd_frame = WinCreateStdWindow(
HWND_DESKTOP, /* Desktop window is parent */
0, /* STD. window styles */
&flCreate, /* Frame control flag */
"MyWindow", /* Client window class name */
"", /* No window text */
0, /* No special class style */
(HMODULE)0L, /* Resource is in .EXE file */
ID_WINDOW, /* Frame window identifier */
&g_hwnd_client /* Client window handle */
)) == 0L)
os2_abort(HWND_DESKTOP, HWND_DESKTOP); /* Terminate the application */
if ((g_hwnd_frame = WinCreateStdWindow(
HWND_DESKTOP, /* Desktop window is parent */
0, /* STD. window styles */
&flCreate, /* Frame control flag */
"MyWindow", /* Client window class name */
"", /* No window text */
0, /* No special class style */
(HMODULE)0L, /* Resource is in .EXE file */
ID_WINDOW, /* Frame window identifier */
&g_hwnd_client /* Client window handle */
)) == 0L)
os2_abort(HWND_DESKTOP, HWND_DESKTOP); /* Terminate the application */
WinSetWindowText(g_hwnd_frame, "GSport");
WinSetWindowText(g_hwnd_frame, "GSport");
if (!WinSetWindowPos( g_hwnd_frame, /* Shows and activates frame */
HWND_TOP, /* window at position 100, 100, */
100, 100, X_A2_WINDOW_WIDTH, height, /* and size 200, 200. */
SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW
))
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
if (!WinSetWindowPos( g_hwnd_frame, /* Shows and activates frame */
HWND_TOP, /* window at position 100, 100, */
100, 100, X_A2_WINDOW_WIDTH, height, /* and size 200, 200. */
SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW
))
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
g_hdc_screen = WinOpenWindowDC(g_hwnd_client);
sizel.cx = X_A2_WINDOW_WIDTH;
sizel.cy = height;
g_hps_screen = GpiCreatePS(g_hab,g_hdc_screen, &sizel, PU_PELS | GPIF_LONG | GPIA_ASSOC);
g_hdc_screen = WinOpenWindowDC(g_hwnd_client);
sizel.cx = X_A2_WINDOW_WIDTH;
sizel.cy = height;
g_hps_screen = GpiCreatePS(g_hab,g_hdc_screen, &sizel, PU_PELS | GPIF_LONG | GPIA_ASSOC);
g_hdc_memory = DevOpenDC(g_hab, OD_MEMORY, "*", 4, (PDEVOPENDATA)&pszData, NULL);
g_hps_memory = GpiCreatePS(g_hab,g_hdc_memory, &sizel, PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC);
g_hdc_memory = DevOpenDC(g_hab, OD_MEMORY, "*", 4, (PDEVOPENDATA)&pszData, NULL);
g_hps_memory = GpiCreatePS(g_hab,g_hdc_memory, &sizel, PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC);
// Call gsplusmain
return gsplusmain(argc, argv);
// Call gsplusmain
return gsplusmain(argc, argv);
}
@ -178,10 +155,9 @@ SIZEL sizel;
* the message command and parameters.
*
*************************************************************************/
MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
{
HPS hps;
RECTL rcl;
MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
HPS hps;
RECTL rcl;
switch( msg )
{
@ -200,7 +176,7 @@ RECTL rcl;
* When Exit is chosen, the application posts itself a WM_CLOSE
* message.
*/
{
{
USHORT command; /* WM_COMMAND command value */
command = SHORT1FROMMP(mp1); /* Extract the command value */
switch (command)
@ -213,7 +189,7 @@ RECTL rcl;
}
break;
}
}
case WM_ERASEBACKGROUND:
/*
* Return TRUE to request PM to paint the window background
@ -224,16 +200,16 @@ RECTL rcl;
/*
* Window contents are drawn here in WM_PAINT processing.
*/
hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl);
WinEndPaint(hps);
g_needfullrefreshfornextframe = 1;
hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl);
WinEndPaint(hps);
g_needfullrefreshfornextframe = 1;
break;
case WM_CLOSE:
/*
* This is the place to put your termination routines
*/
WinPostMsg( hwnd, WM_QUIT, (MPARAM)0,(MPARAM)0 ); /* Cause termination*/
exit(0);
exit(0);
break;
default:
/*
@ -247,262 +223,232 @@ RECTL rcl;
return (MRESULT)FALSE;
} /* End of MyWindowProc */
void
check_input_events()
{
void check_input_events() {
/*
* Get and dispatch messages from the application message queue
* until WinGetMsg returns FALSE, indicating a WM_QUIT message.
*/
while(WinPeekMsg(g_hab, &qmsg, g_hwnd_frame, 0, 0, PM_NOREMOVE)) {
if(WinGetMsg(g_hab, &qmsg, 0L, 0, 0) > 0) {
//TranslateMessage(&qmsg);
WinDispatchMsg(g_hab, &qmsg);
} else {
printf("GetMessage returned <= 0\n");
my_exit(2);
}
}
while(WinPeekMsg(g_hab, &qmsg, g_hwnd_frame, 0, 0, PM_NOREMOVE)) {
if(WinGetMsg(g_hab, &qmsg, 0L, 0, 0) > 0) {
//TranslateMessage(&qmsg);
WinDispatchMsg(g_hab, &qmsg);
} else {
printf("GetMessage returned <= 0\n");
my_exit(2);
}
}
}
void
x_update_color(int col_num, int red, int green, int blue, word32 rgb)
{
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) {
}
void
x_update_physical_colormap()
{
void x_update_physical_colormap() {
}
void
show_xcolor_array()
{
void show_xcolor_array() {
}
void
xdriver_end()
{
printf("OS/2 driver_end\n");
void xdriver_end() {
printf("OS/2 driver_end\n");
}
void
x_get_kimage(Kimage *kimage_ptr)
{
byte *ptr;
int width;
int height;
int depth, mdepth;
int size;
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;
width = kimage_ptr->width_req;
height = kimage_ptr->height;
depth = kimage_ptr->depth;
mdepth = kimage_ptr->mdepth;
size = 0;
size = 0;
if(depth == g_screen_depth) {
/* Use g_bmapinfo_ptr, adjusting width, height */
g_bmaphdr_ptr->cx = width;
g_bmaphdr_ptr->cy = height;
if(depth == g_screen_depth) {
/* Use g_bmapinfo_ptr, adjusting width, height */
g_bmaphdr_ptr->cx = width;
g_bmaphdr_ptr->cy = height;
kimage_ptr->dev_handle = GpiCreateBitmap(
kimage_ptr->dev_handle = GpiCreateBitmap(
(HPS)g_hps_memory, (PBITMAPINFOHEADER2)g_bmaphdr_ptr,
0L, (PBYTE)kimage_ptr->data_ptr,
(PBITMAPINFO2)g_bmapinfo_ptr);
(HPS)g_hps_memory, (PBITMAPINFOHEADER2)g_bmaphdr_ptr,
0L, (PBYTE)kimage_ptr->data_ptr,
(PBITMAPINFO2)g_bmapinfo_ptr);
size = (width*height*mdepth) >> 3;
ptr = (byte *)malloc(size);
size = (width*height*mdepth) >> 3;
ptr = (byte *)malloc(size);
if(ptr == 0) {
printf("malloc for data failed, mdepth: %d\n", mdepth);
exit(2);
}
if(ptr == 0) {
printf("malloc for data failed, mdepth: %d\n", mdepth);
exit(2);
}
kimage_ptr->data_ptr = ptr;
kimage_ptr->data_ptr = ptr;
} else {
/* allocate buffers for video.c to draw into */
} else {
/* allocate buffers for video.c to draw into */
size = (width*height*mdepth) >> 3;
ptr = (byte *)malloc(size);
size = (width*height*mdepth) >> 3;
ptr = (byte *)malloc(size);
if(ptr == 0) {
printf("malloc for data failed, mdepth: %d\n", mdepth);
exit(2);
}
if(ptr == 0) {
printf("malloc for data failed, mdepth: %d\n", mdepth);
exit(2);
}
kimage_ptr->data_ptr = ptr;
kimage_ptr->data_ptr = ptr;
kimage_ptr->dev_handle = (void *)-1;
kimage_ptr->dev_handle = (void *)-1;
}
}
return;
return;
}
void
dev_video_init()
{
int lores_col;
int i;
void dev_video_init() {
int lores_col;
int i;
printf("Preparing graphics system\n");
printf("Preparing graphics system\n");
g_screen_depth = 24;
g_screen_mdepth = 32;
g_screen_depth = 24;
g_screen_mdepth = 32;
g_bmapinfo_ptr = (BITMAPINFO2 *)malloc(sizeof(BITMAPINFOHEADER2));
g_bmaphdr_ptr = (BITMAPINFOHEADER2 *)g_bmapinfo_ptr;
g_bmaphdr_ptr->cbFix = sizeof(BITMAPINFOHEADER2);
g_bmaphdr_ptr->cx = A2_WINDOW_WIDTH;
g_bmaphdr_ptr->cy = A2_WINDOW_HEIGHT;
g_bmaphdr_ptr->cPlanes = 1;
g_bmaphdr_ptr->cBitCount = g_screen_mdepth;
g_bmaphdr_ptr->ulCompression = BCA_UNCOMP;
g_bmaphdr_ptr->cclrUsed = 0;
g_bmapinfo_ptr = (BITMAPINFO2 *)malloc(sizeof(BITMAPINFOHEADER2));
g_bmaphdr_ptr = (BITMAPINFOHEADER2 *)g_bmapinfo_ptr;
g_bmaphdr_ptr->cbFix = sizeof(BITMAPINFOHEADER2);
g_bmaphdr_ptr->cx = A2_WINDOW_WIDTH;
g_bmaphdr_ptr->cy = A2_WINDOW_HEIGHT;
g_bmaphdr_ptr->cPlanes = 1;
g_bmaphdr_ptr->cBitCount = g_screen_mdepth;
g_bmaphdr_ptr->ulCompression = BCA_UNCOMP;
g_bmaphdr_ptr->cclrUsed = 0;
video_get_kimages();
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);
}
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];
}
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;
g_installed_full_superhires_colormap = 1;
printf("Done with dev_video_init\n");
fflush(stdout);
printf("Done with dev_video_init\n");
fflush(stdout);
}
void
x_redraw_status_lines()
{
void x_redraw_status_lines() {
int line,len,height;
POINTL pt;
char *buf;
int line,len,height;
POINTL pt;
char *buf;
printf("x_redraw_status_lines() called\n");
printf("x_redraw_status_lines() called\n");
/*
if (g_status_ptrs[0] != NULL)
{
height = 16;
pt.x = 5; pt.y = 0;
GpiSetColor( g_hps_screen, CLR_NEUTRAL );
GpiSetBackColor( g_hps_screen, CLR_BACKGROUND );
GpiSetBackMix( g_hps_screen, BM_OVERPAINT );
if (g_status_ptrs[0] != NULL)
{
height = 16;
pt.x = 5; pt.y = 0;
GpiSetColor( g_hps_screen, CLR_NEUTRAL );
GpiSetBackColor( g_hps_screen, CLR_BACKGROUND );
GpiSetBackMix( g_hps_screen, BM_OVERPAINT );
for (line = 0; line < MAX_STATUS_LINES; line++)
{
buf = g_status_ptrs[line];
if (buf != 0)
{
pt.y = height * (line+1);
len = strlen(buf);
GpiCharStringAt( g_hps_screen, &pt, (LONG)strlen( buf ), buf );
}
}
}
*/
for (line = 0; line < MAX_STATUS_LINES; line++)
{
buf = g_status_ptrs[line];
if (buf != 0)
{
pt.y = height * (line+1);
len = strlen(buf);
GpiCharStringAt( g_hps_screen, &pt, (LONG)strlen( buf ), buf );
}
}
}
*/
}
void
x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy,
int width, int height)
{
RECTL rc;
POINTL pt[4];
HBITMAP hbmOld, hbmNew;
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy,
int width, int height) {
RECTL rc;
POINTL pt[4];
HBITMAP hbmOld, hbmNew;
char *szString = "Hello, world!\0";
char *szString = "Hello, world!\0";
printf("x_push_kimage() called: Src: (%d,%d) Dest: (%d,%d) Width: %d Height: %d\n",srcx,srcy,destx,desty,width,height);
pt[0].x = destx; /* Target X1 */
pt[0].y = desty+(MAX_STATUS_LINES*16); /* Target Y1 */
pt[1].x = destx+width; /* Target X2 */
pt[1].y = desty+height+(MAX_STATUS_LINES*16); /* Target Y2: Translate up, make room for status border */
pt[2].x = srcx; /* Source X */
pt[2].y = srcy; /* Source Y */
pt[3].x = srcx+width;
pt[3].y = srcy+height;
printf("x_push_kimage() called: Src: (%d,%d) Dest: (%d,%d) Width: %d Height: %d\n",srcx,srcy,destx,desty,width,height);
pt[0].x = destx; /* Target X1 */
pt[0].y = desty+(MAX_STATUS_LINES*16); /* Target Y1 */
pt[1].x = destx+width; /* Target X2 */
pt[1].y = desty+height+(MAX_STATUS_LINES*16); /* Target Y2: Translate up, make room for status border */
pt[2].x = srcx; /* Source X */
pt[2].y = srcy; /* Source Y */
pt[3].x = srcx+width;
pt[3].y = srcy+height;
if (width == 560)
{
/* Paint a known-good bitmap until we can figure out why images aren't showing up */
hbmNew = GpiLoadBitmap(g_hps_memory,NULLHANDLE,ID_BITMAP,560,400);
hbmOld = GpiSetBitmap(g_hps_memory, hbmNew);
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
GpiSetBitmap(g_hps_memory, hbmOld);
GpiDeleteBitmap(hbmNew);
}
else
{
hbmOld = GpiSetBitmap(g_hps_memory, (HBITMAP)kimage_ptr->dev_handle);
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
GpiSetBitmap(g_hps_memory, hbmOld);
}
if (width == 560)
{
/* Paint a known-good bitmap until we can figure out why images aren't showing up */
hbmNew = GpiLoadBitmap(g_hps_memory,NULLHANDLE,ID_BITMAP,560,400);
hbmOld = GpiSetBitmap(g_hps_memory, hbmNew);
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
GpiSetBitmap(g_hps_memory, hbmOld);
GpiDeleteBitmap(hbmNew);
}
else
{
hbmOld = GpiSetBitmap(g_hps_memory, (HBITMAP)kimage_ptr->dev_handle);
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
GpiSetBitmap(g_hps_memory, hbmOld);
}
}
// OG Adding release
void x_release_kimage(Kimage* kimage_ptr)
{
if (kimage_ptr->dev_handle == (void*)-1)
{
free(kimage_ptr->data_ptr);
kimage_ptr->data_ptr = NULL;
}
else
{
}
void x_release_kimage(Kimage* kimage_ptr) {
if (kimage_ptr->dev_handle == (void*)-1)
{
free(kimage_ptr->data_ptr);
kimage_ptr->data_ptr = NULL;
}
else
{
}
}
void
x_push_done()
{
void x_push_done() {
}
void
x_auto_repeat_on(int must)
{
void x_auto_repeat_on(int must) {
}
void
x_auto_repeat_off(int must)
{
void x_auto_repeat_off(int must) {
}
void
x_hide_pointer(int do_hide)
{
void x_hide_pointer(int do_hide) {
}
void
x_full_screen(int do_full)
{
return;
void x_full_screen(int do_full) {
return;
}
int x_calc_ratio(float ratiox,float ratioy)
{
return 0; // not stretched
int x_calc_ratio(float ratiox,float ratioy) {
return 0; // not stretched
}
/**************************************************************************/
@ -511,33 +457,30 @@ int x_calc_ratio(float ratiox,float ratioy)
/* The error message is displayed using a message box */
/* */
/**************************************************************************/
VOID DispErrorMessage()
{
PERRINFO pErrInfoBlk;
PSZ pszOffSet, pszErrMsg;
ERRORID ErrorId;
PCH ErrorStr;
VOID DispErrorMessage() {
PERRINFO pErrInfoBlk;
PSZ pszOffSet, pszErrMsg;
ERRORID ErrorId;
PCH ErrorStr;
ErrorId = WinGetLastError(g_hab);
ErrorId = WinGetLastError(g_hab);
if ((pErrInfoBlk = WinGetErrorInfo(g_hab)) != (PERRINFO)NULL)
{
pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet);
if ((pErrInfoBlk = WinGetErrorInfo(g_hab)) != (PERRINFO)NULL)
{
pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet);
WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */
g_hwnd_frame, /* Owner window is our frame */
pszErrMsg, /* PMWIN Error message */
"Error", /* Title bar message */
0, /* Message identifier */
MB_MOVEABLE | MB_CANCEL ); /* Flags */
WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */
g_hwnd_frame, /* Owner window is our frame */
pszErrMsg, /* PMWIN Error message */
"Error", /* Title bar message */
0, /* Message identifier */
MB_MOVEABLE | MB_CANCEL ); /* Flags */
WinFreeErrorInfo(pErrInfoBlk);
}
WinFreeErrorInfo(pErrInfoBlk);
}
}
void
os2_abort(HWND g_hwnd_frame, HWND g_hwnd_client)
{
void os2_abort(HWND g_hwnd_frame, HWND g_hwnd_client) {
exit(-1);
}

View File

@ -1,23 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2010 by GSport contributors
Copyright (C) 2016 - Dagen Brock
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
int g_preferred_rate = 48000;

View File

@ -18,48 +18,45 @@
* 02111-1307 USA.
*
*/
#include <stdio.h>
#include <string.h>
#include "dirport.h"
DIR *opendir (char *path)
{
APIRET ulrc;
ULONG cnt = 1;
DIR *dir;
char *name;
if (!(dir = (DIR*)calloc(1, sizeof(DIR)))) {
return NULL;
}
if (name = (char*)calloc(1, strlen(path) + 3)) {
strcat(strcpy(name, path),path[strlen(path) - 1] == '\\' ? "*" : "\\*");
dir->handle = HDIR_CREATE;
ulrc = DosFindFirst(name, &(dir->handle), _A_ANY, &(dir->buffer), sizeof(struct _FILEFINDBUF3), &cnt, FIL_STANDARD);
free(name);
}
if (!name || ulrc) {
DosFindClose (dir->handle);
free(dir);
dir = NULL;
}
return dir;
}
struct dirent *readdir (DIR *dir)
{
ULONG cnt = 1;
return DosFindNext (dir->handle, &(dir->buffer), sizeof(struct _FILEFINDBUF), &cnt) ? NULL : &(dir->buffer);
}
int closedir (DIR *dir)
{
APIRET ulrc = DosFindClose (dir->handle);
DIR *opendir (char *path) {
APIRET ulrc;
ULONG cnt = 1;
DIR *dir;
char *name;
if (!(dir = (DIR*)calloc(1, sizeof(DIR)))) {
return NULL;
}
if (name = (char*)calloc(1, strlen(path) + 3)) {
strcat(strcpy(name, path),path[strlen(path) - 1] == '\\' ? "*" : "\\*");
dir->handle = HDIR_CREATE;
ulrc = DosFindFirst(name, &(dir->handle), _A_ANY, &(dir->buffer), sizeof(struct _FILEFINDBUF3), &cnt, FIL_STANDARD);
free(name);
}
if (!name || ulrc) {
DosFindClose (dir->handle);
free(dir);
return (int)ulrc;
dir = NULL;
}
return dir;
}
struct dirent *readdir (DIR *dir) {
ULONG cnt = 1;
return DosFindNext (dir->handle, &(dir->buffer), sizeof(struct _FILEFINDBUF), &cnt) ? NULL : &(dir->buffer);
}
int closedir (DIR *dir) {
APIRET ulrc = DosFindClose (dir->handle);
free(dir);
return (int)ulrc;
}
@ -71,7 +68,7 @@ int closedir (DIR *dir)
snprintf.c
- a portable implementation of snprintf,
including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf
snprintf is a routine to convert numeric and string arguments to
formatted strings. It is similar to sprintf(3) provided in a system's
C library, yet it requires an additional argument - the buffer size -
@ -81,10 +78,10 @@ int closedir (DIR *dir)
not or do provide an inadequate (slow or idiosyncratic) version, which
calls for a portable implementation of this routine.
Author
Author
Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000
Copyright © 1999, Mark Martinec
Copyright <EFBFBD> 1999, Mark Martinec
*/
@ -167,14 +164,14 @@ Author
#define fast_memcpy(d,s,n) \
{ register size_t nn = (size_t)(n); \
if (nn >= breakeven_point) memcpy((d), (s), nn); \
else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
else if (nn > 0) { /* proc call overhead is worth only for large strings*/ \
register char *dd; register const char *ss; \
for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
#define fast_memset(d,c,n) \
{ register size_t nn = (size_t)(n); \
if (nn >= breakeven_point) memset((d), (int)(c), nn); \
else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
else if (nn > 0) { /* proc call overhead is worth only for large strings*/ \
register char *dd; register const int cc=(int)(c); \
for (dd=(d); nn>0; nn--) *dd++ = cc; } }
@ -251,8 +248,7 @@ int vasprintf(char **ptr, const char *fmt, va_list ap) {
{ va_list ap2;
va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
va_end(ap2);
}
va_end(ap2);}
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
*ptr = (char *) malloc(str_m = (size_t)str_l + 1);
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
@ -300,8 +296,7 @@ int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
{ va_list ap2;
va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
va_end(ap2);
}
va_end(ap2);}
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */
/* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
@ -358,14 +353,14 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
if (!p) p = "";
while (*p) {
if (*p != '%') {
/* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */
/* but the following code achieves better performance for cases
* where format string is long and contains few conversions */
/* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */
/* but the following code achieves better performance for cases
* where format string is long and contains few conversions */
const char *q = strchr(p+1,'%');
size_t n = !q ? strlen(p) : (q-p);
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memcpy(str+str_l, p, (n>avail?avail:n));
fast_memcpy(str+str_l, p, (n>avail ? avail : n));
}
p += n; str_l += n;
} else {
@ -382,45 +377,45 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
size_t str_arg_l; /* natural field width of arg without padding
and sign */
unsigned char uchar_arg;
/* unsigned char argument value - only defined for c conversion.
N.B. standard explicitly states the char argument for
the c conversion is unsigned */
/* unsigned char argument value - only defined for c conversion.
N.B. standard explicitly states the char argument for
the c conversion is unsigned */
size_t number_of_zeros_to_pad = 0;
/* number of zeros to be inserted for numeric conversions
as required by the precision or minimal field width */
/* number of zeros to be inserted for numeric conversions
as required by the precision or minimal field width */
size_t zero_padding_insertion_ind = 0;
/* index into tmp where zero padding is to be inserted */
/* index into tmp where zero padding is to be inserted */
char fmt_spec = '\0';
/* current conversion specifier character */
/* current conversion specifier character */
str_arg = credits;/* just to make compiler happy (defined but not used)*/
str_arg = NULL;
starting_p = p; p++; /* skip '%' */
/* parse flags */
/* parse flags */
while (*p == '0' || *p == '-' || *p == '+' ||
*p == ' ' || *p == '#' || *p == '\'') {
switch (*p) {
case '0': zero_padding = 1; break;
case '-': justify_left = 1; break;
case '+': force_sign = 1; space_for_positive = 0; break;
case ' ': force_sign = 1;
/* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
case '0': zero_padding = 1; break;
case '-': justify_left = 1; break;
case '+': force_sign = 1; space_for_positive = 0; break;
case ' ': force_sign = 1;
/* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
#ifdef PERL_COMPATIBLE
/* ... but in Perl the last of ' ' and '+' applies */
space_for_positive = 1;
/* ... but in Perl the last of ' ' and '+' applies */
space_for_positive = 1;
#endif
break;
case '#': alternate_form = 1; break;
case '\'': break;
break;
case '#': alternate_form = 1; break;
case '\'': break;
}
p++;
}
/* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
/* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
/* parse field width */
/* parse field width */
if (*p == '*') {
int j;
p++; j = va_arg(ap, int);
@ -433,7 +428,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
min_field_width = uj;
}
/* parse precision */
/* parse precision */
if (*p == '.') {
p++; precision_specified = 1;
if (*p == '*') {
@ -442,12 +437,12 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
if (j >= 0) precision = j;
else {
precision_specified = 0; precision = 0;
/* NOTE:
* Solaris 2.6 man page claims that in this case the precision
* should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page
* claim that this case should be treated as unspecified precision,
* which is what we do here.
*/
/* NOTE:
* Solaris 2.6 man page claims that in this case the precision
* should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page
* claim that this case should be treated as unspecified precision,
* which is what we do here.
*/
}
} else if (isdigit((int)(*p))) {
/* size_t could be wider than unsigned int;
@ -457,7 +452,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
precision = uj;
}
}
/* parse 'h', 'l' and 'll' length modifiers */
/* parse 'h', 'l' and 'll' length modifiers */
if (*p == 'h' || *p == 'l') {
length_modifier = *p; p++;
if (length_modifier == 'l' && *p == 'l') { /* double l = long long */
@ -470,336 +465,334 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
}
}
fmt_spec = *p;
/* common synonyms: */
/* common synonyms: */
switch (fmt_spec) {
case 'i': fmt_spec = 'd'; break;
case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
default: break;
case 'i': fmt_spec = 'd'; break;
case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
default: break;
}
/* get parameter value, do initial processing */
/* get parameter value, do initial processing */
switch (fmt_spec) {
case '%': /* % behaves similar to 's' regarding flags and field widths */
case 'c': /* c behaves similar to 's' regarding flags and field widths */
case 's':
length_modifier = '\0'; /* wint_t and wchar_t not supported */
/* the result of zero padding flag with non-numeric conversion specifier*/
/* is undefined. Solaris and HPUX 10 does zero padding in this case, */
/* Digital Unix and Linux does not. */
#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
zero_padding = 0; /* turn zero padding off for string conversions */
#endif
str_arg_l = 1;
switch (fmt_spec) {
case '%':
str_arg = p; break;
case 'c': {
int j = va_arg(ap, int);
uchar_arg = (unsigned char) j; /* standard demands unsigned char */
str_arg = (const char *) &uchar_arg;
break;
}
case '%': /* % behaves similar to 's' regarding flags and field widths */
case 'c': /* c behaves similar to 's' regarding flags and field widths */
case 's':
str_arg = va_arg(ap, const char *);
if (!str_arg) str_arg_l = 0;
/* make sure not to address string beyond the specified precision !!! */
else if (!precision_specified) str_arg_l = strlen(str_arg);
/* truncate string if necessary as requested by precision */
else if (precision == 0) str_arg_l = 0;
else {
/* memchr on HP does not like n > 2^31 !!! */
const char *q = memchr(str_arg, '\0',
precision <= 0x7fffffff ? precision : 0x7fffffff);
str_arg_l = !q ? precision : (q-str_arg);
length_modifier = '\0'; /* wint_t and wchar_t not supported */
/* the result of zero padding flag with non-numeric conversion specifier*/
/* is undefined. Solaris and HPUX 10 does zero padding in this case, */
/* Digital Unix and Linux does not. */
#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
zero_padding = 0; /* turn zero padding off for string conversions */
#endif
str_arg_l = 1;
switch (fmt_spec) {
case '%':
str_arg = p; break;
case 'c': {
int j = va_arg(ap, int);
uchar_arg = (unsigned char) j; /* standard demands unsigned char */
str_arg = (const char *) &uchar_arg;
break;
}
case 's':
str_arg = va_arg(ap, const char *);
if (!str_arg) str_arg_l = 0;
/* make sure not to address string beyond the specified precision !!! */
else if (!precision_specified) str_arg_l = strlen(str_arg);
/* truncate string if necessary as requested by precision */
else if (precision == 0) str_arg_l = 0;
else {
/* memchr on HP does not like n > 2^31 !!! */
const char *q = memchr(str_arg, '\0',
precision <= 0x7fffffff ? precision : 0x7fffffff);
str_arg_l = !q ? precision : (q-str_arg);
}
break;
default: break;
}
break;
default: break;
}
break;
case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
/* NOTE: the u, o, x, X and p conversion specifiers imply
the value is unsigned; d implies a signed value */
case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
/* NOTE: the u, o, x, X and p conversion specifiers imply
the value is unsigned; d implies a signed value */
int arg_sign = 0;
int arg_sign = 0;
/* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
+1 if greater than zero (or nonzero for unsigned arguments),
-1 if negative (unsigned argument is never negative) */
+1 if greater than zero (or nonzero for unsigned arguments),
-1 if negative (unsigned argument is never negative) */
int int_arg = 0; unsigned int uint_arg = 0;
int int_arg = 0; unsigned int uint_arg = 0;
/* only defined for length modifier h, or for no length modifiers */
long int long_arg = 0; unsigned long int ulong_arg = 0;
long int long_arg = 0; unsigned long int ulong_arg = 0;
/* only defined for length modifier l */
void *ptr_arg = NULL;
void *ptr_arg = NULL;
/* pointer argument value -only defined for p conversion */
#ifdef SNPRINTF_LONGLONG_SUPPORT
long long int long_long_arg = 0;
unsigned long long int ulong_long_arg = 0;
long long int long_long_arg = 0;
unsigned long long int ulong_long_arg = 0;
/* only defined for length modifier ll */
#endif
if (fmt_spec == 'p') {
/* HPUX 10: An l, h, ll or L before any other conversion character
* (other than d, i, u, o, x, or X) is ignored.
* Digital Unix:
* not specified, but seems to behave as HPUX does.
* Solaris: If an h, l, or L appears before any other conversion
* specifier (other than d, i, u, o, x, or X), the behavior
* is undefined. (Actually %hp converts only 16-bits of address
* and %llp treats address as 64-bit data which is incompatible
* with (void *) argument on a 32-bit system).
*/
if (fmt_spec == 'p') {
/* HPUX 10: An l, h, ll or L before any other conversion character
* (other than d, i, u, o, x, or X) is ignored.
* Digital Unix:
* not specified, but seems to behave as HPUX does.
* Solaris: If an h, l, or L appears before any other conversion
* specifier (other than d, i, u, o, x, or X), the behavior
* is undefined. (Actually %hp converts only 16-bits of address
* and %llp treats address as 64-bit data which is incompatible
* with (void *) argument on a 32-bit system).
*/
#ifdef SOLARIS_COMPATIBLE
# ifdef SOLARIS_BUG_COMPATIBLE
/* keep length modifiers even if it represents 'll' */
/* keep length modifiers even if it represents 'll' */
# else
if (length_modifier == '2') length_modifier = '\0';
if (length_modifier == '2') length_modifier = '\0';
# endif
#else
length_modifier = '\0';
length_modifier = '\0';
#endif
ptr_arg = va_arg(ap, void *);
if (ptr_arg != NULL) arg_sign = 1;
} else if (fmt_spec == 'd') { /* signed */
switch (length_modifier) {
case '\0':
case 'h':
/* It is non-portable to specify a second argument of char or short
* to va_arg, because arguments seen by the called function
* are not char or short. C converts char and short arguments
* to int before passing them to a function.
*/
int_arg = va_arg(ap, int);
if (int_arg > 0) arg_sign = 1;
else if (int_arg < 0) arg_sign = -1;
break;
case 'l':
long_arg = va_arg(ap, long int);
if (long_arg > 0) arg_sign = 1;
else if (long_arg < 0) arg_sign = -1;
break;
ptr_arg = va_arg(ap, void *);
if (ptr_arg != NULL) arg_sign = 1;
} else if (fmt_spec == 'd') { /* signed */
switch (length_modifier) {
case '\0':
case 'h':
/* It is non-portable to specify a second argument of char or short
* to va_arg, because arguments seen by the called function
* are not char or short. C converts char and short arguments
* to int before passing them to a function.
*/
int_arg = va_arg(ap, int);
if (int_arg > 0) arg_sign = 1;
else if (int_arg < 0) arg_sign = -1;
break;
case 'l':
long_arg = va_arg(ap, long int);
if (long_arg > 0) arg_sign = 1;
else if (long_arg < 0) arg_sign = -1;
break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2':
long_long_arg = va_arg(ap, long long int);
if (long_long_arg > 0) arg_sign = 1;
else if (long_long_arg < 0) arg_sign = -1;
break;
case '2':
long_long_arg = va_arg(ap, long long int);
if (long_long_arg > 0) arg_sign = 1;
else if (long_long_arg < 0) arg_sign = -1;
break;
#endif
}
} else { /* unsigned */
switch (length_modifier) {
case '\0':
case 'h':
uint_arg = va_arg(ap, unsigned int);
if (uint_arg) arg_sign = 1;
break;
case 'l':
ulong_arg = va_arg(ap, unsigned long int);
if (ulong_arg) arg_sign = 1;
break;
}
} else { /* unsigned */
switch (length_modifier) {
case '\0':
case 'h':
uint_arg = va_arg(ap, unsigned int);
if (uint_arg) arg_sign = 1;
break;
case 'l':
ulong_arg = va_arg(ap, unsigned long int);
if (ulong_arg) arg_sign = 1;
break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2':
ulong_long_arg = va_arg(ap, unsigned long long int);
if (ulong_long_arg) arg_sign = 1;
break;
case '2':
ulong_long_arg = va_arg(ap, unsigned long long int);
if (ulong_long_arg) arg_sign = 1;
break;
#endif
}
}
}
str_arg = tmp; str_arg_l = 0;
/* NOTE:
* For d, i, u, o, x, and X conversions, if precision is specified,
* the '0' flag should be ignored. This is so with Solaris 2.6,
* Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
*/
str_arg = tmp; str_arg_l = 0;
/* NOTE:
* For d, i, u, o, x, and X conversions, if precision is specified,
* the '0' flag should be ignored. This is so with Solaris 2.6,
* Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
*/
#ifndef PERL_COMPATIBLE
if (precision_specified) zero_padding = 0;
if (precision_specified) zero_padding = 0;
#endif
if (fmt_spec == 'd') {
if (force_sign && arg_sign >= 0)
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
/* leave negative numbers for sprintf to handle,
to avoid handling tricky cases like (short int)(-32768) */
if (fmt_spec == 'd') {
if (force_sign && arg_sign >= 0)
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
/* leave negative numbers for sprintf to handle,
to avoid handling tricky cases like (short int)(-32768) */
#ifdef LINUX_COMPATIBLE
} else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
} else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
#endif
} else if (alternate_form) {
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
} else if (alternate_form) {
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
{ tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
/* alternate form should have no effect for p conversion, but ... */
/* alternate form should have no effect for p conversion, but ... */
#ifdef HPUX_COMPATIBLE
else if (fmt_spec == 'p'
/* HPUX 10: for an alternate form of p conversion,
* a nonzero result is prefixed by 0x. */
else if (fmt_spec == 'p'
/* HPUX 10: for an alternate form of p conversion,
* a nonzero result is prefixed by 0x. */
#ifndef HPUX_BUG_COMPATIBLE
/* Actually it uses 0x prefix even for a zero value. */
&& arg_sign != 0
/* Actually it uses 0x prefix even for a zero value. */
&& arg_sign != 0
#endif
) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
#endif
}
zero_padding_insertion_ind = str_arg_l;
if (!precision_specified) precision = 1; /* default precision is 1 */
if (precision == 0 && arg_sign == 0
}
zero_padding_insertion_ind = str_arg_l;
if (!precision_specified) precision = 1; /* default precision is 1 */
if (precision == 0 && arg_sign == 0
#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
&& fmt_spec != 'p'
/* HPUX 10 man page claims: With conversion character p the result of
* converting a zero value with a precision of zero is a null string.
* Actually HP returns all zeroes, and Linux returns "(nil)". */
&& fmt_spec != 'p'
/* HPUX 10 man page claims: With conversion character p the result of
* converting a zero value with a precision of zero is a null string.
* Actually HP returns all zeroes, and Linux returns "(nil)". */
#endif
) {
/* converted to null string */
/* When zero value is formatted with an explicit precision 0,
the resulting formatted string is empty (d, i, u, o, x, X, p). */
} else {
char f[5]; int f_l = 0;
f[f_l++] = '%'; /* construct a simple format string for sprintf */
if (!length_modifier) { }
else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
else f[f_l++] = length_modifier;
f[f_l++] = fmt_spec; f[f_l++] = '\0';
if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
else if (fmt_spec == 'd') { /* signed */
switch (length_modifier) {
case '\0':
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break;
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
) {
/* converted to null string */
/* When zero value is formatted with an explicit precision 0,
the resulting formatted string is empty (d, i, u, o, x, X, p). */
} else {
char f[5]; int f_l = 0;
f[f_l++] = '%'; /* construct a simple format string for sprintf */
if (!length_modifier) { }
else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
else f[f_l++] = length_modifier;
f[f_l++] = fmt_spec; f[f_l++] = '\0';
if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
else if (fmt_spec == 'd') { /* signed */
switch (length_modifier) {
case '\0':
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break;
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
#endif
}
} else { /* unsigned */
switch (length_modifier) {
case '\0':
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break;
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg); break;
#endif
}
}
} else { /* unsigned */
switch (length_modifier) {
case '\0':
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break;
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
#endif
/* include the optional minus sign and possible "0x"
in the region before the zero padding insertion point */
if (zero_padding_insertion_ind < str_arg_l &&
tmp[zero_padding_insertion_ind] == '-') {
zero_padding_insertion_ind++;
}
if (zero_padding_insertion_ind+1 < str_arg_l &&
tmp[zero_padding_insertion_ind] == '0' &&
(tmp[zero_padding_insertion_ind+1] == 'x' ||
tmp[zero_padding_insertion_ind+1] == 'X') ) {
zero_padding_insertion_ind += 2;
}
}
/* include the optional minus sign and possible "0x"
in the region before the zero padding insertion point */
if (zero_padding_insertion_ind < str_arg_l &&
tmp[zero_padding_insertion_ind] == '-') {
zero_padding_insertion_ind++;
}
if (zero_padding_insertion_ind+1 < str_arg_l &&
tmp[zero_padding_insertion_ind] == '0' &&
(tmp[zero_padding_insertion_ind+1] == 'x' ||
tmp[zero_padding_insertion_ind+1] == 'X') ) {
zero_padding_insertion_ind += 2;
}
}
{ size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
if (alternate_form && fmt_spec == 'o'
{ size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
if (alternate_form && fmt_spec == 'o'
#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */
&& (str_arg_l > 0)
&& (str_arg_l > 0)
#endif
#ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */
#else
/* unless zero is already the first character */
&& !(zero_padding_insertion_ind < str_arg_l
&& tmp[zero_padding_insertion_ind] == '0')
/* unless zero is already the first character */
&& !(zero_padding_insertion_ind < str_arg_l
&& tmp[zero_padding_insertion_ind] == '0')
#endif
) { /* assure leading zero for alternate-form octal numbers */
if (!precision_specified || precision < num_of_digits+1) {
/* precision is increased to force the first character to be zero,
except if a zero value is formatted with an explicit precision
of zero */
precision = num_of_digits+1; precision_specified = 1;
) { /* assure leading zero for alternate-form octal numbers */
if (!precision_specified || precision < num_of_digits+1) {
/* precision is increased to force the first character to be zero,
except if a zero value is formatted with an explicit precision
of zero */
precision = num_of_digits+1; precision_specified = 1;
}
}
/* zero padding to specified precision? */
if (num_of_digits < precision)
number_of_zeros_to_pad = precision - num_of_digits; }
/* zero padding to specified minimal field width? */
if (!justify_left && zero_padding) {
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) number_of_zeros_to_pad += n;
}
/* zero padding to specified precision? */
if (num_of_digits < precision)
number_of_zeros_to_pad = precision - num_of_digits;
break;
}
/* zero padding to specified minimal field width? */
if (!justify_left && zero_padding) {
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) number_of_zeros_to_pad += n;
}
break;
}
default: /* unrecognized conversion specifier, keep format string as-is*/
zero_padding = 0; /* turn zero padding off for non-numeric convers. */
default: /* unrecognized conversion specifier, keep format string as-is*/
zero_padding = 0; /* turn zero padding off for non-numeric convers. */
#ifndef DIGITAL_UNIX_COMPATIBLE
justify_left = 1; min_field_width = 0; /* reset flags */
justify_left = 1; min_field_width = 0; /* reset flags */
#endif
#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
/* keep the entire format string unchanged */
str_arg = starting_p; str_arg_l = p - starting_p;
/* well, not exactly so for Linux, which does something inbetween,
* and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */
/* keep the entire format string unchanged */
str_arg = starting_p; str_arg_l = p - starting_p;
/* well, not exactly so for Linux, which does something inbetween,
* and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */
#else
/* discard the unrecognized conversion, just keep *
* the unrecognized conversion character */
str_arg = p; str_arg_l = 0;
/* discard the unrecognized conversion, just keep *
* the unrecognized conversion character */
str_arg = p; str_arg_l = 0;
#endif
if (*p) str_arg_l++; /* include invalid conversion specifier unchanged
if not at end-of-string */
break;
if (*p) str_arg_l++; /* include invalid conversion specifier unchanged
if not at end-of-string */
break;
}
if (*p) p++; /* step over the just processed conversion specifier */
/* insert padding to the left as requested by min_field_width;
this does not include the zero padding in case of numerical conversions*/
/* insert padding to the left as requested by min_field_width;
this does not include the zero padding in case of numerical conversions*/
if (!justify_left) { /* left padding with blank or zero */
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
fast_memset(str+str_l, (zero_padding ? '0' : ' '), (n>avail ? avail : n));
}
str_l += n;
}
}
/* zero padding as requested by the precision or by the minimal field width
* for numeric conversions required? */
/* zero padding as requested by the precision or by the minimal field width
* for numeric conversions required? */
if (number_of_zeros_to_pad <= 0) {
/* will not copy first part of numeric right now, *
* force it to be copied later in its entirety */
/* will not copy first part of numeric right now, *
* force it to be copied later in its entirety */
zero_padding_insertion_ind = 0;
} else {
/* insert first part of numerics (sign or '0x') before zero padding */
/* insert first part of numerics (sign or '0x') before zero padding */
int n = zero_padding_insertion_ind;
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
fast_memcpy(str+str_l, str_arg, (n>avail ? avail : n));
}
str_l += n;
}
/* insert zero padding as requested by the precision or min field width */
/* insert zero padding as requested by the precision or min field width */
n = number_of_zeros_to_pad;
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memset(str+str_l, '0', (n>avail?avail:n));
fast_memset(str+str_l, '0', (n>avail ? avail : n));
}
str_l += n;
}
}
/* insert formatted string
* (or as-is conversion specifier for unknown conversions) */
/* insert formatted string
* (or as-is conversion specifier for unknown conversions) */
{ int n = str_arg_l - zero_padding_insertion_ind;
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
(n>avail?avail:n));
(n>avail ? avail : n));
}
str_l += n;
}
}
/* insert right padding */
}}
/* insert right padding */
if (justify_left) { /* right blank padding to the field width */
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memset(str+str_l, ' ', (n>avail?avail:n));
fast_memset(str+str_l, ' ', (n>avail ? avail : n));
}
str_l += n;
}
@ -829,7 +822,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
#endif
#endif /* ndef HAVE_SNPRINTF */
/*
Local Variables:
tab-width: 3
end:
*/
Local Variables:
tab-width: 3
end:
*/

View File

@ -1,23 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/** This module implements AARP, a necessary protocol for ELAP communication. **/
@ -38,10 +24,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct amt_entry_t
{
struct at_addr_t protocol;
struct ether_addr_t hardware;
struct at_addr_t protocol;
struct ether_addr_t hardware;
struct amt_entry_t* next;
struct amt_entry_t* next;
};
typedef struct amt_entry_t* amt_t;
@ -52,253 +38,237 @@ static unsigned int retry_count;
static clock_t retry_timer;
void aarp_init()
{
aarp_retry_reset();
void aarp_init() {
aarp_retry_reset();
}
void aarp_shutdown()
{
struct amt_entry_t* entry = amt;
while (entry)
{
struct amt_entry_t* next = entry->next;
free(entry);
entry = next;
}
void aarp_shutdown() {
struct amt_entry_t* entry = amt;
while (entry)
{
struct amt_entry_t* next = entry->next;
free(entry);
entry = next;
}
}
////
static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr)
{
if (source_at_addr && dest_at_addr && dest_hw_addr)
{
struct aarp_header_t response;
response.hardware_type = htons(AARP_HARDWARE_ETHER);
response.protocol_type = htons(AARP_PROTOCOL_TYPE);
response.hw_addr_len = AARP_HW_ADDR_LEN;
response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN;
response.function = htons(function);
static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr) {
if (source_at_addr && dest_at_addr && dest_hw_addr)
{
struct aarp_header_t response;
response.hardware_type = htons(AARP_HARDWARE_ETHER);
response.protocol_type = htons(AARP_PROTOCOL_TYPE);
response.hw_addr_len = AARP_HW_ADDR_LEN;
response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN;
response.function = htons(function);
memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr));
response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network);
response.source_proto_addr.zero = 0x00;
memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr));
response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network);
response.source_proto_addr.zero = 0x00;
memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr));
response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network);
response.dest_proto_addr.zero = 0x00;
memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr));
response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network);
response.dest_proto_addr.zero = 0x00;
memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac));
memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac));
memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac));
memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac));
if (dest_hw_addr == &HW_ZERO)
elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
else
elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
}
if (dest_hw_addr == &HW_ZERO)
elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
else
elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
}
}
void aarp_probe(const struct at_addr_t* addr)
{
if (addr)
{
aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO);
}
void aarp_probe(const struct at_addr_t* addr) {
if (addr)
{
aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO);
}
}
static void aarp_request(const struct at_addr_t* addr)
{
if (addr)
{
aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO);
}
static void aarp_request(const struct at_addr_t* addr) {
if (addr)
{
aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO);
}
}
////
static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware)
{
if (hardware)
{
struct amt_entry_t* entry = amt;
while (entry)
{
if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0)
return entry;
entry = entry->next;
}
}
return 0;
static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware) {
if (hardware)
{
struct amt_entry_t* entry = amt;
while (entry)
{
if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0)
return entry;
entry = entry->next;
}
}
return 0;
}
static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol)
{
if (protocol)
{
struct amt_entry_t* entry = amt;
while (entry)
{
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
return entry;
entry = entry->next;
}
}
return 0;
static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol) {
if (protocol)
{
struct amt_entry_t* entry = amt;
while (entry)
{
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
return entry;
entry = entry->next;
}
}
return 0;
}
static void amt_delete_entry_protocol(const struct at_addr_t* protocol)
{
if (protocol)
{
struct amt_entry_t* entry = amt;
struct amt_entry_t* previous = amt;
while (entry)
{
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
{
previous->next = entry->next;
free(entry);
break;
}
previous = entry;
entry = entry->next;
}
}
static void amt_delete_entry_protocol(const struct at_addr_t* protocol) {
if (protocol)
{
struct amt_entry_t* entry = amt;
struct amt_entry_t* previous = amt;
while (entry)
{
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
{
previous->next = entry->next;
free(entry);
break;
}
previous = entry;
entry = entry->next;
}
}
}
static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware)
{
// Does an entry matching one of the protocol or hardware addresses exist? If so, update it.
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
if (entry)
{
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
return;
}
static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) {
// Does an entry matching one of the protocol or hardware addresses exist? If so, update it.
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
if (entry)
{
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
return;
}
entry = amt_lookup_entry_hardware(hardware);
if (entry)
{
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
return;
}
entry = amt_lookup_entry_hardware(hardware);
if (entry)
{
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
return;
}
// Otherwise, add a new entry.
entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t));
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
entry->next = amt;
amt = entry;
// Otherwise, add a new entry.
entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t));
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
entry->next = amt;
amt = entry;
}
const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol)
{
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
if (entry)
{
aarp_retry_reset();
return (const struct ether_addr_t*)&entry->hardware;
}
else
{
// The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period.
if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) &&
(retry_count > 0))
{
aarp_request(protocol);
retry_count--;
retry_timer = clock();
//atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer);
}
const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol) {
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
if (entry)
{
aarp_retry_reset();
return (const struct ether_addr_t*)&entry->hardware;
}
else
{
// The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period.
if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) &&
(retry_count > 0))
{
aarp_request(protocol);
return 0;
}
retry_count--;
retry_timer = clock();
//atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer);
}
return 0;
}
}
const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware)
{
struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware);
if (entry)
return (const struct at_addr_t*)&entry->protocol;
else
return 0;
const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware) {
struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware);
if (entry)
return (const struct at_addr_t*)&entry->protocol;
else
return 0;
}
bool aarp_retry()
{
return retry_count > 0;
bool aarp_retry() {
return retry_count > 0;
}
void aarp_retry_reset()
{
retry_count = AARP_REQUEST_COUNT;
retry_timer = clock();
void aarp_retry_reset() {
retry_count = AARP_REQUEST_COUNT;
retry_timer = clock();
}
void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware)
{
amt_add(protocol, hardware);
void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) {
amt_add(protocol, hardware);
}
bool aarp_address_used(const struct at_addr_t* protocol)
{
// reference 2-8
if (protocol)
{
// Check for reserved node numbers, per reference 3-9.
if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff)
return true;
bool aarp_address_used(const struct at_addr_t* protocol) {
// reference 2-8
if (protocol)
{
// Check for reserved node numbers, per reference 3-9.
if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff)
return true;
// Look for the address in the AMT. If it's there, another node is using this address.
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
if (entry)
return true;
// Look for the address in the AMT. If it's there, another node is using this address.
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
if (entry)
return true;
// Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet.
// Return true to advise the caller that the address is not known to be in use. The caller should
// retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT),
// per the AARP protocol definition, before choosing this address.
aarp_probe(protocol);
return false;
}
return false;
// Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet.
// Return true to advise the caller that the address is not known to be in use. The caller should
// retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT),
// per the AARP protocol definition, before choosing this address.
aarp_probe(protocol);
return false;
}
return false;
}
////
void aarp_handle_packet(const struct aarp_header_t* aarp)
{
if (aarp &&
aarp->hardware_type == AARP_HARDWARE_ETHER &&
aarp->protocol_type == AARP_PROTOCOL_TYPE &&
aarp->hw_addr_len == AARP_HW_ADDR_LEN &&
aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN)
{
switch (aarp->function)
{
case AARP_FUNCTION_REQUEST:
if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) ||
(aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) &&
(aarp->dest_proto_addr.addr.node == atbridge_get_node()))
{
// Generate a response for the AARP request.
aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr);
}
break;
case AARP_FUNCTION_RESPONSE:
aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr);
aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr);
break;
case AARP_FUNCTION_PROBE:
// AMT entry aging, method 2, reference 2-11
amt_delete_entry_protocol(&aarp->dest_proto_addr.addr);
break;
default:
break;
}
}
void aarp_handle_packet(const struct aarp_header_t* aarp) {
if (aarp &&
aarp->hardware_type == AARP_HARDWARE_ETHER &&
aarp->protocol_type == AARP_PROTOCOL_TYPE &&
aarp->hw_addr_len == AARP_HW_ADDR_LEN &&
aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN)
{
switch (aarp->function)
{
case AARP_FUNCTION_REQUEST:
if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) ||
(aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) &&
(aarp->dest_proto_addr.addr.node == atbridge_get_node()))
{
// Generate a response for the AARP request.
aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr);
}
break;
case AARP_FUNCTION_RESPONSE:
aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr);
aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr);
break;
case AARP_FUNCTION_PROBE:
// AMT entry aging, method 2, reference 2-11
amt_delete_entry_protocol(&aarp->dest_proto_addr.addr);
break;
default:
break;
}
}
}

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
struct at_addr_t;

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
typedef byte at_node_t;

View File

@ -1,23 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/** This module is the "heart" of the bridge and provides the connection between the ELAP and LLAP ports. **/
@ -51,378 +37,357 @@ static const at_node_t NODE_STARTUP_HIGH = 0xFE;
static void send_rtmp_request();
bool atbridge_init()
{
// If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT.
if (local_address.network == 0)
{
// Obtain a provisional node address and startup range network.
//
// This isn't correct for an extended network (like ELAP) but works adequately on small networks.
// The bridge should follow the complicated process on page 4-9 to obtain the network and node number.
srand((unsigned int)time(0));
local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW);
local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01);
bool atbridge_init() {
// If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT.
if (local_address.network == 0)
{
// Obtain a provisional node address and startup range network.
//
// This isn't correct for an extended network (like ELAP) but works adequately on small networks.
// The bridge should follow the complicated process on page 4-9 to obtain the network and node number.
srand((unsigned int)time(0));
local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW);
local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01);
aarp_init();
llap_init();
if (!elap_init())
{
atbridge_shutdown();
return false;
}
}
return true;
aarp_init();
llap_init();
if (!elap_init())
{
atbridge_shutdown();
return false;
}
}
return true;
}
void atbridge_shutdown()
{
llap_shutdown();
elap_shutdown();
aarp_shutdown();
void atbridge_shutdown() {
llap_shutdown();
elap_shutdown();
aarp_shutdown();
}
void atbridge_set_diagnostics(bool enabled)
{
diagnostics = enabled;
void atbridge_set_diagnostics(bool enabled) {
diagnostics = enabled;
}
bool atbridge_get_diagnostics()
{
return diagnostics;
bool atbridge_get_diagnostics() {
return diagnostics;
}
void atbridge_printf(const char *fmt, ...)
{
if (atbridge_get_diagnostics())
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
void atbridge_printf(const char *fmt, ...) {
if (atbridge_get_diagnostics())
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
}
const struct at_addr_t* atbridge_get_addr()
{
return &local_address;
const struct at_addr_t* atbridge_get_addr() {
return &local_address;
}
const at_network_t atbridge_get_net()
{
return local_address.network;
const at_network_t atbridge_get_net() {
return local_address.network;
}
const at_node_t atbridge_get_node()
{
return local_address.node;
const at_node_t atbridge_get_node() {
return local_address.node;
}
void atbridge_set_net(at_network_t net)
{
local_address.network = net;
void atbridge_set_net(at_network_t net) {
local_address.network = net;
}
void atbridge_set_node(at_node_t node)
{
local_address.node = node;
void atbridge_set_node(at_node_t node) {
local_address.node = node;
}
bool atbridge_address_used(const struct at_addr_t* addr)
{
if (!sent_rtmp_request)
send_rtmp_request();
return aarp_address_used(addr);
bool atbridge_address_used(const struct at_addr_t* addr) {
if (!sent_rtmp_request)
send_rtmp_request();
return aarp_address_used(addr);
}
/* Calculate a DDP checksum, per Apple's documented algorithm in 4-17 of "Inside AppleTalk". */
static word16 get_checksum(size_t size, byte data[])
{
word16 cksum = 0;
for (unsigned int i = 0; i < size; i++)
{
cksum += data[i];
cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left
}
if (cksum == 0)
cksum = 0xffff;
return cksum;
static word16 get_checksum(size_t size, byte data[]) {
word16 cksum = 0;
for (unsigned int i = 0; i < size; i++)
{
cksum += data[i];
cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left
}
if (cksum == 0)
cksum = 0xffff;
return cksum;
}
static void calculate_checksum(struct packet_t* packet)
{
if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG))
{
struct DDP_LONG* header = (struct DDP_LONG*)(packet->data);
header->checksum = htons(get_checksum(
packet->size - offsetof(struct DDP_LONG, dest_net),
(byte*)&header->dest_net));
}
static void calculate_checksum(struct packet_t* packet) {
if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG))
{
struct DDP_LONG* header = (struct DDP_LONG*)(packet->data);
header->checksum = htons(get_checksum(
packet->size - offsetof(struct DDP_LONG, dest_net),
(byte*)&header->dest_net));
}
}
/* Convert a long-form DDP header to a short-form header. This function only converts the headers. */
static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out)
{
word16 size;
static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out) {
word16 size;
if (!in || !out)
return 0;
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
if (!in || !out)
return 0;
out->length[0] = (size >> 8) & 0x03;
out->length[1] = size & 0xff;
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
out->dest_socket = in->dest_socket;
out->source_socket = in->source_socket;
out->type = in->type;
out->length[0] = (size >> 8) & 0x03;
out->length[1] = size & 0xff;
return size;
out->dest_socket = in->dest_socket;
out->source_socket = in->source_socket;
out->type = in->type;
return size;
}
/* Convert a short-form DDP header to a long-form header. ELAP requires long-form, but LLAP often uses short-form. */
/* This function only converts the headers. */
static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out)
{
word16 size;
static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out) {
word16 size;
if (!in || !out)
return 0;
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
out->length[0] = (size >> 8) & 0x03;
out->length[1] = size & 0xff;
out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */
if (dest.network)
out->dest_net = dest.network;
else
out->dest_net = atbridge_get_net();
out->dest_net = (at_network_t)htons(out->dest_net);
if (!in || !out)
return 0;
if (source.network)
out->source_net = source.network;
else
out->source_net = atbridge_get_net();
out->source_net = (at_network_t)htons(out->source_net);
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
out->length[0] = (size >> 8) & 0x03;
out->length[1] = size & 0xff;
out->dest_node = dest.node;
out->source_node = source.node;
out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */
out->dest_socket = in->dest_socket;
out->source_socket = in->source_socket;
if (dest.network)
out->dest_net = dest.network;
else
out->dest_net = atbridge_get_net();
out->dest_net = (at_network_t)htons(out->dest_net);
out->type = in->type;
if (source.network)
out->source_net = source.network;
else
out->source_net = atbridge_get_net();
out->source_net = (at_network_t)htons(out->source_net);
return size;
out->dest_node = dest.node;
out->source_node = source.node;
out->dest_socket = in->dest_socket;
out->source_socket = in->source_socket;
out->type = in->type;
return size;
}
/* Convert a short-form DDP packet to a long-form packet. */
/* This function converts an entire packet, not just the header. */
static void convert_ddp_packet_to_long(struct packet_t* packet)
{
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT)))
{
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
static void convert_ddp_packet_to_long(struct packet_t* packet) {
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT)))
{
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
const size_t payload_size = packet->size - sizeof(struct DDP_SHORT);
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG));
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
const size_t payload_size = packet->size - sizeof(struct DDP_SHORT);
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG));
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
packet->dest.network = ntohs(header_long->dest_net);
packet->source.network = ntohs(header_long->source_net);
const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
packet->dest.network = ntohs(header_long->dest_net);
packet->source.network = ntohs(header_long->source_net);
memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size);
memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size);
packet->type = LAP_DDP_LONG;
packet->size = size;
packet->type = LAP_DDP_LONG;
packet->size = size;
// Replace the original short-form packet data.
free(packet->data);
packet->data = data;
// Replace the original short-form packet data.
free(packet->data);
packet->data = data;
calculate_checksum(packet);
}
calculate_checksum(packet);
}
}
/* Convert a long-form DDP packet to short-form. */
static void convert_ddp_packet_to_short(struct packet_t* packet)
{
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
{
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
static void convert_ddp_packet_to_short(struct packet_t* packet) {
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
{
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
const size_t payload_size = packet->size - sizeof(struct DDP_LONG);
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT));
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
const size_t payload_size = packet->size - sizeof(struct DDP_LONG);
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT));
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
const word16 size = convert_ddp_header_to_short(header_long, header_short);
const word16 size = convert_ddp_header_to_short(header_long, header_short);
memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size);
memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size);
packet->type = LAP_DDP_SHORT;
packet->size = size;
packet->type = LAP_DDP_SHORT;
packet->size = size;
free(packet->data);
packet->data = data;
}
free(packet->data);
packet->data = data;
}
}
/*static void convert_rtmp_to_extended(struct packet_t* packet)
{
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data)
{
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP)
return;
{
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data)
{
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP)
return;
struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT));
struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT));
// Construct a new long-form DDP packet header.
size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t);
byte* data = (byte*)malloc(size);
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG));
out->net = in->net;
out->id_length = in->id_length;
out->node = in->node;
// Construct a new long-form DDP packet header.
size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t);
byte* data = (byte*)malloc(size);
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
// Copy the routing tuples.
struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t));
struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size);
while ((byte*)in_tuple < (packet->data + packet->size))
{
size += sizeof(struct rtmp_extended_tuple_t);
realloc(data, size);
out_tuple->range_start = in_tuple->net;
out_tuple->distance = in_tuple->distance | 0x80;
out_tuple->range_end = in_tuple->net;
out_tuple->delimiter = RTMP_TUPLE_DELIMITER;
in_tuple++;
}
struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG));
out->net = in->net;
out->id_length = in->id_length;
out->node = in->node;
free(packet->data);
packet->data = data;
packet->size = size;
packet->type = LAP_DDP_LONG;
}
}*/
// Copy the routing tuples.
struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t));
struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size);
while ((byte*)in_tuple < (packet->data + packet->size))
{
size += sizeof(struct rtmp_extended_tuple_t);
realloc(data, size);
out_tuple->range_start = in_tuple->net;
out_tuple->distance = in_tuple->distance | 0x80;
out_tuple->range_end = in_tuple->net;
out_tuple->delimiter = RTMP_TUPLE_DELIMITER;
in_tuple++;
}
static void convert_rtmp_to_nonextended(struct packet_t* packet)
{
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
{
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
return;
free(packet->data);
packet->data = data;
packet->size = size;
packet->type = LAP_DDP_LONG;
}
}*/
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
static void convert_rtmp_to_nonextended(struct packet_t* packet) {
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
{
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
return;
size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t);
byte* data = (byte*)malloc(size);
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
convert_ddp_header_to_short(header_long, header_short);
header_short->length[0] = (size >> 8) & 0x03;
header_short->length[1] = size & 0xff;
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT));
out->net = in->net;
out->id_length = in->id_length;
out->node = in->node;
size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t);
byte* data = (byte*)malloc(size);
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
convert_ddp_header_to_short(header_long, header_short);
header_short->length[0] = (size >> 8) & 0x03;
header_short->length[1] = size & 0xff;
/*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t));
rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size);
while ((byte*)in_tuple < (packet->data + packet->size))
{
size += sizeof(rtmp_nonextended_tuple_t);
realloc(data, size);
out_tuple->net = in_tuple->range_start;
out_tuple->distance = in_tuple->distance & 0x7f;
in_tuple++;
}*/
struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT));
out->net = in->net;
out->id_length = in->id_length;
out->node = in->node;
free(packet->data);
packet->data = data;
packet->size = size;
packet->type = LAP_DDP_SHORT;
}
/*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t));
rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size);
while ((byte*)in_tuple < (packet->data + packet->size))
{
size += sizeof(rtmp_nonextended_tuple_t);
realloc(data, size);
out_tuple->net = in_tuple->range_start;
out_tuple->distance = in_tuple->distance & 0x7f;
in_tuple++;
}*/
free(packet->data);
packet->data = data;
packet->size = size;
packet->type = LAP_DDP_SHORT;
}
}
/* Learn our network number from RTMP packets. */
/* "Inside AppleTalk", section 4-8, describes this approach for non-extended networks.
Technically, we probably should be doing the more complicated extended network approach (also on 4-8),
but the easy approach using RTMP seems adequate for now. */
static void glean_net_from_rtmp(struct packet_t* packet)
{
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
{
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
return;
static void glean_net_from_rtmp(struct packet_t* packet) {
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
{
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
return;
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
atbridge_set_net(ntohs(in->net));
}
atbridge_set_net(ntohs(in->net));
}
}
static void send_rtmp_request()
{
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
packet->type = LAP_DDP_LONG;
packet->dest.network = atbridge_get_net();
packet->dest.node = 255;
packet->source.network = atbridge_get_net();
packet->source.node = atbridge_get_node();
packet->next = 0;
packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t);
packet->data = (byte*)malloc(packet->size);
static void send_rtmp_request() {
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
struct DDP_LONG* header = (struct DDP_LONG*)packet->data;
header->type = DDP_TYPE_RTMP_REQUEST;
header->source_net = htons(packet->source.network);
header->source_node = packet->source.node;
header->source_socket = DDP_SOCKET_RTMP;
header->dest_net = htons(packet->dest.network);
header->dest_node = packet->dest.node;
header->dest_socket = DDP_SOCKET_RTMP;
header->length[0] = (packet->size >> 8) & 0x03;
header->length[1] = packet->size & 0xff;
packet->type = LAP_DDP_LONG;
packet->dest.network = atbridge_get_net();
packet->dest.node = 255;
packet->source.network = atbridge_get_net();
packet->source.node = atbridge_get_node();
packet->next = 0;
packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t);
packet->data = (byte*)malloc(packet->size);
struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG));
request->function = RTMP_FUNCTION_REQUEST;
struct DDP_LONG* header = (struct DDP_LONG*)packet->data;
header->type = DDP_TYPE_RTMP_REQUEST;
header->source_net = htons(packet->source.network);
header->source_node = packet->source.node;
header->source_socket = DDP_SOCKET_RTMP;
header->dest_net = htons(packet->dest.network);
header->dest_node = packet->dest.node;
header->dest_socket = DDP_SOCKET_RTMP;
header->length[0] = (packet->size >> 8) & 0x03;
header->length[1] = packet->size & 0xff;
calculate_checksum(packet);
elap_enqueue_out(packet);
sent_rtmp_request = true;
struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG));
request->function = RTMP_FUNCTION_REQUEST;
calculate_checksum(packet);
elap_enqueue_out(packet);
sent_rtmp_request = true;
}
void atbridge_process()
{
elap_process();
//llap_process();
struct packet_t* packet = elap_dequeue_in();
if (packet)
{
glean_net_from_rtmp(packet);
convert_rtmp_to_nonextended(packet);
// The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process).
convert_ddp_packet_to_short(packet);
llap_enqueue_out(packet);
}
packet = llap_dequeue_in();
if (packet)
{
// ELAP does not support short-form DDP, so convert such packets to long-form.
convert_ddp_packet_to_long(packet);
elap_enqueue_out(packet);
}
void atbridge_process() {
elap_process();
//llap_process();
struct packet_t* packet = elap_dequeue_in();
if (packet)
{
glean_net_from_rtmp(packet);
convert_rtmp_to_nonextended(packet);
// The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process).
convert_ddp_packet_to_short(packet);
llap_enqueue_out(packet);
}
packet = llap_dequeue_in();
if (packet)
{
// ELAP does not support short-form DDP, so convert such packets to long-form.
convert_ddp_packet_to_long(packet);
elap_enqueue_out(packet);
}
}

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/**
@ -46,4 +32,3 @@ const at_node_t atbridge_get_node();
void atbridge_set_net(at_network_t net);
void atbridge_set_node(at_node_t node);
bool atbridge_address_used(const struct at_addr_t* addr);

View File

@ -1,23 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/** This module implements the ELAP port of the bridge. **/
@ -51,350 +37,338 @@ static struct packet_port_t elap_port;
static struct ether_addr_t HW_LOCAL;
/*static void dump_device_list(pcap_if_t* devices)
{
int i = 0;
for(pcap_if_t* device = devices; device; device = device->next)
{
printf("%d. %s", ++i, device->name);
if (device->description)
printf(" (%s)\n", device->description);
else
printf(" (No description available)\n");
}
}*/
{
int i = 0;
for(pcap_if_t* device = devices; device; device = device->next)
{
printf("%d. %s", ++i, device->name);
if (device->description)
printf(" (%s)\n", device->description);
else
printf(" (No description available)\n");
}
}*/
static void elap_clone_host_mac(pcap_if_t* device)
{
if (!device)
return;
static void elap_clone_host_mac(pcap_if_t* device) {
if (!device)
return;
#ifdef WIN32
////
// Extract the device GUID, which Windows uses to identify the device.
char* name = device->name;
while (name && *name != '{')
name++;
size_t guidLen = strlen(name);
////
// Extract the device GUID, which Windows uses to identify the device.
char* name = device->name;
while (name && *name != '{')
name++;
size_t guidLen = strlen(name);
////
// Find and copy the device MAC address.
ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15;
IP_ADAPTER_ADDRESSES* addresses = malloc(size);
ULONG result = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
if (result == ERROR_BUFFER_OVERFLOW)
{
// The addresses buffer is too small. Allocate a bigger buffer.
free(addresses);
addresses = malloc(size);
result = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
}
////
// Find and copy the device MAC address.
ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15;
IP_ADAPTER_ADDRESSES* addresses = malloc(size);
if (result == NO_ERROR)
{
// Search for the desired adapter address.
IP_ADAPTER_ADDRESSES* current = addresses;
while (current)
{
if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0)
{
memcpy(&HW_LOCAL.mac, &current->PhysicalAddress, sizeof(HW_LOCAL.mac));
break;
}
current = current->Next;
}
}
else
{
halt_printf("ATBridge: Failed to find host MAC address (%d).", result);
}
ULONG result = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
free(addresses);
if (result == ERROR_BUFFER_OVERFLOW)
{
// The addresses buffer is too small. Allocate a bigger buffer.
free(addresses);
addresses = malloc(size);
result = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
}
if (result == NO_ERROR)
{
// Search for the desired adapter address.
IP_ADAPTER_ADDRESSES* current = addresses;
while (current)
{
if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0)
{
memcpy(&HW_LOCAL.mac, &current->PhysicalAddress, sizeof(HW_LOCAL.mac));
break;
}
current = current->Next;
}
}
else
{
halt_printf("ATBridge: Failed to find host MAC address (%d).", result);
}
free(addresses);
#else
#ifdef AF_PACKET
struct pcap_addr* address;
for (address = device->addresses; address != 0; address = address->next)
if (address->addr->sa_family == AF_PACKET)
{
struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr;
memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac));
}
struct pcap_addr* address;
for (address = device->addresses; address != 0; address = address->next)
if (address->addr->sa_family == AF_PACKET)
{
struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr;
memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac));
}
#endif
#endif
}
const struct ether_addr_t* elap_get_mac()
{
return &HW_LOCAL;
const struct ether_addr_t* elap_get_mac() {
return &HW_LOCAL;
}
bool elap_init()
{
port_init(&elap_port);
bool elap_init() {
port_init(&elap_port);
memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL));
memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL));
pcap_if_t* device;
pcap_if_t* alldevs;
int i = 0;
char errbuf[PCAP_ERRBUF_SIZE];
// Load the PCAP library.
if (!pcapdelay_load())
{
halt_printf("ATBridge: PCAP not available.\n");
return false;
}
pcap_if_t* device;
pcap_if_t* alldevs;
int i = 0;
// Retrieve the device list.
if(pcapdelay_findalldevs(&alldevs, errbuf) == -1)
{
atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf);
return false;
}
//dump_device_list(alldevs);
char errbuf[PCAP_ERRBUF_SIZE];
// Jump to the selected adapter.
for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++);
if (!device)
{
halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n");
return false;
}
// Load the PCAP library.
if (!pcapdelay_load())
{
halt_printf("ATBridge: PCAP not available.\n");
return false;
}
// Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback
// interface), the interface, even in promiscous mode, filters foreign MAC addresses.
elap_clone_host_mac(device);
// Retrieve the device list.
if(pcapdelay_findalldevs(&alldevs, errbuf) == -1)
{
atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf);
return false;
}
//dump_device_list(alldevs);
// Open the adapter,
if ((pcap_session = pcapdelay_open_live(device->name, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode (nonzero means promiscuous)
1, // read timeout
errbuf // error buffer
)) == NULL)
{
halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name);
pcapdelay_freealldevs(alldevs);
return false;
}
// Jump to the selected adapter.
for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++);
if (!device)
{
halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n");
return false;
}
// The device must support Ethernet because the bridge "speaks" EtherTalk.
if (pcapdelay_datalink(pcap_session) == DLT_EN10MB)
{
pcapdelay_setnonblock(pcap_session, 1, errbuf);
// Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback
// interface), the interface, even in promiscous mode, filters foreign MAC addresses.
elap_clone_host_mac(device);
atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n",
device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]);
pcapdelay_freealldevs(alldevs);
return true;
}
else
{
pcapdelay_close(pcap_session);
pcap_session = 0;
halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description);
pcapdelay_freealldevs(alldevs);
return false;
}
// Open the adapter,
if ((pcap_session = pcapdelay_open_live(device->name, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode (nonzero means promiscuous)
1, // read timeout
errbuf // error buffer
)) == NULL)
{
halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name);
pcapdelay_freealldevs(alldevs);
return false;
}
// The device must support Ethernet because the bridge "speaks" EtherTalk.
if (pcapdelay_datalink(pcap_session) == DLT_EN10MB)
{
pcapdelay_setnonblock(pcap_session, 1, errbuf);
atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n",
device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]);
pcapdelay_freealldevs(alldevs);
return true;
}
else
{
pcapdelay_close(pcap_session);
pcap_session = 0;
halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description);
pcapdelay_freealldevs(alldevs);
return false;
}
}
void elap_shutdown()
{
port_shutdown(&elap_port);
if (pcap_session)
{
pcapdelay_close(pcap_session);
pcap_session = 0;
}
pcapdelay_unload();
void elap_shutdown() {
port_shutdown(&elap_port);
if (pcap_session)
{
pcapdelay_close(pcap_session);
pcap_session = 0;
}
pcapdelay_unload();
}
void elap_enqueue_out(struct packet_t* packet)
{
enqueue_packet(&elap_port.out, packet);
void elap_enqueue_out(struct packet_t* packet) {
enqueue_packet(&elap_port.out, packet);
}
struct packet_t* elap_dequeue_in()
{
return dequeue(&elap_port.in);
struct packet_t* elap_dequeue_in() {
return dequeue(&elap_port.in);
}
void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[])
{
if (pcap_session && dest && discriminator)
{
// Allocate heap space for the frame.
const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size;
u_char* frame_data;
size_t pad = 0;
if (frame_size < ETHER_MIN_SIZE)
pad = ETHER_MIN_SIZE - frame_size;
frame_data = (u_char*)malloc(frame_size + pad);
void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]) {
if (pcap_session && dest && discriminator)
{
// Allocate heap space for the frame.
const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size;
u_char* frame_data;
size_t pad = 0;
if (frame_size < ETHER_MIN_SIZE)
pad = ETHER_MIN_SIZE - frame_size;
frame_data = (u_char*)malloc(frame_size + pad);
// Build the 802.3 header.
struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data;
memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac));
memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac));
ether->length = htons(frame_size - sizeof(struct ethernet_header_t));
// Build the 802.3 header.
struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data;
memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac));
memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac));
ether->length = htons(frame_size - sizeof(struct ethernet_header_t));
// Build the 802.2 header.
struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t));
snap->dsap = SNAP_DSAP;
snap->ssap = SNAP_SSAP;
snap->control = SNAP_CONTROL;
memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator));
// Build the 802.2 header.
struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t));
snap->dsap = SNAP_DSAP;
snap->ssap = SNAP_SSAP;
snap->control = SNAP_CONTROL;
memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator));
// Add the data payload.
struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
memcpy(payload, data, size);
// Add the data payload.
struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
memcpy(payload, data, size);
// Add padding to meet minimum Ethernet frame size.
if (pad > 0)
memset(frame_data + frame_size, 0, pad);
// Add padding to meet minimum Ethernet frame size.
if (pad > 0)
memset(frame_data + frame_size, 0, pad);
pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad);
}
pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad);
}
}
static bool elap_send_one_queued()
{
// Attempt to send one packet out the host network interface.
struct packet_t* packet = queue_peek(&elap_port.out);
if (packet)
{
// Find the MAC address.
const struct ether_addr_t* dest;
if (packet->dest.node == at_broadcast_node)
dest = &HW_APPLETALK_BROADCAST;
else
dest = aarp_request_hardware(&packet->dest);
static bool elap_send_one_queued() {
// Attempt to send one packet out the host network interface.
struct packet_t* packet = queue_peek(&elap_port.out);
if (packet)
{
// Find the MAC address.
const struct ether_addr_t* dest;
if (packet->dest.node == at_broadcast_node)
dest = &HW_APPLETALK_BROADCAST;
else
dest = aarp_request_hardware(&packet->dest);
// Send it.
if (dest)
{
elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data);
// Send it.
if (dest)
{
elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data);
dequeue(&elap_port.out);
free(packet->data);
free(packet);
}
else
{
// AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet.
if (!aarp_retry())
{
// However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on.
atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node);
aarp_retry_reset();
dequeue(&elap_port.out);
free(packet->data);
free(packet);
}
}
return true;
}
else
return false;
dequeue(&elap_port.out);
free(packet->data);
free(packet);
}
else
{
// AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet.
if (!aarp_retry())
{
// However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on.
atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node);
aarp_retry_reset();
dequeue(&elap_port.out);
free(packet->data);
free(packet);
}
}
return true;
}
else
return false;
}
static void elap_send_all_queued()
{
while (elap_send_one_queued());
static void elap_send_all_queued() {
while (elap_send_one_queued());
}
static bool elap_receive_one()
{
if (!pcap_session)
return false;
static bool elap_receive_one() {
if (!pcap_session)
return false;
struct pcap_pkthdr header;
const u_char* packet = pcapdelay_next(pcap_session, &header);
if (packet)
{
// Receive and process one packet from the host network interface.
////
struct pcap_pkthdr header;
const u_char* packet = pcapdelay_next(pcap_session, &header);
if (packet)
{
// Receive and process one packet from the host network interface.
////
// Check the Ethernet 802.3 header.
const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet;
if (header.len > sizeof(struct ethernet_header_t) &&
ntohs(ether->length) <= ETHER_MAX_SIZE &&
ntohs(ether->length) > sizeof(struct snap_header_t) &&
(memcmp(&ether->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */
(memcmp(&ether->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */
memcmp(&ether->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */)
)
{
// Check the 802.2 SNAP header.
const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t));
if (snap->dsap == SNAP_DSAP &&
snap->ssap == SNAP_SSAP &&
snap->control == SNAP_CONTROL)
{
if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0)
{
// Handle an AppleTalk packet.
const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t);
const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t);
// Check the Ethernet 802.3 header.
const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet;
if (header.len > sizeof(struct ethernet_header_t) &&
ntohs(ether->length) <= ETHER_MAX_SIZE &&
ntohs(ether->length) > sizeof(struct snap_header_t) &&
(memcmp(&ether->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */
(memcmp(&ether->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */
memcmp(&ether->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */)
)
{
// Check the 802.2 SNAP header.
const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t));
if (snap->dsap == SNAP_DSAP &&
snap->ssap == SNAP_SSAP &&
snap->control == SNAP_CONTROL)
{
if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0)
{
// Handle an AppleTalk packet.
const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t);
const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t);
byte* copy = (byte*)malloc(payload_size);
memcpy(copy, payload, payload_size);
byte* copy = (byte*)malloc(payload_size);
memcpy(copy, payload, payload_size);
// ELAP does not support short-form DDP, so this must be a long-form DDP packet.
struct at_addr_t source, dest;
if (payload_size >= sizeof(struct DDP_LONG))
{
// Extract the protocol address from the header.
//
// ELAP really shouldn't be looking at the header for the next level of the protocol stack,
// but this is a convenient place to glean addresses for the AMT, a process that needs both
// hardware and protocol addresses.
struct DDP_LONG* header = (struct DDP_LONG*)copy;
dest.network = (at_network_t)ntohs(header->dest_net);
source.network = (at_network_t)ntohs(header->source_net);
dest.node = header->dest_node;
source.node = header->source_node;
// ELAP does not support short-form DDP, so this must be a long-form DDP packet.
struct at_addr_t source, dest;
if (payload_size >= sizeof(struct DDP_LONG))
{
// Extract the protocol address from the header.
//
// ELAP really shouldn't be looking at the header for the next level of the protocol stack,
// but this is a convenient place to glean addresses for the AMT, a process that needs both
// hardware and protocol addresses.
struct DDP_LONG* header = (struct DDP_LONG*)copy;
dest.network = (at_network_t)ntohs(header->dest_net);
source.network = (at_network_t)ntohs(header->source_net);
dest.node = header->dest_node;
source.node = header->source_node;
enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy);
enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy);
aarp_glean(&source, &ether->source);
}
else
atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n");
}
else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0)
{
// Handle an AARP packet.
struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network);
aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network);
aarp->function = ntohs(aarp->function);
aarp->hardware_type = ntohs(aarp->hardware_type);
aarp->protocol_type = ntohs(aarp->protocol_type);
aarp_handle_packet(aarp);
}
}
}
aarp_glean(&source, &ether->source);
}
else
atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n");
}
else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0)
{
// Handle an AARP packet.
struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network);
aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network);
aarp->function = ntohs(aarp->function);
aarp->hardware_type = ntohs(aarp->hardware_type);
aarp->protocol_type = ntohs(aarp->protocol_type);
aarp_handle_packet(aarp);
}
}
}
return true;
}
else
return false;
return true;
}
else
return false;
}
static void elap_receive_all()
{
while (elap_receive_one());
static void elap_receive_all() {
while (elap_receive_one());
}
void elap_process()
{
elap_receive_all();
elap_send_all_queued();
void elap_process() {
elap_receive_all();
elap_send_all_queued();
}

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/** ELAP port of the AppleTalk Bridge **/

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/* Ethernet addresses are 6 bytes */

View File

@ -1,23 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/** This module implements the LLAP port of the bridge. **/
@ -28,12 +14,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "llap.h"
typedef enum {
LLAP_DDP_SHORT = 0x01,
LLAP_DDP_LONG = 0x02,
LLAP_ENQ = 0x81,
LLAP_ACK = 0x82,
LLAP_RTS = 0x84,
LLAP_CTS = 0x85
LLAP_DDP_SHORT = 0x01,
LLAP_DDP_LONG = 0x02,
LLAP_ENQ = 0x81,
LLAP_ACK = 0x82,
LLAP_RTS = 0x84,
LLAP_CTS = 0x85
} LLAP_TYPES;
const unsigned int LLAP_PACKET_MAX = 603 /* bytes */;
@ -45,290 +31,279 @@ const double GAP_TOLERANCE = 4.0;
static struct packet_port_t llap_port;
typedef enum {
DIALOG_READY,
DIALOG_GOT_CTS,
DIALOG_WAIT_IDG
DIALOG_READY,
DIALOG_GOT_CTS,
DIALOG_WAIT_IDG
} DIALOG_STATE;
static DIALOG_STATE dialog_state;
static double dialog_end_dcycs;
static double last_frame_dcycs;
void llap_init()
{
dialog_state = DIALOG_READY;
last_frame_dcycs = 0;
port_init(&llap_port);
void llap_init() {
dialog_state = DIALOG_READY;
last_frame_dcycs = 0;
port_init(&llap_port);
}
void llap_shutdown()
{
port_shutdown(&llap_port);
void llap_shutdown() {
port_shutdown(&llap_port);
}
/** Queue one data packet out from the bridge's LLAP port and into the guest. **/
void llap_enqueue_out(struct packet_t* packet)
{
// Generate the RTS.
struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t));
rts->source.network = packet->source.network;
rts->source.node = packet->source.node;
rts->dest.network = packet->dest.network;
rts->dest.node = packet->dest.node;
rts->size = 0;
rts->data = 0;
rts->type = LLAP_RTS;
enqueue_packet(&llap_port.out, rts);
void llap_enqueue_out(struct packet_t* packet) {
// Generate the RTS.
struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t));
rts->source.network = packet->source.network;
rts->source.node = packet->source.node;
rts->dest.network = packet->dest.network;
rts->dest.node = packet->dest.node;
rts->size = 0;
rts->data = 0;
rts->type = LLAP_RTS;
enqueue_packet(&llap_port.out, rts);
// Enqueue the data.
enqueue_packet(&llap_port.out, packet);
// Enqueue the data.
enqueue_packet(&llap_port.out, packet);
}
struct packet_t* llap_dequeue_in()
{
return dequeue(&llap_port.in);
struct packet_t* llap_dequeue_in() {
return dequeue(&llap_port.in);
}
static void llap_dump_packet(size_t size, byte data[])
{
if (size < LLAP_PACKET_MIN)
atbridge_printf("LLAP short packet.\n");
else if (size > LLAP_PACKET_MAX)
atbridge_printf("LLAP long packet.\n");
else
{
at_node_t dest = data[0];
at_node_t source = data[1];
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
const char* typeName = 0;
switch (type)
{
case LLAP_DDP_SHORT:
typeName = "DDP (short)";
break;
case LLAP_DDP_LONG:
typeName = "DDP (long)";
break;
case LLAP_ENQ:
typeName = "lapENQ";
break;
case LLAP_ACK:
typeName = "lapACK";
break;
case LLAP_RTS:
typeName = "lapRTS";
break;
case LLAP_CTS:
typeName = "lapCTS";
break;
}
static void llap_dump_packet(size_t size, byte data[]) {
if (size < LLAP_PACKET_MIN)
atbridge_printf("LLAP short packet.\n");
else if (size > LLAP_PACKET_MAX)
atbridge_printf("LLAP long packet.\n");
else
{
at_node_t dest = data[0];
at_node_t source = data[1];
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
if (typeName)
atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size);
else
atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size);
/*for (size_t i = 0; i < size; i++)
atbridge_printf("%02x ", data[i]);
atbridge_printf("\n");*/
}
const char* typeName = 0;
switch (type)
{
case LLAP_DDP_SHORT:
typeName = "DDP (short)";
break;
case LLAP_DDP_LONG:
typeName = "DDP (long)";
break;
case LLAP_ENQ:
typeName = "lapENQ";
break;
case LLAP_ACK:
typeName = "lapACK";
break;
case LLAP_RTS:
typeName = "lapRTS";
break;
case LLAP_CTS:
typeName = "lapCTS";
break;
}
if (typeName)
atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size);
else
atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size);
/*for (size_t i = 0; i < size; i++)
atbridge_printf("%02x ", data[i]);
atbridge_printf("\n");*/
}
}
/** Reply to a control packet from the GS **/
static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type)
{
struct at_addr_t dest_addr = { 0, dest };
struct at_addr_t source_addr = { 0, source };
static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type) {
struct at_addr_t dest_addr = { 0, dest };
struct at_addr_t source_addr = { 0, source };
// Insert control packets at the head of the queue contrary to normal FIFO queue operation
// to ensure that control frames arrive in the intended order.
insert(&llap_port.out, dest_addr, source_addr, type, 0, 0);
// Insert control packets at the head of the queue contrary to normal FIFO queue operation
// to ensure that control frames arrive in the intended order.
insert(&llap_port.out, dest_addr, source_addr, type, 0, 0);
}
/** Accept a data packet from the GS. **/
static void llap_handle_data(size_t size, byte data[])
{
at_node_t dest = data[0];
at_node_t source = data[1];
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
static void llap_handle_data(size_t size, byte data[]) {
at_node_t dest = data[0];
at_node_t source = data[1];
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
const size_t data_size = size - 3;
byte* data_copy = (byte*)malloc(data_size);
memcpy(data_copy, data + 3, data_size);
const size_t data_size = size - 3;
byte* data_copy = (byte*)malloc(data_size);
memcpy(data_copy, data + 3, data_size);
struct at_addr_t dest_addr = { 0, dest };
struct at_addr_t source_addr = { 0, source };
enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy);
struct at_addr_t dest_addr = { 0, dest };
struct at_addr_t source_addr = { 0, source };
enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy);
}
/** Accept a control packet from the GS. **/
static void llap_handle_control(size_t size, byte data[])
{
at_node_t dest = data[0];
at_node_t source = data[1];
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
static void llap_handle_control(size_t size, byte data[]) {
at_node_t dest = data[0];
at_node_t source = data[1];
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
struct at_addr_t addr = { atbridge_get_net(), dest };
struct at_addr_t addr = { atbridge_get_net(), dest };
switch (type)
{
case LLAP_ENQ:
// Require the GS to take a valid "client" address not known to be in use.
if (dest > 127 || dest == 0 || atbridge_address_used(&addr))
llap_reply_control(source, dest, LLAP_ACK);
break;
case LLAP_ACK:
break;
case LLAP_RTS:
if (dest != at_broadcast_node)
// The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake.
// Note that broadcast packets do not require a CTS.
llap_reply_control(source, dest, LLAP_CTS);
break;
case LLAP_CTS:
// The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet.
dialog_state = DIALOG_GOT_CTS;
break;
default:
break;
}
switch (type)
{
case LLAP_ENQ:
// Require the GS to take a valid "client" address not known to be in use.
if (dest > 127 || dest == 0 || atbridge_address_used(&addr))
llap_reply_control(source, dest, LLAP_ACK);
break;
case LLAP_ACK:
break;
case LLAP_RTS:
if (dest != at_broadcast_node)
// The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake.
// Note that broadcast packets do not require a CTS.
llap_reply_control(source, dest, LLAP_CTS);
break;
case LLAP_CTS:
// The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet.
dialog_state = DIALOG_GOT_CTS;
break;
default:
break;
}
}
/** Occassionally, we receive an invalid packet from the GS. I'm unsure if this is due to a bug in GS/OS
or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the
current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover.
**/
static void llap_reset_dialog()
{
dialog_state = DIALOG_READY;
last_frame_dcycs = 0;
or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the
current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover.
**/
static void llap_reset_dialog() {
dialog_state = DIALOG_READY;
last_frame_dcycs = 0;
// Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS).
while (true)
{
struct packet_t* packet = queue_peek(&llap_port.out);
if (packet && (packet->type != LLAP_RTS))
{
packet = dequeue(&llap_port.out);
if (packet->data)
free(packet->data);
free(packet);
}
else
break;
}
// Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS).
while (true)
{
struct packet_t* packet = queue_peek(&llap_port.out);
if (packet && (packet->type != LLAP_RTS))
{
packet = dequeue(&llap_port.out);
if (packet->data)
free(packet->data);
free(packet);
}
else
break;
}
}
/** Transfer (send) one LLAP packet from the GS. **/
void llap_enqueue_in(double dcycs, size_t size, byte data[])
{
atbridge_printf("<%0.0f> TX: ", dcycs);
llap_dump_packet(size, data);
void llap_enqueue_in(double dcycs, size_t size, byte data[]) {
atbridge_printf("<%0.0f> TX: ", dcycs);
llap_dump_packet(size, data);
if (size < LLAP_PACKET_MIN)
atbridge_printf("ATBridge: Dropping LLAP short packet.\n");
else if (size > LLAP_PACKET_MAX)
atbridge_printf("ATBridge: Dropping LLAP long packet.\n");
else
{
last_frame_dcycs = dcycs;
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
if (size < LLAP_PACKET_MIN)
atbridge_printf("ATBridge: Dropping LLAP short packet.\n");
else if (size > LLAP_PACKET_MAX)
atbridge_printf("ATBridge: Dropping LLAP long packet.\n");
else
{
last_frame_dcycs = dcycs;
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
switch (type)
{
case LLAP_DDP_SHORT:
case LLAP_DDP_LONG:
llap_handle_data(size, data);
break;
case LLAP_ENQ:
case LLAP_ACK:
case LLAP_RTS:
case LLAP_CTS:
llap_handle_control(size, data);
break;
default:
// Intentionally check for valid types and ingore packets with invalid types.
// Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge.
atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n");
llap_reset_dialog();
}
}
switch (type)
{
case LLAP_DDP_SHORT:
case LLAP_DDP_LONG:
llap_handle_data(size, data);
break;
case LLAP_ENQ:
case LLAP_ACK:
case LLAP_RTS:
case LLAP_CTS:
llap_handle_control(size, data);
break;
default:
// Intentionally check for valid types and ingore packets with invalid types.
// Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge.
atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n");
llap_reset_dialog();
}
}
}
/** Transfer (receive) one LLAP packet to the GS. **/
void llap_dequeue_out(double dcycs, size_t* size, byte* data[])
{
*size = 0;
void llap_dequeue_out(double dcycs, size_t* size, byte* data[]) {
*size = 0;
// The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG).
// If necessary, wait for the IDG.
if (dialog_state == DIALOG_WAIT_IDG)
// The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG).
// If necessary, wait for the IDG.
if (dialog_state == DIALOG_WAIT_IDG)
{
if ((dcycs - dialog_end_dcycs) >= LLAP_IDG)
// The IDG is done.
dialog_state = DIALOG_READY;
else
// Continue waiting for the IDG.
return;
}
// The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG).
// If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case,
// discard the current dialog and try again.
if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG)))
{
llap_reset_dialog();
atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n");
}
struct packet_t* packet = queue_peek(&llap_port.out);
if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG)))
{
llap_reset_dialog();
packet = queue_peek(&llap_port.out);
atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n");
}
if (packet &&
((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */
(!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */
(!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */
{
dequeue(&llap_port.out);
// Prepend the LLAP header.
*size = packet->size + 3 + 2;
*data = (byte*)malloc(*size);
(*data)[0] = packet->dest.node;
(*data)[1] = packet->source.node;
(*data)[2] = packet->type;
// Insert the data into the new LLAP packet.
if (*size)
memcpy((*data) + 3, packet->data, packet->size);
// Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually
// check the FCS, the value of the FCS doesn't matter.
(*data)[packet->size + 3 + 0] = 0xff;
(*data)[packet->size + 3 + 1] = 0xff;
atbridge_printf("<%0.0f> RX: ", dcycs);
llap_dump_packet(*size, *data);
if (packet->type & 0x80)
dialog_state = DIALOG_READY;
else
{
if ((dcycs - dialog_end_dcycs) >= LLAP_IDG)
// The IDG is done.
dialog_state = DIALOG_READY;
else
// Continue waiting for the IDG.
return;
// This was the last packet in the dialog.
dialog_state = DIALOG_WAIT_IDG;
dialog_end_dcycs = dcycs;
}
// The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG).
// If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case,
// discard the current dialog and try again.
if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG)))
{
llap_reset_dialog();
atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n");
}
struct packet_t* packet = queue_peek(&llap_port.out);
last_frame_dcycs = dcycs;
if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG)))
{
llap_reset_dialog();
packet = queue_peek(&llap_port.out);
atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n");
}
if (packet &&
((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */
(!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */
(!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */
{
dequeue(&llap_port.out);
// Prepend the LLAP header.
*size = packet->size + 3 + 2;
*data = (byte*)malloc(*size);
(*data)[0] = packet->dest.node;
(*data)[1] = packet->source.node;
(*data)[2] = packet->type;
// Insert the data into the new LLAP packet.
if (*size)
memcpy((*data) + 3, packet->data, packet->size);
// Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually
// check the FCS, the value of the FCS doesn't matter.
(*data)[packet->size + 3 + 0] = 0xff;
(*data)[packet->size + 3 + 1] = 0xff;
atbridge_printf("<%0.0f> RX: ", dcycs);
llap_dump_packet(*size, *data);
if (packet->type & 0x80)
dialog_state = DIALOG_READY;
else
{
// This was the last packet in the dialog.
dialog_state = DIALOG_WAIT_IDG;
dialog_end_dcycs = dcycs;
}
last_frame_dcycs = dcycs;
free(packet->data);
free(packet);
}
free(packet->data);
free(packet);
}
}

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
struct packet_t;

View File

@ -1,23 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include <stdbool.h>
#include "pcap_delay.h"
@ -31,143 +17,130 @@ static void* module = 0;
#endif
bool pcapdelay_load()
{
if (!pcapdelay_is_loaded())
{
bool pcapdelay_load() {
if (!pcapdelay_is_loaded())
{
#ifdef WIN32
module = LoadLibrary("wpcap.dll");
module = LoadLibrary("wpcap.dll");
#elif __linux__
module = dlopen("libpcap.so", RTLD_LAZY);
module = dlopen("libpcap.so", RTLD_LAZY);
#endif
}
return pcapdelay_is_loaded();
}
return pcapdelay_is_loaded();
}
bool pcapdelay_is_loaded()
{
bool pcapdelay_is_loaded() {
#ifdef WIN32
return module != NULL;
return module != NULL;
#elif __linux__
return module != 0;
return module != 0;
#endif
return 0;
}
void pcapdelay_unload()
{
if (pcapdelay_is_loaded())
{
void pcapdelay_unload() {
if (pcapdelay_is_loaded())
{
#ifdef WIN32
FreeLibrary(module);
module = NULL;
FreeLibrary(module);
module = NULL;
#elif __linux__
dlclose(module);
module = 0;
dlclose(module);
module = 0;
#endif
}
}
}
typedef void (*PFNVOID)();
static PFNVOID delay_load(const char* proc, PFNVOID* ppfn)
{
if (pcapdelay_load() && proc && ppfn && !*ppfn)
{
static PFNVOID delay_load(const char* proc, PFNVOID* ppfn) {
if (pcapdelay_load() && proc && ppfn && !*ppfn)
{
#ifdef WIN32
*ppfn = (PFNVOID)GetProcAddress(module, proc);
*ppfn = (PFNVOID)GetProcAddress(module, proc);
#elif __linux__
*ppfn = (PFNVOID)dlsym(module, proc);
*ppfn = (PFNVOID)dlsym(module, proc);
#endif
}
if (ppfn)
return *ppfn;
else
return 0;
}
if (ppfn)
return *ppfn;
else
return 0;
}
void pcapdelay_freealldevs(pcap_if_t* a0)
{
typedef void (*PFN)(pcap_if_t*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn)))
(*pfn)(a0);
void pcapdelay_freealldevs(pcap_if_t* a0) {
typedef void (*PFN)(pcap_if_t*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn)))
(*pfn)(a0);
}
pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4)
{
typedef pcap_t* (*PFN)(const char*, int, int, int, char*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2, a3, a4);
else
return 0;
pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4) {
typedef pcap_t* (*PFN)(const char*, int, int, int, char*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2, a3, a4);
else
return 0;
}
void pcapdelay_close(pcap_t* a0)
{
typedef void (*PFN)(pcap_t*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn)))
(*pfn)(a0);
void pcapdelay_close(pcap_t* a0) {
typedef void (*PFN)(pcap_t*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn)))
(*pfn)(a0);
}
int pcapdelay_findalldevs(pcap_if_t** a0, char* a1)
{
typedef int (*PFN)(pcap_if_t**, char*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1);
else
return 0;
int pcapdelay_findalldevs(pcap_if_t** a0, char* a1) {
typedef int (*PFN)(pcap_if_t**, char*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1);
else
return 0;
}
int pcapdelay_datalink(pcap_t* a0)
{
typedef int(*PFN)(pcap_t*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn)))
return (*pfn)(a0);
else
return 0;
int pcapdelay_datalink(pcap_t* a0) {
typedef int (*PFN)(pcap_t*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn)))
return (*pfn)(a0);
else
return 0;
}
int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2)
{
typedef int(*PFN)(pcap_t*, int, char*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2);
else
return 0;
int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2) {
typedef int (*PFN)(pcap_t*, int, char*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2);
else
return 0;
}
int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2)
{
typedef int(*PFN)(pcap_t*, u_char*, int);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2);
else
return 0;
int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2) {
typedef int (*PFN)(pcap_t*, u_char*, int);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2);
else
return 0;
}
const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1)
{
typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1);
else
return 0;
const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1) {
typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1);
else
return 0;
}
int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3)
{
typedef const int(*PFN)(pcap_t *, int, pcap_handler, u_char *);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2, a3);
else
return 0;
int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3) {
typedef const int (*PFN)(pcap_t *, int, pcap_handler, u_char *);
static PFN pfn = 0;
if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn)))
return (*pfn)(a0, a1, a2, a3);
else
return 0;
}

View File

@ -1,23 +1,10 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/*
This interface provides a thin, delay-loaded wrapper around the PCAP library so that
you may start GSport without intalling PCAP. Of course, some features that require

View File

@ -1,23 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/** This module implements queues for storing and transferring packets within the bridge. **/
@ -25,117 +11,107 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "atalk.h"
#include "port.h"
void port_init(struct packet_port_t* port)
{
if (port)
{
queue_init(&port->in);
queue_init(&port->out);
}
void port_init(struct packet_port_t* port) {
if (port)
{
queue_init(&port->in);
queue_init(&port->out);
}
}
void port_shutdown(struct packet_port_t* port)
{
if (port)
{
queue_shutdown(&port->in);
queue_shutdown(&port->out);
}
void port_shutdown(struct packet_port_t* port) {
if (port)
{
queue_shutdown(&port->in);
queue_shutdown(&port->out);
}
}
void queue_init(struct packet_queue_t* queue)
{
if (queue)
{
queue->head = queue->tail = 0;
}
void queue_init(struct packet_queue_t* queue) {
if (queue)
{
queue->head = queue->tail = 0;
}
}
void queue_shutdown(struct packet_queue_t* queue)
{
if (queue)
{
struct packet_t* packet = dequeue(queue);
while (packet)
{
if (packet->data)
free(packet->data);
free(packet);
packet = dequeue(queue);
}
}
void queue_shutdown(struct packet_queue_t* queue) {
if (queue)
{
struct packet_t* packet = dequeue(queue);
while (packet)
{
if (packet->data)
free(packet->data);
free(packet);
packet = dequeue(queue);
}
}
}
void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[])
{
if (!queue)
return;
void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) {
if (!queue)
return;
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
packet->dest.network = dest.network;
packet->dest.node = dest.node;
packet->source.network = source.network;
packet->source.node = source.node;
packet->type = type;
packet->size = size;
packet->data = data;
enqueue_packet(queue, packet);
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
packet->dest.network = dest.network;
packet->dest.node = dest.node;
packet->source.network = source.network;
packet->source.node = source.node;
packet->type = type;
packet->size = size;
packet->data = data;
enqueue_packet(queue, packet);
}
void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet)
{
packet->next = 0;
void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet) {
packet->next = 0;
if (queue->tail)
queue->tail->next = packet;
else
queue->head = packet;
queue->tail = packet;
if (queue->tail)
queue->tail->next = packet;
else
queue->head = packet;
queue->tail = packet;
}
void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[])
{
if (!queue)
return;
void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) {
if (!queue)
return;
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
packet->dest.network = dest.network;
packet->dest.node = dest.node;
packet->source.network = source.network;
packet->source.node = source.node;
packet->type = type;
packet->size = size;
packet->data = data;
insert_packet(queue, packet);
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
packet->dest.network = dest.network;
packet->dest.node = dest.node;
packet->source.network = source.network;
packet->source.node = source.node;
packet->type = type;
packet->size = size;
packet->data = data;
insert_packet(queue, packet);
}
void insert_packet(struct packet_queue_t* queue, struct packet_t* packet)
{
packet->next = queue->head;
queue->head = packet;
if (!queue->tail)
queue->tail = queue->head;
void insert_packet(struct packet_queue_t* queue, struct packet_t* packet) {
packet->next = queue->head;
queue->head = packet;
if (!queue->tail)
queue->tail = queue->head;
}
struct packet_t* dequeue(struct packet_queue_t* queue)
{
if (queue && queue->head)
{
struct packet_t* packet = queue->head;
if (queue->tail == queue->head)
queue->tail = queue->head = 0;
else
queue->head = packet->next;
return packet;
}
else
return 0;
struct packet_t* dequeue(struct packet_queue_t* queue) {
if (queue && queue->head)
{
struct packet_t* packet = queue->head;
if (queue->tail == queue->head)
queue->tail = queue->head = 0;
else
queue->head = packet->next;
return packet;
}
else
return 0;
}
struct packet_t* queue_peek(struct packet_queue_t* queue)
{
if (queue)
return queue->head;
else
return 0;
struct packet_t* queue_peek(struct packet_queue_t* queue) {
if (queue)
return queue->head;
else
return 0;
}

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013-2014 by Peter Neubauer
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
struct packet_t

View File

@ -1,28 +1,13 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 - 2012 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include "defc.h"
#include <time.h>
#include "glog.h"
#ifdef _WIN32
# include <windows.h>
# include <mmsystem.h>
@ -31,421 +16,396 @@
#endif
extern int Verbose;
extern word32 g_vbl_count; // OG change int to word32
extern word32 g_vbl_count; // OG change int to word32
extern int g_rom_version;
extern int g_config_gsplus_update_needed;
#define CLK_IDLE 1
#define CLK_TIME 2
#define CLK_INTERNAL 3
#define CLK_BRAM1 4
#define CLK_BRAM2 5
#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;
int g_clk_mode = CLK_IDLE;
int g_clk_read = 0;
int g_clk_reg1 = 0;
extern int g_c033_data;
extern int g_c034_val;
byte g_bram[2][256];
byte *g_bram_ptr = &(g_bram[0][0]);
byte g_temp_boot_slot = 254;
byte g_orig_boot_slot = 0;
byte g_bram[2][256];
byte *g_bram_ptr = &(g_bram[0][0]);
byte g_temp_boot_slot = 254;
byte g_orig_boot_slot = 0;
word32 g_clk_cur_time = 0xa0000000;
int g_clk_next_vbl_update = 0;
word32 g_clk_cur_time = 0xa0000000;
int g_clk_next_vbl_update = 0;
double
get_dtime()
{
double get_dtime() {
#ifndef _WIN32
struct timeval tp1;
double dsec;
double dusec;
struct timeval tp1;
double dsec;
double dusec;
#endif
double dtime;
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 */
/* 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;
dtime = timeGetTime() / 1000.0;
#else
# ifdef SOLARIS
gettimeofday(&tp1, (void *)0);
gettimeofday(&tp1, (void *)0);
# else
gettimeofday(&tp1, (struct timezone *)0);
gettimeofday(&tp1, (struct timezone *)0);
# endif
dsec = (double)tp1.tv_sec;
dusec = (double)tp1.tv_usec;
dsec = (double)tp1.tv_sec;
dusec = (double)tp1.tv_usec;
dtime = dsec + (dusec / (1000.0 * 1000.0));
dtime = dsec + (dusec / (1000.0 * 1000.0));
#endif
return dtime;
return dtime;
}
int
micro_sleep(double dtime)
{
int micro_sleep(double dtime) {
#ifndef _WIN32
struct timeval Timer;
int ret;
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(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);
printf("usleep: %f\n", dtime);
#endif
#ifdef _WIN32
Sleep((DWORD)(dtime * 1000));
Sleep((DWORD)(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;
}
Timer.tv_sec = 0;
Timer.tv_usec = (dtime * 1000000.0);
if( (ret = select(0, 0, 0, 0, &Timer)) < 0) {
glogf("micro_sleep (select) ret: %d, errno: %d", ret, errno);
return -1;
}
#endif
return 0;
return 0;
}
void
clk_bram_zero()
{
int i, j;
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]);
/* 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_bram_set(int bram_num, int offset, int val) {
g_bram[bram_num][offset] = val;
}
extern void x_clk_setup_bram_version();
void
clk_setup_bram_version()
{
x_clk_setup_bram_version();
void clk_setup_bram_version() {
x_clk_setup_bram_version();
}
void
clk_write_bram(FILE *fconf)
{
int i, j, k;
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");
}
}
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
clk_calculate_bram_checksum(void) {
int checksum = 0;
int i;
if (g_bram_ptr[251] == 0xff) {
// Only make the checksum valid if we have non-zeron data!
// Otherwise you have very valid zeroes, which confuses the GS firmware mightily.
for (i = 250; i >= 0; i--) {
checksum = (checksum & 0xFFFF) << 1;
checksum = (checksum & 0xFFFF)
+ g_bram_ptr[i]
+ ((int)g_bram_ptr[i + 1] << 8)
+ (checksum >> 16);
}
checksum &= 0xFFFF;
checksum += ((checksum ^ 0xAAAA) << 16);
void clk_calculate_bram_checksum(void) {
int checksum = 0;
int i;
if (g_bram_ptr[251] == 0xff) {
// Only make the checksum valid if we have non-zeron data!
// Otherwise you have very valid zeroes, which confuses the GS firmware mightily.
for (i = 250; i >= 0; i--) {
checksum = (checksum & 0xFFFF) << 1;
checksum = (checksum & 0xFFFF)
+ g_bram_ptr[i]
+ ((int)g_bram_ptr[i + 1] << 8)
+ (checksum >> 16);
}
checksum &= 0xFFFF;
checksum += ((checksum ^ 0xAAAA) << 16);
#if defined(GSPLUS_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command
g_bram_ptr[252] = (checksum & 0xFF);
g_bram_ptr[253] = (checksum >> 8);
g_bram_ptr[254] = (checksum >> 16);
g_bram_ptr[255] = (checksum >> 24);
g_bram_ptr[252] = (checksum & 0xFF);
g_bram_ptr[253] = (checksum >> 8);
g_bram_ptr[254] = (checksum >> 16);
g_bram_ptr[255] = (checksum >> 24);
#else
g_bram_ptr[255] = (checksum & 0xFF);
g_bram_ptr[254] = (checksum >> 8);
g_bram_ptr[253] = (checksum >> 16);
g_bram_ptr[252] = (checksum >> 24);
g_bram_ptr[255] = (checksum & 0xFF);
g_bram_ptr[254] = (checksum >> 8);
g_bram_ptr[253] = (checksum >> 16);
g_bram_ptr[252] = (checksum >> 24);
#endif
}
}
}
void
update_cur_time()
{
struct tm *tm_ptr;
time_t cur_time;
unsigned int secs, secs2;
void update_cur_time() {
struct tm *tm_ptr;
time_t cur_time;
unsigned int secs, secs2;
#ifdef UNDER_CE // OG Not supported on WIndows CE
/*
SYSTEMTIME stime;
FILETIME ftime;
GetLocalTime(&stime);
SystemTimeToFileTime(&stime,&ftime);
cur_time = ftime.dwLowDateTime;
*/
cur_time = time(0);
#ifdef UNDER_CE // OG Not supported on WIndows CE
/*
SYSTEMTIME stime;
FILETIME ftime;
GetLocalTime(&stime);
SystemTimeToFileTime(&stime,&ftime);
cur_time = ftime.dwLowDateTime;
*/
cur_time = time(0);
secs=0;
secs2=0;
secs=0;
secs2=0;
#else
cur_time = time(0);
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 = (unsigned int)mktime(gmtime(&cur_time));
tm_ptr = localtime(&cur_time);
secs = (unsigned int)mktime(tm_ptr);
/* Figure out the timezone (effectively) by diffing two times. */
/* this is probably not right for a few hours around daylight savings*/
/* time transition */
secs2 = (unsigned int)mktime(gmtime(&cur_time));
tm_ptr = localtime(&cur_time);
secs = (unsigned int)mktime(tm_ptr);
#ifdef MAC
/* Mac OS X's mktime function modifies the tm_ptr passed in for */
/* the CDT timezone and breaks this algorithm. So on a Mac, we */
/* will use the tm_ptr->gmtoff member to correct the time */
secs = secs + tm_ptr->tm_gmtoff;
/* Mac OS X's mktime function modifies the tm_ptr passed in for */
/* the CDT timezone and breaks this algorithm. So on a Mac, we */
/* will use the tm_ptr->gmtoff member to correct the time */
secs = secs + tm_ptr->tm_gmtoff;
#else
secs = (unsigned int)cur_time - (secs2 - secs);
secs = (unsigned int)cur_time - (secs2 - secs);
if(tm_ptr->tm_isdst) {
/* adjust for daylight savings time */
secs += 3600;
}
if(tm_ptr->tm_isdst) {
/* adjust for daylight savings time */
secs += 3600;
}
#endif
#endif
/* 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);
/* 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;
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;
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() {
/* Nothing to do */
}
void
clock_update_if_needed()
{
int diff;
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();
}
diff = g_clk_next_vbl_update - g_vbl_count;
if(diff < 0 || diff > 60) {
/* Been a while, re-read the clock */
update_cur_time();
}
}
void
clock_write_c034(word32 val)
{
g_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 clock_write_c034(word32 val) {
g_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;
void do_clock_data() {
word32 mask;
int read;
int op;
clk_printf("In do_clock_data, g_clk_mode: %02x\n", g_clk_mode);
clk_printf("In do_clock_data, g_clk_mode: %02x\n", g_clk_mode);
read = g_c034_val & 0x40;
switch(g_clk_mode) {
case CLK_IDLE:
g_clk_read = (g_c033_data >> 7) & 1;
g_clk_reg1 = (g_c033_data >> 2) & 3;
op = (g_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 = (g_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 = (g_c033_data >> 2) & 0xf;
break;
default:
halt_printf("Bad c033_data in CLK_IDLE: %02x\n",
g_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((g_c033_data & 0x83) == 0x00) {
/* more address bits */
g_clk_reg1 |= ((g_c033_data >> 2) & 0x1f);
g_clk_mode = CLK_BRAM1;
} else {
halt_printf("CLK_BRAM2: c033_data: %02x!\n",
g_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 */
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)){
// Modify boot slot
g_c033_data = g_temp_boot_slot;
clk_calculate_bram_checksum();
} else {
g_c033_data = g_bram_ptr[g_clk_reg1];
}
clk_printf("Reading BRAM loc %02x: %02x\n",
g_clk_reg1, g_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 */
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)) {
// Modify boot slot
g_bram_ptr[g_clk_reg1] = g_temp_boot_slot;
clk_calculate_bram_checksum();
} else {
g_bram_ptr[g_clk_reg1] = g_c033_data;
}
clk_printf("Writing BRAM loc %02x with %02x\n",
g_clk_reg1, g_c033_data);
g_config_gsplus_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");
}
g_c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) &
0xff;
clk_printf("Returning time byte %d: %02x\n",
g_clk_reg1, g_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, g_c033_data);
mask = 0xff << (8 * g_clk_reg1);
read = g_c034_val & 0x40;
switch(g_clk_mode) {
case CLK_IDLE:
g_clk_read = (g_c033_data >> 7) & 1;
g_clk_reg1 = (g_c033_data >> 2) & 3;
op = (g_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 = (g_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 = (g_c033_data >> 2) & 0xf;
break;
default:
halt_printf("Bad c033_data in CLK_IDLE: %02x\n",
g_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((g_c033_data & 0x83) == 0x00) {
/* more address bits */
g_clk_reg1 |= ((g_c033_data >> 2) & 0x1f);
g_clk_mode = CLK_BRAM1;
} else {
halt_printf("CLK_BRAM2: c033_data: %02x!\n",
g_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 */
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)) {
// Modify boot slot
g_c033_data = g_temp_boot_slot;
clk_calculate_bram_checksum();
} else {
g_c033_data = g_bram_ptr[g_clk_reg1];
}
clk_printf("Reading BRAM loc %02x: %02x\n",
g_clk_reg1, g_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 */
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)) {
// Modify boot slot
g_bram_ptr[g_clk_reg1] = g_temp_boot_slot;
clk_calculate_bram_checksum();
} else {
g_bram_ptr[g_clk_reg1] = g_c033_data;
}
clk_printf("Writing BRAM loc %02x with %02x\n",
g_clk_reg1, g_c033_data);
g_config_gsplus_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");
}
g_c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) &
0xff;
clk_printf("Returning time byte %d: %02x\n",
g_clk_reg1, g_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, g_c033_data);
mask = 0xff << (8 * g_clk_reg1);
g_clk_cur_time = (g_clk_cur_time & (~mask)) |
((g_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(g_c033_data & 0xc0) {
printf("Writing test reg: %02x!\n",
g_c033_data);
/* set_halt(1); */
}
break;
case 0x1: /* write protect reg */
clk_printf("Writing clk wr_protect: %02x\n",
g_c033_data);
if(g_c033_data & 0x80) {
printf("Stop, wr clk wr_prot: %02x\n",
g_c033_data);
/* set_halt(1); */
}
break;
default:
halt_printf("Writing int reg: %02x with %02x\n",
g_clk_reg1, g_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;
}
g_clk_cur_time = (g_clk_cur_time & (~mask)) |
((g_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(g_c033_data & 0xc0) {
printf("Writing test reg: %02x!\n",
g_c033_data);
/* set_halt(1); */
}
break;
case 0x1: /* write protect reg */
clk_printf("Writing clk wr_protect: %02x\n",
g_c033_data);
if(g_c033_data & 0x80) {
printf("Stop, wr clk wr_prot: %02x\n",
g_c033_data);
/* set_halt(1); */
}
break;
default:
halt_printf("Writing int reg: %02x with %02x\n",
g_clk_reg1, g_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;
}
}

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
char g_compile_time[] = "Compiled: " __DATE__ " " __TIME__ ;
char g_compile_time[] = "Compiled: " __DATE__ " " __TIME__;

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +1,23 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#define CONF_BUF_LEN 1024
#define COPY_BUF_SIZE 4096
#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 CFG_PATH_MAX 1024
#define CFG_NUM_SHOWENTS 16
#define CFGTYPE_MENU 1
#define CFGTYPE_INT 2
#define CFGTYPE_INT 2
#define CFGTYPE_DISK 3
#define CFGTYPE_FUNC 4
#define CFGTYPE_FILE 5
#define CFGTYPE_STR 6
#define CFGTYPE_DIR 7
/* CFGTYPE limited to just 4 bits: 0-15 */
/* Cfg_menu, Cfg_dirent and Cfg_listhdr are defined in defc.h */
@ -44,3 +27,33 @@ STRUCT(Cfg_defval) {
int intval;
char *strval;
};
int cfg_get_fd_size(char *filename);
int cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size);
int cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, Disk *dsk);
int cfg_maybe_insert_disk(int slot, int drive, const char *namestr);
int cfg_stat(char *path, struct stat *sb);
int cfg_partition_make_list(char *filename, FILE *file);
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 *menuptr, 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_update_ptr(char *str);
void cfg_file_selected(int);
void cfg_file_handle_key(int key);

45
src/config.txt Normal file
View File

@ -0,0 +1,45 @@
# GSplus configuration file version 0.10a
s5d1 =
s5d2 =
s6d1 =
s6d2 =
s7d1 =
bram1[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram1[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

1505
src/debug.c Normal file

File diff suppressed because it is too large Load Diff

8
src/debug.h Normal file
View File

@ -0,0 +1,8 @@
extern void debug_init();
extern void debug_poll_only();
extern void debug_cpu_test();
// used in sim65816.c
void debug_server_poll();
int debug_events_waiting();
void debug_handle_event();

View File

@ -1,25 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include "defcomm.h"
@ -28,8 +12,8 @@
#include <stdio.h>
extern "C" int outputInfo(const char* format,...);
extern "C" int fOutputInfo(FILE*,const char* format,...);
#define printf outputInfo
#define fprintf fOutputInfo
#define printf outputInfo
#define fprintf fOutputInfo
#endif
#define STRUCT(a) typedef struct _ ## a a; struct _ ## a
@ -46,30 +30,31 @@ typedef unsigned long long word64;
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 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_RAW (262.0 * 65.0)
#define DCYCS_IN_16MS_RAW (262.0 * 65.0)
/* Use precisely 17030 instead of forcing 60 Hz since this is the number of */
/* 1MHz cycles per screen */
#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW))
#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS))
#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW))
#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS))
#ifdef GSPLUS_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))
// @todo: look at using <byteswap.h> for fastest platform implementations
# 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)
# define BIGEND(a) (a)
# define GET_BE_WORD16(a) (a)
# define GET_BE_WORD32(a) (a)
#endif
#define MAXNUM_HEX_PER_LINE 32
@ -78,7 +63,7 @@ void U_STACK_TRACE();
# include <libc.h>
#endif
#if !defined(_WIN32) && !defined (__OS2__) && !defined(UNDER_CE) // OG
#if !defined(_WIN32) && !defined(UNDER_CE) // OG
# include <unistd.h>
# include <sys/ioctl.h>
# include <sys/wait.h>
@ -92,7 +77,7 @@ void U_STACK_TRACE();
#include <string.h>
#include <stdarg.h>
#ifndef UNDER_CE // OG CE SPecific
#ifndef UNDER_CE // OG CE SPecific
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -108,24 +93,24 @@ extern int open(const char* name,int,...);
extern int read(int,char*,int);
extern int close(int);
extern int write( int fd, const void *buffer, unsigned int count );
extern int lseek(int,int,int);
extern int lseek(int,int,int);
struct stat { int st_size; };
extern int stat(const char* name, struct stat*);
extern int fstat(int, struct stat*);
#define O_RDWR 1
#define O_BINARY 2
#define O_RDONLY 4
#define O_WRONLY 8
#define O_CREAT 16
#define O_TRUNC 32
#define EAGAIN 11
#define EINTR 4
#define O_RDWR 1
#define O_BINARY 2
#define O_RDONLY 4
#define O_WRONLY 8
#define O_CREAT 16
#define O_TRUNC 32
#define EAGAIN 11
#define EINTR 4
#endif
#ifdef HPUX
# include <machine/inline.h> /* for GET_ITIMER */
# include <machine/inline.h> /* for GET_ITIMER */
#endif
#ifdef SOLARIS
@ -134,232 +119,232 @@ extern int fstat(int, struct stat*);
#ifndef O_BINARY
/* work around some Windows junk */
# define O_BINARY 0
# 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;
double dcycs;
word32 dbank_kpc;
word32 instr;
word32 psr_acc;
word32 xreg_yreg;
word32 stack_direct;
word32 pad;
};
STRUCT(Data_log) {
double dcycs;
word32 addr;
word32 val;
word32 size;
double dcycs;
word32 addr;
word32 val;
word32 size;
};
STRUCT(Event) {
double dcycs;
int type;
Event *next;
double dcycs;
int type;
Event *next;
};
STRUCT(Fplus) {
double plus_1;
double plus_2;
double plus_3;
double plus_x_minus_1;
double plus_1;
double plus_2;
double plus_3;
double plus_x_minus_1;
};
STRUCT(Engine_reg) {
double fcycles;
word32 kpc;
word32 acc;
double fcycles;
word32 kpc;
word32 acc;
word32 xreg;
word32 yreg;
word32 xreg;
word32 yreg;
word32 stack;
word32 dbank;
word32 stack;
word32 dbank;
word32 direct;
word32 psr;
Fplus *fplus_ptr;
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;
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;
Pg_info rd_wr;
};
STRUCT(Cfg_menu) {
const char *str;
void *ptr;
const char *name_str;
void *defptr;
int cfgtype;
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;
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;
Cfg_dirent *direntptr;
int max;
int last;
int invalid;
int curent;
int topent;
int curent;
int topent;
int num_to_show;
int num_to_show;
};
STRUCT(Emustate_intlist) {
const char *str;
int *iptr;
const char *str;
int *iptr;
};
STRUCT(Emustate_dbllist) {
const char *str;
double *dptr;
const char *str;
double *dptr;
};
STRUCT(Emustate_word32list) {
const char *str;
word32 *wptr;
const char *str;
word32 *wptr;
};
#ifdef __LP64__
# define PTR2WORD(a) ((unsigned long)(a))
# define PTR2WORD(a) ((unsigned long)(a))
#else
# define PTR2WORD(a) ((unsigned int)(a))
# define PTR2WORD(a) ((unsigned int)(a))
#endif
#define ALTZP (g_c068_statereg & 0x80)
#define ALTZP (g_c068_statereg & 0x80)
/* #define PAGE2 (g_c068_statereg & 0x40) */
#define RAMRD (g_c068_statereg & 0x20)
#define RAMWRT (g_c068_statereg & 0x10)
#define RDROM (g_c068_statereg & 0x08)
#define LCBANK2 (g_c068_statereg & 0x04)
#define ROMB (g_c068_statereg & 0x02)
#define INTCX (g_c068_statereg & 0x01)
#define RAMRD (g_c068_statereg & 0x20)
#define RAMWRT (g_c068_statereg & 0x10)
#define RDROM (g_c068_statereg & 0x08)
#define LCBANK2 (g_c068_statereg & 0x04)
#define ROMB (g_c068_statereg & 0x02)
#define INTCX (g_c068_statereg & 0x01)
#define C041_EN_25SEC_INTS 0x10
#define C041_EN_VBL_INTS 0x08
#define C041_EN_SWITCH_INTS 0x04
#define C041_EN_MOVE_INTS 0x02
#define C041_EN_MOUSE 0x01
#define C041_EN_25SEC_INTS 0x10
#define C041_EN_VBL_INTS 0x08
#define C041_EN_SWITCH_INTS 0x04
#define C041_EN_MOVE_INTS 0x02
#define C041_EN_MOUSE 0x01
/* WARNING: SCC1 and SCC0 interrupts must be in this order for scc.c */
/* This order matches the SCC hardware */
#define IRQ_PENDING_SCC1_ZEROCNT 0x00001
#define IRQ_PENDING_SCC1_TX 0x00002
#define IRQ_PENDING_SCC1_RX 0x00004
#define IRQ_PENDING_SCC0_ZEROCNT 0x00008
#define IRQ_PENDING_SCC0_TX 0x00010
#define IRQ_PENDING_SCC0_RX 0x00020
#define IRQ_PENDING_C023_SCAN 0x00100
#define IRQ_PENDING_C023_1SEC 0x00200
#define IRQ_PENDING_C046_25SEC 0x00400
#define IRQ_PENDING_C046_VBL 0x00800
#define IRQ_PENDING_ADB_KBD_SRQ 0x01000
#define IRQ_PENDING_ADB_DATA 0x02000
#define IRQ_PENDING_ADB_MOUSE 0x04000
#define IRQ_PENDING_DOC 0x08000
#define IRQ_PENDING_SCC1_ZEROCNT 0x00001
#define IRQ_PENDING_SCC1_TX 0x00002
#define IRQ_PENDING_SCC1_RX 0x00004
#define IRQ_PENDING_SCC0_ZEROCNT 0x00008
#define IRQ_PENDING_SCC0_TX 0x00010
#define IRQ_PENDING_SCC0_RX 0x00020
#define IRQ_PENDING_C023_SCAN 0x00100
#define IRQ_PENDING_C023_1SEC 0x00200
#define IRQ_PENDING_C046_25SEC 0x00400
#define IRQ_PENDING_C046_VBL 0x00800
#define IRQ_PENDING_ADB_KBD_SRQ 0x01000
#define IRQ_PENDING_ADB_DATA 0x02000
#define IRQ_PENDING_ADB_MOUSE 0x04000
#define IRQ_PENDING_DOC 0x08000
#define EXTRU(val, pos, len) \
( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \
(((val) >> (31-(pos)) ) & ( (1<<(len) ) - 1) ) )
#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 DEP1(val, pos, old_val) \
(((old_val) & ~(1 << (31 - (pos))) ) | \
( ((val) & 1) << (31 - (pos))) )
#define set_halt(val) \
if(val) { set_halt_act(val); }
if(val) { set_halt_act(val); }
#define clear_halt() \
clr_halt_act()
clr_halt_act()
#define GET_PAGE_INFO_RD(page) \
(page_info_rd_wr[page].rd_wr)
(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)
(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;
; 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;
; 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
#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
# define DO_VERBOSE 0
#else
# define DO_VERBOSE 1
# 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 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_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); \
}
#define HALT_ON(a, msg) \
if(Halt_on & a) { \
halt_printf(msg); \
}
#ifndef MIN
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
# define MAX(a,b) (((a) < (b)) ? (b) : (a))
# define MAX(a,b) (((a) < (b)) ? (b) : (a))
#endif
#define GET_ITIMER(dest) dest = get_itimer();
#define GET_ITIMER(dest) dest = get_itimer();
#include "iwm.h"
#include "protos.h"
@ -368,5 +353,8 @@ STRUCT(Emustate_word32list) {
#define JOYSTICK_TYPE_MOUSE 1
#define JOYSTICK_TYPE_NATIVE_1 2
#define JOYSTICK_TYPE_NATIVE_2 3
#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None
#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None
#define NB_JOYSTICK_TYPE 5
// starting window x/y position if Undefined
#define WINDOWPOS_UNDEFINED 0xFFFFFFFF

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#define SHIFT_PER_CHANGE 3

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include "defcomm.h"
@ -65,4 +49,3 @@ ftmp2 .reg %fr5
fscr1 .reg %fr6
#define LDC(val,reg) ldil L%val,reg ! ldo R%val(reg),reg

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#ifdef ASM

2088
src/dis.c

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
enum {

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
.code

View File

@ -1,25 +1,9 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2013 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/*
* fbdriver - Linux fullscreen framebuffer graphics driver
@ -43,11 +27,11 @@ extern word32 g_palette_8to1624[256];
extern word32 g_a2palette_8to1624[256];
extern word32 g_a2_screen_buffer_changed;
extern word32 g_c025_val;
#define SHIFT_DOWN ( (g_c025_val & 0x01) )
#define CTRL_DOWN ( (g_c025_val & 0x02) )
#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) )
#define OPTION_DOWN ( (g_c025_val & 0x40) )
#define CMD_DOWN ( (g_c025_val & 0x80) )
#define SHIFT_DOWN ( (g_c025_val & 0x01) )
#define CTRL_DOWN ( (g_c025_val & 0x02) )
#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) )
#define OPTION_DOWN ( (g_c025_val & 0x40) )
#define CMD_DOWN ( (g_c025_val & 0x80) )
extern int g_video_act_margin_left;
extern int g_video_act_margin_right;
extern int g_video_act_margin_top;
@ -69,491 +53,469 @@ extern int g_green_right_shift;
extern int g_blue_right_shift;
extern Kimage g_mainwin_kimage;
int keycode_to_a2code[128] =
int keycode_to_a2code[128] =
{
-1, // KEY_RESERVED
0x35, // KEY_ESC
0x12, // KEY_1
0x13, // KEY_2
0x14, // KEY_3
0x15, // KEY_4
0x17, // KEY_5
0x16, // KEY_6
0x1A, // KEY_7
0x1C, // KEY_8
0x19, // KEY_9
0x1D, // KEY_0
0x1B, // KEY_MINUS
0x18, // KEY_EQUAL
0x3B, // KEY_BACKSPACE0
0x30, // KEY_TAB
0x0C, // KEY_Q
0x0D, // KEY_W
0x0E, // KEY_E
0x0F, // KEY_R
0x11, // KEY_T
0x10, // KEY_Y
0x20, // KEY_U
0x22, // KEY_I
0x1F, // KEY_O
0x23, // KEY_P
0x21, // KEY_LEFTBRACE
0x1E, // KEY_RIGHTBRACE
0x24, // KEY_ENTER
0x36, // KEY_LEFTCTRL
0x00, // KEY_A
0x01, // KEY_S
0x02, // KEY_D
0x03, // KEY_F
0x05, // KEY_G
0x04, // KEY_H
0x26, // KEY_J
0x28, // KEY_K
0x25, // KEY_L
0x29, // KEY_SEMICOLON
0x27, // KEY_APOSTROPHE
0x32, // KEY_GRAVE
0x38, // KEY_LEFTSHIFT
0x2A, // KEY_BACKSLASH
0x06, // KEY_Z
0x07, // KEY_X
0x08, // KEY_C
0x09, // KEY_V
0x0B, // KEY_B
0x2D, // KEY_N
0x2E, // KEY_M
0x2B, // KEY_COMMA
0x2F, // KEY_DOT
0x2C, // KEY_SLASH
0x38, // KEY_RIGHTSHIFT
0x43, // KEY_KPASTERISK
0x37, // KEY_LEFTALT
0x31, // KEY_SPACE
0x39, // KEY_CAPSLOCK
0x7A, // KEY_F1
0x78, // KEY_F2
0x63, // KEY_F3
0x76, // KEY_F4
0x60, // KEY_F5
0x61, // KEY_F6
0x62, // KEY_F7
0x64, // KEY_F8
0x65, // KEY_F9
0x6D, // KEY_F10
0x47, // KEY_NUMLOCK
0x37, // KEY_SCROLLLOCK
0x59, // KEY_KP7
0x5B, // KEY_KP8
0x5C, // KEY_KP9
0x4E, // KEY_KPMINUS
0x56, // KEY_KP4
0x57, // KEY_KP5
0x58, // KEY_KP6
0x45, // KEY_KPPLUS
0x53, // KEY_KP1
0x54, // KEY_KP2
0x55, // KEY_KP3
0x52, // KEY_KP0
0x41, // KEY_KPDOT
-1,
-1, // KEY_ZENKAKUHANKAKU
-1, // KEY_102ND
0x67, // KEY_F11
0x6F, // KEY_F12
-1, // KEY_RO
-1, // KEY_KATAKANA
-1, // KEY_HIRAGANA
-1, // KEY_HENKAN
-1, // KEY_KATAKANAHIRAGANA
-1, // KEY_MUHENKAN
-1, // KEY_KPJPCOMMA
0x4C, // KEY_KPENTER
0x36, // KEY_RIGHTCTRL
0x4B, // KEY_KPSLASH
0x7F, // KEY_SYSRQ
0x37, // KEY_RIGHTALT
0x6E, // KEY_LINEFEED
0x73, // KEY_HOME
0x3E, // KEY_UP
0x74, // KEY_PAGEUP
0x3B, // KEY_LEFT
0x3C, // KEY_RIGHT
0x77, // KEY_END
0x3D, // KEY_DOWN
0x79, // KEY_PAGEDOWN
0x72, // KEY_INSERT
0x33, // KEY_DELETE
-1, // KEY_MACRO
-1, // KEY_MUTE
-1, // KEY_VOLUMEDOWN
-1, // KEY_VOLUMEUP
0x7F, // KEY_POWER /* SC System Power Down */
0x51, // KEY_KPEQUAL
0x4E, // KEY_KPPLUSMINUS
-1, // KEY_PAUSE
-1, // KEY_SCALE /* AL Compiz Scale (Expose) */
0x2B, // KEY_KPCOMMA
-1, // KEY_HANGEUL
-1, // KEY_HANJA
-1, // KEY_YEN
0x3A, // KEY_LEFTMETA
0x3A, // KEY_RIGHTMETA
-1 // KEY_COMPOSE
-1, // KEY_RESERVED
0x35, // KEY_ESC
0x12, // KEY_1
0x13, // KEY_2
0x14, // KEY_3
0x15, // KEY_4
0x17, // KEY_5
0x16, // KEY_6
0x1A, // KEY_7
0x1C, // KEY_8
0x19, // KEY_9
0x1D, // KEY_0
0x1B, // KEY_MINUS
0x18, // KEY_EQUAL
0x3B, // KEY_BACKSPACE0
0x30, // KEY_TAB
0x0C, // KEY_Q
0x0D, // KEY_W
0x0E, // KEY_E
0x0F, // KEY_R
0x11, // KEY_T
0x10, // KEY_Y
0x20, // KEY_U
0x22, // KEY_I
0x1F, // KEY_O
0x23, // KEY_P
0x21, // KEY_LEFTBRACE
0x1E, // KEY_RIGHTBRACE
0x24, // KEY_ENTER
0x36, // KEY_LEFTCTRL
0x00, // KEY_A
0x01, // KEY_S
0x02, // KEY_D
0x03, // KEY_F
0x05, // KEY_G
0x04, // KEY_H
0x26, // KEY_J
0x28, // KEY_K
0x25, // KEY_L
0x29, // KEY_SEMICOLON
0x27, // KEY_APOSTROPHE
0x32, // KEY_GRAVE
0x38, // KEY_LEFTSHIFT
0x2A, // KEY_BACKSLASH
0x06, // KEY_Z
0x07, // KEY_X
0x08, // KEY_C
0x09, // KEY_V
0x0B, // KEY_B
0x2D, // KEY_N
0x2E, // KEY_M
0x2B, // KEY_COMMA
0x2F, // KEY_DOT
0x2C, // KEY_SLASH
0x38, // KEY_RIGHTSHIFT
0x43, // KEY_KPASTERISK
0x37, // KEY_LEFTALT
0x31, // KEY_SPACE
0x39, // KEY_CAPSLOCK
0x7A, // KEY_F1
0x78, // KEY_F2
0x63, // KEY_F3
0x76, // KEY_F4
0x60, // KEY_F5
0x61, // KEY_F6
0x62, // KEY_F7
0x64, // KEY_F8
0x65, // KEY_F9
0x6D, // KEY_F10
0x47, // KEY_NUMLOCK
0x37, // KEY_SCROLLLOCK
0x59, // KEY_KP7
0x5B, // KEY_KP8
0x5C, // KEY_KP9
0x4E, // KEY_KPMINUS
0x56, // KEY_KP4
0x57, // KEY_KP5
0x58, // KEY_KP6
0x45, // KEY_KPPLUS
0x53, // KEY_KP1
0x54, // KEY_KP2
0x55, // KEY_KP3
0x52, // KEY_KP0
0x41, // KEY_KPDOT
-1,
-1, // KEY_ZENKAKUHANKAKU
-1, // KEY_102ND
0x67, // KEY_F11
0x6F, // KEY_F12
-1, // KEY_RO
-1, // KEY_KATAKANA
-1, // KEY_HIRAGANA
-1, // KEY_HENKAN
-1, // KEY_KATAKANAHIRAGANA
-1, // KEY_MUHENKAN
-1, // KEY_KPJPCOMMA
0x4C, // KEY_KPENTER
0x36, // KEY_RIGHTCTRL
0x4B, // KEY_KPSLASH
0x7F, // KEY_SYSRQ
0x37, // KEY_RIGHTALT
0x6E, // KEY_LINEFEED
0x73, // KEY_HOME
0x3E, // KEY_UP
0x74, // KEY_PAGEUP
0x3B, // KEY_LEFT
0x3C, // KEY_RIGHT
0x77, // KEY_END
0x3D, // KEY_DOWN
0x79, // KEY_PAGEDOWN
0x72, // KEY_INSERT
0x33, // KEY_DELETE
-1, // KEY_MACRO
-1, // KEY_MUTE
-1, // KEY_VOLUMEDOWN
-1, // KEY_VOLUMEUP
0x7F, // KEY_POWER /* SC System Power Down */
0x51, // KEY_KPEQUAL
0x4E, // KEY_KPPLUSMINUS
-1, // KEY_PAUSE
-1, // KEY_SCALE /* AL Compiz Scale (Expose) */
0x2B, // KEY_KPCOMMA
-1, // KEY_HANGEUL
-1, // KEY_HANJA
-1, // KEY_YEN
0x3A, // KEY_LEFTMETA
0x3A, // KEY_RIGHTMETA
-1 // KEY_COMPOSE
};
struct termios org_tio;
struct fb_var_screeninfo orig_vinfo;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
int pix_size, g_screen_mdepth, g_use_shmem = 1;
#define MOUSE_LBTN_DOWN 0x01
#define MOUSE_MBTN_DOWN 0x02
#define MOUSE_RBTN_DOWN 0x04
#define MOUSE_LBTN_UP 0x00
#define MOUSE_MBTN_UP 0x00
#define MOUSE_RBTN_UP 0x00
#define MOUSE_BTN_ACTIVE 0x07
#define UPDATE_INPUT_MOUSE 0x10
int pix_size, g_screen_mdepth, g_use_shmem = 1;
#define MOUSE_LBTN_DOWN 0x01
#define MOUSE_MBTN_DOWN 0x02
#define MOUSE_RBTN_DOWN 0x04
#define MOUSE_LBTN_UP 0x00
#define MOUSE_MBTN_UP 0x00
#define MOUSE_RBTN_UP 0x00
#define MOUSE_BTN_ACTIVE 0x07
#define UPDATE_INPUT_MOUSE 0x10
#define MAX_EVDEV 8
char *fb_ptr, g_inputstate = 0;
int evfd[MAX_EVDEV], evdevs, termfd, fbfd = 0;
int evfd[MAX_EVDEV], evdevs, termfd, fbfd = 0;
/*
* Clean up
*/
void xdriver_end(void)
{
char c;
static char xexit = 0;
if (!xexit)
void xdriver_end(void) {
char c;
static char xexit = 0;
if (!xexit)
{
// cleanup
munmap(fb_ptr, finfo.smem_len);
ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo);
close(fbfd);
if (termfd > 0)
{
// cleanup
munmap(fb_ptr, finfo.smem_len);
ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo);
close(fbfd);
if (termfd > 0)
{
// Flush input
while (read(termfd, &c, 1) == 1);
ioctl(termfd, KDSETMODE, KD_TEXT);
tcsetattr(termfd, TCSANOW, &org_tio);
close(termfd);
}
fclose(stdout);
fclose(stderr);
while (evdevs--)
close(evfd[evdevs]);
xexit = 1;
// Flush input
while (read(termfd, &c, 1) == 1);
ioctl(termfd, KDSETMODE, KD_TEXT);
tcsetattr(termfd, TCSANOW, &org_tio);
close(termfd);
}
fclose(stdout);
fclose(stderr);
while (evdevs--)
close(evfd[evdevs]);
xexit = 1;
}
}
/*
* Init framebuffer and input
*/
void dev_video_init(void)
{
int i;
char evdevname[20];
struct termios termio;
void dev_video_init(void) {
int i;
char evdevname[20];
struct termios termio;
// Set graphics mode on console
if ((termfd = open("/dev/tty", O_RDWR)) < 0)
{
fprintf(stderr, "Error opening tty device.\n");
exit(-1);
}
// Save input settings.
tcgetattr(termfd, &termio); /* save current port settings */
memcpy(&org_tio, &termio, sizeof(struct termios));
ioctl(termfd, KDSETMODE, KD_GRAPHICS);
// Open the file for reading and writing
if ((fbfd = open("/dev/fb0", O_RDWR)) < 0)
{
fprintf(stderr, "Error opening framebuffer device.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
{
fprintf(stderr, "Error reading variable screen information.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// Store for reset(copy vinfo to vinfo_orig)
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
// Change variable info
//vinfo.bits_per_pixel = 8;
// Change resolution
vinfo.xres = 640;
vinfo.yres = 400;
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
{
fprintf(stderr, "Error setting variable screen information (640x400x8).\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
fprintf(stderr, "Error reading fixed screen information.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// map fb to user mem
fb_ptr = (char*)mmap(0,
finfo.smem_len,
PROT_READ|PROT_WRITE,
MAP_SHARED,
fbfd,
0);
if ((int)fb_ptr == -1)
{
printf("Failed to mmap framebuffer.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit (-1);
}
g_screen_depth = vinfo.bits_per_pixel;
g_screen_mdepth = g_screen_depth;
if (g_screen_depth > 8)
g_screen_mdepth = 16;
if (g_screen_depth > 16)
g_screen_mdepth = 32;
pix_size = g_screen_mdepth / 8;
if (vinfo.bits_per_pixel > 8)
{
g_red_mask = (1 << vinfo.red.length) - 1;
g_green_mask = (1 << vinfo.green.length) - 1;
g_blue_mask = (1 << vinfo.blue.length) - 1;
g_red_left_shift = vinfo.red.offset;
g_green_left_shift = vinfo.green.offset;
g_blue_left_shift = vinfo.blue.offset;
g_red_right_shift = 8 - vinfo.red.length;
g_green_right_shift = 8 - vinfo.green.length;
g_blue_right_shift = 8 - vinfo.blue.length;
}
video_get_kimages();
if (g_screen_depth > 8)
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth);
for (i = 0; i < 256; i++)
{
video_update_color_raw(i, g_lores_colors[i & 0xf]);
g_a2palette_8to1624[i] = g_palette_8to1624[i];
}
fclose(stdin);
freopen("gsport.log", "w+", stdout);
freopen("gsport.err", "w+", stderr);
termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD;
termio.c_iflag = IGNPAR;
termio.c_oflag = 0;
termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
termio.c_cc[VTIME] = 0; /* inter-character timer unused */
termio.c_cc[VMIN] = 0; /* non-blocking read */
tcsetattr(termfd, TCSANOW, &termio);
// Open input event devices
for (evdevs = 0; evdevs < MAX_EVDEV; evdevs++)
{
sprintf(evdevname, "/dev/input/event%c", evdevs + '0');
if ((evfd[evdevs] = open(evdevname, O_RDONLY|O_NONBLOCK)) < 0)
break;
}
g_video_act_margin_left = 0;
g_video_act_margin_right = 1;
g_video_act_margin_top = 0;
g_video_act_margin_bottom = 0;
// Set graphics mode on console
if ((termfd = open("/dev/tty", O_RDWR)) < 0)
{
fprintf(stderr, "Error opening tty device.\n");
exit(-1);
}
// Save input settings.
tcgetattr(termfd, &termio); /* save current port settings */
memcpy(&org_tio, &termio, sizeof(struct termios));
ioctl(termfd, KDSETMODE, KD_GRAPHICS);
// Open the file for reading and writing
if ((fbfd = open("/dev/fb0", O_RDWR)) < 0)
{
fprintf(stderr, "Error opening framebuffer device.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
{
fprintf(stderr, "Error reading variable screen information.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// Store for reset(copy vinfo to vinfo_orig)
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
// Change variable info
//vinfo.bits_per_pixel = 8;
// Change resolution
vinfo.xres = 640;
vinfo.yres = 400;
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
{
fprintf(stderr, "Error setting variable screen information (640x400x8).\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
fprintf(stderr, "Error reading fixed screen information.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit(-1);
}
// map fb to user mem
fb_ptr = (char*)mmap(0,
finfo.smem_len,
PROT_READ|PROT_WRITE,
MAP_SHARED,
fbfd,
0);
if ((int)fb_ptr == -1)
{
printf("Failed to mmap framebuffer.\n");
ioctl(termfd, KDSETMODE, KD_TEXT);
exit (-1);
}
g_screen_depth = vinfo.bits_per_pixel;
g_screen_mdepth = g_screen_depth;
if (g_screen_depth > 8)
g_screen_mdepth = 16;
if (g_screen_depth > 16)
g_screen_mdepth = 32;
pix_size = g_screen_mdepth / 8;
if (vinfo.bits_per_pixel > 8)
{
g_red_mask = (1 << vinfo.red.length) - 1;
g_green_mask = (1 << vinfo.green.length) - 1;
g_blue_mask = (1 << vinfo.blue.length) - 1;
g_red_left_shift = vinfo.red.offset;
g_green_left_shift = vinfo.green.offset;
g_blue_left_shift = vinfo.blue.offset;
g_red_right_shift = 8 - vinfo.red.length;
g_green_right_shift = 8 - vinfo.green.length;
g_blue_right_shift = 8 - vinfo.blue.length;
}
video_get_kimages();
if (g_screen_depth > 8)
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth);
for (i = 0; i < 256; i++)
{
video_update_color_raw(i, g_lores_colors[i & 0xf]);
g_a2palette_8to1624[i] = g_palette_8to1624[i];
}
fclose(stdin);
freopen("gsport.log", "w+", stdout);
freopen("gsport.err", "w+", stderr);
termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD;
termio.c_iflag = IGNPAR;
termio.c_oflag = 0;
termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
termio.c_cc[VTIME] = 0; /* inter-character timer unused */
termio.c_cc[VMIN] = 0; /* non-blocking read */
tcsetattr(termfd, TCSANOW, &termio);
// Open input event devices
for (evdevs = 0; evdevs < MAX_EVDEV; evdevs++)
{
sprintf(evdevname, "/dev/input/event%c", evdevs + '0');
if ((evfd[evdevs] = open(evdevname, O_RDONLY|O_NONBLOCK)) < 0)
break;
}
g_video_act_margin_left = 0;
g_video_act_margin_right = 1;
g_video_act_margin_top = 0;
g_video_act_margin_bottom = 0;
}
/*
* Colormap
*/
__u16 cmapred[256], cmapgreen[256], cmapblue[256];
int cmapstart, cmaplen, cmapdirty = 0;
void x_update_color(int col_num, int red, int green, int blue, word32 rgb)
{
cmapred[col_num] = red | (red << 8);
cmapgreen[col_num] = green | (green << 8);
cmapblue[col_num] = blue | (blue << 8);
if (cmapdirty == 0)
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) {
cmapred[col_num] = red | (red << 8);
cmapgreen[col_num] = green | (green << 8);
cmapblue[col_num] = blue | (blue << 8);
if (cmapdirty == 0)
{
cmapstart = col_num;
cmaplen = 1;
cmapdirty = 1;
}
else
{
if (col_num < cmapstart)
{
cmapstart = col_num;
cmaplen = 1;
cmapdirty = 1;
}
else
{
if (col_num < cmapstart)
{
cmaplen += cmapstart - col_num;
cmapstart = col_num;
}
else if (col_num > cmapstart + cmaplen)
cmaplen = col_num - cmapstart + 1;
cmaplen += cmapstart - col_num;
cmapstart = col_num;
}
else if (col_num > cmapstart + cmaplen)
cmaplen = col_num - cmapstart + 1;
}
}
void x_update_physical_colormap(void)
{
struct fb_cmap fbcol;
if (cmapdirty)
{
cmapdirty = 0;
fbcol.start = cmapstart;
fbcol.len = cmaplen;
fbcol.red = cmapred;
fbcol.green = cmapgreen;
fbcol.blue = cmapblue;
fbcol.transp = NULL;
ioctl(fbfd, FBIOPUTCMAP, &fbcol);
}
void x_update_physical_colormap(void) {
struct fb_cmap fbcol;
if (cmapdirty)
{
cmapdirty = 0;
fbcol.start = cmapstart;
fbcol.len = cmaplen;
fbcol.red = cmapred;
fbcol.green = cmapgreen;
fbcol.blue = cmapblue;
fbcol.transp = NULL;
ioctl(fbfd, FBIOPUTCMAP, &fbcol);
}
}
void show_xcolor_array(void)
{
void show_xcolor_array(void) {
}
/*
* Screen update
*/
void x_get_kimage(Kimage *kimage_ptr)
{
kimage_ptr->data_ptr = (byte *)malloc(kimage_ptr->width_req * kimage_ptr->height * kimage_ptr->mdepth / 8);
void x_get_kimage(Kimage *kimage_ptr) {
kimage_ptr->data_ptr = (byte *)malloc(kimage_ptr->width_req * kimage_ptr->height * kimage_ptr->mdepth / 8);
}
void x_release_kimage(Kimage* kimage_ptr)
{
if (kimage_ptr->data_ptr)
if (kimage_ptr->width_req != 640 || kimage_ptr->height != 400)
free(kimage_ptr->data_ptr);
kimage_ptr->data_ptr = NULL;
void x_release_kimage(Kimage* kimage_ptr) {
if (kimage_ptr->data_ptr)
if (kimage_ptr->width_req != 640 || kimage_ptr->height != 400)
free(kimage_ptr->data_ptr);
kimage_ptr->data_ptr = NULL;
}
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height)
{
byte *src_ptr, *dst_ptr;
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) {
byte *src_ptr, *dst_ptr;
// Copy sub-image to framebuffer
dst_ptr = (byte *)fb_ptr + desty * finfo.line_length + destx * pix_size;
src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pix_size;
width *= pix_size;
while (height--)
{
memcpy(dst_ptr, src_ptr, width);
dst_ptr += finfo.line_length;
src_ptr += kimage_ptr->width_act * pix_size;
}
// Copy sub-image to framebuffer
dst_ptr = (byte *)fb_ptr + desty * finfo.line_length + destx * pix_size;
src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pix_size;
width *= pix_size;
while (height--)
{
memcpy(dst_ptr, src_ptr, width);
dst_ptr += finfo.line_length;
src_ptr += kimage_ptr->width_act * pix_size;
}
}
void x_push_done(void)
{
void x_push_done(void) {
}
/*
* NOP routines
*/
void x_dialog_create_gsport_conf(const char *str)
{
// Just write the config file already...
config_write_config_gsplus_file();
void x_dialog_create_gsport_conf(const char *str) {
// Just write the config file already...
config_write_config_gsplus_file();
}
int x_show_alert(int is_fatal, const char *str)
{
// Not implemented yet
adb_all_keys_up();
clear_fatal_logs();
return 0;
int x_show_alert(int is_fatal, const char *str) {
// Not implemented yet
adb_all_keys_up();
clear_fatal_logs();
return 0;
}
void x_toggle_status_lines(void)
{
void x_toggle_status_lines(void) {
}
void x_redraw_status_lines(void)
{
void x_redraw_status_lines(void) {
}
void x_hide_pointer(int do_hide)
{
void x_hide_pointer(int do_hide) {
}
void x_auto_repeat_on(int must)
{
void x_auto_repeat_on(int must) {
}
void x_full_screen(int do_full)
{
void x_full_screen(int do_full) {
}
int x_calc_ratio(float x, float y)
{
return 1;
int x_calc_ratio(float x, float y) {
return 1;
}
void clipboard_paste(void)
{
void clipboard_paste(void) {
}
int clipboard_get_char(void)
{
return 0;
int clipboard_get_char(void) {
return 0;
}
/*
* Input handling
*/
void check_input_events(void)
{
struct input_event ev;
int i;
for (i = 0; i < evdevs; i++)
// Check input events
while (read(evfd[i], &ev, sizeof(struct input_event)) == sizeof(struct input_event))
{
if (ev.type == EV_REL)
{
if (ev.code == REL_X)
{
g_mouse_raw_x += ev.value;
if (g_mouse_raw_x < 0)
g_mouse_raw_x = 0;
if (g_mouse_raw_x > 639)
g_mouse_raw_x = 639;
}
else // REL_Y
{
g_mouse_raw_y += ev.value;
if (g_mouse_raw_y < 0)
g_mouse_raw_y = 0;
if (g_mouse_raw_y > 399)
g_mouse_raw_y = 399;
}
g_inputstate |= UPDATE_INPUT_MOUSE;
}
else if (ev.type == EV_KEY)
{
if (ev.code < 128)
{
void check_input_events(void) {
struct input_event ev;
int i;
for (i = 0; i < evdevs; i++)
// Check input events
while (read(evfd[i], &ev, sizeof(struct input_event)) == sizeof(struct input_event))
{
if (ev.type == EV_REL)
{
if (ev.code == REL_X)
{
g_mouse_raw_x += ev.value;
if (g_mouse_raw_x < 0)
g_mouse_raw_x = 0;
if (g_mouse_raw_x > 639)
g_mouse_raw_x = 639;
}
else // REL_Y
{
g_mouse_raw_y += ev.value;
if (g_mouse_raw_y < 0)
g_mouse_raw_y = 0;
if (g_mouse_raw_y > 399)
g_mouse_raw_y = 399;
}
g_inputstate |= UPDATE_INPUT_MOUSE;
}
else if (ev.type == EV_KEY)
{
if (ev.code < 128)
{
#if 0
if ((ev.code == KEY_F10) && SHIFT_DOWN)
{
//quitEmulator();
iwm_shut();
xdriver_end();
my_exit(1);
}
if ((ev.code == KEY_F10) && SHIFT_DOWN)
{
//quitEmulator();
iwm_shut();
xdriver_end();
my_exit(1);
}
#endif
if (keycode_to_a2code[ev.code] >= 0)
adb_physical_key_update(keycode_to_a2code[ev.code], !ev.value);
}
else if (ev.code == BTN_LEFT)
{
g_inputstate = ev.value ? UPDATE_INPUT_MOUSE | MOUSE_LBTN_DOWN
: UPDATE_INPUT_MOUSE | MOUSE_LBTN_UP;
}
}
else if (ev.type == EV_SYN)
{
if (g_inputstate & UPDATE_INPUT_MOUSE)
update_mouse(g_mouse_raw_x, g_mouse_raw_y, g_inputstate & MOUSE_BTN_ACTIVE, MOUSE_BTN_ACTIVE);
g_inputstate &= ~UPDATE_INPUT_MOUSE;
}
}
if (keycode_to_a2code[ev.code] >= 0)
adb_physical_key_update(keycode_to_a2code[ev.code], !ev.value);
}
else if (ev.code == BTN_LEFT)
{
g_inputstate = ev.value ? UPDATE_INPUT_MOUSE | MOUSE_LBTN_DOWN
: UPDATE_INPUT_MOUSE | MOUSE_LBTN_UP;
}
}
else if (ev.type == EV_SYN)
{
if (g_inputstate & UPDATE_INPUT_MOUSE)
update_mouse(g_mouse_raw_x, g_mouse_raw_y, g_inputstate & MOUSE_BTN_ACTIVE, MOUSE_BTN_ACTIVE);
g_inputstate &= ~UPDATE_INPUT_MOUSE;
}
}
}
static void sig_bye(int signo)
{
xdriver_end();
exit (-1);
static void sig_bye(int signo) {
xdriver_end();
exit (-1);
}
/*
* Application entrypoint
*/
int main(int argc,char *argv[])
{
if (signal(SIGINT, sig_bye) == SIG_ERR)
exit(-1);
if (signal(SIGHUP, sig_bye) == SIG_ERR)
exit(-1);
gsplusmain(argc, argv);
xdriver_end();
return 0;
int main(int argc,char *argv[]) {
if (signal(SIGINT, sig_bye) == SIG_ERR)
exit(-1);
if (signal(SIGHUP, sig_bye) == SIG_ERR)
exit(-1);
gsplusmain(argc, argv);
xdriver_end();
return 0;
}

26
src/fix_mac_menu.m Normal file
View File

@ -0,0 +1,26 @@
#import <Cocoa/Cocoa.h>
void fix_mac_menu(void) {
/*
* add an option-key modifier to all menu shortcuts
* eg, command-Q -> option+command-Q
*/
@autoreleasepool {
if (NSApp) {
NSMenu *menu = [NSApp mainMenu];
for (NSMenuItem *a in [menu itemArray]) {
for (NSMenuItem *b in [[a submenu] itemArray]) {
unsigned m = [b keyEquivalentModifierMask];
if (m & NSEventModifierFlagCommand)
[b setKeyEquivalentModifierMask: m | NSEventModifierFlagOption];
}
}
}
}
}

182
src/fst.h Normal file
View File

@ -0,0 +1,182 @@
/* generated on Tue Oct 18 20:54:09 2016 */
#define GSString255_length 0
#define GSString255_text 2
#define GSString32_length 0
#define GSString32_text 2
#define ResultBuf255_bufSize 0
#define ResultBuf255_bufString 2
#define ResultBuf32_bufSize 0
#define ResultBuf32_bufString 2
#define TimeRec_second 0
#define TimeRec_minute 1
#define TimeRec_hour 2
#define TimeRec_year 3
#define TimeRec_day 4
#define TimeRec_month 5
#define TimeRec_extra 6
#define TimeRec_weekDay 7
#define CreateRecGS_pCount 0
#define CreateRecGS_pathname 2
#define CreateRecGS_access 6
#define CreateRecGS_fileType 8
#define CreateRecGS_auxType 10
#define CreateRecGS_storageType 14
#define CreateRecGS_eof 16
#define CreateRecGS_resourceEOF 20
#define CreateRec_pathname 0
#define CreateRec_fAccess 4
#define CreateRec_fileType 6
#define CreateRec_auxType 8
#define CreateRec_storageType 12
#define CreateRec_createDate 14
#define CreateRec_createTime 16
#define DirEntryRecGS_pCount 0
#define DirEntryRecGS_refNum 2
#define DirEntryRecGS_flags 4
#define DirEntryRecGS_base 6
#define DirEntryRecGS_displacement 8
#define DirEntryRecGS_name 10
#define DirEntryRecGS_entryNum 14
#define DirEntryRecGS_fileType 16
#define DirEntryRecGS_eof 18
#define DirEntryRecGS_blockCount 22
#define DirEntryRecGS_createDateTime 26
#define DirEntryRecGS_modDateTime 34
#define DirEntryRecGS_access 42
#define DirEntryRecGS_auxType 44
#define DirEntryRecGS_fileSysID 48
#define DirEntryRecGS_optionList 50
#define DirEntryRecGS_resourceEOF 54
#define DirEntryRecGS_resourceBlocks 58
#define DirEntryRec_refNum 0
#define DirEntryRec_flags 2
#define DirEntryRec_base 4
#define DirEntryRec_displacement 6
#define DirEntryRec_nameBuffer 8
#define DirEntryRec_entryNum 12
#define DirEntryRec_fileType 14
#define DirEntryRec_endOfFile 16
#define DirEntryRec_blockCount 20
#define DirEntryRec_createTime 24
#define DirEntryRec_modTime 32
#define DirEntryRec_access 40
#define DirEntryRec_auxType 42
#define DirEntryRec_fileSysID 46
#define FileInfoRecGS_pCount 0
#define FileInfoRecGS_pathname 2
#define FileInfoRecGS_access 6
#define FileInfoRecGS_fileType 8
#define FileInfoRecGS_auxType 10
#define FileInfoRecGS_storageType 14
#define FileInfoRecGS_createDateTime 16
#define FileInfoRecGS_modDateTime 24
#define FileInfoRecGS_optionList 32
#define FileInfoRecGS_eof 36
#define FileInfoRecGS_blocksUsed 40
#define FileInfoRecGS_resourceEOF 44
#define FileInfoRecGS_resourceBlocks 48
#define FileRec_pathname 0
#define FileRec_fAccess 4
#define FileRec_fileType 6
#define FileRec_auxType 8
#define FileRec_storageType 12
#define FileRec_createDate 14
#define FileRec_createTime 16
#define FileRec_modDate 18
#define FileRec_modTime 20
#define FileRec_blocksUsed 22
#define OpenRecGS_pCount 0
#define OpenRecGS_refNum 2
#define OpenRecGS_pathname 4
#define OpenRecGS_requestAccess 8
#define OpenRecGS_resourceNumber 10
#define OpenRecGS_access 12
#define OpenRecGS_fileType 14
#define OpenRecGS_auxType 16
#define OpenRecGS_storageType 20
#define OpenRecGS_createDateTime 22
#define OpenRecGS_modDateTime 30
#define OpenRecGS_optionList 38
#define OpenRecGS_eof 42
#define OpenRecGS_blocksUsed 46
#define OpenRecGS_resourceEOF 50
#define OpenRecGS_resourceBlocks 54
#define OpenRec_openRefNum 0
#define OpenRec_openPathname 2
#define OpenRec_ioBuffer 6
#define VolumeRecGS_pCount 0
#define VolumeRecGS_devName 2
#define VolumeRecGS_volName 6
#define VolumeRecGS_totalBlocks 10
#define VolumeRecGS_freeBlocks 14
#define VolumeRecGS_fileSysID 18
#define VolumeRecGS_blockSize 20
#define VolumeRecGS_characteristics 22
#define VolumeRecGS_deviceID 24
#define VolumeRec_deviceName 0
#define VolumeRec_volName 4
#define VolumeRec_totalBlocks 8
#define VolumeRec_freeBlocks 12
#define VolumeRec_fileSysID 16
#define JudgeNameRecGS_pCount 0
#define JudgeNameRecGS_fileSysID 2
#define JudgeNameRecGS_nameType 4
#define JudgeNameRecGS_syntax 6
#define JudgeNameRecGS_maxLen 10
#define JudgeNameRecGS_name 12
#define JudgeNameRecGS_nameFlags 16
#define PositionRecGS_pCount 0
#define PositionRecGS_refNum 2
#define PositionRecGS_position 4
#define MarkRec_markRefNum 0
#define MarkRec_position 2
#define EOFRecGS_pCount 0
#define EOFRecGS_refNum 2
#define EOFRecGS_eof 4
#define EOFRec_eofRefNum 0
#define EOFRec_eofPosition 2
#define IORecGS_pCount 0
#define IORecGS_refNum 2
#define IORecGS_dataBuffer 4
#define IORecGS_requestCount 8
#define IORecGS_transferCount 12
#define IORecGS_cachePriority 16
#define FileIORec_fileRefNum 0
#define FileIORec_dataBuffer 2
#define FileIORec_requestCount 6
#define FileIORec_transferCount 10
#define SetPositionRecGS_pCount 0
#define SetPositionRecGS_refNum 2
#define SetPositionRecGS_base 4
#define SetPositionRecGS_displacement 6
#define DevNumRecGS_pCount 0
#define DevNumRecGS_devName 2
#define DevNumRecGS_devNum 6
#define DevNumRec_devName 0
#define DevNumRec_devNum 4

47
src/glog.c Normal file
View File

@ -0,0 +1,47 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
#include "glog.h"
int glog(const char *s) {
time_t timer;
char buffer[26];
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
printf("%s - %s\n", buffer, s);
return 0;
}
int glogf(const char *fmt, ...) {
time_t timer;
char buffer[26];
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
printf("%s - ", buffer);
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fputc('\n', stdout);
return 0;
}

8
src/glog.h Normal file
View File

@ -0,0 +1,8 @@
#ifdef __cplusplus
extern "C" {
#endif
int glog(const char *s);
int glogf(const char *s, ...);
#ifdef __cplusplus
}
#endif

164
src/gsos.h Normal file
View File

@ -0,0 +1,164 @@
#define readEnableAllowWrite 0x0000
#define readEnable 0x0001
#define writeEnable 0x0002
#define readWriteEnable 0x0003
#define fileInvisible 0x0004 /* Invisible bit */
#define backupNeeded 0x0020 /* backup needed bit: CreateRec/ OpenRec access field. (Must be 0 in requestAccess field ) */
#define renameEnable 0x0040 /* rename enable bit: CreateRec/ OpenRec access and requestAccess fields */
#define destroyEnable 0x0080 /* destroy enable bit: CreateRec/ OpenRec access and requestAccess fields */
#define startPlus 0x0000 /* base -> setMark = displacement */
#define eofMinus 0x0001 /* base -> setMark = eof - displacement */
#define markPlus 0x0002 /* base -> setMark = mark + displacement */
#define markMinus 0x0003 /* base -> setMark = mark - displacement */
/* cachePriority Codes */
#define cacheOff 0x0000 /* do not cache blocks invloved in this read */
#define cacheOn 0x0001 /* cache blocks invloved in this read if possible */
/* Error Codes */
#define badSystemCall 0x0001 /* bad system call number */
#define invalidPcount 0x0004 /* invalid parameter count */
#define gsosActive 0x0007 /* GS/OS already active */
#ifndef devNotFound /* device not found */
#define devNotFound 0x0010
#endif
#define invalidDevNum 0x0011 /* invalid device number */
#define drvrBadReq 0x0020 /* bad request or command */
#define drvrBadCode 0x0021 /* bad control or status code */
#define drvrBadParm 0x0022 /* bad call parameter */
#define drvrNotOpen 0x0023 /* character device not open */
#define drvrPriorOpen 0x0024 /* character device already open */
#define irqTableFull 0x0025 /* interrupt table full */
#define drvrNoResrc 0x0026 /* resources not available */
#define drvrIOError 0x0027 /* I/O error */
#define drvrNoDevice 0x0028 /* device not connected */
#define drvrBusy 0x0029 /* call aborted; driver is busy */
#define drvrWrtProt 0x002B /* device is write protected */
#define drvrBadCount 0x002C /* invalid byte count */
#define drvrBadBlock 0x002D /* invalid block address */
#define drvrDiskSwitch 0x002E /* disk has been switched */
#define drvrOffLine 0x002F /* device off line/ no media present */
#define badPathSyntax 0x0040 /* invalid pathname syntax */
#define tooManyFilesOpen 0x0042 /* too many files open on server volume */
#define invalidRefNum 0x0043 /* invalid reference number */
#ifndef pathNotFound /* subdirectory does not exist */
#define pathNotFound 0x0044
#endif
#define volNotFound 0x0045 /* volume not found */
#ifndef fileNotFound /* file not found */
#define fileNotFound 0x0046
#endif
#define dupPathname 0x0047 /* create or rename with existing name */
#define volumeFull 0x0048 /* volume full error */
#define volDirFull 0x0049 /* volume directory full */
#define badFileFormat 0x004A /* version error (incompatible file format) */
#ifndef badStoreType /* unsupported (or incorrect) storage type */
#define badStoreType 0x004B
#endif
#ifndef eofEncountered /* end-of-file encountered */
#define eofEncountered 0x004C
#endif
#define outOfRange 0x004D /* position out of range */
#define invalidAccess 0x004E /* access not allowed */
#define buffTooSmall 0x004F /* buffer too small */
#define fileBusy 0x0050 /* file is already open */
#define dirError 0x0051 /* directory error */
#define unknownVol 0x0052 /* unknown volume type */
#ifndef paramRangeErr /* parameter out of range */
#define paramRangeErr 0x0053
#endif
#define outOfMem 0x0054 /* out of memory */
#define dupVolume 0x0057 /* duplicate volume name */
#define notBlockDev 0x0058 /* not a block device */
#ifndef invalidLevel /* specifield level outside legal range */
#define invalidLevel 0x0059
#endif
#define damagedBitMap 0x005A /* block number too large */
#define badPathNames 0x005B /* invalid pathnames for ChangePath */
#define notSystemFile 0x005C /* not an executable file */
#define osUnsupported 0x005D /* Operating System not supported */
#ifndef stackOverflow /* too many applications on stack */
#define stackOverflow 0x005F
#endif
#define dataUnavail 0x0060 /* Data unavailable */
#define endOfDir 0x0061 /* end of directory has been reached */
#define invalidClass 0x0062 /* invalid FST call class */
#define resForkNotFound 0x0063 /* file does not contain required resource */
#define invalidFSTID 0x0064 /* error - FST ID is invalid */
#define invalidFSTop 0x0065 /* invalid FST operation */
#define fstCaution 0x0066 /* FST handled call, but result is weird */
#define devNameErr 0x0067 /* device exists with same name as replacement name */
#define defListFull 0x0068 /* device list is full */
#define supListFull 0x0069 /* supervisor list is full */
#define fstError 0x006a /* generic FST error */
#define resExistsErr 0x0070 /* cannot expand file, resource already exists */
#define resAddErr 0x0071 /* cannot add resource fork to this type file */
#define networkError 0x0088 /* generic network error */
/* fileSys IDs */
#define proDOSFSID 0x0001 /* ProDOS/SOS */
#define dos33FSID 0x0002 /* DOS 3.3 */
#define dos32FSID 0x0003 /* DOS 3.2 */
#define dos31FSID 0x0003 /* DOS 3.1 */
#define appleIIPascalFSID 0x0004 /* Apple II Pascal */
#define mfsFSID 0x0005 /* Macintosh (flat file system) */
#define hfsFSID 0x0006 /* Macintosh (hierarchical file system) */
#define lisaFSID 0x0007 /* Lisa file system */
#define appleCPMFSID 0x0008 /* Apple CP/M */
#define charFSTFSID 0x0009 /* Character FST */
#define msDOSFSID 0x000A /* MS/DOS */
#define highSierraFSID 0x000B /* High Sierra */
#define iso9660FSID 0x000C /* ISO 9660 */
#define appleShareFSID 0x000D /* ISO 9660 */
/* FSTInfo.attributes Codes */
#define characterFST 0x4000 /* character FST */
#define ucFST 0x8000 /* SCM should upper case pathnames before passing them to the FST */
/* QuitRec.flags Codes */
#define onStack 0x8000 /* place state information about quitting program on the quit return stack */
#define restartable 0x4000 /* the quitting program is capable of being restarted from its dormant memory */
/* storageType Codes */
#define seedling 0x0001 /* standard file with seedling structure */
#define standardFile 0x0001 /* standard file type (no resource fork) */
#define sapling 0x0002 /* standard file with sapling structure */
#define tree 0x0003 /* standard file with tree structure */
#define pascalRegion 0x0004 /* UCSD Pascal region on a partitioned disk */
#define extendedFile 0x0005 /* extended file type (with resource fork) */
#define directoryFile 0x000D /* volume directory or subdirectory file */
/* version Codes */
#define minorRelNumMask 0x00FF /* minor release number */
#define majorRelNumMask 0x7F00 /* major release number */
#define finalRelNumMask 0x8000 /* final release number */
/* Other Constants */
#define isFileExtended 0x8000 /* GetDirEntryGS */
/* DControl Codes */
#define resetDevice 0x0000
#define formatDevice 0x0001
#define eject 0x0002
#define setConfigParameters 0x0003
#define setWaitStatus 0x0004
#define setFormatOptions 0x0005
#define assignPartitionOwner 0x0006
#define armSignal 0x0007
#define disarmSignal 0x0008
#define setPartitionMap 0x0009

BIN
src/gsp_icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -1,24 +1,8 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Copyright (C) 2016 - Dagen Brock
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
/* char 0x00 (raw 0x40) */

90
src/headless_driver.c Normal file
View File

@ -0,0 +1,90 @@
/*
GSPLUS - Advanced Apple IIGS Emulator Environment
Based on the KEGS emulator written by Kent Dickey
See COPYRIGHT.txt for Copyright information
See LICENSE.txt for license (GPL v2)
*/
#include "defc.h"
#include "glog.h"
int
main(int argc, char **argv)
{
return gsplusmain(argc, argv);
}
int g_screen_mdepth = 0;
int g_screenshot_requested = 0;
int g_use_shmem = 0;
extern int g_screen_depth;
extern word32 g_palette_8to1624[256];
extern word32 g_a2palette_8to1624[256];
extern Kimage g_mainwin_kimage;
extern int g_lores_colors[];
void check_input_events() {}
int clipboard_get_char() { return 0; }
void clipboard_paste(void) { }
void dev_video_init() {
g_screen_depth = 24;
g_screen_mdepth = 32;
video_get_kimages();
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth);
for(int i = 0; i < 256; i++) {
word32 lores_col = g_lores_colors[i & 0xf];
video_update_color_raw(i, lores_col);
g_a2palette_8to1624[i] = g_palette_8to1624[i];
}
}
void x_dialog_create_gsport_conf(const char *str) { }
int x_show_alert(int is_fatal, const char *str) { return 0; }
void get_ximage(Kimage *kimage_ptr) { }
void x_toggle_status_lines() { }
void x_redraw_status_lines() { }
void x_hide_pointer(int do_hide) { }
void x_auto_repeat_on(int must) { }
void x_auto_repeat_off(int must) { }
void x_release_kimage(Kimage* kimage_ptr) { }
int x_calc_ratio(float x,float y) { return 1; }
void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr) { }
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { }
void x_update_physical_colormap() { }
void show_xcolor_array() { }
void xdriver_end() { }
void x_push_done() { }
void x_full_screen(int do_full) { }
void
x_get_kimage(Kimage *kimage_ptr) {
byte *data;
int width;
int height;
int depth;
width = kimage_ptr->width_req;
height = kimage_ptr->height;
depth = kimage_ptr->depth;
data = malloc(width*height*(depth/4));
kimage_ptr->data_ptr = data;
}
void
x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height)
{
}

1030
src/host_common.c Normal file

File diff suppressed because it is too large Load Diff

105
src/host_common.h Normal file
View File

@ -0,0 +1,105 @@
enum {
file_non,
file_regular,
file_resource,
file_directory,
};
enum {
translate_none,
translate_crlf,
translate_merlin,
};
struct file_info {
time_t create_date;
time_t modified_date;
word16 access;
word16 storage_type;
word16 file_type;
word32 aux_type;
word32 eof;
word32 blocks;
word32 resource_eof;
word32 resource_blocks;
mode_t st_mode;
int has_fi;
byte finder_info[32];
};
extern Engine_reg engine;
#define SEC() engine.psr |= 0x01
#define CLC() engine.psr &= ~0x01
#define SEV() engine.psr |= 0x40
#define CLV() engine.psr &= ~0x40
#define SEZ() engine.psr |= 0x02
#define CLZ() engine.psr &= ~0x02
#define SEI() engine.psr |= 0x04
#define CLI() engine.psr &= ~0x04
enum {
C = 0x01,
Z = 0x02,
I = 0x04,
D = 0x08,
X = 0x10,
M = 0x20,
V = 0x40,
N = 0x80
};
extern int g_cfg_host_read_only;
extern int g_cfg_host_crlf;
extern int g_cfg_host_merlin;
extern char *host_root;
unsigned host_startup(void);
void host_shutdown(void);
int host_is_root(struct stat *);
/* garbage collected string routines */
void *host_gc_malloc(size_t size);
void host_gc_free(void);
char *host_gc_strdup(const char *src);
char *host_gc_append_path(const char *a, const char *b);
char *host_gc_append_string(const char *a, const char *b);
/* text conversion */
void host_cr_to_lf(byte *buffer, size_t size);
void host_lf_to_cr(byte *buffer, size_t size);
void host_merlin_to_text(byte *buffer, size_t size);
void host_text_to_merlin(byte *buffer, size_t size);
/* errno -> IIgs/mli error */
word32 host_map_errno(int xerrno);
word32 host_map_errno_path(int xerrno, const char *path);
const char *host_error_name(word16 error);
/* file info */
int host_file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_type);
void host_get_file_xinfo(const char *path, struct file_info *fi);
word32 host_get_file_info(const char *path, struct file_info *fi);
word32 host_set_file_info(const char *path, struct file_info *fi);
void host_set_date_time_rec(word32 ptr, time_t time);
void host_set_date_time(word32 ptr, time_t time);
time_t host_get_date_time(word32 ptr);
time_t host_get_date_time_rec(word32 ptr);
/* convert to prodos date/time */
word32 host_convert_date_time(time_t time);
void host_hexdump(word32 address, int size);
void host_hexdump_native(void *data, unsigned address, int size);

Some files were not shown because too many files have changed in this diff Show More