diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..1a6397284
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
+guidelines = 80, 120
+
+[*.{c,h}]
+cpp_new_line_before_open_brace_block=same_line
+cpp_new_line_before_open_brace_function=new_line
+cpp_space_before_function_open_parenthesis=insert
+cpp_new_line_before_else=false
diff --git a/.github/checks/spaces.sh b/.github/checks/spaces.sh
index 945e9acc3..e231f6c2d 100755
--- a/.github/checks/spaces.sh
+++ b/.github/checks/spaces.sh
@@ -5,7 +5,7 @@ CHECK_PATH=.
cd $SCRIPT_PATH/../../
-FILES=`find $CHECK_PATH -type f \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -l ' $'`
+FILES=`find $CHECK_PATH -type f \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "test/" | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -l ' $'`
cd $OLDCWD
diff --git a/.github/checks/tabs.sh b/.github/checks/tabs.sh
index 1c32def17..80dac3f2d 100755
--- a/.github/checks/tabs.sh
+++ b/.github/checks/tabs.sh
@@ -5,7 +5,7 @@ CHECK_PATH=.
cd $SCRIPT_PATH/../../
-FILES=`find $CHECK_PATH -type f \( \( -name \*.inc -a \! -name Makefile.inc \) -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -l $'\t'`
+FILES=`find $CHECK_PATH -type f \( \( -name \*.inc -a \! -name Makefile.inc \) -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "test/" | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -l $'\t'`
cd $OLDCWD
diff --git a/.github/workflows/build-on-pull-request.yml b/.github/workflows/build-on-pull-request.yml
index 05d6a4a39..146964a30 100644
--- a/.github/workflows/build-on-pull-request.yml
+++ b/.github/workflows/build-on-pull-request.yml
@@ -19,7 +19,7 @@ jobs:
- shell: bash
run: git config --global core.autocrlf input
- name: Checkout Source
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Do some simple style checks
shell: bash
@@ -43,13 +43,18 @@ jobs:
- name: Build the document files.
shell: bash
run: make -j2 doc
+ - name: Upload a documents snapshot.
+ uses: actions/upload-artifact@v4
+ with:
+ name: docs
+ path: ./html
- name: Build 64-bit Windows versions of the tools.
run: |
make -C src clean
make -j2 bin USER_CFLAGS=-Werror CROSS_COMPILE=x86_64-w64-mingw32-
build_windows:
- name: Build (Windows)
+ name: Build and Test (Windows)
runs-on: windows-latest
steps:
@@ -57,13 +62,31 @@ jobs:
run: git config --global core.autocrlf input
- name: Checkout Source
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Add msbuild to PATH
- uses: microsoft/setup-msbuild@v1.1
+ uses: microsoft/setup-msbuild@v2
- - name: Build app (debug)
- run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Debug
+ - name: Build app (x86 debug)
+ run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Debug -property:Platform=Win32
- - name: Build app (release)
- run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Release
+ - name: Build app (x86 release)
+ run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Release -property:Platform=Win32
+
+ - name: Build app (x64 release)
+ run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Debug -property:Platform=x64
+
+ - name: Build app (x64 release)
+ run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Release -property:Platform=x64
+
+ - name: Build utils (MinGW)
+ shell: cmd
+ run: make -j2 util SHELL=cmd
+
+ - name: Build the platform libraries (make lib)
+ shell: cmd
+ run: make -j2 lib QUIET=1 SHELL=cmd
+
+ - name: Run the regression tests (make test)
+ shell: cmd
+ run: make test QUIET=1 SHELL=cmd
diff --git a/.github/workflows/snapshot-on-push-master.yml b/.github/workflows/snapshot-on-push-master.yml
index e8be4400e..d58bff8ed 100644
--- a/.github/workflows/snapshot-on-push-master.yml
+++ b/.github/workflows/snapshot-on-push-master.yml
@@ -18,10 +18,10 @@ jobs:
run: git config --global core.autocrlf input
- name: Checkout Source
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Add msbuild to PATH
- uses: microsoft/setup-msbuild@v1.1
+ uses: microsoft/setup-msbuild@v2
- name: Build app (debug)
run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Debug
@@ -44,7 +44,7 @@ jobs:
- shell: bash
run: git config --global core.autocrlf input
- name: Checkout Source
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Do some simple style checks
shell: bash
@@ -86,20 +86,24 @@ jobs:
mv cc65.zip cc65-snapshot-win32.zip
- name: Upload a 32-bit Snapshot Zip
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
- name: cc65-snapshot-win32.zip
+ name: cc65-snapshot-win32
path: cc65-snapshot-win32.zip
- name: Upload a 64-bit Snapshot Zip
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
- name: cc65-snapshot-win64.zip
+ name: cc65-snapshot-win64
path: cc65-snapshot-win64.zip
- name: Get the online documents repo.
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
repository: cc65/doc
+ # this token will expire, if it does, generate a new one as decribed in https://github.com/cc65/cc65/issues/2065
+ # - apparently only a "classic" token works here
+ # - the token must exist in the cc65/cc65 repo
+ token: ${{ secrets.DOC_PAT }} # use secret token instead of default
path: doc.git
- name: Update the online documents.
run: |
@@ -110,11 +114,19 @@ jobs:
git config user.email "cc65.nomail@github.com"
git config push.default simple
git add -A
- git commit -m "Updated from cc65 commit ${GITHUB_SHA}."
- #git push -v
+ # prevent failure when there is nothing to commit
+ git diff-index --quiet HEAD || git commit -m "Updated from https://github.com/cc65/cc65/commit/${GITHUB_SHA}"
+ git push
+ - name: Package offline documents.
+ run: 7z a cc65-snapshot-docs.zip ./html/*.*
+ - name: Upload a Documents Snapshot Zip
+ uses: actions/upload-artifact@v4
+ with:
+ name: cc65-snapshot-docs
+ path: cc65-snapshot-docs.zip
# enter secrets under "repository secrets"
- - name: Upload snapshot to sourceforge
+ - name: Upload 32-bit Windows snapshot to sourceforge
uses: nogsantos/scp-deploy@master
with:
src: cc65-snapshot-win32.zip
@@ -123,5 +135,23 @@ jobs:
port: ${{ secrets.SSH_PORT }}
user: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
+ - name: Upload 64-bit Windows snapshot to sourceforge
+ uses: nogsantos/scp-deploy@master
+ with:
+ src: cc65-snapshot-win64.zip
+ host: ${{ secrets.SSH_HOST }}
+ remote: ${{ secrets.SSH_DIR }}
+ port: ${{ secrets.SSH_PORT }}
+ user: ${{ secrets.SSH_USER }}
+ key: ${{ secrets.SSH_KEY }}
+ - name: Upload documents snapshot to sourceforge
+ uses: nogsantos/scp-deploy@master
+ with:
+ src: cc65-snapshot-docs.zip
+ host: ${{ secrets.SSH_HOST }}
+ remote: ${{ secrets.SSH_DIR }}
+ port: ${{ secrets.SSH_PORT }}
+ user: ${{ secrets.SSH_USER }}
+ key: ${{ secrets.SSH_KEY }}
# TODO: Publish snapshot zip at https://github.com/cc65/cc65.github.io
diff --git a/.github/workflows/windows-test-scheduled.yml b/.github/workflows/windows-test-scheduled.yml
new file mode 100644
index 000000000..f72254273
--- /dev/null
+++ b/.github/workflows/windows-test-scheduled.yml
@@ -0,0 +1,78 @@
+name: Windows Test Scheduled
+# Scheduled or manually dispatched because it's slower than the Linux test.
+
+on:
+ schedule:
+ - cron: '0 0 */1 * *'
+ # every 1 days
+ workflow_dispatch:
+ # allow manual dispatch
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+ # don't run more than once at a time
+
+jobs:
+ build_windows:
+ name: Build, Test (Windows MSVC)
+ runs-on: windows-latest
+
+ steps:
+
+ # This cache is used to remember the last build.
+ # If there are no changes and the last build was successful,
+ # the build and test steps will be omitted.
+ # If the last build failed, the full attempt will be repeated.
+ # Github Actions will retain the last build cache for up to 7 days.
+
+ - name: Create Cache
+ shell: bash
+ run: mkdir ~/.cache-sha
+
+ - name: Cache SHA
+ uses: actions/cache@v4
+ id: check-sha
+ with:
+ path: ~/.cache-sha
+ key: cache-sha-wintest-${{ github.sha }}
+
+ - name: Git Setup
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ shell: bash
+ run: git config --global core.autocrlf input
+
+ - name: Checkout source
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ uses: actions/checkout@v4
+
+ - name: Add msbuild to PATH
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ uses: microsoft/setup-msbuild@v2
+
+ - name: Build app (MSVC debug)
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Debug
+
+ - name: Build app (MSVC release)
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ run: msbuild src\cc65.sln -t:rebuild -property:Configuration=Release
+
+ - name: Build utils (MinGW)
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ shell: cmd
+ run: make -j2 util SHELL=cmd
+
+ - name: Build the platform libraries (make lib)
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ shell: cmd
+ run: make -j2 lib QUIET=1 SHELL=cmd
+
+ - name: Run the regression tests (make test)
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ shell: cmd
+ run: make test QUIET=1 SHELL=cmd
+
+ - name: Test that the samples can be built (make samples)
+ if: steps.check-sha.outputs.cache-hit != 'true'
+ shell: cmd
+ run: make -j2 samples SHELL=cmd
diff --git a/Contributing.md b/Contributing.md
index 6fa5ba7c2..1fde873f2 100644
--- a/Contributing.md
+++ b/Contributing.md
@@ -1,4 +1,6 @@
-This document contains all kinds of information that you should know if you want to contribute to the cc65 project. Before you start, please read all of it. If something is not clear to you, please ask - this document is an ongoing effort and may well be incomplete.
+This document contains all kinds of information that you should know if you want to contribute to the cc65 project. Before you start, please read all of it. If something is not clear to you, please ask - this document is an ongoing effort and may well be incomplete.
+
+Also, before you put a lot of work into implementing something you want to contribute, please get in touch with one of the developers and ask if what you are going to do is actually wanted and has a chance of being merged. Perhaps someone else is already working on it, or perhaps what you have in mind is not how we'd expect it to be - talking to us before you start might save you a lot of work in those cases.
(''Note:'' The word "must" indicates a requirement. The word "should" indicates a recomendation.)
@@ -74,10 +76,12 @@ color := $0787
The following is still very incomplete - if in doubt please look at existing sourcefiles and adapt to the existing style
-* Your files should obey the C89 standard.
+* Your files should generally obey the C89 standard, with a few C99 things (this is a bit similar to what cc65 itself supports). The exceptions are:
+ * use stdint.h for variables that require a certain bit size
+ * In printf-style functions use the PRIX64 (and similar) macros to deal with 64bit values (from inttypes.h)
+This list is not necessarily complete - if in doubt, please ask.
* We generally have a "no warnings" policy
-* Warnings must not be hidden by using typecasts - fix the code instead
- * In printf-style functions use the PRIX64 (and similar) macros to deal with 64bit values
+ * Warnings must not be hidden by using typecasts - fix the code instead
* The normal indentation width should be four spaces.
* You must use ANSI C comments (```/* */```); you must not use C++ comments (```//```).
* When you add functions to an existing file, you should separate them by the same number of blank lines that separate the functions that already are in that file.
@@ -134,7 +138,22 @@ You can refer to Annex B of the ISO C99 standard ([here](https://www.open-std.or
* Hexadecimal number constants should be used except where decimal or binary numbers make much more sense in that constant's context.
* Hexadecimal letters should be upper-case.
* When you set two registers or two memory locations to an immediate 16-bit zero, you should use the expressions ```#<$0000``` and ```#>$0000``` (they make it obvious where you are putting the lower and upper bytes).
-* If a function is declared to return a char-sized value, it actually must return an integer-sized value. (When cc65 promotes a returned value, it sometimes assumes that the value already is an integer.)
+* If a function is declared to return a char-sized value, it actually must return an integer-sized value. (When cc65 promotes a returned value, it sometimes assumes that the value already is an integer.) This must be done in one of the following ways:
+
+sometimes jumping to return0 could save a byte:
+
+ .assert RETURN_VALUE = 0
+ jmp return 0
+
* Functions, that are intended for a platform's system library, should be optimized as much as possible.
* Sometimes, there must be a trade-off between size and speed. If you think that a library function won't be used often, then you should make it small. Otherwise, you should make it fast.
* Comments that are put on the right side of instructions must be aligned (start in the same character columns).
@@ -181,9 +200,13 @@ The only exception to the above are actions that are exclusive to the github act
* the printf family of function does not completely implement all printf modifiers and does not behave as expected in some cases - all this should be documented in detail
-## Floating point support
+## Compiler
-The first step is implementing the datatype "float" as IEEE488 floats. Help welcomed!
+* We need a way that makes it possible to feed arbitrary assembler code into the optimzer, so we can have proper tests for it
+
+### Floating point support
+
+The first step is implementing the datatype "float" as IEEE 754 floats. Help welcomed!
* WIP compiler/library changes are here: https://github.com/cc65/cc65/pull/1777
diff --git a/Makefile b/Makefile
index 909de81ec..29fcbbf96 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ mostlyclean clean:
avail unavail bin:
@$(MAKE) -C src --no-print-directory $@
-lib:
+lib libtest:
@$(MAKE) -C libsrc --no-print-directory $@
doc html info:
@@ -43,7 +43,7 @@ util:
checkstyle:
@$(MAKE) -C .github/checks --no-print-directory $@
-# simple "test" target, only run regression tests for c64 target
+# runs regression tests, requires libtest target libraries
test:
@$(MAKE) -C test --no-print-directory $@
diff --git a/README.md b/README.md
index 536e59243..dce9a07bc 100644
--- a/README.md
+++ b/README.md
@@ -7,12 +7,20 @@ For details look at the [Website](https://cc65.github.io).
## People
+Project founders:
+
+* John R. Dunning: [original implementation](https://public.websites.umich.edu/~archive/atari/8bit/Languages/Cc65/) of the C compiler and runtime library, Atari hosted
+* Ullrich von Bassewitz:
+ * move the code to modern systems
+ * rewrite most parts of the compiler
+ * complete rewrite of the runtime library
+
Core team members:
* [Christian Groessler](https://github.com/groessler): Atari, Atari5200, and CreatiVision library Maintainer
* [dqh](https://github.com/dqh-au): GHA help
* [Greg King](https://github.com/greg-king5): all around hackery
-* [groepaz](https://github.com/mrdudz): CBM libary, Project Maintainer
+* [groepaz](https://github.com/mrdudz): CBM library, Project Maintainer
* [Oliver Schmidt](https://github.com/oliverschmidt): Apple II library Maintainer
External contributors:
@@ -23,6 +31,8 @@ External contributors:
* [karrika](https://github.com/karrika): Atari 7800 target
* [Stephan Mühlstrasser](https://github.com/smuehlst): osic1p target
* [Wayne Parham](https://github.com/WayneParham): Sym-1 target
+* [Dave Plummer](https://github.com/davepl): KIM-1 target
+* [rumbledethumps](https://github.com/rumbledethumps): Picocomputer target
*(The above list is incomplete, if you feel left out - please speak up or add yourself in a PR)*
@@ -44,8 +54,10 @@ Some of us may also be around on IRC [#cc65](https://web.libera.chat/#cc65) on l
# Downloads
-* [Windows Snapshot](https://sourceforge.net/projects/cc65/files/cc65-snapshot-win32.zip)
+* [Windows 64bit Snapshot](https://sourceforge.net/projects/cc65/files/cc65-snapshot-win64.zip)
-* [Linux Snapshot DEB and RPM](https://software.opensuse.org//download.html?project=home%3Astrik&package=cc65)
+* [Windows 32bit Snapshot](https://sourceforge.net/projects/cc65/files/cc65-snapshot-win32.zip)
+
+* [Linux Snapshot DEB and RPM](https://software.opensuse.org/download.html?project=home%3Astrik&package=cc65)
[![Snapshot Build](https://github.com/cc65/cc65/actions/workflows/snapshot-on-push-master.yml/badge.svg?branch=master)](https://github.com/cc65/cc65/actions/workflows/snapshot-on-push-master.yml)
diff --git a/asminc/cx16.inc b/asminc/cx16.inc
index 1a916ecdb..d264add38 100644
--- a/asminc/cx16.inc
+++ b/asminc/cx16.inc
@@ -239,12 +239,12 @@ BASIC_BUF := $0200 ; Location of command-line
BASIC_BUF_LEN = 81 ; Maximum length of command-line
SCREEN_PTR := $0262 ; Pointer to current row on text screen (16 bits)
-STATUS := $0289 ; Status from previous I/O operation
-IN_DEV := $028D ; Current input device number
-OUT_DEV := $028E ; Current output device number
-FNAM_LEN := $0291 ; Length of filename
-SECADR := $0293 ; Secondary address
-DEVNUM := $0294 ; Device number
+STATUS := $0287 ; Status from previous I/O operation
+IN_DEV := $028B ; Current input device number
+OUT_DEV := $028C ; Current output device number
+FNAM_LEN := $028F ; Length of filename
+SECADR := $0291 ; Secondary address
+DEVNUM := $0292 ; Device number
CURS_COLOR := $0373 ; Color under the cursor
CHARCOLOR := $0376 ; Cursor's color nybbles (high: background, low: foreground)
RVS := $0377 ; Reverse flag
@@ -258,8 +258,8 @@ LLEN := $0386 ; Line length
NLINES := $0387 ; Number of screen lines
; BASIC
-VARTAB := $03E2 ; Pointer to start of BASIC variables
-MEMSIZE := $03EA ; Pointer to highest BASIC RAM location (+1)
+VARTAB := $03E1 ; Pointer to start of BASIC variables
+MEMSIZE := $0259 ; Pointer to highest BASIC RAM location (+1)
; ---------------------------------------------------------------------------
; Vector and other locations
diff --git a/asminc/generic.mac b/asminc/generic.mac
index bc6f5924e..5e5b210f5 100644
--- a/asminc/generic.mac
+++ b/asminc/generic.mac
@@ -31,10 +31,8 @@
; bgt - jump if unsigned greater
.macro bgt Arg
- .local L
- beq L
+ beq *+4
bcs Arg
-L:
.endmacro
; ble - jump if unsigned less or equal
diff --git a/asminc/kim1.inc b/asminc/kim1.inc
new file mode 100644
index 000000000..81e83b83c
--- /dev/null
+++ b/asminc/kim1.inc
@@ -0,0 +1,31 @@
+; ---------------------------------------------------------------------------
+;
+; KIM-1 definitions
+;
+; ---------------------------------------------------------------------------
+
+
+RAMSTART := $0200 ; Entry point
+
+
+; ---------------------------------------------------------------------------
+; Monitor Functions
+; ---------------------------------------------------------------------------
+OUTCHR := $1EA0 ; Output character
+INTCHR := $1E5A ; Input character without case conversion
+DUMPT := $1800 ; Dump memory to tape
+LOADT := $1873 ; Load memory from tape
+START := $1C4F ; Enter KIM-1 monitor
+SCANDS := $1F1F ; Scan 7-segment display
+KEYIN := $1F40 ; Open up keyboard channel
+GETKEY := $1F6A ; Return key from keyboard
+
+
+; ---------------------------------------------------------------------------
+; System Memory
+; ---------------------------------------------------------------------------
+SAL := $17F5 ; Tape load address low
+SAH := $17F6 ; Tape load address high
+EAL := $17F7 ; Tape address end low
+EAH := $17F8 ; Tape address end high
+ID := $17F9 ; Tape Identification number
diff --git a/asminc/lynx.inc b/asminc/lynx.inc
index 403d15d07..0d34e1c7c 100644
--- a/asminc/lynx.inc
+++ b/asminc/lynx.inc
@@ -81,8 +81,42 @@ MATHJ = $FC6F
; Suzy Misc
-SPRCTL0 = $FC80
+SPRCTL0 = $FC80
+; Sprite bits-per-pixel definitions
+BPP_MASK = %11000000 ; Mask for settings bits per pixel
+BPP_1 = %00000000
+BPP_2 = %01000000
+BPP_3 = %10000000
+BPP_4 = %11000000
+; More sprite control 0 bit definitions
+HFLIP = %00100000
+VFLIP = %00010000
+; Sprite types - redefined to reflect the reality caused by the shadow error
+TYPE_SHADOW = %00000111
+TYPE_XOR = %00000110
+TYPE_NONCOLL = %00000101 ; Non-colliding
+TYPE_NORMAL = %00000100
+TYPE_BOUNDARY = %00000011
+TYPE_BSHADOW = %00000010 ; Background shadow
+TYPE_BACKNONCOLL = %00000001 ; Background non-colliding
+TYPE_BACKGROUND = %00000000
+
SPRCTL1 = $FC81
+LITERAL = %10000000
+PACKED = %00000000
+ALGO3 = %01000000 ; Broken, do not set this bit!
+; Sprite reload mask definitions
+RELOAD_MASK = %00110000
+RENONE = %00000000 ; Reload nothing
+REHV = %00010000 ; Reload hsize, vsize
+REHVS = %00100000 ; Reload hsize, vsize, stretch
+REHVST = %00110000 ; Reload hsize, vsize, stretch, tilt
+; More sprite control 1 bit definitions
+REUSEPAL = %00001000
+SKIP = %00000100
+DRAWUP = %00000010
+DRAWLEFT = %00000001
+
SPRCOLL = $FC82
SPRINIT = $FC83
SUZYHREV = $FC88
@@ -225,30 +259,44 @@ SND_INTERRUPT = TIMER7_INTERRUPT
INTRST = $FD80
INTSET = $FD81
+
MAGRDY0 = $FD84
MAGRDY1 = $FD85
AUDIN = $FD86
SYSCTL1 = $FD87
MIKEYHREV = $FD88
MIKEYSREV = $FD89
-IODIR = $FD8A
-IODAT = $FD8B
-TxIntEnable = %10000000
-RxIntEnable = %01000000
-TxParEnable = %00010000
-ResetErr = %00001000
-TxOpenColl = %00000100
-TxBreak = %00000010
-ParEven = %00000001
-TxReady = %10000000
-RxReady = %01000000
-TxEmpty = %00100000
-RxParityErr = %00010000
-RxOverrun = %00001000
-RxFrameErr = %00000100
-RxBreak = %00000010
-ParityBit = %00000001
-SERCTL = $FD8C
+
+IODIR = $FD8A
+IODAT = $FD8B
+; IODIR and IODAT bit definitions
+AUDIN_BIT = $10 ; Note that there is also the address AUDIN
+READ_ENABLE = $10 ; Same bit for AUDIN_BIT
+RESTLESS = $08
+NOEXP = $04 ; If set, redeye is not connected
+CART_ADDR_DATA = $02
+CART_POWER_OFF = $02 ; Same bit for CART_ADDR_DATA
+EXTERNAL_POWER = $01
+
+SERCTL = $FD8C
+; SERCTL bit definitions for write operations
+TXINTEN = $80
+RXINTEN = $40
+PAREN = $10
+RESETERR = $08
+TXOPEN = $04
+TXBRK = $02
+PAREVEN = $01
+; SERCTL bit definitions for read operations
+TXRDY = $80
+RXRDY = $40
+TXEMPTY = $20
+PARERR = $10
+OVERRUN = $08
+FRAMERR = $04
+RXBRK = $02
+PARBIT = $01
+
SERDAT = $FD8D
SDONEACK = $FD90
CPUSLEEP = $FD91
diff --git a/asminc/rp6502.inc b/asminc/rp6502.inc
new file mode 100644
index 000000000..7dd1b8fcd
--- /dev/null
+++ b/asminc/rp6502.inc
@@ -0,0 +1,97 @@
+; Picocomputer 6502 general defines
+
+; RIA UART
+RIA_READY := $FFE0 ; TX=$80 RX=$40
+RIA_TX := $FFE1
+RIA_RX := $FFE2
+
+; VSYNC from PIX VGA
+RIA_VSYNC := $FFE3
+
+; RIA XRAM portal 0
+RIA_RW0 := $FFE4
+RIA_STEP0 := $FFE5
+RIA_ADDR0 := $FFE6
+
+; RIA XRAM portal 1
+RIA_RW1 := $FFE8
+RIA_STEP1 := $FFE9
+RIA_ADDR1 := $FFEA
+
+; RIA OS fastcall
+RIA_XSTACK := $FFEC
+RIA_ERRNO := $FFED
+RIA_OP := $FFEF
+RIA_IRQ := $FFF0
+RIA_SPIN := $FFF1
+RIA_BUSY := $FFF2 ; Bit $80
+RIA_A := $FFF4
+RIA_X := $FFF6
+RIA_SREG := $FFF8
+
+; RIA OS operation numbers
+RIA_OP_EXIT := $FF
+RIA_OP_ZXSTACK := $00
+RIA_OP_XREG := $01
+RIA_OP_PHI2 := $02
+RIA_OP_CODEPAGE := $03
+RIA_OP_LRAND := $04
+RIA_OP_STDIN_OPT := $05
+RIA_OP_CLOCK_GETRES := $10
+RIA_OP_CLOCK_GETTIME := $11
+RIA_OP_CLOCK_SETTIME := $12
+RIA_OP_CLOCK_GETTIMEZONE := $13
+RIA_OP_OPEN := $14
+RIA_OP_CLOSE := $15
+RIA_OP_READ_XSTACK := $16
+RIA_OP_READ_XRAM := $17
+RIA_OP_WRITE_XSTACK := $18
+RIA_OP_WRITE_XRAM := $19
+RIA_OP_LSEEK := $1A
+RIA_OP_UNLINK := $1B
+RIA_OP_RENAME := $1C
+
+; 6522 VIA
+VIA := $FFD0 ; VIA base address
+VIA_PB := VIA+$0 ; Port register B
+VIA_PA1 := VIA+$1 ; Port register A
+VIA_PRB := VIA+$0 ; *** Deprecated ***
+VIA_PRA := VIA+$1 ; *** Deprecated ***
+VIA_DDRB := VIA+$2 ; Data direction register B
+VIA_DDRA := VIA+$3 ; Data direction register A
+VIA_T1CL := VIA+$4 ; Timer 1, low byte
+VIA_T1CH := VIA+$5 ; Timer 1, high byte
+VIA_T1LL := VIA+$6 ; Timer 1 latch, low byte
+VIA_T1LH := VIA+$7 ; Timer 1 latch, high byte
+VIA_T2CL := VIA+$8 ; Timer 2, low byte
+VIA_T2CH := VIA+$9 ; Timer 2, high byte
+VIA_SR := VIA+$A ; Shift register
+VIA_CR := VIA+$B ; Auxiliary control register
+VIA_PCR := VIA+$C ; Peripheral control register
+VIA_IFR := VIA+$D ; Interrupt flag register
+VIA_IER := VIA+$E ; Interrupt enable register
+VIA_PA2 := VIA+$F ; Port register A w/o handshake
+
+; Values in ___oserror are the union of these FatFs errors and errno.inc
+.enum
+ FR_OK = 32 ; Succeeded
+ FR_DISK_ERR ; A hard error occurred in the low level disk I/O layer
+ FR_INT_ERR ; Assertion failed
+ FR_NOT_READY ; The physical drive cannot work
+ FR_NO_FILE ; Could not find the file
+ FR_NO_PATH ; Could not find the path
+ FR_INVALID_NAME ; The path name format is invalid
+ FR_DENIED ; Access denied due to prohibited access or directory full
+ FR_EXIST ; Access denied due to prohibited access
+ FR_INVALID_OBJECT ; The file/directory object is invalid
+ FR_WRITE_PROTECTED ; The physical drive is write protected
+ FR_INVALID_DRIVE ; The logical drive number is invalid
+ FR_NOT_ENABLED ; The volume has no work area
+ FR_NO_FILESYSTEM ; There is no valid FAT volume
+ FR_MKFS_ABORTED ; The f_mkfs() aborted due to any problem
+ FR_TIMEOUT ; Could not get a grant to access the volume within defined period
+ FR_LOCKED ; The operation is rejected according to the file sharing policy
+ FR_NOT_ENOUGH_CORE ; LFN working buffer could not be allocated
+ FR_TOO_MANY_OPEN_FILES ; Number of open files > FF_FS_LOCK
+ FR_INVALID_PARAMETER ; Given parameter is invalid
+.endenum
diff --git a/asminc/stat.inc b/asminc/stat.inc
new file mode 100644
index 000000000..e5248f06d
--- /dev/null
+++ b/asminc/stat.inc
@@ -0,0 +1,64 @@
+;****************************************************************************
+;* *
+;* stat.inc *
+;* *
+;* Stat struct *
+;* *
+;* *
+;* *
+;*(C) 2023 Colin Leroy-Mira *
+;* *
+;* *
+;*This software is provided 'as-is', without any expressed or implied *
+;*warranty. In no event will the authors be held liable for any damages *
+;*arising from the use of this software. *
+;* *
+;*Permission is granted to anyone to use this software for any purpose, *
+;*including commercial applications, and to alter it and redistribute it *
+;*freely, subject to the following restrictions: *
+;* *
+;*1. The origin of this software must not be misrepresented; you must not *
+;* claim that you wrote the original software. If you use this software *
+;* in a product, an acknowledgment in the product documentation would be *
+;* appreciated but is not required. *
+;*2. Altered source versions must be plainly marked as such, and must not *
+;* be misrepresented as being the original software. *
+;*3. This notice may not be removed or altered from any source *
+;* distribution. *
+;* *
+;****************************************************************************
+
+ .include "time.inc"
+
+;------------------------------------------------------------------------------
+; st_mode values
+
+S_IFDIR = $01
+S_IFREG = $02
+
+;------------------------------------------------------------------------------
+; struct stat
+
+.struct stat
+ st_dev .dword
+ st_ino .dword
+ st_mode .byte
+ st_nlink .dword
+ st_uid .byte
+ st_gid .byte
+ st_size .dword
+ st_atim .tag timespec
+ st_ctim .tag timespec
+ st_mtim .tag timespec
+ .ifdef __APPLE2__
+ st_access .byte
+ st_type .byte
+ st_auxtype .word
+ st_storagetype .byte
+ st_blocks .word
+ st_mod_date .word
+ st_mod_time .word
+ st_create_date .word
+ st_create_time .word
+ .endif
+.endstruct
diff --git a/asminc/statvfs.inc b/asminc/statvfs.inc
new file mode 100644
index 000000000..8674b045d
--- /dev/null
+++ b/asminc/statvfs.inc
@@ -0,0 +1,46 @@
+;****************************************************************************
+;* *
+;* statvfs.inc *
+;* *
+;* Statvfs struct *
+;* *
+;* *
+;* *
+;*(C) 2023 Colin Leroy-Mira *
+;* *
+;* *
+;*This software is provided 'as-is', without any expressed or implied *
+;*warranty. In no event will the authors be held liable for any damages *
+;*arising from the use of this software. *
+;* *
+;*Permission is granted to anyone to use this software for any purpose, *
+;*including commercial applications, and to alter it and redistribute it *
+;*freely, subject to the following restrictions: *
+;* *
+;*1. The origin of this software must not be misrepresented; you must not *
+;* claim that you wrote the original software. If you use this software *
+;* in a product, an acknowledgment in the product documentation would be *
+;* appreciated but is not required. *
+;*2. Altered source versions must be plainly marked as such, and must not *
+;* be misrepresented as being the original software. *
+;*3. This notice may not be removed or altered from any source *
+;* distribution. *
+;* *
+;****************************************************************************
+
+;------------------------------------------------------------------------------
+; struct statvfs
+
+.struct statvfs
+ f_bsize .dword
+ f_frsize .dword
+ f_blocks .dword
+ f_bfree .dword
+ f_bavail .dword
+ f_files .dword
+ f_ffree .dword
+ f_favail .dword
+ f_fsid .dword
+ f_flag .dword
+ f_namemax .dword
+.endstruct
diff --git a/asminc/telestrat.inc b/asminc/telestrat.inc
index 682696887..bbfabdf40 100644
--- a/asminc/telestrat.inc
+++ b/asminc/telestrat.inc
@@ -257,8 +257,11 @@ XBINDX = $28 ; Convert a number into hex and displays on chan
XDECIM = $29
XHEXA = $2A ; Convert a number into hex
+XMAINARGS = $2C ; Only available for Orix
+
XEDT = $2D ; Launch editor
XINSER = $2E
+XGETARGV = $2E ; Only available for Orix
XSCELG = $2F ; Search a line in editor mode
XOPEN = $30 ; Only in Orix
@@ -277,6 +280,8 @@ XRECLK = $3C ; Reset clock
XCLCL = $3D ; Close clock
XWRCLK = $3E ; Displays clock in the address in A & Y registers
+XFSEEK = $3F ; Only in Orix
+
; Sound primitives
XSONPS = $40 ; Send data to PSG register (14 values)
XOUPS = $42 ; Send Oups sound into PSG
diff --git a/cfg/apple2-hgr.cfg b/cfg/apple2-hgr.cfg
index cfe577e00..109fbe4f6 100644
--- a/cfg/apple2-hgr.cfg
+++ b/cfg/apple2-hgr.cfg
@@ -27,7 +27,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro start = $4000;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/apple2-overlay.cfg b/cfg/apple2-overlay.cfg
index a0b7678c1..754ece90f 100644
--- a/cfg/apple2-overlay.cfg
+++ b/cfg/apple2-overlay.cfg
@@ -43,7 +43,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/apple2-system.cfg b/cfg/apple2-system.cfg
index 0170feb93..3dd94d793 100644
--- a/cfg/apple2-system.cfg
+++ b/cfg/apple2-system.cfg
@@ -22,7 +22,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/apple2.cfg b/cfg/apple2.cfg
index a6809cf89..19932b1f9 100644
--- a/cfg/apple2.cfg
+++ b/cfg/apple2.cfg
@@ -26,7 +26,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/apple2enh-hgr.cfg b/cfg/apple2enh-hgr.cfg
index cfe577e00..109fbe4f6 100644
--- a/cfg/apple2enh-hgr.cfg
+++ b/cfg/apple2enh-hgr.cfg
@@ -27,7 +27,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro start = $4000;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/apple2enh-overlay.cfg b/cfg/apple2enh-overlay.cfg
index a0b7678c1..754ece90f 100644
--- a/cfg/apple2enh-overlay.cfg
+++ b/cfg/apple2enh-overlay.cfg
@@ -43,7 +43,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/apple2enh-system.cfg b/cfg/apple2enh-system.cfg
index 0170feb93..3dd94d793 100644
--- a/cfg/apple2enh-system.cfg
+++ b/cfg/apple2enh-system.cfg
@@ -22,7 +22,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/apple2enh.cfg b/cfg/apple2enh.cfg
index a6809cf89..19932b1f9 100644
--- a/cfg/apple2enh.cfg
+++ b/cfg/apple2enh.cfg
@@ -26,7 +26,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
LC: load = MAIN, run = LC, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/atari-overlay.cfg b/cfg/atari-overlay.cfg
index 9311a1b22..60f98e453 100644
--- a/cfg/atari-overlay.cfg
+++ b/cfg/atari-overlay.cfg
@@ -52,7 +52,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes;
diff --git a/cfg/atari-xex.cfg b/cfg/atari-xex.cfg
index cabde3708..deab5c7a5 100644
--- a/cfg/atari-xex.cfg
+++ b/cfg/atari-xex.cfg
@@ -36,7 +36,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
}
FEATURES {
diff --git a/cfg/atari.cfg b/cfg/atari.cfg
index 106c75e63..37337ea53 100644
--- a/cfg/atari.cfg
+++ b/cfg/atari.cfg
@@ -40,7 +40,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
}
diff --git a/cfg/atarixl-largehimem.cfg b/cfg/atarixl-largehimem.cfg
index 38fb68db9..8f70597aa 100644
--- a/cfg/atarixl-largehimem.cfg
+++ b/cfg/atarixl-largehimem.cfg
@@ -67,7 +67,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
}
diff --git a/cfg/atarixl-overlay.cfg b/cfg/atarixl-overlay.cfg
index 339228ea0..3b8da4256 100644
--- a/cfg/atarixl-overlay.cfg
+++ b/cfg/atarixl-overlay.cfg
@@ -78,7 +78,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
diff --git a/cfg/atarixl-xex.cfg b/cfg/atarixl-xex.cfg
index 1b76855d0..853096c6f 100644
--- a/cfg/atarixl-xex.cfg
+++ b/cfg/atarixl-xex.cfg
@@ -58,7 +58,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
SRPREPHDR: load = UNUSED, type = ro;
SRPREPTRL: load = UNUSED, type = ro;
diff --git a/cfg/atarixl.cfg b/cfg/atarixl.cfg
index cece23555..1517afb5a 100644
--- a/cfg/atarixl.cfg
+++ b/cfg/atarixl.cfg
@@ -65,7 +65,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = bss, optional = yes;
BSS: load = MAIN, type = bss, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
}
diff --git a/cfg/atmos.cfg b/cfg/atmos.cfg
index 35f184f4f..4c370903a 100644
--- a/cfg/atmos.cfg
+++ b/cfg/atmos.cfg
@@ -23,7 +23,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BASTAIL: load = MAIN, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/cfg/c64-overlay.cfg b/cfg/c64-overlay.cfg
index 0f42434ad..ae760b30c 100644
--- a/cfg/c64-overlay.cfg
+++ b/cfg/c64-overlay.cfg
@@ -44,7 +44,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
OVL1ADDR: load = OVL1ADDR, type = ro;
diff --git a/cfg/c64.cfg b/cfg/c64.cfg
index 5bd8d8240..59cadd46b 100644
--- a/cfg/c64.cfg
+++ b/cfg/c64.cfg
@@ -23,7 +23,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
}
diff --git a/cfg/creativision.cfg b/cfg/creativision.cfg
index 2eb9ac427..f3b7ac0f4 100644
--- a/cfg/creativision.cfg
+++ b/cfg/creativision.cfg
@@ -11,10 +11,10 @@ SEGMENTS {
ZP: load = ZP, type = zp, optional = yes;
VECTORS: load = ROM, run = RAM, type = rw, define = yes;
DATA: load = ROM, run = RAM, type = rw, define = yes, start = $0204;
+ INIT: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes;
ONCE: load = ROM, type = ro, optional = yes;
CODE: load = ROM, type = ro;
- INIT: load = ROM, type = ro;
RODATA: load = ROM, type = ro;
AUDIO: load = ROM, type = ro, optional = yes, start = $BF00;
SETUP: load = ROM, type = ro, start = $BFE8;
diff --git a/cfg/cx16-bank.cfg b/cfg/cx16-bank.cfg
index d3c2c02ae..264b6fcba 100644
--- a/cfg/cx16-bank.cfg
+++ b/cfg/cx16-bank.cfg
@@ -57,7 +57,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = rw, optional = yes; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
BRAM01ADDR: load = BRAM01ADDR, type = ro, optional = yes;
diff --git a/cfg/cx16.cfg b/cfg/cx16.cfg
index 4b6025fb6..a160a6718 100644
--- a/cfg/cx16.cfg
+++ b/cfg/cx16.cfg
@@ -24,7 +24,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw, optional = yes;
+ INIT: load = MAIN, type = rw, optional = yes; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BSS: load = BSS, type = bss, define = yes;
}
diff --git a/cfg/kim1-60k.cfg b/cfg/kim1-60k.cfg
new file mode 100644
index 000000000..087715560
--- /dev/null
+++ b/cfg/kim1-60k.cfg
@@ -0,0 +1,41 @@
+# kim1-60k.cfg (4k)
+#
+# for expanded KIM-1
+#
+# ld65 --config kim1-60k.cfg -o .bin .o
+
+FEATURES {
+ STARTADDRESS: default = $2000;
+ CONDES: segment = STARTUP,
+ type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__;
+ CONDES: segment = STARTUP,
+ type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__;
+}
+
+SYMBOLS {
+ __STACKSIZE__: type = weak, value = $0080; # 128 byte program stack
+ __STARTADDRESS__: type = export, value = %S;
+}
+
+MEMORY {
+ ZP: file = %O, define = yes, start = $0000, size = $00EE;
+ CPUSTACK: file = "", define = yes, start = $0100, size = $0100;
+ RAM: file = %O, define = yes, start = %S, size = $E000 - %S - __STACKSIZE__;
+ MAINROM: file = "", define = yes, start = $E000, size = $1000;
+ TOP: file = "", define = yes, start = $F000, size = $1000;
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp, define = yes;
+ STARTUP: load = RAM, type = ro, define = yes;
+ CODE: load = RAM, type = ro, define = yes;
+ RODATA: load = RAM, type = ro, define = yes;
+ ONCE: load = RAM, type = ro, define = yes;
+ DATA: load = RAM, type = rw, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+}
+
diff --git a/cfg/kim1-mtu60k.cfg b/cfg/kim1-mtu60k.cfg
new file mode 100644
index 000000000..4f24a4bf4
--- /dev/null
+++ b/cfg/kim1-mtu60k.cfg
@@ -0,0 +1,41 @@
+# kim1-mtu60k.cfg (4k)
+#
+# for expanded KIM-1 w/ K-1008 Graphics and 60K RAM
+#
+# ld65 --config kim1-mtu60k.cfg -o .bin .o
+
+FEATURES {
+ STARTADDRESS: default = $2000;
+ CONDES: segment = STARTUP,
+ type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__;
+ CONDES: segment = STARTUP,
+ type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__;
+}
+
+SYMBOLS {
+ __STACKSIZE__: type = weak, value = $0080; # 128 byte program stack
+ __STARTADDRESS__: type = export, value = %S;
+}
+
+MEMORY {
+ ZP: file = %O, define = yes, start = $0000, size = $00EE;
+ CPUSTACK: file = "", define = yes, start = $0100, size = $0100;
+ RAM: file = %O, define = yes, start = %S, size = $E000 - %S - __STACKSIZE__;
+ MAINROM: file = "", define = yes, start = $E000, size = $1000;
+ TOP: file = "", define = yes, start = $F000, size = $1000;
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp, define = yes;
+ STARTUP: load = RAM, type = ro, define = yes;
+ CODE: load = RAM, type = ro, define = yes;
+ RODATA: load = RAM, type = ro, define = yes;
+ ONCE: load = RAM, type = ro, define = yes;
+ DATA: load = RAM, type = rw, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+}
+
diff --git a/cfg/kim1-mtuE000.cfg b/cfg/kim1-mtuE000.cfg
new file mode 100644
index 000000000..5f93cc13f
--- /dev/null
+++ b/cfg/kim1-mtuE000.cfg
@@ -0,0 +1,41 @@
+# kim1-mtu60k.cfg (4k)
+#
+# for expanded KIM-1 w/ K-1008 Graphics and 60K RAM
+#
+# ld65 --config kim1-mtu60k.cfg -o .bin .o
+
+FEATURES {
+ STARTADDRESS: default = $E000;
+ CONDES: segment = STARTUP,
+ type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__;
+ CONDES: segment = STARTUP,
+ type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__;
+}
+
+SYMBOLS {
+ __STACKSIZE__: type = weak, value = $0080; # 128 byte program stack
+ __STARTADDRESS__: type = export, value = %S;
+}
+
+MEMORY {
+ ZP: file = %O, define = yes, start = $0000, size = $00EE;
+ CPUSTACK: file = "", define = yes, start = $0100, size = $0100;
+ RAM: file = %O, define = yes, start = $2000, size = $E000 - $2000 - __STACKSIZE__;
+ MAINROM: file = "", define = yes, start = $E000, size = $1000;
+ TOP: file = "", define = yes, start = $F000, size = $1000;
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp, define = yes;
+ STARTUP: load = RAM, type = ro, define = yes;
+ CODE: load = RAM, type = ro, define = yes;
+ RODATA: load = RAM, type = ro, define = yes;
+ ONCE: load = RAM, type = ro, define = yes;
+ DATA: load = RAM, type = rw, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+}
+
diff --git a/cfg/kim1.cfg b/cfg/kim1.cfg
new file mode 100644
index 000000000..f48fed80e
--- /dev/null
+++ b/cfg/kim1.cfg
@@ -0,0 +1,41 @@
+# kim1.cfg (4k)
+#
+# for unexpanded KIM-1
+#
+# ld65 --config kim1.cfg -o .bin .o
+
+FEATURES {
+ STARTADDRESS: default = $0200;
+ CONDES: segment = STARTUP,
+ type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__;
+ CONDES: segment = STARTUP,
+ type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__;
+}
+
+SYMBOLS {
+ __STACKSIZE__: type = weak, value = $0080; # 128 byte program stack
+ __STARTADDRESS__: type = export, value = %S;
+}
+
+MEMORY {
+ ZP: file = %O, define = yes, start = $0000, size = $00EE;
+ CPUSTACK: file = "", define = yes, start = $0100, size = $0100;
+ RAM: file = %O, define = yes, start = %S, size = $1000 - %S - __STACKSIZE__;
+ MAINROM: file = "", define = yes, start = $E000, size = $1000;
+ TOP: file = "", define = yes, start = $F000, size = $1000;
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp, define = yes;
+ STARTUP: load = RAM, type = ro, define = yes;
+ CODE: load = RAM, type = ro, define = yes;
+ RODATA: load = RAM, type = ro, define = yes;
+ ONCE: load = RAM, type = ro, define = yes;
+ DATA: load = RAM, type = rw, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+}
+
diff --git a/cfg/lynx-uploader.cfg b/cfg/lynx-uploader.cfg
index 476b3c5de..62269de90 100644
--- a/cfg/lynx-uploader.cfg
+++ b/cfg/lynx-uploader.cfg
@@ -5,16 +5,17 @@ SYMBOLS {
__BANK1BLOCKSIZE__: type = weak, value = $0000; # bank 1 block size
__EXEHDR__: type = import;
__BOOTLDR__: type = import;
- __DEFDIR__: type = import;
__UPLOADER__: type = import;
+ __UPLOADERSIZE__: type = export, value = $61;
+ __HEADERSIZE__: type = export, value = 64;
}
MEMORY {
ZP: file = "", define = yes, start = $0000, size = $0100;
- HEADER: file = %O, start = $0000, size = $0040;
+ HEADER: file = %O, start = $0000, size = __HEADERSIZE__;
BOOT: file = %O, start = $0200, size = __STARTOFDIRECTORY__;
- DIR: file = %O, start = $0000, size = 8;
- MAIN: file = %O, define = yes, start = $0200, size = $BD38 - __STACKSIZE__;
- UPLDR: file = %O, define = yes, start = $BFDC, size = $005C;
+ DIR: file = %O, start = $0000, size = 16;
+ MAIN: file = %O, define = yes, start = $0200, size = $C038 - __UPLOADERSIZE__ - $200 - __STACKSIZE__;
+ UPLOAD: file = %O, define = yes, start = $C038 - __UPLOADERSIZE__, size = $0061;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
@@ -30,8 +31,8 @@ SEGMENTS {
RODATA: load = MAIN, type = ro, define = yes;
DATA: load = MAIN, type = rw, define = yes;
BSS: load = MAIN, type = bss, define = yes;
- UPCODE: load = UPLDR, type = ro, define = yes;
- UPDATA: load = UPLDR, type = rw, define = yes;
+ UPCODE: load = UPLOAD, type = ro, define = yes;
+ UPDATA: load = UPLOAD, type = rw, define = yes;
}
FEATURES {
CONDES: type = constructor,
diff --git a/cfg/rp6502.cfg b/cfg/rp6502.cfg
new file mode 100644
index 000000000..ed40e467d
--- /dev/null
+++ b/cfg/rp6502.cfg
@@ -0,0 +1,34 @@
+SYMBOLS {
+ __STARTUP__: type = import;
+ __STACKSIZE__: type = weak, value = $0800;
+}
+MEMORY {
+ ZP: file = "", define = yes, start = $0000, size = $0100;
+ CPUSTACK: file = "", start = $0100, size = $0100;
+ RAM: file = %O, define = yes, start = $0200, size = $FD00 - __STACKSIZE__;
+}
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ STARTUP: load = RAM, type = ro;
+ LOWCODE: load = RAM, type = ro, optional = yes;
+ ONCE: load = RAM, type = ro, optional = yes;
+ CODE: load = RAM, type = ro;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+}
+FEATURES {
+ CONDES: type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__,
+ segment = ONCE;
+ CONDES: type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__,
+ segment = RODATA;
+ CONDES: type = interruptor,
+ label = __INTERRUPTOR_TABLE__,
+ count = __INTERRUPTOR_COUNT__,
+ segment = RODATA,
+ import = __CALLIRQ__;
+}
diff --git a/cfg/telestrat.cfg b/cfg/telestrat.cfg
index bd720fb8d..52b982eef 100644
--- a/cfg/telestrat.cfg
+++ b/cfg/telestrat.cfg
@@ -22,7 +22,7 @@ SEGMENTS {
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
- INIT: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw; # uninitialized, but reserves output space
ONCE: load = MAIN, type = ro, define = yes;
BASTAIL: load = MAIN, type = ro, optional = yes;
BSS: load = BSS, type = bss, define = yes;
diff --git a/doc/apple2.sgml b/doc/apple2.sgml
index 63b40c6f8..99ff8139e 100644
--- a/doc/apple2.sgml
+++ b/doc/apple2.sgml
@@ -62,7 +62,7 @@ Special locations:
While running Apple ][ specific functions
-The functions listed below are special for the Apple ][. See
-the for declaration and
+The functions and variables listed below are special for the Apple ][.
+See the for declaration and
usage.
_auxtype
_dos_type
_filetype
+_datetime
+beep
get_ostype
+gmtime_dt
+mktime_dt
rebootafterexit
ser_apple2_slot
tgi_apple2_mix
+Apple IIgs specific functions in accelerator.h
+
+In addition to those, the for declaration and
+usage.
+
+
+detect_iigs
+get_iigs_speed
+set_iigs_speed
+
+
+
Hardware access
There's currently no support for direct hardware access. This does not mean
@@ -427,17 +445,47 @@ The names in the parentheses denote the symbols to be used for static linking of
- Driver for the Apple II Super Serial Card. Supports up to 19200 baud,
- requires hardware flow control (RTS/CTS) and does interrupt driven receives.
+ Driver for the Apple II Super Serial Card.
+ The SSC is an extension card for the II, II+, IIe; the Apple //c and //c+ have
+ the same hardware and firmware integrated.
+ It supports up to 9600 baud, supports no flow control and hardware flow control
+ (RTS/CTS) and does interrupt driven receives. Speeds faster than 9600 baud
+ aren't reachable because the ROM and ProDOS IRQ handlers are too slow.
+ Software flow control (XON/XOFF) is not supported.
+
Note that because of the peculiarities of the 6551 chip transmits are not
interrupt driven, and the transceiver blocks if the receiver asserts
flow control because of a full buffer.
+ Note that using the driver at SER_BAUD_115200 will disable IRQs. It will be up
+ to the users to use the serial port, either by re-enabling IRQs themselves,
+ or by directly poll-reading the ACIA DATA register without the help of ser_get().
+
The driver defaults to slot 2. Call
+ Driver for the Apple IIgs serial ports (printer and modem).
+ It supports up to 9600 baud, supports no flow control and hardware flow control
+ (RTS/CTS) and does interrupt driven receives. Speeds faster than 9600 baud
+ aren't reachable because the ROM and ProDOS IRQ handlers are too slow.
+ Software flow control (XON/XOFF) is not supported.
+ Note that transmits are not interrupt driven, and the transceiver blocks if
+ the receiver asserts flow control because of a full buffer.
+
+ The driver defaults to opening the modem port. Calling
@@ -544,6 +592,28 @@ program. See the discussion of the .
+ProDOS date/time manipulation
+
+
+The readdir and stat function return ProDOS timestamps in their file
+creation/modification time attributes. You can convert them to more portable
+time representations using either:
+
+
+
+
DIO
@@ -603,7 +673,17 @@ url="ca65.html" name="assembler manual">.
The header file
+
+ extern struct datetime _datetime;
+
+
Example
diff --git a/doc/apple2enh.sgml b/doc/apple2enh.sgml
index 15ceed04f..9c46bd4fb 100644
--- a/doc/apple2enh.sgml
+++ b/doc/apple2enh.sgml
@@ -21,7 +21,8 @@ as it comes with the cc65 C compiler. It describes the memory layout,
enhanced Apple //e specific header files, available drivers, and any
pitfalls specific to that platform.
-Please note that enhanced Apple //e specific functions are just mentioned
+Please note that this target requires a 65C02 or 65816 CPU,
+enhanced Apple //e specific functions are just mentioned
here, they are described in detail in the separate . Even functions marked as "platform dependent" may
be available on more than one platform. Please see the function reference for
@@ -62,7 +63,7 @@ Special locations:
While running Enhanced Apple //e specific functions
-The functions listed below are special for the enhanced Apple //e. See
-the for declaration and
+The functions and variables listed below are special for the Apple ][.
+See the for declaration and
usage.
_auxtype
_dos_type
_filetype
+_datetime
+beep
get_ostype
+gmtime_dt
+mktime_dt
rebootafterexit
ser_apple2_slot
tgi_apple2_mix
@@ -338,6 +343,20 @@ usage.
+Apple IIgs specific functions in accelerator.h
+
+In addition to those, the for declaration and
+usage.
+
+
+detect_iigs
+get_iigs_speed
+set_iigs_speed
+
+
+
Hardware access
There's currently no support for direct hardware access. This does not mean
@@ -427,17 +446,47 @@ The names in the parentheses denote the symbols to be used for static linking of
- Driver for the Apple II Super Serial Card. Supports up to 19200 baud,
- requires hardware flow control (RTS/CTS) and does interrupt driven receives.
+ Driver for the Apple II Super Serial Card.
+ The SSC is an extension card for the II, II+, IIe; the Apple //c and //c+ have
+ the same hardware and firmware integrated.
+ It supports up to 9600 baud, supports no flow control and hardware flow control
+ (RTS/CTS) and does interrupt driven receives. Speeds faster than 9600 baud
+ aren't reachable because the ROM and ProDOS IRQ handlers are too slow.
+ Software flow control (XON/XOFF) is not supported.
+
Note that because of the peculiarities of the 6551 chip transmits are not
interrupt driven, and the transceiver blocks if the receiver asserts
flow control because of a full buffer.
+ Note that using the driver at SER_BAUD_115200 will disable IRQs. It will be up
+ to the users to use the serial port, either by re-enabling IRQs themselves,
+ or by directly poll-reading the ACIA DATA register without the help of ser_get().
+
The driver defaults to slot 2. Call
+ Driver for the Apple IIgs serial ports (printer and modem).
+ It supports up to 9600 baud, supports no flow control and hardware flow control
+ (RTS/CTS) and does interrupt driven receives. Speeds faster than 9600 baud
+ aren't reachable because the ROM and ProDOS IRQ handlers are too slow.
+ Software flow control (XON/XOFF) is not supported.
+ Note that transmits are not interrupt driven, and the transceiver blocks if
+ the receiver asserts flow control because of a full buffer.
+
+ The driver defaults to opening the modem port. Calling
@@ -549,6 +598,28 @@ program. See the discussion of the .
+ProDOS date/time manipulation
+
+
+The readdir and stat function return ProDOS timestamps in their file
+creation/modification time attributes. You can convert them to more portable
+time representations using either:
+
+
+
+
DIO
@@ -593,7 +664,7 @@ url="ca65.html" name="assembler manual">.
auxiliary type. Therefore, some additional mechanism for specifying
the file types is needed.
- Specifying the File Type and Auxiliary Type
+ Specifying the File Type, Auxiliary Type and creation date
There are two global variables provided that allow the file type
and auxiliary type to be specified before a call to .
that can be used to set these variables. It is included in
+
+ extern struct datetime _datetime;
+
+
+
Example
A text file cannot be created with just the
diff --git a/doc/atari.sgml b/doc/atari.sgml
index 2e2db0402..3057cd8a6 100644
--- a/doc/atari.sgml
+++ b/doc/atari.sgml
@@ -332,6 +332,7 @@ See the for declaration and u
_scroll
_setcolor
_setcolor_low
+_sound
waitvsync
diff --git a/doc/ca65.sgml b/doc/ca65.sgml
index 19fd3aa2a..c5c6893da 100644
--- a/doc/ca65.sgml
+++ b/doc/ca65.sgml
@@ -120,11 +120,12 @@ Long options:
--list-bytes n Maximum number of bytes per listing line
--memory-model model Set the memory model
--pagelength n Set the page length for the listing
- --relax-checks Relax some checks (see docs)
+ --relax-checks Disables some error checks
--smart Enable smart mode
--target sys Set the target system
--verbose Increase verbosity
--version Print the assembler version
+ --warnings-as-errors Treat warnings as errors
---------------------------------------------------------------------------
@@ -183,7 +184,7 @@ Here is a description of all the command line options:
Enable an emulation feature. This is identical as using
@@ -264,14 +265,17 @@ Here is a description of all the command line options:
@@ -448,6 +468,17 @@ mnemonics:
TSA is an alias for TSC
+The
+ mvn #^src, #^dst ; bank of src to bank of dst
+ mvn src, dst ; bank of src to bank of dst
+ mvp #$12, #$78 ; bank $12 to $78
+ mvp $123456, $789ABC ; bank $12 to $78
+
+
6502X mode
@@ -1339,17 +1370,22 @@ writable.
Reading this pseudo variable will give the assembler version according to
the following formula:
- VER_MAJOR*$100 + VER_MINOR*$10
+ (VER_MAJOR * 0x100) + VER_MINOR
- It may be used to encode the assembler version or check the assembler for
- special features not available with older versions.
+ The upper 8 bits are the major-, the lower 8 bits are the minor version.
Example:
- Version 2.14 of the assembler will return $2E0 as numerical constant when
- reading the pseudo variable (VER_MAJOR * 0x100) + VER_MINOR * 0x10 -
+ which resulted in broken values starting at version 2.16 of the assembler. For
+ this reason the value of this pseudo variable is considered purely informal - you should
+ not use it to check for a specific assembler version and use different code
+ according to the detected version - please update your code to work with the
+ recent version of the assembler instead (There is very little reason to not use
+ the most recent version - and even less to support older versions in your code).
Pseudo functions
@@ -1381,10 +1417,6 @@ either a string or an expression value.
.endmacro
- This command is new and must be enabled with the
-
.BANK
@@ -2019,7 +2051,7 @@ Here's a list of all control commands and a description, what they do:
.A16
- Valid only in 65816 mode. Switch the accumulator to 16 bit.
+ Valid only in 65816 mode. Assume the accumulator is 16 bit.
Note: This command will not emit any code, it will tell the assembler to
create 16 bit operands for immediate accumulator addressing mode.
@@ -2029,7 +2061,7 @@ Here's a list of all control commands and a description, what they do:
.A8
- Valid only in 65816 mode. Switch the accumulator to 8 bit.
+ Valid only in 65816 mode. Assume the accumulator is 8 bit.
Note: This command will not emit any code, it will tell the assembler to
create 8 bit operands for immediate accu addressing mode.
@@ -2112,15 +2144,15 @@ Here's a list of all control commands and a description, what they do:
the assembler will force a segment alignment to the least common multiple of
- 15, 18 and 251 - which is 22590. To protect the user against errors, the
- assembler will issue a warning when the combined alignment exceeds 256. The
- command line option will disable this warning.
+ 15, 18 and 251 - which is 22590. To protect the user against errors, when the
+ combined alignment is larger than the explicitly requested alignments,
+ the assembler will issue a warning if it also exceeds 256. The command line
+ option
+ will disable this warning.
- Please note that with alignments that are a power of two (which were the
- only alignments possible in older versions of the assembler), the problem is
- less severe, because the least common multiple of powers to the same base is
- always the larger one.
+ Please note that with only alignments that are a power of two, a warning will
+ never occur, because the least common multiple of powers to the same base is
+ always simply the larger one.
@@ -2255,7 +2287,7 @@ See: ,,,
- Marks the end of a macro definition.
+ Marks the end of a macro definition. Note, .ENDMACRO should be on
+ its own line to successfully end the macro definition. It is possible to use
+ to create a symbol that references
+ .ENDMACRO without ending the macro definition.
+
+ Example:
+
+
+ .macro new_mac
+ .define startmac .macro
+ .define endmac .endmacro
+ .endmacro
+
See: ,
,
@@ -2738,25 +2782,23 @@ See: ,
-
- Enables the .ADDRSIZE pseudo function. This function is experimental and not enabled by default.
-
- See also:
-
at_in_identifiers
Accept the at character ('@') as a valid character in identifiers. The
@@ -2825,6 +2867,43 @@ See: ,
+
+ Switch on or off line continuations using the backslash character
+ before a newline. The option is off by default.
+ Note: Line continuations do not work in a comment. A backslash at the
+ end of a comment is treated as part of the comment and does not trigger
+ line continuation.
+
+ Example:
+
+
+ .feature line_continuations + ; Allow line continuations
+
+ lda \
+ #$20 ; This is legal now
+
+
+ For backward compatibility reasons, the .LINECONT + control command
+ is also supported and enables the same feature.
+
+ long_jsr_jmp_rts
+
+ Affects 65816 mode only.
+
+ Allows jsr and jmp to produce long jumps if the target
+ address has been previously declared in a far segment,
+ or imported as far.
+ Otherwise jsl and jml must be used instead.
+
+ Also allows to convert rts
+ to a long return rtl when the enclosing scope or memory model
+ indicates returning from a far procedure.
+
+ This permits compatibility with the old behavior of this assembler, or other
+ assemblers which similarly allowed jsr and jmp to be used
+ this way.
+
loose_char_term
Accept single quotes as well as double quotes as terminators for char
@@ -3036,7 +3115,7 @@ See: ,
- Valid only in 65816 mode. Switch the index registers to 16 bit.
+ Valid only in 65816 mode. Assume the index registers are 16 bit.
Note: This command will not emit any code, it will tell the assembler to
create 16 bit operands for immediate operands.
@@ -3047,7 +3126,7 @@ See: ,
- Valid only in 65816 mode. Switch the index registers to 8 bit.
+ Valid only in 65816 mode. Assume the index registers are 8 bit.
Note: This command will not emit any code, it will tell the assembler to
create 8 bit operands for immediate operands.
@@ -3312,29 +3391,9 @@ See: ,
-
- Switch on or off line continuations using the backslash character
- before a newline. The option is off by default.
- Note: Line continuations do not work in a comment. A backslash at the
- end of a comment is treated as part of the comment and does not trigger
- line continuation.
- The command must be followed by a '+' or '-' character to switch the
- option on or off respectively.
-
- Example:
-
-
- .linecont + ; Allow line continuations
-
- lda \
- #$20 ; This is legal now
-
-
-
.LIST
- Enable output to the listing. The command must be followed by a boolean
+ Enable output to the listing. The command can be followed by a boolean
switch ("on", "off", "+" or "-") and will enable or disable listing
output.
The option has no effect if the listing is not enabled by the command line
@@ -3979,7 +4038,7 @@ See: ,.SMART
- Switch on or off smart mode. The command must be followed by a '+' or '-'
+ Switch on or off smart mode. The command can be followed by a '+' or '-'
character to switch the option on or off respectively. The default is off
(that is, the assembler doesn't try to be smart), but this default may be
changed by the -s switch on the command line.
@@ -3994,7 +4053,9 @@ See: ,In 65816 mode, replace a In 65816 mode, if the feature is enabled,
+ smart mode will replace a ,.TAG
- Allocate space for a struct or union.
+ Allocate space for a struct or union. This is equivalent to
+ with the
+ of a struct.
Example:
@@ -4039,6 +4102,7 @@ See: ,
+ See: .UNDEF, .UNDEFINE
@@ -4199,8 +4263,13 @@ macro actually takes in the definition. You may also leave intermediate
parameters empty. Empty parameters are replaced by empty space (that is,
they are removed when the macro is expanded). If you have a look at our
macro definition above, you will see, that replacing the "addr" parameter
-by nothing will lead to wrong code in most lines. To help you, writing
-macros with a variable parameter list, there are some control commands:
+by nothing will lead to wrong code in most lines.
+
+The names "a", "x" and "y" should be avoided for macro parameters, as these
+will usually conflict with the 6502 registers.
+
+For writing macros with a variable parameter list, control commands are
+available:
tests the rest of the line and
returns true, if there are any tokens on the remainder of the line. Since
@@ -4211,15 +4280,15 @@ opposite.
Look at this example:
-.macro ldaxy a, x, y
-.ifnblank a
- lda #a
+.macro ldaxy i, j, k
+.ifnblank i
+ lda #i
.endif
-.ifnblank x
- ldx #x
+.ifnblank j
+ ldx #j
.endif
-.ifnblank y
- ldy #y
+.ifnblank k
+ ldy #k
.endif
.endmacro
@@ -4423,9 +4492,9 @@ different:
Macros defined with may not
span more than a line. You may use line continuation (see ) to spread the definition over
- more than one line for increased readability, but the macro itself
- may not contain an end-of-line token.
+ id="line_continuations" name="line_continuations">
) to spread the
+ definition over more than one line for increased readability, but the
+ macro itself may not contain an end-of-line token.
Macros defined with share
the name space with classic macros, but they are detected and replaced
@@ -4799,10 +4868,15 @@ compiler, depending on the target system selected:
Structs and unions are special forms of . They
are, to some degree, comparable to their C counterparts. Both have a list of
-members. Each member allocates storage, and optionally may have a name whose
-value, in the case of a struct, usually is the storage offset from the
-beginning, and in the case of a union, doesn't change, and usually is zero.
+members. Each member allocates storage, and optionally may have a name.
+Each named member has a constant value equal to the storage offset from the
+beginning of the structure. In the case of a union, all members are placed at
+the same offset, typically 0.
+
+Each named member also has a storage size which can be accessed with the
+ operator. The struct or union itself
+also has a Declaration
@@ -4829,8 +4903,9 @@ A struct or union may not necessarily have a name. If it is anonymous, no
local scope is opened; the identifiers used to name the members are placed
into the current scope instead.
-A struct may contain unnamed members and definitions of local structs/unions.
-The storage allocators may contain a multiplier, as in the example below:
+Storage allocators may contain a multiplier. A struct may also contain members
+and definitions of local structs/unions. Example:
+
.struct Circle
.struct Point
@@ -4839,7 +4914,8 @@ The storage allocators may contain a multiplier, as in the example below:
Radius .word
.endstruct
-The size of the Circle struct is 6 (three words).
+
+In this example the size of the Circle struct is 6 (three words).
The storage allocator keywords
@@ -4849,7 +4925,7 @@ The size of the Circle struct is 6 (three words).
@@ -4902,13 +4987,54 @@ name=".TAG"> directive.
C: .tag Circle
-Currently, members are just offsets from the start of the struct or union. To
+Members are just offsets from the start of the struct or union. To
access a field of a struct, the member offset must be added to the address of
the struct variable itself:
- lda C+Circle::Radius ; Load circle radius into A
+ lda C + Circle::Radius ; Load circle radius
+ lda C + Circle::Origin + Point::ycoord ; Load circle origin.ycoord
-That may change in a future version of the assembler.
+
+Nested structures or unions are treated differently depending on whether they
+are anonymous. If named, a new structure definition is created within the
+enclosing scope, with its offsets beginning at 0. If anonymous, the members of
+the new structure are added to the enclosing scope instead, with offsets
+continuing through that scope. Example:
+
+
+ .struct Object
+ id .byte ; Object::id = 0
+ target .struct Point ; Object::target = 1
+ xcoord .word ; Object::Point::xcoord = 0
+ ycoord .word ; Object::Point::ycoord = 2
+ .endstruct
+ cost .struct ; Object::cost = 5
+ price .word ; Object::price = 5
+ tax .word ; Object::tax = 7
+ .endstruct
+ .struct
+ radius .word ; Object::radius = 9
+ .endstruct
+ .endstruct
+
+O: .tag Object
+ lda O + Object::target + Object::Point::ycoord ; Named struct
+ lda O + Object::tax ; Anonymous
+ lda O + Object::radius ; Anonymous
+
+ ; Be careful not to use a named nested structure without also adding the
+ ; offset to the nested structure itself.
+ lda O + Object::Point::ycoord ; Incorrect!
+ lda O + Object::target + Object::Point::ycoord ; Correct
+
+
+In this example, the first nested structure is named "Point", and its member
+offsets begin at 0. On the other hand, the two anonymous structures simply
+continue to add members to the enclosing "Object" structure.
+
+Note that an anonymous structure does not need a member name, since all of its
+members become part of the enclosing structure. The "cost" member in the
+example is redundantly the same offset as its first member "price".
Limitations
diff --git a/doc/cc65-intern.sgml b/doc/cc65-intern.sgml
index 8e36578b5..904cee070 100644
--- a/doc/cc65-intern.sgml
+++ b/doc/cc65-intern.sgml
@@ -6,7 +6,8 @@
Internal details of cc65 code generation,
-such as calling assembly functions from C.
+such as the expected linker configuration,
+and calling assembly functions from C.
@@ -16,6 +17,76 @@ such as calling assembly functions from C.
+Linker configuration
+
+The C libraries and code generation depend directly on a suitable linker configuration.
+There are premade configuration files in the
+
+Used by the C library and generated code for efficient internal and temporary state storage,
+also called "pseudo-registers".
+
+
+
+Used by each platform instance of the C library in
+
+The default segment for generated code, and most C library code will be located here.
+
+Use
+
+Used for uninitialized variables.
+Originally an acronym for "Block Started by Symbol", but the meaning of this is now obscure.
+
+Use
+
+Used for initialized variables.
+
+On some platforms, this may be initialized as part of the program loading process,
+but on others it may have a separate
+
+Used for read-only (constant) data.
+
+Use
+
+This currently defines table locations for the Calling assembly functions from C
Calling conventions
diff --git a/doc/cc65.sgml b/doc/cc65.sgml
index 683249bda..efe48b61b 100644
--- a/doc/cc65.sgml
+++ b/doc/cc65.sgml
@@ -741,7 +741,7 @@ Here is a description of all the command line options:
Warn about no return statement in function returning non-void.
- Warn when passing structs by value.
+ Warn when passing structs by value. (Disabled by default.)
Warn about #pragmas that aren't recognized by cc65.
@@ -754,6 +754,8 @@ Here is a description of all the command line options:
Warn about unused function parameters.
Warn about unused variables.
+
+ Warn if numerical constant conversion implies overflow. (Disabled by default.)
The full list of available warning names can be retrieved by using the
@@ -805,10 +807,12 @@ and the one defined by the ISO standard:
The datatypes "float" and "double" are not available.
+ Floating point constants may be used, though they will have to be
+ converted and stored into integer values.
+ Floating point arithmetic expressions are not supported.
- C Functions may not return structs (or unions), and structs may not
- be passed as parameters by value. However, struct assignment *is*
- possible.
+ C Functions may pass and return structs (or unions) by value, but only
+ of 1, 2 or 4 byte sizes.
Most of the C library is available with only the fastcall calling
convention (). It means
@@ -833,21 +837,21 @@ This cc65 version has some extensions to the ISO C standard.
- The compiler allows to insert assembler statements into the output
- file. The syntax is
+ The compiler allows to insert inline assembler code in the form of the
+
- asm [optional volatile] (<string literal>[, optional parameters]) ;
+ asm [optional volatile] (<string literal>[, optional parameters])
or
- __asm__ [optional volatile] (<string literal>[, optional parameters]) ;
+ __asm__ [optional volatile] (<string literal>[, optional parameters])
The first form is in the user namespace; and, is disabled if the .
@@ -1004,6 +1008,13 @@ This cc65 version has some extensions to the ISO C standard.
/) and will
+ always be in the host encoding. On the other hand, any character or
+ string literals present in the condition expression of the
+ cc65 supports bit-fields of any integral type that is int-sized or
smaller, and enumerated types with those types as their underlying
type. (Only #pragma charmap (<index>, <code>)
- Each literal string and each literal character in the source is translated
+ Each literal string and each literal character in the preprocessed source,
+ except when used in an function will be used
to determine the number from the bank attribute defined in the linker config,
see . Note that
@@ -1616,6 +1629,11 @@ parameter with the Inline assembler
-The compiler allows to insert assembler statements into the output file. The
-syntax is
+The compiler allows to insert inline assembler code in the form of the
- asm [optional volatile] (<string literal>[, optional parameters]) ;
+ asm [optional volatile] (<string literal>[, optional parameters])
or
- __asm__ [optional volatile] (<string literal>[, optional parameters]) ;
+ __asm__ [optional volatile] (<string literal>[, optional parameters])
The first form is in the user namespace; and, is disabled by if the argument is not /) and will always
+be in the host encoding. On the other hand, all character and string literals
+as the arguments for replacing the format specifiers will be translated as
+usual.
+
Note: Do not embed the assembler labels that are used as names of global
-variables or functions into your
int foo;
diff --git a/doc/cl65.sgml b/doc/cl65.sgml
index 24d2f5927..f48e1353c 100644
--- a/doc/cl65.sgml
+++ b/doc/cl65.sgml
@@ -261,6 +261,9 @@ different options for different files on the command line. As an example.
translates main.c with full optimization and module.c with less optimization
and debug info enabled.
+Note that the target system (-t , --target) must be specified before any file
+unless using the default target of c64
+
The type of an input file is derived from its extension:
diff --git a/doc/da65.sgml b/doc/da65.sgml
index 185dbe0e6..113eb6f97 100644
--- a/doc/da65.sgml
+++ b/doc/da65.sgml
@@ -115,14 +115,14 @@ Here is a description of all the command line options:
6502dtv
65sc02
65c02
+ 65816
huc6280
4510
6502x is for the NMOS 6502 with unofficial opcodes. 6502dtv is for the
emulated CPU of the C64DTV device. huc6280 is the CPU of the PC engine.
- 4510 is the CPU of the Commodore C65. Support for the 65816 currently
- is not available.
+ 4510 is the CPU of the Commodore C65. 65816 is the CPU of the SNES.
@@ -184,7 +184,7 @@ Here is a description of all the command line options:
--mnemonic-column n
- Specifies the column where a mnemonic or pseudo instrcuction is output.
+ Specifies the column where a mnemonic or pseudo instruction is output.
@@ -263,8 +263,9 @@ can produce output that can not be re-assembled, when one or more of those
branches point outside of the disassembled memory. This can happen when text
or binary data is processed.
-While there is some code for the 65816 in the sources, it is currently
-unsupported.
+The 65816 support requires annotating ranges with the M and X flag states.
+This can be recorded with an emulator that supports Code and Data Logging,
+for example. Disassemble one bank at a time.
Attribute map
@@ -282,7 +283,7 @@ Some instructions may generate labels in the first pass, while most other
instructions do not generate labels, but use them if they are available. Among
others, the branch and jump instructions will generate labels for the target
of the branch in the first pass. External labels (taken from the info file)
-have precedence over internally generated ones, They must be valid identifiers
+have precedence over internally generated ones. They must be valid identifiers
as specified for the ca65 assembler. Internal labels (generated by the
disassembler) have the form for more information.
The info file contains lists of specifications grouped together. Each group
directive has an identifying token and an attribute list enclosed in curly
braces. Attributes have a name followed by a value. The syntax of the value
-depends on the type of the attribute. String attributes are places in double
+depends on the type of the attribute. String attributes are placed in double
quotes, numeric attributes may be specified as decimal numbers or hexadecimal
with a leading dollar sign. There are also attributes where the attribute
value is a keyword; in this case, the keyword is given as-is (without quotes or
@@ -316,8 +317,8 @@ anything). Each attribute is terminated by a semicolon.
Comments
-Comments start with a hash mark (//);
-and, extend from the position of the mark to the end of the current line.
+Comments start with a hash mark (//)
+and extend from the position of the mark to the end of the current line.
Hash marks or double slashes inside of strings will
- The attribute is followed by a boolean value. If true, offsets to labels are
+ This attribute is followed by a boolean value. If true, offsets to labels are
output in hex, otherwise they're output in decimal notation. The default is
false. The attribute may be changed on the command line using the option.
- The attribute is followed by a string value, which gives the name of the
+ This attribute is followed by a string value, which gives the name of the
input file to read. If it is present, the disassembler does not accept an
input file name on the command line.
- The attribute is followed by a numerical value that gives an offset into
+ This attribute is followed by a numerical value that gives an offset into
the input file which is skipped before reading data. The attribute may be
used to skip headers or unwanted code sections in the input file.
@@ -411,7 +412,7 @@ following attributes are recognized:
- The attribute is followed by string value, which gives the name of the
+ This attribute is followed by string value, which gives the name of the
output file to write. If it is present, specification of an output file on
the command line using the option is
not allowed.
@@ -432,8 +433,8 @@ following attributes are recognized:
This attribute may be used instead of the option on the command line. It takes a numerical
parameter. The default for the start address is $10000 minus the size of
- the input file (this assumes that the input file is a ROM that contains the
- reset and irq vectors).
+ the input file. (This assumes that the input file is a ROM that contains the
+ reset and irq vectors.)
@@ -467,7 +468,7 @@ following attributes are recognized:
NAME
This is a convenience attribute. It takes a string argument and will cause
the disassembler to define a label for the start of the range with the
- given name. So a separate
+ given name so a separate
directive is not needed.
START
@@ -508,8 +509,8 @@ following attributes are recognized:
SKIP
The range is simply ignored when generating the output file. Please note
that this means that reassembling the output file will TEXTTABLE
@@ -521,6 +522,16 @@ following attributes are recognized:
+ UNIT
+ Split the table into sections of this size. For example, if you have a
+ ByteTable of size 48, but it has logical groups of size 16, specifying
+ 16 for UNIT adds newlines after every 16 bytes. UNIT is always in bytes.
+
+ ADDRMODE
+ When disassembling 65816 code, this specifies the M and X flag states
+ for this range. It's a string argument of the form "mx". Capital letters
+ mean the flag is enabled.
+
@@ -550,9 +561,9 @@ code. The following attributes are recognized:
NAME
The attribute is followed by a string value which gives the name of the
- label. Empty names are allowed, in this case the disassembler will create
- an unnamed label (see the assembler docs for more information about unnamed
- labels).
+ label. Empty names are allowed; in this case the disassembler will create
+ an unnamed label. (See the assembler docs for more information about unnamed
+ labels.)
SIZE
This attribute is optional and may be used to specify the size of the data
@@ -584,15 +595,18 @@ disassembled code. The following attributes are recognized:
START
- Followed by a numerical value. Specifies the start address of the segment.
+ This attribute is followed by a numerical value which specifies the start
+ address of the segment.
END
- Followed by a numerical value. Specifies the end address of the segment. The
- end address is the last address that is a part of the segment.
+ This attribute is followed by a numerical value which specifies the end
+ address of the segment. The end address is the last address that is a part of
+ the segment.
NAME
- The attribute is followed by a string value which gives the name of the
+ This attribute is followed by a string value which gives the name of the
segment.
+
All attributes are mandatory. Segments must not overlap. The disassembler will
@@ -624,10 +638,11 @@ The following attributes are recognized:
FILE
- Followed by a string value. Specifies the name of the file to read.
+ This attribute is followed by a string value. It specifies the name of the
+ file to read.
COMMENTSTART
- The optional attribute is followed by a character constant. It specifies the
+ This optional attribute is followed by a character constant. It specifies the
character that starts a comment. The default value is a semicolon. This
value is ignored if Helper scripts
+
+util/parse-bsnes-log.awk is a supplied script for 65816 disassembly,
+to parse bsnes-plus Code-Data log files and output the RANGE sections
+for your info file. For typical usage, you'd check the S-CPU log and trace
+log mask boxes in the bsnes-plus debugger, play through the game, then grep
+for the bank you're disassembling, and pass that to this script.
+
+
+grep ^83 my-game-log | parse-bsnes-log.awk
+
+
+
+
Copyright
@@ -451,6 +473,18 @@ see also testcode/lib/em-test.c and samples/multidemo.c.
+
+
+
+
+
+
+
+
+
+(incomplete)
+
+
@@ -821,6 +855,20 @@ communication, see also testcode/lib/ser-test.c.
(incomplete)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(incomplete)
@@ -975,7 +1023,7 @@ previously been allocated by /, / or /.
Passing a pointer to a block that was is not the result of one of the
-allocation functions, or that has been free'd will give unpredicable results.
+allocation functions, or that has been free'd will give unpredictable results.
The function is available only as a fastcall function; so, it may be used
only in the presence of a prototype.
@@ -1108,6 +1156,46 @@ considered random to a certain degree.
+_sound
+
+
+/
+
+The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
+The function is specific to the Atari 8 bit.
+ Voice can be any of 0-3 different sound channels.
+ Pitch goes from 0-255 (about 125 Hz to 32 Khz).
+ Distortion (0-14) uses poly dividers to reshape wave in order to create a noise effect. Use 10 for a "pure" square-wave sound.
+Volume (0-15) is the intensity for the wave.
+Extra bits in those parameters will be ignored.
+Parameters are the same as for the AtariBASIC SOUND statement.
+
+
+
+#include
+int main(void)
+{
+ int i=0;
+ unsigned char j;
+ printf("playing sound \n");
+ for (j=0; j<144; j++) {
+ _sound(1,144-j,10,8); //change the pitch for voice 1
+ for (i=0; i<50; i++); //pause for sound duration
+ }
+ _sound(1,0,0,0); //use zero in other parameters to stop the sound
+ return 0;
+}
+
+
+
+_stroserror
@@ -1685,16 +1773,17 @@ used in presence of a prototype.
/
+/
-The function is specific to the Sym-1.
+The function is specific to the Sym-1 and Apple2 platforms.
,
,
-,
+
@@ -1839,7 +1928,7 @@ be used in presence of a prototype.
,
,
,
-,
+
@@ -1912,7 +2001,7 @@ sent a command to TALK and a secondary address if it needs one.
,
+
@@ -2314,8 +2403,8 @@ function, in order to provide input from the keyboard.
,
,
-,
-
+
+
@@ -2786,6 +2875,79 @@ setting the time may not work. See also the platform-specific information.
+gmtime_dt
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+This function is only available on Apple II.
+On Apple II, you can't stat() an opened file. stat() before opening.
+
+
+
+#include
+#include
+#include
+int main(void)
+{
+ struct stat st;
+ struct tm* tm;
+ if (stat ("/disk/file", &st) == 0) {
+ tm = gmtime_dt (&st.st_ctime);
+ if (tm)
+ printf ("File created on %s\n", asctime(tm));
+ }
+}
+
+
+
+
+
+mktime_dt
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+This function is only available on Apple II.
+
+
+
+#include
+#include
+#include
+int main(void)
+{
+ struct stat st;
+ if (stat ("/disk/file", &st) == 0) {
+ printf ("File created on %s\n",
+ localtime (mktime_dt (&st.st_ctime)));
+ }
+}
+
+
+
+
+
clrscr
@@ -3233,7 +3395,7 @@ used in presence of a prototype.
,
-,
+
@@ -3273,7 +3435,7 @@ used in presence of a prototype.
,
-,
+
@@ -3299,6 +3461,26 @@ used in presence of a prototype.
+detect_iigs
+
+
+
+/
+
+The function is specific to the Apple2 and Apple2enh platforms.
+
+,
+,
+
+
+
+
detect_scpu
@@ -3399,11 +3581,11 @@ int main(void)
/
+/, /
-The function is specific to the Sym-1.
+The function is specific to the Sym-1 and KIM-1.
The return value is status. Non-zero status indicates an error.
The function is only available as fastcall function, so it may only
be used in presence of a prototype.
@@ -3412,7 +3594,7 @@ be used in presence of a prototype.
,
,
-,
+
@@ -3792,7 +3974,7 @@ switching the CPU into double clock mode.
,
,
-,
+
@@ -3908,7 +4090,8 @@ be used in presence of a prototype.
,
-, /
+, ,
+/
+get_iigs_speed
+
+
+
+/
+
+The function is specific to the Apple2 and Apple2enh platforms.
+See the accelerator.h header for the speed definitions.
+
+,
+,
+
+
+
+
get_scpu_speed
@@ -4148,7 +4352,7 @@ be used in presence of a prototype.
chdir (getdevicedir (device, buf, sizeof buf));
-cf.
@@ -4347,6 +4551,45 @@ to undefined behaviour.
+htonl
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+
+
+
+
+
+
+htons
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+
+
+
+
+
isalnum
@@ -5043,11 +5286,11 @@ used in presence of a prototype.
/
+/, /
-The function is specific to the Sym-1.
+The function is specific to the Sym-1 and KIM-1.
The return value is status. Non-zero status indicates an error.
The function is only available as fastcall function, so it may only
be used in presence of a prototype.
@@ -5056,7 +5299,7 @@ be used in presence of a prototype.
,
,
-,
+
@@ -5716,6 +5959,44 @@ memory allocated for the driver.
+ntohl
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+
+
+
+
+
+ntohs
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+
+
+
+
+
offsetof
@@ -6086,6 +6367,9 @@ be used in presence of a prototype.
The returned pointer may point to a statically allocated instance of
On the Apple II platform, the d_ctime and d_mtime returned are in the
+ProDOS format. You can convert them to more portable time representations using
+the ProDOS datetime conversion functions.
On several platforms, namely the CBMs and the Atari, the disk drives get
confused when opening/closing files between directory reads. So for example a
program that reads the list of files on a disk, and after each call to
@@ -6565,7 +6849,8 @@ be used in presence of a prototype.
/
+set_iigs_speed
+
+
+
+/
+
+The function is specific to the Apple2 and Apple2enh platforms.
+See the accelerator.h header for the speed definitions.
+Accepted parameters are SPEED_SLOW and SPEED_FAST (all other values are
+considered SPEED_FAST).
+
+,
+,
+
+
+
+
set_scpu_speed
@@ -6908,7 +7217,6 @@ switching the CPU into single clock mode.
-
srand
@@ -6932,6 +7240,85 @@ be used in presence of a prototype.
+stat
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+On the Apple II platform, the st_ctim, st_mtim and st_atim members are left
+to zero, for size and performance reasons. The ProDOS creation and modification dates
+are returned in the ProDOS format in st_ctime and st_mtime. The access date does
+not exist. You can convert them to POSIX-style time representations using
+the .
+
+
+
+#include <sys/stat.h>
+
+#define FILENAME "helloworld"
+struct stat stbuf;
+if (stat (FILENAME, &stbuf) == 0) {
+ printf ("%s size is %lu bytes (created on %s)\n", FILENAME, stbuf.st_size,
+#ifndef __APPLE2__
+ localtime (&stbuf.st_ctim.tv_sec)
+#else
+ localtime (mktime_dt (&stbuf.st_ctime))
+#endif
+ );
+} else {
+ printf ("There was a problem stat'ing %s: %d\n", FILENAME, errno);
+}
+
+
+
+
+
+statvfs
+
+
+
+/
+
+The function is only available as fastcall function, so it may only
+be used in presence of a prototype.
+The function requires an absolute pathname.
+
+
+
+#include <sys/statvfs.h>
+
+#define FILENAME "/disk/helloworld"
+struct statvfs stvbuf;
+if (statvfs (FILENAME, &stvbuf) == 0) {
+ printf ("%s filesystem has %u blocks of %u size, %u of them free.\n", FILENAME, stvbuf.f_blocks, stvbuf.f_bsize, stvbuf.f_bfree);
+} else {
+ printf ("There was a problem statvfs'ing %s: %d\n", FILENAME, errno);
+}
+
+
+
+
+
strcasecmp
diff --git a/doc/grc65.sgml b/doc/grc65.sgml
index c03815ade..d256c31e6 100644
--- a/doc/grc65.sgml
+++ b/doc/grc65.sgml
@@ -270,7 +270,7 @@ required for the correct process of GEOS sequential application building.
Large GEOS applications typically don't fit in one piece in their designated
memory area. They are therefore split into overlays which are loaded into memory
on demand. The individual overlays are stored as records of a VLIR (Variable
-Length Index Record) file. When GEOS starts a VLIR overlay appliation it loads
+Length Index Record) file. When GEOS starts a VLIR overlay application it loads
record number 0 which is supposed to contain the main program. The record numbers
starting with 1 are to be used for the actual overlays.
diff --git a/doc/index.sgml b/doc/index.sgml
index bb3ad5357..92df5e018 100644
--- a/doc/index.sgml
+++ b/doc/index.sgml
@@ -59,7 +59,7 @@
Contains hints on creating the most effective code with cc65.
- Describes internal details of cc65, such as calling conventions.
+ Describes internal details of cc65: linker configuration, calling conventions, etc.
Build programs, using the GNU Make utility.
@@ -154,6 +154,9 @@
Topics specific to the Bit Corporation Gamate Console.
+
+ Topics specific to the MOS Technology KIM-1.
+
Topics specific to the Atari Lynx Game Console.
@@ -172,6 +175,9 @@
Topics specific to the Commodore Plus/4.
+
+ Topics specific to the Picocomputer 6502.
+
Topics specific to the Watara Supervision Console.
diff --git a/doc/kim1.sgml b/doc/kim1.sgml
new file mode 100644
index 000000000..1387d3b19
--- /dev/null
+++ b/doc/kim1.sgml
@@ -0,0 +1,150 @@
+
+
+
+MOS Technology KIM-1 specific information for cc65
+
+
+
+An overview of the KIM-1 runtime system as it is implemented for the cc65 C compiler.
+
+
+
+
+
+
+
+Overview
+
+This file contains an overview of the KIM-1 runtime system as it comes with the cc65 C compiler.
+It describes the memory layout, KIM-1 specific header files, available drivers, and any pitfalls
+specific to the platform.
+
+Please note that KIM-1 specific functions are just mentioned here, they are described in detail
+in the separate . Even functions marked as
+"platform dependent" may be available on more than one platform. Please see the
+function reference for more information.
+
+Binary format
+
+The output format generated by the linker for the KIM-1 target is a raw binary BIN file, which
+is essentially a memory image. You can convert this to a papertape format file using
+Convert8bithexformat or KIMPaper, which are open-source conversion utility programs.
+A papertape format files can be transferred to the KIM-1 using the RS-232 terminal port (TTY),
+just as if the machine-code was entered by hand. Enter 'L' in the TTY and start the paper tape file
+transfer.
+
+
+
+Included with this distribution is a 4k configuration file and a 60k config file. The KIM-1
+on-board memory is limited to 4 kbytes but system memory can be increased to 60 kbytes of
+contiguous RAM with aftermarket add-on boards. So choose the config file that matches your
+system configuration before compiling and linking user programs.
+
+Memory layout
+
+The ROMs and I/O areas are defined in the configuration files, as are most of the entry points
+for useful subroutines in the KIM-1 monitor ROM. cc65 generated programs compiled and linked
+using 4k config run in the memory range of $200 - $0FFF. The 60k config expands
+this range to $DFFF. When using the 4k config the starting memory location and entry point
+for running the program is $200, so when the program is transferred to the KIM-1, it is
+executed by typing '200 G'. With the 60k config the default starting memory location and entry
+point is $2000.
+
+Special locations:
+
+
+
+
+Platform specific header files
+
+Programs containing KIM-1 code may use the Loadable drivers
+
+Graphics drivers
+
+No graphics drivers are currently available for the KIM-1.
+
+Joystick drivers
+
+No joystick driver is currently available for the KIM-1.
+
+Mouse drivers
+
+No mouse drivers are currently available for the KIM-1.
+
+RS232 device drivers
+
+No communication port drivers are currently available for the KIM-1. It has only the "master console"
+e.g. stdin and stdout.
+
+Limitations
+
+Disk I/O
+
+The existing library for the KIM-1 doesn't implement C file I/O.
+
+To be more specific, this limitation means that you cannot use any of the following functions (and a few others):
+
+
+fopen
+fclose
+fread
+fwrite
+...
+
+
+Other hints
+
+kim1.h
+This header exposes KIM-1 specific I/O functions that are useful for reading and writing its ports and front panel.
+See the Limited memory applications
+
+As stated earlier, there are config files for 4kb and 60kb systems. If you have 60kb RAM, then you will probably
+want to use the kim1-60k configuration, but if not - if you are using the kim1-4k configuration - then you may
+want to use functions like getchar, putchar, gets and puts rather than functions like scanf and printf.
+Printf, for example, requires about 1KB because it needs to know how to process all the format specifiers.
+
+Sample programs
+
+These sample programs can be found in the samples/kim1 directory:
+
+
+kimHello prints "Hello World!" and then inputs characters, which are echoed on the screen.
+ This program will run on both 4kb and 60kb systems.
+kimSieve finds the prime numbers up to 100,000 using the Sieve of Eratosthenes algorithm, and prints how many
+ prime numbers were found. This program requires a 60kb system to run.
+
+
+License
+
+This software is provided 'as-is', without any expressed or implied warranty. In no event will the authors be held
+liable for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter
+it and redistribute it freely, subject to the following restrictions:
+
+
+ The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+ This notice may not be removed or altered from any source
+ distribution.
+
+
+
diff --git a/doc/ld65.sgml b/doc/ld65.sgml
index 307caeaa4..1ad04b395 100644
--- a/doc/ld65.sgml
+++ b/doc/ld65.sgml
@@ -90,6 +90,7 @@ Long options:
--start-group Start a library group
--target sys Set the target system
--version Print the linker version
+ --warnings-as-errors Treat warnings as errors
---------------------------------------------------------------------------
@@ -330,6 +331,13 @@ Here is a description of all of the command-line options:
directory, in the list of directories specified using
+ --warnings-as-errors
+
+ An error will be generated if any warnings were produced.
+
+
diff --git a/doc/osi.sgml b/doc/osi.sgml
index eeaee4a97..62d466406 100644
--- a/doc/osi.sgml
+++ b/doc/osi.sgml
@@ -187,8 +187,21 @@ Currently the following extra screen configuration modules are implemented:
osic1p-screen-s3-32x28.o: 32 columns by 28 lines mode
for Briel Superboard ///
+osic1p-screen-c1p-48x12.s: 48 columns by 12 lines mode
+for Challenger 1P
+On the Briel Superboard /// you enter 32 column mode by holding down
+the BREAK key on powerup.
+
+On the Challenger 1P you can enable 48 column mode by writing a 1 to
+bit 0 of address $D800, and writing a 0 to go back to 24 column mode.
+You can use code like the following to do this:
+
+
+*(char*)0xd800 = 1; /* Switch to 48 column mode */
+
+
Limitations
stdio implementation
diff --git a/doc/rp6502.sgml b/doc/rp6502.sgml
new file mode 100644
index 000000000..201f0a06b
--- /dev/null
+++ b/doc/rp6502.sgml
@@ -0,0 +1,96 @@
+
+
+
+Picocomputer 6502 - specific information for cc65
+
+
+
+An overview over the Picocomputer 6502 and its interfaces to the cc65 C
+compiler.
+
+
+
+
+
+
+
+Overview
+
+The Picocomputer 6502 is a modern W65C02S computer with a custom operating
+system designed to be POSIX-like. The reference design includes a W65C02S,
+W65C22S, RP6502-RIA, and optionally a RP6502-VGA. Peripheral devices like
+keyboards, mice, and flash storage are connected by USB to the RP6502-RIA.
+Audio is generated by the RP6502-RIA. Video is generated by the RP6502-VGA.
+
+
+
+Binary format
+
+The standard binary output format generated by the linker for the RP6502 target
+is a plain machine language program without any prefix or postfix.
+
+The RP6502 Integrated Development Environment, based on Visual Studio Code,
+will convert the cc65 binary output into RP6502 ROM files that can be loaded
+directly from the RP6502 monitor or installed on the RIA to be loaded at boot.
+
+
+
+Memory layout
+
+
+
+
+
+
+Platform-specific header files
+
+Programs containing RP6502-specific code may use the License
+
+This software is provided "as-is", without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated, but is not required.
+ Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+ This notice may not be removed or altered from any source
+ distribution.
+
+
+
diff --git a/doc/sim65.sgml b/doc/sim65.sgml
index 310de4667..c2740bbad 100644
--- a/doc/sim65.sgml
+++ b/doc/sim65.sgml
@@ -44,6 +44,13 @@ The simulator is called as follows:
--version Print the simulator version number
+sim65 will exit with the error code of the simulated program,
+which is limited to an 8-bit result 0-255.
+
+An error in sim65, like bad arguments or an internal problem will exit with Command line options in detail
@@ -126,9 +133,17 @@ a set of built-in paravirtualization functions (Creating a Test in Assembly
Assembly tests may similarly be assembled and linked with
-
+
+Return from
The binary file has a 12 byte header:
diff --git a/doc/smc.sgml b/doc/smc.sgml
index 71de20208..ed9b1ba20 100644
--- a/doc/smc.sgml
+++ b/doc/smc.sgml
@@ -104,7 +104,7 @@ placeholder has two advantages:
The code is better documented. It is clearly visible that the given
value is about to be changed.
When examining an (initial) disassembly (e.g. in a debugger), these
- placegolders can be better identified: They are fixed and, you may
+ placeholders can be better identified: They are fixed and, you may
notice that below, quite eye catching defined.
diff --git a/doc/sp65.sgml b/doc/sp65.sgml
index 255d7a552..e1bcdd558 100644
--- a/doc/sp65.sgml
+++ b/doc/sp65.sgml
@@ -44,6 +44,7 @@ Short options:
-lc List all possible conversions
-r file[,attrlist] Read an input file
-v Increase verbosity
+ -p tgt,file[,attrlist] Write the palette to a file
-w file[,attrlist] Write the output to a file
Long options:
@@ -56,6 +57,7 @@ Long options:
--slice x,y,w,h Generate a slice from the loaded bitmap
--verbose Increase verbosity
--version Print the version number and exit
+ --palette tgt,file{,attrlist] Write the palette to a file
--write file[,attrlist] Write the output to a file
---------------------------------------------------------------------------
@@ -124,6 +126,13 @@ attribute lists see .
bugfixes, please include the version number.
+
+ -p, --palette target,filename[,attrlist]
+
+ Write the palette of the input bitmap to a file in a format suitable of
+ the target.
+
+
-w, --write filename[,attrlist]
@@ -265,6 +274,7 @@ of a sprite is roughly 508 pixels but in reality the Lynx screen is only 160 by
102 pixels which makes very large sprites useless.
The number per pixels is taken from the number of colors of the input bitmap.
+You can also force the number of pens used in the conversion.
There are a few attributes that you can give to the conversion software.
@@ -273,7 +283,7 @@ There are a few attributes that you can give to the conversion software.
diff --git a/include/_atari5200os.h b/include/_atari5200os.h
index 5bba43016..196b69e56 100644
--- a/include/_atari5200os.h
+++ b/include/_atari5200os.h
@@ -54,7 +54,21 @@ struct __os {
unsigned char color2; // = $0E PF color 2
unsigned char color3; // = $0F PF color 3
unsigned char color4; // = $10 PF color 4
- unsigned char _free_1[0xEF]; // = $11-$FF User space
+ unsigned char paddl0; // = $11 POT0 Shadow
+ unsigned char paddl1; // = $12 POT1 Shadow
+ unsigned char paddl2; // = $13 POT2 Shadow
+ unsigned char paddl3; // = $14 POT3 Shadow
+ unsigned char paddl4; // = $15 POT4 Shadow
+ unsigned char paddl5; // = $16 POT5 Shadow
+ unsigned char paddl6; // = $17 POT6 Shadow
+ unsigned char paddl7; // = $18 POT7 Shadow
+
+ /*cc65 runtime zero page variables*/
+ unsigned char rowcrs_5200; // = $19 Cursor row (conio)
+ unsigned char colcrs_5200; // = $1A Cursor column (conio)
+ unsigned char* savmsc; // = $1B/$1C Pointer to screen memory (conio)
+
+ unsigned char _filler_1[0xE3]; // = $1D-$FF Filler
/*Stack*/
unsigned char stack[0x100]; // = $100-$1FF Stack
diff --git a/include/_atarios.h b/include/_atarios.h
index ec33b98c9..cbf33bda6 100644
--- a/include/_atarios.h
+++ b/include/_atarios.h
@@ -334,17 +334,17 @@ struct __os {
void (*vserin)(void); // = $020A/$020B POKEY SERIAL INPUT READY IRQ
void (*vseror)(void); // = $020C/$020D POKEY SERIAL OUTPUT READY IRQ
void (*vseroc)(void); // = $020E/$020F POKEY SERIAL OUTPUT COMPLETE IRQ
- void (*vtimr1)(void); // = $0210/$0201 POKEY TIMER 1 IRQ
- void (*vtimr2)(void); // = $0212/$0203 POKEY TIMER 2 IRQ
- void (*vtimr4)(void); // = $0214/$0205 POKEY TIMER 4 IRQ
- void (*vimirq)(void); // = $0216/$0207 IMMEDIATE IRQ VECTOR
- unsigned int cdtmv1; // = $0218/$0210 COUNT DOWN TIMER 1
+ void (*vtimr1)(void); // = $0210/$0211 POKEY TIMER 1 IRQ
+ void (*vtimr2)(void); // = $0212/$0213 POKEY TIMER 2 IRQ
+ void (*vtimr4)(void); // = $0214/$0215 POKEY TIMER 4 IRQ
+ void (*vimirq)(void); // = $0216/$0217 IMMEDIATE IRQ VECTOR
+ unsigned int cdtmv1; // = $0218/$0219 COUNT DOWN TIMER 1
unsigned int cdtmv2; // = $021A/$021B COUNT DOWN TIMER 2
unsigned int cdtmv3; // = $021C/$021D COUNT DOWN TIMER 3
unsigned int cdtmv4; // = $021E/$021F COUNT DOWN TIMER 4
unsigned int cdtmv5; // = $0220/$0221 COUNT DOWN TIMER 5
void (*vvblki)(void); // = $0222/$0223 IMMEDIATE VERTICAL BLANK NMI VECTOR
- void (*vvblkd)(void); // = $0224/$0224 DEFERRED VERTICAL BLANK NMI VECTOR
+ void (*vvblkd)(void); // = $0224/$0225 DEFERRED VERTICAL BLANK NMI VECTOR
void (*cdtma1)(void); // = $0226/$0227 COUNT DOWN TIMER 1 JSR ADDRESS
void (*cdtma2)(void); // = $0228/$0229 COUNT DOWN TIMER 2 JSR ADDRESS
unsigned char cdtmf3; // = $022A COUNT DOWN TIMER 3 FLAG
diff --git a/include/accelerator.h b/include/accelerator.h
index b5d8d0194..0137a7fed 100644
--- a/include/accelerator.h
+++ b/include/accelerator.h
@@ -304,6 +304,36 @@ unsigned char detect_turbomaster (void);
* 0x01 : C64 Turbo Master cartridge present
*/
+unsigned char __fastcall__ set_iigs_speed (unsigned char speed);
+
+/* Set the speed of the Apple IIgs CPU.
+ *
+ * Possible values:
+ * SPEED_SLOW : 1 Mhz mode
+ * SPEED_FAST : Fast mode (2.8MHz or more, depending on the presence of
+ * an accelerator)
+ *
+ * Any other value will be interpreted as SPEED_FAST.
+ */
+
+unsigned char get_iigs_speed (void);
+
+/* Get the speed of the Apple IIgs CPU.
+ *
+ * Possible return values:
+ * SPEED_SLOW : 1 Mhz mode
+ * SPEED_FAST : Fast mode (2.8MHz or more, depending on the presence of
+ * an accelerator)
+ */
+
+unsigned char detect_iigs (void);
+
+/* Check whether we are running on an Apple IIgs.
+ *
+ * Possible return values:
+ * 0x00 : No
+ * 0x01 : Yes
+ */
+
/* End of accelerator.h */
#endif
-
diff --git a/include/apple2.h b/include/apple2.h
index cb15cab97..875c10661 100644
--- a/include/apple2.h
+++ b/include/apple2.h
@@ -41,6 +41,7 @@
# error This module may only be used when compiling for the Apple ][!
#endif
+#include
#include
@@ -142,6 +143,27 @@ extern unsigned char _dos_type;
** ProDOS 8 2.4.x - 0x24
*/
+/* struct stat.st_mode values */
+#define S_IFDIR 0x01
+#define S_IFREG 0x02
+#define S_IFBLK 0xFF
+#define S_IFCHR 0xFF
+#define S_IFIFO 0xFF
+#define S_IFLNK 0xFF
+#define S_IFSOCK 0xFF
+
+struct datetime {
+ struct {
+ unsigned day :5;
+ unsigned mon :4;
+ unsigned year :7;
+ } date;
+ struct {
+ unsigned char min;
+ unsigned char hour;
+ } time;
+};
+
/*****************************************************************************/
@@ -151,27 +173,18 @@ extern unsigned char _dos_type;
/* The file stream implementation and the POSIX I/O functions will use the
-** following struct to set the date and time stamp on files. This specificially
+** following struct to set the date and time stamp on files. This specifically
** applies to the open and fopen functions.
*/
-extern struct {
- struct {
- unsigned day :5;
- unsigned mon :4;
- unsigned year :7;
- } createdate; /* Current date: 0 */
- struct {
- unsigned char min;
- unsigned char hour;
- } createtime; /* Current time: 0 */
-} _datetime;
+extern struct datetime _datetime;
/* The addresses of the static drivers */
#if !defined(__APPLE2ENH__)
extern void a2_auxmem_emd[];
extern void a2_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
extern void a2_stdmou_mou[]; /* Referred to by mouse_static_stddrv[] */
-extern void a2_ssc_ser[];
+extern void a2_ssc_ser[]; /* Referred to by ser_static_stddrv[] */
+extern void a2_gs_ser[]; /* IIgs serial driver */
extern void a2_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */
extern void a2_lo_tgi[];
#endif
@@ -184,6 +197,9 @@ extern void a2_lo_tgi[];
+void beep (void);
+/* Beep beep. */
+
unsigned char get_ostype (void);
/* Get the machine type. Returns one of the APPLE_xxx codes. */
@@ -210,6 +226,12 @@ void rebootafterexit (void);
#define _cpeekcolor() COLOR_WHITE
#define _cpeekrevers() 0
+struct tm* __fastcall__ gmtime_dt (const struct datetime* dt);
+/* Converts a ProDOS date/time structure to a struct tm */
+
+time_t __fastcall__ mktime_dt (const struct datetime* dt);
+/* Converts a ProDOS date/time structure to a time_t UNIX timestamp */
+
/* End of apple2.h */
diff --git a/include/apple2enh.h b/include/apple2enh.h
index 58e0b397f..3989d0b8d 100644
--- a/include/apple2enh.h
+++ b/include/apple2enh.h
@@ -99,7 +99,8 @@
extern void a2e_auxmem_emd[];
extern void a2e_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
extern void a2e_stdmou_mou[]; /* Referred to by mouse_static_stddrv[] */
-extern void a2e_ssc_ser[];
+extern void a2e_ssc_ser[]; /* Referred to by ser_static_stddrv[] */
+extern void a2e_gs_ser[]; /* IIgs serial driver */
extern void a2e_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */
extern void a2e_lo_tgi[];
diff --git a/libsrc/common/asctime.c b/include/arpa/inet.h
similarity index 73%
rename from libsrc/common/asctime.c
rename to include/arpa/inet.h
index b46f29128..cd353a2bb 100644
--- a/libsrc/common/asctime.c
+++ b/include/arpa/inet.h
@@ -1,15 +1,12 @@
/*****************************************************************************/
/* */
-/* asctime.c */
+/* arpa/inet.h */
/* */
-/* Convert a broken down time into a string */
+/* Endianness utilities for cc65 */
/* */
/* */
/* */
-/* (C) 2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 2023 Colin Leroy-Mira, */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
@@ -33,8 +30,8 @@
-#include
-#include
+#ifndef _ARPA_INET_H
+#define _ARPA_INET_H
@@ -42,18 +39,29 @@
/* Code */
/*****************************************************************************/
-/*
- CAUTION: we need to reserve enough space to be able to hold the maximum
- length string:
- 1234567890123456789012345678901234567
- "Wednesday September ..1 00:00:00 1970"
-*/
-char* __fastcall__ asctime (const struct tm* timep)
-{
- static char buf[38];
+#if (__OPT_i__ < 200)
+int __fastcall__ ntohs (int val);
+int __fastcall__ htons (int val);
+#else
- /* Format into given buffer and return the result */
- return strftime (buf, sizeof (buf), "%c\n", timep)? buf : 0;
-}
+#define ntohs(x) \
+ ( \
+ __AX__=(x), \
+ asm("sta tmp1"), \
+ asm("txa"), \
+ asm("ldx tmp1"), \
+ __AX__ \
+ )
+#define htons(x) ntohs(x)
+
+#endif
+
+long __fastcall__ ntohl (long val);
+long __fastcall__ htonl (long val);
+
+
+
+/* End of arpa/inet.h */
+#endif
diff --git a/include/atari.h b/include/atari.h
index 781ee7a80..04cacab33 100644
--- a/include/atari.h
+++ b/include/atari.h
@@ -235,6 +235,12 @@ extern void __fastcall__ _scroll (signed char numlines);
/* numlines < 0 scrolls down */
+/*****************************************************************************/
+/* Sound function */
+/*****************************************************************************/
+
+extern void __fastcall__ _sound (unsigned char voice, unsigned char frequency, unsigned char distortion, unsigned char volume);
+
/*****************************************************************************/
/* Misc. functions */
/*****************************************************************************/
@@ -261,7 +267,7 @@ extern void atrst_mou[]; /* referred to by mouse_static_stddrv[]
extern void atrami_mou[];
extern void atrtrk_mou[];
extern void atrtt_mou[];
-extern void atrrdev_ser[];
+extern void atrrdev_ser[]; /* referred to by ser_static_stddrv[] */
extern void atr3_tgi[];
extern void atr4_tgi[];
extern void atr5_tgi[];
@@ -286,7 +292,7 @@ extern void atrxst_mou[]; /* referred to by mouse_static_stddrv[]
extern void atrxami_mou[];
extern void atrxtrk_mou[];
extern void atrxtt_mou[];
-extern void atrxrdev_ser[];
+extern void atrxrdev_ser[]; /* referred to by ser_static_stddrv[] */
extern void atrx3_tgi[];
extern void atrx4_tgi[];
extern void atrx5_tgi[];
diff --git a/include/atmos.h b/include/atmos.h
index 227c387aa..38d423c46 100644
--- a/include/atmos.h
+++ b/include/atmos.h
@@ -133,7 +133,7 @@
/* The addresses of the static drivers */
extern void atmos_pase_joy[]; /* Referred to by joy_static_stddrv[] */
extern void atmos_ijk_joy[];
-extern void atmos_acia_ser[];
+extern void atmos_acia_ser[]; /* Referred to by ser_static_stddrv[] */
extern void atmos_228_200_3_tgi[];
extern void atmos_240_200_2_tgi[]; /* Referred to by tgi_static_stddrv[] */
diff --git a/include/c128.h b/include/c128.h
index ee1dce99e..5a34904e0 100644
--- a/include/c128.h
+++ b/include/c128.h
@@ -140,7 +140,7 @@ extern void c128_1351_mou[]; /* Referred to by mouse_static_stddrv[] */
extern void c128_joy_mou[];
extern void c128_inkwell_mou[];
extern void c128_pot_mou[];
-extern void c128_swlink_ser[];
+extern void c128_swlink_ser[]; /* Referred to by ser_static_stddrv[] */
extern void c128_hi_tgi[];
extern void c128_vdc_tgi[]; /* Referred to by tgi_static_stddrv[] */
extern void c128_vdc2_tgi[];
diff --git a/include/c64.h b/include/c64.h
index 13d252dcb..ffac801ef 100644
--- a/include/c64.h
+++ b/include/c64.h
@@ -155,7 +155,7 @@ extern void c64_1351_mou[]; /* Referred to by mouse_static_stddrv[]
extern void c64_joy_mou[];
extern void c64_inkwell_mou[];
extern void c64_pot_mou[];
-extern void c64_swlink_ser[];
+extern void c64_swlink_ser[]; /* Referred to by ser_static_stddrv[] */
extern void c64_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */
diff --git a/include/cbm510.h b/include/cbm510.h
index 20b334ed9..8ebbdf3c1 100644
--- a/include/cbm510.h
+++ b/include/cbm510.h
@@ -128,7 +128,7 @@ extern void cbm510_inkwl_mou[];
extern void cbm510_joy_mou[]; /* Referred to by mouse_static_stddrv[] */
extern void cbm510_ram_emd[];
extern void cbm510_std_joy[]; /* Referred to by joy_static_stddrv[] */
-extern void cbm510_std_ser[];
+extern void cbm510_std_ser[]; /* Referred to by ser_static_stddrv[] */
diff --git a/include/cbm610.h b/include/cbm610.h
index de7aa50f8..64beab9e6 100644
--- a/include/cbm610.h
+++ b/include/cbm610.h
@@ -105,7 +105,7 @@
/* The addresses of the static drivers */
extern void cbm610_ram_emd[];
-extern void cbm610_std_ser[];
+extern void cbm610_std_ser[]; /* Referred to by ser_static_stddrv[] */
diff --git a/include/cx16.h b/include/cx16.h
index 66f21843e..5bbd21247 100644
--- a/include/cx16.h
+++ b/include/cx16.h
@@ -256,6 +256,42 @@ struct __vera {
unsigned char vstart; /* Vertical start position */
unsigned char vstop; /* Vertical stop position */
};
+ struct { /* Visible when DCSEL flag = 2 */
+ unsigned char fxctrl;
+ unsigned char fxtilebase;
+ unsigned char fxmapbase;
+ unsigned char fxmult;
+ };
+ struct { /* Visible when DCSEL flag = 3 */
+ unsigned char fxxincrl;
+ unsigned char fxxincrh;
+ unsigned char fxyincrl;
+ unsigned char fxyincrh;
+ };
+ struct { /* Visible when DCSEL flag = 4 */
+ unsigned char fxxposl;
+ unsigned char fxxposh;
+ unsigned char fxyposl;
+ unsigned char fxyposh;
+ };
+ struct { /* Visible when DCSEL flag = 5 */
+ unsigned char fxxposs;
+ unsigned char fxyposs;
+ unsigned char fxpolyfilll;
+ unsigned char fxpolyfillh;
+ };
+ struct { /* Visible when DCSEL flag = 6 */
+ unsigned char fxcachel;
+ unsigned char fxcachem;
+ unsigned char fxcacheh;
+ unsigned char fxcacheu;
+ };
+ struct { /* Visible when DCSEL flag = 63 */
+ unsigned char dcver0;
+ unsigned char dcver1;
+ unsigned char dcver2;
+ unsigned char dcver3;
+ };
} display;
struct {
unsigned char config; /* Layer map geometry */
diff --git a/include/dirent.h b/include/dirent.h
index 124c7f224..b95646833 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -33,6 +33,8 @@
#ifndef _DIRENT_H
#define _DIRENT_H
+#include
+
/*****************************************************************************/
@@ -46,31 +48,15 @@ typedef struct DIR DIR;
#if defined(__APPLE2__)
struct dirent {
- char d_name[16];
- unsigned d_ino;
- unsigned d_blocks;
- unsigned long d_size;
- unsigned char d_type;
- struct {
- unsigned day :5;
- unsigned mon :4;
- unsigned year :7;
- } d_cdate;
- struct {
- unsigned char min;
- unsigned char hour;
- } d_ctime;
- unsigned char d_access;
- unsigned d_auxtype;
- struct {
- unsigned day :5;
- unsigned mon :4;
- unsigned year :7;
- } d_mdate;
- struct {
- unsigned char min;
- unsigned char hour;
- } d_mtime;
+ char d_name[16];
+ unsigned d_ino;
+ unsigned d_blocks;
+ unsigned long d_size;
+ unsigned char d_type;
+ struct datetime d_ctime;
+ unsigned char d_access;
+ unsigned d_auxtype;
+ struct datetime d_mtime;
};
#define _DE_ISREG(t) ((t) != 0x0F)
diff --git a/include/geos/gconst.h b/include/geos/gconst.h
index e70eb9304..3e42feed7 100644
--- a/include/geos/gconst.h
+++ b/include/geos/gconst.h
@@ -4,13 +4,15 @@
reassembled by Maciej 'YTM/Elysium' Witkowiak
*/
-/* Here are constants which didn't fit into any other cathegory... */
+/* Here are constants which didn't fit into any other category... */
#ifndef _GCONST_H
#define _GCONST_H
-#define NULL 0
-#define FALSE NULL
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+#define FALSE 0
#define TRUE 0xff
#define MOUSE_SPRNUM 0
#define DISK_DRV_LGH 0x0d80
diff --git a/include/kim1.h b/include/kim1.h
new file mode 100644
index 000000000..03c496223
--- /dev/null
+++ b/include/kim1.h
@@ -0,0 +1,73 @@
+/*****************************************************************************/
+/* */
+/* kim1.h */
+/* */
+/* KIM-1 system-specific definitions */
+/* */
+/* */
+/* */
+/* (C) 2022 Dave Plummer */
+/* Email: davepl@davepl.com */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+#ifndef _KIM1_H
+#define _KIM1_H
+
+/* Check for errors */
+#if !defined(__KIM1__)
+# error This module may only be used when compiling for the KIM-1!
+#endif
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Hardware */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+/* Read from tape */
+int __fastcall__ loadt (unsigned char);
+
+/* Write to tape */
+int __fastcall__ dumpt (unsigned char, const void*, const void*);
+
+
+/* Write to 7-segment LED display. Due to hardware limitations it only
+** displays briefly, so must be called repeatedly to update the
+** display.
+**/
+void __fastcall__ scandisplay(unsigned char left, unsigned char middle, unsigned char right);
+
+/*
+** Get a keypress from the keypad. Returns $00-$0F(0-F), $10(AD), $11(DA), $12(+),
+** $13(GO), $14(PC) or $15 for no keypress.
+**/
+int __fastcall__ getkey();
+
+/* End of kim1.h */
+#endif
diff --git a/include/locale.h b/include/locale.h
index 3f23e01d2..f408e1ef3 100644
--- a/include/locale.h
+++ b/include/locale.h
@@ -39,9 +39,8 @@
/* NULL pointer */
-#ifndef _HAVE_NULL
-#define NULL 0
-#define _HAVE_NULL
+#ifndef NULL
+#define NULL ((void *) 0)
#endif
/* Locale information constants */
@@ -82,6 +81,3 @@ char* __fastcall__ setlocale (int category, const char* locale);
/* End of locale.h */
#endif
-
-
-
diff --git a/include/lynx.h b/include/lynx.h
index 1b4828a72..41dc5acb3 100644
--- a/include/lynx.h
+++ b/include/lynx.h
@@ -115,7 +115,7 @@
/* The addresses of the static drivers */
extern void lynx_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
-extern void lynx_comlynx_ser[];
+extern void lynx_comlynx_ser[]; /* Referred to by ser_static_stddrv[] */
extern void lynx_160_102_16_tgi[]; /* Referred to by tgi_static_stddrv[] */
diff --git a/include/plus4.h b/include/plus4.h
index 325ba7d89..7730938e8 100644
--- a/include/plus4.h
+++ b/include/plus4.h
@@ -56,7 +56,7 @@
/* The addresses of the static drivers */
extern void plus4_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
-extern void plus4_stdser_ser[];
+extern void plus4_stdser_ser[]; /* Referred to by ser_static_stddrv[] */
diff --git a/include/rp6502.h b/include/rp6502.h
new file mode 100644
index 000000000..2b40cfc71
--- /dev/null
+++ b/include/rp6502.h
@@ -0,0 +1,264 @@
+/*****************************************************************************/
+/* */
+/* rp6502.h */
+/* */
+/* Picocomputer 6502 */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+#ifndef _RP6502_H
+#define _RP6502_H
+
+/* RP6502 VIA $FFD0-$FFDF */
+
+#include <_6522.h>
+#define VIA (*(volatile struct __6522 *)0xFFD0)
+
+/* RP6502 RIA $FFE0-$FFF9 */
+
+struct __RP6502
+{
+ const unsigned char ready;
+ unsigned char tx;
+ const unsigned char rx;
+ const unsigned char vsync;
+ unsigned char rw0;
+ unsigned char step0;
+ unsigned int addr0;
+ unsigned char rw1;
+ unsigned char step1;
+ unsigned int addr1;
+ unsigned char xstack;
+ unsigned char errno_lo;
+ unsigned char errno_hi;
+ unsigned char op;
+ unsigned char irq;
+ const unsigned char spin;
+ const unsigned char busy;
+ const unsigned char lda;
+ unsigned char a;
+ const unsigned char ldx;
+ unsigned char x;
+ const unsigned char rts;
+ unsigned int sreg;
+};
+#define RIA (*(volatile struct __RP6502 *)0xFFE0)
+
+#define RIA_READY_TX_BIT 0x80
+#define RIA_READY_RX_BIT 0x40
+#define RIA_BUSY_BIT 0x80
+
+/* XSTACK helpers */
+
+void __fastcall__ ria_push_long (unsigned long val);
+void __fastcall__ ria_push_int (unsigned int val);
+#define ria_push_char(v) RIA.xstack = v
+
+long ria_pop_long (void);
+int ria_pop_int (void);
+#define ria_pop_char() RIA.xstack
+
+/* Set the RIA fastcall register */
+
+void __fastcall__ ria_set_axsreg (unsigned long axsreg);
+void __fastcall__ ria_set_ax (unsigned int ax);
+#define ria_set_a(v) RIA.a = v
+
+/* Run an OS operation */
+
+int __fastcall__ ria_call_int (unsigned char op);
+long __fastcall__ ria_call_long (unsigned char op);
+
+/* These run _mappederrno() on error */
+
+int __fastcall__ ria_call_int_errno (unsigned char op);
+long __fastcall__ ria_call_long_errno (unsigned char op);
+
+/* OS operation numbers */
+
+#define RIA_OP_EXIT 0xFF
+#define RIA_OP_ZXSTACK 0x00
+#define RIA_OP_XREG 0x01
+#define RIA_OP_PHI2 0x02
+#define RIA_OP_CODEPAGE 0x03
+#define RIA_OP_LRAND 0x04
+#define RIA_OP_STDIN_OPT 0x05
+#define RIA_OP_CLOCK_GETRES 0x10
+#define RIA_OP_CLOCK_GETTIME 0x11
+#define RIA_OP_CLOCK_SETTIME 0x12
+#define RIA_OP_CLOCK_GETTIMEZONE 0x13
+#define RIA_OP_OPEN 0x14
+#define RIA_OP_CLOSE 0x15
+#define RIA_OP_READ_XSTACK 0x16
+#define RIA_OP_READ_XRAM 0x17
+#define RIA_OP_WRITE_XSTACK 0x18
+#define RIA_OP_WRITE_XRAM 0x19
+#define RIA_OP_LSEEK 0x1A
+#define RIA_OP_UNLINK 0x1B
+#define RIA_OP_RENAME 0x1C
+
+/* C API for the operating system. */
+
+int __cdecl__ xreg (char device, char channel, unsigned char address, ...);
+int phi2 (void);
+int codepage (void);
+long lrand (void);
+int __fastcall__ stdin_opt (unsigned long ctrl_bits, unsigned char str_length);
+int __fastcall__ read_xstack (void* buf, unsigned count, int fildes);
+int __fastcall__ read_xram (unsigned buf, unsigned count, int fildes);
+int __fastcall__ write_xstack (const void* buf, unsigned count, int fildes);
+int __fastcall__ write_xram (unsigned buf, unsigned count, int fildes);
+
+/* XREG location helpers */
+
+#define xreg_ria_keyboard(...) xreg(0, 0, 0, __VA_ARGS__)
+#define xreg_ria_mouse(...) xreg(0, 0, 1, __VA_ARGS__)
+#define xreg_vga_canvas(...) xreg(1, 0, 0, __VA_ARGS__)
+#define xreg_vga_mode(...) xreg(1, 0, 1, __VA_ARGS__)
+
+/* XRAM structure helpers */
+
+#define xram0_struct_set(addr, type, member, val) \
+ RIA.addr0 = (unsigned)(&((type *)0)->member) + (unsigned)addr; \
+ switch (sizeof(((type *)0)->member)) \
+ { \
+ case 1: \
+ RIA.rw0 = val; \
+ break; \
+ case 2: \
+ RIA.step0 = 1; \
+ RIA.rw0 = val & 0xff; \
+ RIA.rw0 = (val >> 8) & 0xff; \
+ break; \
+ case 4: \
+ RIA.step0 = 1; \
+ RIA.rw0 = (unsigned long)val & 0xff; \
+ RIA.rw0 = ((unsigned long)val >> 8) & 0xff; \
+ RIA.rw0 = ((unsigned long)val >> 16) & 0xff; \
+ RIA.rw0 = ((unsigned long)val >> 24) & 0xff; \
+ break; \
+ }
+
+#define xram1_struct_set(addr, type, member, val) \
+ RIA.addr1 = (unsigned)(&((type *)0)->member) + (unsigned)addr; \
+ switch (sizeof(((type *)0)->member)) \
+ { \
+ case 1: \
+ RIA.rw1 = val; \
+ break; \
+ case 2: \
+ RIA.step1 = 1; \
+ RIA.rw1 = val & 0xff; \
+ RIA.rw1 = (val >> 8) & 0xff; \
+ break; \
+ case 4: \
+ RIA.step1 = 1; \
+ RIA.rw1 = (unsigned long)val & 0xff; \
+ RIA.rw1 = ((unsigned long)val >> 8) & 0xff; \
+ RIA.rw1 = ((unsigned long)val >> 16) & 0xff; \
+ RIA.rw1 = ((unsigned long)val >> 24) & 0xff; \
+ break; \
+ }
+
+typedef struct
+{
+ unsigned char x_wrap; // bool
+ unsigned char y_wrap; // bool
+ int x_pos_px;
+ int y_pos_px;
+ int width_chars;
+ int height_chars;
+ unsigned xram_data_ptr;
+ unsigned xram_palette_ptr;
+ unsigned xram_font_ptr;
+} vga_mode1_config_t;
+
+typedef struct
+{
+ unsigned char x_wrap; // bool
+ unsigned char y_wrap; // bool
+ int x_pos_px;
+ int y_pos_px;
+ int width_tiles;
+ int height_tiles;
+ unsigned xram_data_ptr;
+ unsigned xram_palette_ptr;
+ unsigned xram_tile_ptr;
+} vga_mode2_config_t;
+
+typedef struct
+{
+ unsigned char x_wrap; // bool
+ unsigned char y_wrap; // bool
+ int x_pos_px;
+ int y_pos_px;
+ int width_px;
+ int height_px;
+ unsigned xram_data_ptr;
+ unsigned xram_palette_ptr;
+} vga_mode3_config_t;
+
+typedef struct
+{
+ int x_pos_px;
+ int y_pos_px;
+ unsigned xram_sprite_ptr;
+ unsigned char log_size;
+ unsigned char has_opacity_metadata; // bool
+} vga_mode4_sprite_t;
+
+typedef struct
+{
+ int transform[6];
+ int x_pos_px;
+ int y_pos_px;
+ unsigned xram_sprite_ptr;
+ unsigned char log_size;
+ unsigned char has_opacity_metadata; // bool
+} vga_mode4_asprite_t;
+
+/* Values in __oserror are the union of these FatFs errors and errno.h */
+
+typedef enum
+{
+ FR_OK = 32, /* Succeeded */
+ FR_DISK_ERR, /* A hard error occurred in the low level disk I/O layer */
+ FR_INT_ERR, /* Assertion failed */
+ FR_NOT_READY, /* The physical drive cannot work */
+ FR_NO_FILE, /* Could not find the file */
+ FR_NO_PATH, /* Could not find the path */
+ FR_INVALID_NAME, /* The path name format is invalid */
+ FR_DENIED, /* Access denied due to prohibited access or directory full */
+ FR_EXIST, /* Access denied due to prohibited access */
+ FR_INVALID_OBJECT, /* The file/directory object is invalid */
+ FR_WRITE_PROTECTED, /* The physical drive is write protected */
+ FR_INVALID_DRIVE, /* The logical drive number is invalid */
+ FR_NOT_ENABLED, /* The volume has no work area */
+ FR_NO_FILESYSTEM, /* There is no valid FAT volume */
+ FR_MKFS_ABORTED, /* The f_mkfs() aborted due to any problem */
+ FR_TIMEOUT, /* Could not get a grant to access the volume within defined period */
+ FR_LOCKED, /* The operation is rejected according to the file sharing policy */
+ FR_NOT_ENOUGH_CORE, /* LFN working buffer could not be allocated */
+ FR_TOO_MANY_OPEN_FILES, /* Number of open files > FF_FS_LOCK */
+ FR_INVALID_PARAMETER /* Given parameter is invalid */
+} FRESULT;
+
+#endif /* _RP6502_H */
diff --git a/include/serial.h b/include/serial.h
index 35d7b8f66..0510cd219 100644
--- a/include/serial.h
+++ b/include/serial.h
@@ -123,6 +123,13 @@ struct ser_params {
unsigned char handshake; /* Type of handshake to use */
};
+/* The name of the standard serial driver for a platform */
+extern const char ser_stddrv[];
+
+/* The address of the static standard serial driver for a platform */
+extern const void ser_static_stddrv[];
+
+
/*****************************************************************************/
/* Code */
diff --git a/include/stddef.h b/include/stddef.h
index ca93edf62..d2bfd6138 100644
--- a/include/stddef.h
+++ b/include/stddef.h
@@ -53,9 +53,8 @@ typedef unsigned size_t;
#endif
/* NULL pointer */
-#ifndef _HAVE_NULL
-#define NULL ((void *) 0)
-#define _HAVE_NULL
+#ifndef NULL
+#define NULL ((void *) 0)
#endif
/* offsetof macro */
@@ -65,6 +64,3 @@ typedef unsigned size_t;
/* End of stddef.h */
#endif
-
-
-
diff --git a/include/stdio.h b/include/stdio.h
index 858dd5059..35ebd7784 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -38,9 +38,8 @@
/* NULL pointer */
-#ifndef _HAVE_NULL
-#define NULL 0
-#define _HAVE_NULL
+#ifndef NULL
+#define NULL ((void *) 0)
#endif
/* size_t is needed */
@@ -87,6 +86,10 @@ extern FILE* stderr;
# define FILENAME_MAX (80+1)
#elif defined(__TELESTRAT__)
# define FILENAME_MAX (50+1)
+#elif defined(__SIM6502__)
+# define FILENAME_MAX (1024+1)
+#elif defined(__SIM65C02__)
+# define FILENAME_MAX (1024+1)
#else
# define FILENAME_MAX (16+1)
#endif
diff --git a/include/stdlib.h b/include/stdlib.h
index 4e7ffbd6a..e789f732b 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -44,6 +44,11 @@ typedef unsigned size_t;
#define _HAVE_size_t
#endif
+/* NULL pointer */
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
/* Standard exit codes */
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
@@ -167,6 +172,3 @@ int __fastcall__ putenv (char* s);
/* End of stdlib.h */
#endif
-
-
-
diff --git a/include/string.h b/include/string.h
index 854359dad..abaf80e7d 100644
--- a/include/string.h
+++ b/include/string.h
@@ -37,9 +37,8 @@
#define _STRING_H
/* NULL pointer */
-#ifndef _HAVE_NULL
-#define NULL 0
-#define _HAVE_NULL
+#ifndef NULL
+#define NULL ((void *) 0)
#endif
/* size_t is needed */
diff --git a/include/sys/stat.h b/include/sys/stat.h
index d8fc09c75..0e1589d52 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -2,7 +2,7 @@
/* */
/* stat.h */
/* */
-/* Constants for the mode argument of open and creat */
+/* stat(2) definition */
/* */
/* */
/* */
@@ -11,6 +11,9 @@
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
+/* (C) 2023 Colin Leroy-Mira */
+/* EMail: colin@colino.net */
+/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
@@ -36,6 +39,10 @@
#ifndef _STAT_H
#define _STAT_H
+#include
+#include
+#include
+
/*****************************************************************************/
@@ -47,6 +54,30 @@
#define S_IREAD 0x01
#define S_IWRITE 0x02
+#define S_IFMT 0x03
+
+struct stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ off_t st_size;
+ struct timespec st_atim;
+ struct timespec st_ctim;
+ struct timespec st_mtim;
+ #ifdef __APPLE2__
+ unsigned char st_access;
+ unsigned char st_type;
+ unsigned int st_auxtype;
+ unsigned char st_storagetype;
+ unsigned int st_blocks;
+ struct datetime st_mtime;
+ struct datetime st_ctime;
+ #endif
+};
+
/*****************************************************************************/
@@ -55,5 +86,9 @@
+int __fastcall__ stat (const char* pathname, struct stat* statbuf);
+
+
+
/* End of stat.h */
#endif
diff --git a/libsrc/common/gmtime.c b/include/sys/statvfs.h
similarity index 66%
rename from libsrc/common/gmtime.c
rename to include/sys/statvfs.h
index 85e9de3d0..d9edc2f23 100644
--- a/libsrc/common/gmtime.c
+++ b/include/sys/statvfs.h
@@ -1,15 +1,13 @@
/*****************************************************************************/
/* */
-/* gmtime.c */
+/* statvfs.h */
/* */
-/* Convert calendar time into broken down time in UTC */
+/* statvfs(3) definition */
/* */
/* */
/* */
-/* (C) 2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 2023 Colin Leroy-Mira */
+/* EMail: colin@colino.net */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
@@ -33,7 +31,32 @@
-#include
+#ifndef _STATVFS_H
+#define _STATVFS_H
+
+#include
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+struct statvfs {
+ unsigned long f_bsize;
+ unsigned long f_frsize;
+ fsblkcnt_t f_blocks;
+ fsblkcnt_t f_bfree;
+ fsblkcnt_t f_bavail;
+ fsfilcnt_t f_files;
+ fsfilcnt_t f_ffree;
+ fsfilcnt_t f_favail;
+ unsigned long f_fsid;
+ unsigned long f_flag;
+ unsigned long f_namemax;
+};
@@ -43,31 +66,9 @@
-struct tm* __fastcall__ gmtime (const time_t* timep)
-{
- static struct tm timebuf;
- time_t t;
+int __fastcall__ statvfs (const char* pathname, struct statvfs* buf);
- /* Check the argument */
- if (timep == 0 || (long) (t = *timep) < 0) {
- /* Invalid arg */
- return 0;
- }
- /* Since our ints are just 16 bits, split the given time into seconds,
- ** hours and days. Each of the values will fit in a 16 bit variable.
- ** The mktime routine will then do the rest.
- */
- timebuf.tm_sec = t % 3600;
- timebuf.tm_min = 0;
- timebuf.tm_hour = (t / 3600) % 24;
- timebuf.tm_mday = (t / (3600UL * 24UL)) + 1;
- timebuf.tm_mon = 0;
- timebuf.tm_year = 70; /* Base value is 1/1/1970 */
- /* Call mktime to do the final conversion */
- mktime (&timebuf);
-
- /* Return the result */
- return &timebuf;
-}
+/* End of statvfs.h */
+#endif
diff --git a/include/sys/types.h b/include/sys/types.h
index e75dd7d46..89b91c5b4 100644
--- a/include/sys/types.h
+++ b/include/sys/types.h
@@ -50,6 +50,46 @@
typedef long int off_t;
#endif
+#ifndef _HAVE_dev_t
+#define _HAVE_dev_t
+typedef unsigned long int dev_t;
+#endif
+
+#ifndef _HAVE_ino_t
+#define _HAVE_ino_t
+typedef unsigned long int ino_t;
+#endif
+
+#ifndef _HAVE_nlink_t
+#define _HAVE_nlink_t
+typedef unsigned long int nlink_t;
+#endif
+
+#ifndef _HAVE_uid_t
+#define _HAVE_uid_t
+typedef unsigned char uid_t;
+#endif
+
+#ifndef _HAVE_gid_t
+#define _HAVE_gid_t
+typedef unsigned char gid_t;
+#endif
+
+#ifndef _HAVE_mode_t
+#define _HAVE_mode_t
+typedef unsigned char mode_t;
+#endif
+
+#ifndef _HAVE_fsblkcnt_t
+#define _HAVE_fsblkcnt_t
+typedef unsigned long int fsblkcnt_t;
+#endif
+
+#ifndef _HAVE_fsfilcnt_t
+#define _HAVE_fsfilcnt_t
+typedef unsigned long int fsfilcnt_t;
+#endif
+
/*****************************************************************************/
@@ -60,6 +100,3 @@ typedef long int off_t;
/* End of types.h */
#endif
-
-
-
diff --git a/include/time.h b/include/time.h
index 642d68c4e..f8977ab0c 100644
--- a/include/time.h
+++ b/include/time.h
@@ -37,11 +37,15 @@
#define _TIME_H
+/* Forward declaration for target.h */
+typedef unsigned long time_t;
+typedef unsigned long clock_t;
+
+
/* NULL pointer */
-#ifndef _HAVE_NULL
-#define NULL 0
-#define _HAVE_NULL
+#ifndef NULL
+#define NULL ((void *) 0)
#endif
/* size_t is needed */
@@ -50,9 +54,6 @@
typedef unsigned size_t;
#endif
-typedef unsigned long time_t;
-typedef unsigned long clock_t;
-
/* Structure for broken down time */
struct tm {
int tm_sec;
diff --git a/libsrc/Makefile b/libsrc/Makefile
index 2018de801..8a4f11414 100644
--- a/libsrc/Makefile
+++ b/libsrc/Makefile
@@ -27,17 +27,23 @@ TARGETS = apple2 \
$(CBMS) \
$(GEOS) \
gamate \
+ kim1 \
lynx \
nes \
none \
osic1p \
pce \
+ rp6502 \
sim6502 \
sim65c02 \
supervision \
sym1 \
telestrat
+TARGETTEST = none \
+ sim6502 \
+ sim65c02
+
DRVTYPES = emd \
joy \
mou \
@@ -52,7 +58,7 @@ OUTPUTDIRS := lib
$(subst ../,,$(wildcard ../target/*/drv/*)) \
$(subst ../,,$(wildcard ../target/*/util))
-.PHONY: all mostlyclean clean install zip lib $(TARGETS)
+.PHONY: all mostlyclean clean install zip lib libtest $(TARGETS)
.SUFFIXES:
@@ -80,6 +86,8 @@ datadir = $(PREFIX)/share/cc65
all lib: $(TARGETS)
+libtest: $(TARGETTEST)
+
mostlyclean:
$(call RMDIR,../libwrk)
@@ -115,13 +123,17 @@ endef # ZIP_recipe
zip:
$(foreach dir,$(OUTPUTDIRS),$(ZIP_recipe))
-$(TARGETS):
+$(TARGETS): | ../lib
@$(MAKE) --no-print-directory $@
+# ../lib must be created globally before doing lib targets in parallel
+../lib:
+ @$(call MKDIR,$@)
+
else # TARGET
-CA65FLAGS =
-CC65FLAGS = -Or -W error
+CA65FLAGS = -g
+CC65FLAGS = -g -Or -W error
EXTZP = cbm510 \
cbm610 \
@@ -286,10 +298,12 @@ $(EXTRA_OBJPAT): $(EXTRA_SRCPAT) | ../libwrk/$(TARGET) ../lib
@echo $(TARGET) - $(exit
jsr reset ; Setup RESET vector
- ; Switch in ROM, in case it wasn't already switched in by a RESET.
- bit $C082
+ ; Switch in LC bank 2 for R/O in case it was switched out by a RESET.
+ bit $C080
; Call the module destructors.
jsr donelib
+ ; Switch in ROM.
+ bit $C082
+
; Restore the original RESET vector.
exit: ldx #$02
: lda rvsave,x
diff --git a/libsrc/apple2/detect_iigs.s b/libsrc/apple2/detect_iigs.s
new file mode 100644
index 000000000..f82a464ac
--- /dev/null
+++ b/libsrc/apple2/detect_iigs.s
@@ -0,0 +1,17 @@
+;
+; Colin Leroy-Mira , 2024
+;
+; void __fastcall__ detect_iigs(void)
+;
+
+ .export _detect_iigs
+ .import ostype, return0, return1
+
+ .include "apple2.inc"
+
+ ; Returns 1 if running on IIgs, 0 otherwise
+_detect_iigs:
+ lda ostype
+ bpl :+
+ jmp return1
+: jmp return0
diff --git a/libsrc/apple2/emd/a2.auxmem.s b/libsrc/apple2/emd/a2.auxmem.s
index 5ef2564b1..c582e9eec 100644
--- a/libsrc/apple2/emd/a2.auxmem.s
+++ b/libsrc/apple2/emd/a2.auxmem.s
@@ -73,7 +73,8 @@ INSTALL:
and #$f0
cmp #$80
bne @L1
- lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ txa
rts
@L1: lda #EM_ERR_NO_DEVICE
; rts
diff --git a/libsrc/apple2/exec.s b/libsrc/apple2/exec.s
index d5cbf8788..ec90f19bb 100644
--- a/libsrc/apple2/exec.s
+++ b/libsrc/apple2/exec.s
@@ -5,8 +5,8 @@
;
.export _exec
- .import pushname, popname
- .import popax, done, _exit
+ .import mli_file_info_direct
+ .import pushname, popname, popax, done, _exit
.include "zeropage.inc"
.include "errno.inc"
@@ -17,13 +17,12 @@
typerr: lda #$4A ; "Incompatible file format"
; Cleanup name
-oserr: jsr popname ; Preserves A
- ; Set ___oserror
- jmp ___mappederrno
+mlierr: jsr popname
+oserr: jmp ___mappederrno
_exec:
- ; Save cmdline
+ ; Store cmdline
sta ptr4
stx ptr4+1
@@ -32,6 +31,9 @@ _exec:
jsr pushname
bne oserr
+ jsr mli_file_info_direct
+ bcs mlierr
+
; ProDOS TechRefMan, chapter 5.1.5.1:
; "The complete or partial pathname of the system program
; is stored at $280, starting with a length byte."
@@ -46,18 +48,6 @@ _exec:
dey
bpl :-
- ; Set pushed name
- lda sp
- ldx sp+1
- sta mliparam + MLI::INFO::PATHNAME
- stx mliparam + MLI::INFO::PATHNAME+1
-
- ; Get file_type and aux_type
- lda #GET_INFO_CALL
- ldx #GET_INFO_COUNT
- jsr callmli
- bcs oserr
-
; If we get here the program file at least exists so we copy
; the loader stub right now and patch it later to set params
ldx #size - 1
@@ -121,35 +111,9 @@ setbuf: lda #$00 ; Low byte
dex
dex
- ; Set I/O buffer
- sta mliparam + MLI::OPEN::IO_BUFFER
- stx mliparam + MLI::OPEN::IO_BUFFER+1
-
- ; PATHNAME already set
- .assert MLI::OPEN::PATHNAME = MLI::INFO::PATHNAME, error
-
- ; Lower file level to avoid program file
- ; being closed by C library shutdown code
- ldx LEVEL
- stx level
- beq :+
- dec LEVEL
-
- ; Open file
-: lda #OPEN_CALL
- ldx #OPEN_COUNT
- jsr callmli
-
- ; Restore file level
- ldx level
- stx LEVEL
- bcc :+
- jmp oserr
-
- ; Get and save fd
-: lda mliparam + MLI::OPEN::REF_NUM
- sta read_ref
- sta close_ref
+ ; Set OPEN MLI call I/O buffer parameter
+ sta io_buffer
+ stx io_buffer+1
.ifdef __APPLE2ENH__
; Calling the 80 column firmware needs the ROM switched
@@ -194,14 +158,25 @@ setbuf: lda #$00 ; Low byte
; Initiate C library shutdown
jmp _exit
- .bss
-
-level : .res 1
-
.rodata
+source:
+ ; Open program file
+ ; PATHNAME parameter is already set (we reuse
+ ; the copy at $0280); IO_BUFFER has been setup
+ ; before shutting down the C library
+ jsr $BF00
+ .byte OPEN_CALL
+ .word open_param
+ bcs error
+
+ ; Copy REF_NUM to MLI READ and CLOSE parameters
+ lda open_ref
+ sta read_ref
+ sta close_ref
+
; Read whole program file
-source: jsr $BF00
+ jsr $BF00
.byte READ_CALL
.word read_param
bcs error
@@ -213,8 +188,6 @@ source: jsr $BF00
bcs error
; Check for cmdline handling
- lda $0100 ; Valid cmdline?
- beq jump ; No, jump to program right away
ldx file_type ; SYS file?
bne system ; Yes, check for startup filename
@@ -256,6 +229,14 @@ jump: jmp (data_buffer)
file_type = * - source + target
.byte $00
+open_param = * - source + target
+ .byte $03 ; PARAM_COUNT
+ .addr $0280 ; PATHNAME
+io_buffer = * - source + target
+ .addr $0000 ; IO_BUFFER
+open_ref = * - source + target
+ .byte $00 ; REF_NUM
+
read_param = * - source + target
.byte $04 ; PARAM_COUNT
read_ref = * - source + target
@@ -287,4 +268,8 @@ size = * - source
target = DOSWARM - size
+ ; Make sure that the loader isn't too big, and
+ ; fits in $300-$3D0
+ .assert target >= $300, error
+
dosvec: jmp quit
diff --git a/libsrc/apple2/filename.s b/libsrc/apple2/filename.s
index aaef6ec2d..0d4b6bedd 100644
--- a/libsrc/apple2/filename.s
+++ b/libsrc/apple2/filename.s
@@ -8,6 +8,7 @@
.import subysp, addysp, decsp1
.include "zeropage.inc"
+ .include "apple2.inc"
.include "mli.inc"
pushname:
@@ -15,7 +16,7 @@ pushname:
stx ptr1+1
; Alloc pathname buffer
- ldy #64+1 ; Max pathname length + zero
+ ldy #FILENAME_MAX
jsr subysp
; Check for full pathname
@@ -71,14 +72,14 @@ copy: lda (ptr1),y
sta (sp),y
beq setlen
iny
- cpy #64+1 ; Max pathname length + zero
+ cpy #FILENAME_MAX
bcc copy
; Load oserror code
lda #$40 ; "Invalid pathname"
; Free pathname buffer
-addsp65:ldy #64+1
+addsp65:ldy #FILENAME_MAX
bne addsp ; Branch always
; Alloc and set length byte
@@ -93,5 +94,5 @@ setlen: tya
popname:
; Cleanup stack
- ldy #1 + 64+1 ; Length byte + max pathname length + zero
-addsp: jmp addysp ; Preserves A
+ ldy #1 + FILENAME_MAX
+addsp: jmp addysp ; Preserves A and X
diff --git a/libsrc/apple2/get_iigs_speed.s b/libsrc/apple2/get_iigs_speed.s
new file mode 100644
index 000000000..1915d7773
--- /dev/null
+++ b/libsrc/apple2/get_iigs_speed.s
@@ -0,0 +1,22 @@
+;
+; Colin Leroy-Mira , 2024
+;
+; unsigned char __fastcall__ get_iigs_speed(void)
+;
+
+ .export _get_iigs_speed
+ .import ostype, return0
+
+ .include "apple2.inc"
+ .include "accelerator.inc"
+
+_get_iigs_speed:
+ lda ostype ; Return SLOW if not IIgs
+ bpl :+
+ lda CYAREG ; Check current setting
+ bpl :+
+ lda #SPEED_FAST
+ ldx #$00
+ rts
+ .assert SPEED_SLOW = 0, error
+: jmp return0 ; SPEED_SLOW
diff --git a/libsrc/apple2/get_ostype.s b/libsrc/apple2/get_ostype.s
index a1b1eb5be..ea9ff25cc 100644
--- a/libsrc/apple2/get_ostype.s
+++ b/libsrc/apple2/get_ostype.s
@@ -5,7 +5,7 @@
;
.constructor initostype, 9
- .export _get_ostype
+ .export _get_ostype, ostype
; Identify machine according to:
; Apple II Miscellaneous TechNote #7, Apple II Family Identification
diff --git a/libsrc/apple2/gettime.s b/libsrc/apple2/gettime.s
index 7467b0189..829aaab3b 100644
--- a/libsrc/apple2/gettime.s
+++ b/libsrc/apple2/gettime.s
@@ -4,7 +4,8 @@
; int __fastcall__ clock_gettime (clockid_t clk_id, struct timespec *tp);
;
- .import pushax, steaxspidx, incsp1, incsp3, return0
+ .import pushax, incsp1, incsp3, steaxspidx, return0
+ .import _mktime_dt
.include "time.inc"
.include "zeropage.inc"
@@ -29,42 +30,12 @@ _clock_gettime:
jsr callmli
bcs oserr
- ; Get date
- lda DATELO+1
- lsr
- php ; Save month msb
- cmp #70 ; Year < 70?
- bcs :+ ; No, leave alone
- adc #100 ; Move 19xx to 20xx
-: sta TM + tm::tm_year
- lda DATELO
- tax ; Save day
- plp ; Restore month msb
- ror
- lsr
- lsr
- lsr
- lsr
- beq erange ; [1..12] allows for validity check
- tay
- dey ; Move [1..12] to [0..11]
- sty TM + tm::tm_mon
- txa ; Restore day
- and #%00011111
- sta TM + tm::tm_mday
+ ; Convert DATELO/TIMELO to time_t
+ lda #DATELO
+ jsr _mktime_dt
- ; Get time
- lda TIMELO+1
- sta TM + tm::tm_hour
- lda TIMELO
- sta TM + tm::tm_min
-
- ; Make time_t
- lda #TM
- jsr _mktime
-
- ; Store tv_sec
+ ; Store
ldy #timespec::tv_sec
jsr steaxspidx
@@ -74,21 +45,8 @@ _clock_gettime:
; Return success
jmp return0
- ; Load errno code
-erange: lda #ERANGE
-
- ; Cleanup stack
- jsr incsp3 ; Preserves A
-
- ; Set __errno
- jmp ___directerrno
-
; Cleanup stack
oserr: jsr incsp3 ; Preserves A
; Set ___oserror
jmp ___mappederrno
-
- .bss
-
-TM: .tag tm
diff --git a/libsrc/apple2/gmtime_dt.s b/libsrc/apple2/gmtime_dt.s
new file mode 100644
index 000000000..a0b8e9f4d
--- /dev/null
+++ b/libsrc/apple2/gmtime_dt.s
@@ -0,0 +1,73 @@
+;
+; Oliver Schmidt, 14.08.2018
+; Colin Leroy-Mira, 2023
+;
+; struct tm * __fastcall__ gmtime_dt(const struct datetime *dt)
+;
+
+ .export _gmtime_dt, tm_buf
+
+ .include "time.inc"
+ .include "zeropage.inc"
+ .include "errno.inc"
+ .include "mli.inc"
+
+ ; Convert ProDOS date/time to a struct tm
+ ; source date address in AX
+ ; on stack:
+ ; destination struct
+
+_gmtime_dt:
+ sta ptr1
+ stx ptr1+1
+
+ ; Get time
+ ldy #$03
+ lda (ptr1),y
+ sta tm_buf + tm::tm_hour
+ dey
+ lda (ptr1),y
+ sta tm_buf + tm::tm_min
+
+ ; Get date
+ dey
+ lda (ptr1),y
+ lsr
+ php ; Save month msb
+ cmp #70 ; Year < 70?
+ bcs :+ ; No, leave alone
+ adc #100 ; Move 19xx to 20xx
+: sta tm_buf + tm::tm_year
+
+ dey
+ lda (ptr1),y
+ tax ; Save day
+ plp ; Restore month msb
+ ror
+ lsr
+ lsr
+ lsr
+ lsr
+ beq erange ; [1..12] allows for validity check
+ tay
+ dey ; Move [1..12] to [0..11]
+ sty tm_buf + tm::tm_mon
+ txa ; Restore day
+ and #%00011111
+ sta tm_buf + tm::tm_mday
+
+ lda #tm_buf
+ rts
+
+ ; Load errno code and return NULL
+erange: lda #ERANGE
+ sta ___errno
+ lda #$00
+ tax
+ rts
+
+ .bss
+
+tm_buf:
+ .tag tm
diff --git a/libsrc/apple2/initcwd.s b/libsrc/apple2/initcwd.s
index 7a12bc52a..03e13bcfb 100644
--- a/libsrc/apple2/initcwd.s
+++ b/libsrc/apple2/initcwd.s
@@ -3,22 +3,37 @@
;
.export initcwd
- .import __cwd
+ .import __cwd, __dos_type
.include "zeropage.inc"
+ .include "apple2.inc"
.include "mli.inc"
initcwd:
- ; Set static prefix buffer
- lda #<__cwd
- ldx #>__cwd
- sta mliparam + MLI::PREFIX::PATHNAME
- stx mliparam + MLI::PREFIX::PATHNAME+1
+ ; Check for ProDOS 8
+ lda __dos_type
+ beq done
- ; Get current working directory
- lda #GET_PREFIX_CALL
- ldx #PREFIX_COUNT
- jsr callmli
+ ; Save random counter
+ lda RNDL
+ pha
+ lda RNDH
+ pha
+
+ ; Call MLI
+ ; We're not using mli.s' callmli because its
+ ; mliparam is in BSS and this will be called
+ ; before LC code is moved to the Language Card.
+
+ jsr $BF00 ; MLI call entry point
+ .byte GET_PREFIX_CALL ; MLI command
+ .addr mli_parameters ; MLI parameter
+
+ ; Restore random counter
+ pla
+ sta RNDH
+ pla
+ sta RNDL
; Check for null prefix
ldx __cwd
@@ -39,3 +54,9 @@ initcwd:
sta __cwd,x
done: rts
+
+ .rodata
+
+mli_parameters:
+ .byte $01 ; Number of parameters
+ .addr __cwd ; Address of parameter
diff --git a/libsrc/apple2/joy/a2.stdjoy.s b/libsrc/apple2/joy/a2.stdjoy.s
index 558013910..11be52eb4 100644
--- a/libsrc/apple2/joy/a2.stdjoy.s
+++ b/libsrc/apple2/joy/a2.stdjoy.s
@@ -71,8 +71,9 @@ INSTALL:
stx gettype+2
gettype:jsr $0000
sta ostype
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; Fall through
; UNINSTALL routine. Is called before the driver is removed from memory.
diff --git a/libsrc/apple2/mktime_dt.s b/libsrc/apple2/mktime_dt.s
new file mode 100644
index 000000000..415f52b9e
--- /dev/null
+++ b/libsrc/apple2/mktime_dt.s
@@ -0,0 +1,37 @@
+;
+; Oliver Schmidt, 14.08.2018
+; Colin Leroy-Mira, 2023
+;
+; time_t __fastcall__ mktime_dt(const struct datetime *dt)
+;
+
+ .import steaxspidx, pushax, incsp2, _gmtime_dt
+ .import tm_buf
+ .export _mktime_dt
+
+ .include "time.inc"
+ .include "zeropage.inc"
+ .include "errno.inc"
+ .include "mli.inc"
+
+ ; Convert ProDOS date/time to UNIX timestamp
+ ; source date address in AX
+
+_mktime_dt:
+ ; Convert to internal tm
+ jsr _gmtime_dt
+ cpx #$00
+ bne :+
+ cmp #$00
+ beq err
+
+ ; Make time_t
+: lda #tm_buf
+ jmp _mktime
+
+err: lda #$00
+ tax
+ sta sreg
+ sta sreg+1
+ rts
diff --git a/libsrc/apple2/mli.inc b/libsrc/apple2/mli.inc
index 42363d9c9..382a071b0 100644
--- a/libsrc/apple2/mli.inc
+++ b/libsrc/apple2/mli.inc
@@ -83,8 +83,8 @@ EOF_COUNT = 2
AUX_TYPE .word
STORAGE_TYPE .byte
BLOCKS .word
- MODE_DATE .word
- MODE_TIME .word
+ MOD_DATE .word
+ MOD_TIME .word
CREATE_DATE .word
CREATE_TIME .word
.endstruct
@@ -139,3 +139,6 @@ LEVEL := $BF94 ; File level: used in open, flush, close
MACHID := $BF98 ; Machine identification
PFIXPTR := $BF9A ; If = 0, no prefix active
KVERSION:= $BFFF ; Kernel version number
+
+; Max filename length
+FILENAME_MAX = 64+1
diff --git a/libsrc/apple2/mli_file_info.s b/libsrc/apple2/mli_file_info.s
new file mode 100644
index 000000000..16e01c07f
--- /dev/null
+++ b/libsrc/apple2/mli_file_info.s
@@ -0,0 +1,33 @@
+;
+; Colin Leroy-Mira, 2023
+;
+
+ .export mli_file_info
+ .import pushname, popname, mli_file_info_direct
+ .import popax
+ .include "zeropage.inc"
+ .include "errno.inc"
+ .include "mli.inc"
+
+ ; Calls ProDOS MLI GET_FILE_INFO on the filename
+ ; stored as C string in AX at top of stack
+ ; Returns with carry set on error, and sets errno
+mli_file_info:
+ ; Get pathname
+ jsr popax
+ jsr pushname
+ bne oserr
+
+ jsr mli_file_info_direct
+ php ; Save return status
+
+ jsr popname ; Preserves A
+
+ plp
+ bcs oserr
+ rts
+
+oserr:
+ jsr ___mappederrno
+ sec
+ rts
diff --git a/libsrc/apple2/mli_file_info_direct.s b/libsrc/apple2/mli_file_info_direct.s
new file mode 100644
index 000000000..c15ebc28f
--- /dev/null
+++ b/libsrc/apple2/mli_file_info_direct.s
@@ -0,0 +1,22 @@
+;
+; Colin Leroy-Mira, 2023
+;
+
+ .export mli_file_info_direct
+ .include "zeropage.inc"
+ .include "mli.inc"
+
+ ; Calls ProDOS MLI GET_FILE_INFO on the ProDOS style
+ ; filename stored on top of stack
+ ; Returns with carry set on error, and sets errno
+mli_file_info_direct:
+ ; Set pushed name
+ lda sp
+ ldx sp+1
+ sta mliparam + MLI::INFO::PATHNAME
+ stx mliparam + MLI::INFO::PATHNAME+1
+
+ ; Get file information
+ lda #GET_INFO_CALL
+ ldx #GET_INFO_COUNT
+ jmp callmli
diff --git a/libsrc/apple2/mou/a2.stdmou.s b/libsrc/apple2/mou/a2.stdmou.s
index dfc69a942..c54c09d34 100644
--- a/libsrc/apple2/mou/a2.stdmou.s
+++ b/libsrc/apple2/mou/a2.stdmou.s
@@ -133,8 +133,8 @@ next: inc ptr1+1
bcc :+
; Mouse firmware not found
- lda #MOUSE_ERR_NO_DEVICE
+ lda #MOUSE_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
; Check Pascal 1.1 Firmware Protocol ID bytes
diff --git a/libsrc/apple2/open.s b/libsrc/apple2/open.s
index 68c203cd6..38793a13e 100644
--- a/libsrc/apple2/open.s
+++ b/libsrc/apple2/open.s
@@ -18,6 +18,7 @@
.include "fcntl.inc"
.include "mli.inc"
.include "filedes.inc"
+ .include "time.inc"
.segment "ONCE"
diff --git a/libsrc/apple2/ser/a2.gs.s b/libsrc/apple2/ser/a2.gs.s
new file mode 100644
index 000000000..e35c6156b
--- /dev/null
+++ b/libsrc/apple2/ser/a2.gs.s
@@ -0,0 +1,750 @@
+;
+; Serial driver for the Apple IIgs Zilog Z8530.
+;
+; Colin Leroy-Mira , 2023
+;
+; This software is licensed under the same license as cc65,
+; the zlib license (see LICENSE file).
+;
+; Documentation from http://www.applelogic.org/files/Z8530UM.pdf (pages
+; referred to where applicable)
+; and https://gswv.apple2.org.za/a2zine/Utils/Z8530_SCCsamples_info.txt
+
+
+
+ .setcpu "65816"
+
+ .include "zeropage.inc"
+ .include "ser-kernel.inc"
+ .include "ser-error.inc"
+
+ .macpack module
+
+; ------------------------------------------------------------------------
+; Header. Includes jump table
+
+ .ifdef __APPLE2ENH__
+ module_header _a2e_gs_ser
+ .else
+ module_header _a2_gs_ser
+ .endif
+
+ ; Driver signature
+ .byte $73, $65, $72 ; "ser"
+ .byte SER_API_VERSION ; Serial API version number
+
+ ; Library reference
+ .addr $0000
+
+ ; Jump table
+ .addr SER_INSTALL
+ .addr SER_UNINSTALL
+ .addr SER_OPEN
+ .addr SER_CLOSE
+ .addr SER_GET
+ .addr SER_PUT
+ .addr SER_STATUS
+ .addr SER_IOCTL
+ .addr SER_IRQ
+
+;----------------------------------------------------------------------------
+; Global variables
+
+ .bss
+
+RecvHead: .res 1 ; Head of receive buffer
+RecvTail: .res 1 ; Tail of receive buffer
+RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
+SendHead: .res 1 ; Head of send buffer
+SendTail: .res 1 ; Tail of send buffer
+SendFreeCnt: .res 1 ; Number of bytes in send buffer
+
+Stopped: .res 1 ; Flow-stopped flag
+RtsOff: .res 1
+HSType: .res 1 ; Flow-control type
+
+RecvBuf: .res 256 ; Receive buffers: 256 bytes
+SendBuf: .res 256 ; Send buffers: 256 bytes
+
+CurClockSource: .res 1 ; Whether to use BRG or RTxC for clock
+
+ .data
+
+Opened: .byte $00 ; 1 when opened
+Channel: .byte $00 ; Channel B by default
+CurChanIrqFlags:.byte $00
+
+SerFlagOrig: .byte $00
+
+RxBitTable: .byte %00000000 ; SER_BITS_5, in WR_RX_CTRL (WR3)
+ .byte %10000000 ; SER_BITS_6 (Ref page 5-7)
+ .byte %01000000 ; SER_BITS_7
+ .byte %11000000 ; SER_BITS_8
+
+TxBitTable: .byte %00000000 ; SER_BITS_5, in WR_TX_CTRL (WR5)
+ .byte %01000000 ; SER_BITS_6 (Ref page 5-9)
+ .byte %00100000 ; SER_BITS_7
+ .byte %01100000 ; SER_BITS_8
+
+ .rodata
+
+ClockMultiplier:.byte %01000000 ; Clock x16 (300-57600bps, WR4, ref page 5-8)
+ .byte %10000000 ; Clock x32 (115200bps, ref page 5-8)
+
+ClockSource: .byte %01010000 ; Use baud rate generator (ch. B) (WR11, page 5-17)
+ .byte %00000000 ; Use RTxC (115200bps) (ch. B)
+ .byte %11010000 ; Use baud rate generator (ch. A)
+ .byte %10000000 ; Use RTxC (115200bps) (ch. A)
+
+BrgEnabled: .byte %00000001 ; Baud rate generator on (WR14, page 5-19)
+ .byte %00000000 ; BRG Off
+
+ChanIrqFlags: .byte %00000101 ; ANDed (RX/special IRQ, ch. B) (page 5-25)
+ .byte %00101000 ; ANDed (RX/special IRQ, ch. A)
+
+ChanIrqMask: .byte %00000111 ; Ch. B IRQ flags mask
+ .byte %00111000 ; Ch. A IRQ flags mask
+
+BaudTable: ; bit7 = 1 means setting is invalid
+ ; Indexes cc65 RS232 SER_BAUD enum
+ ; into WR12/13 register values
+ ; (Ref page 5-18 and 5-19)
+ .word $FFFF ; SER_BAUD_45_5
+ .word $FFFF ; SER_BAUD_50
+ .word $FFFF ; SER_BAUD_75
+ .word $FFFF ; SER_BAUD_110
+ .word $FFFF ; SER_BAUD_134_5
+ .word $FFFF ; SER_BAUD_150
+ .word $017E ; SER_BAUD_300
+ .word $FFFF ; SER_BAUD_600
+ .word $005E ; SER_BAUD_1200
+ .word $FFFF ; SER_BAUD_1800
+ .word $002E ; SER_BAUD_2400
+ .word $FFFF ; SER_BAUD_3600
+ .word $0016 ; SER_BAUD_4800
+ .word $FFFF ; SER_BAUD_7200
+ .word $000A ; SER_BAUD_9600
+ .word $0004 ; SER_BAUD_19200
+ .word $0001 ; SER_BAUD_38400
+ .word $0000 ; SER_BAUD_57600
+ .word $0000 ; SER_BAUD_115200 (constant unused at that speed)
+ .word $FFFF ; SER_BAUD_230400
+
+; About the speed selection: either we use the baud rate generator:
+; - Load the time constants from BaudTable into WR12/WR13
+; - Setup the TX/RX clock source to BRG (ClockSource into WR11)
+; - Setup the clock multiplier (WR4)
+; - Enable the baud rate generator (WR14)
+; In this case, the baud rate will be:
+; rate = crystal_clock/(2+BRG_time_constant))/(2*clock_multiplier)
+; Example: (3686400/(2+0x0004)) / (2*16) = 19200 bps
+;
+; Or we don't use the baud rate generator:
+; - Setup the TX/RX clock source to RTxC
+; - Setup the clock multiplier
+; - Disable the baud rate generator
+; - WR12 and 13 are ignored
+; In this case, the baud rate will be:
+; rate = crystal_clock/clock_multiplier
+; Example: 3686400/32 = 115200 bps
+
+StopTable: .byte %00000100 ; SER_STOP_1, in WR_TX_RX_CTRL (WR4)
+ .byte %00001100 ; SER_STOP_2 (Ref page 5-8)
+
+ParityTable: .byte %00000000 ; SER_PAR_NONE, in WR_TX_RX_CTRL (WR4)
+ .byte %00000001 ; SER_PAR_ODD (Ref page 5-8)
+ .byte %00000011 ; SER_PAR_EVEN
+ .byte $FF ; SER_PAR_MARK
+ .byte $FF ; SER_PAR_SPACE
+
+; ------------------------------------------------------------------------
+; Addresses
+
+SCCAREG := $C039
+SCCBREG := $C038
+SCCADATA := $C03B
+SCCBDATA := $C03A
+
+; We're supposed to get SerFlag's address using GetAddr on ROMs 1 and 3.
+; (https://archive.org/details/IIgs_2523018_SCC_Access, page 9)
+; But, it's the same value as on ROM0. As we don't expect a ROM 4 anytime
+; soon with a different value, let's keep it simple.
+
+SER_FLAG := $E10104
+
+; ------------------------------------------------------------------------
+; Channels
+
+CHANNEL_B = 0
+CHANNEL_A = 1
+
+; ------------------------------------------------------------------------
+; Write registers, read registers, and values that interest us
+
+WR_INIT_CTRL = 0
+RR_INIT_STATUS = 0
+INIT_CTRL_CLEAR_EIRQ = %00010000
+INIT_CTRL_CLEAR_ERR = %00110000
+INIT_STATUS_READY = %00000100
+INIT_STATUS_RTS = %00100000
+
+WR_TX_RX_MODE_CTRL = 1
+TX_RX_MODE_OFF = %00000000
+TX_RX_MODE_RXIRQ = %00010001
+
+WR_RX_CTRL = 3 ; (Ref page 5-7)
+RR_RX_STATUS = 9 ; Corresponding status register
+RX_CTRL_ON = %00000001 ; ORed, Rx enabled
+RX_CTRL_OFF = %11111110 ; ANDed,Rx disabled
+
+WR_TX_RX_CTRL = 4
+RR_TX_RX_STATUS = 4
+
+WR_TX_CTRL = 5 ; (Ref page 5-9)
+RR_TX_STATUS = 5 ; Corresponding status register
+TX_CTRL_ON = %00001000 ; ORed, Tx enabled
+TX_CTRL_OFF = %11110111 ; ANDed,Tx disabled
+TX_DTR_ON = %01111111 ; ANDed,DTR ON (high)
+TX_DTR_OFF = %10000000 ; ORed, DTR OFF
+TX_RTS_ON = %00000010 ; ORed, RTS ON (low)
+TX_RTS_OFF = %11111101 ; ANDed, RTS OFF
+
+WR_MASTER_IRQ_RST = 9 ; (Ref page 5-14)
+MASTER_IRQ_SHUTDOWN = %00000010 ; STA'd
+MASTER_IRQ_MIE_RST = %00001010 ; STA'd
+MASTER_IRQ_SET = %00011001 ; STA'd
+
+WR_CLOCK_CTRL = 11 ; (Ref page 5-17)
+
+WR_BAUDL_CTRL = 12 ; (Ref page 5-18)
+WR_BAUDH_CTRL = 13 ; (Ref page 5-19)
+
+WR_MISC_CTRL = 14 ; (Ref page 5-19)
+
+WR_IRQ_CTRL = 15 ; (Ref page 5-20)
+IRQ_CLEANUP_EIRQ = %00001000
+
+RR_SPEC_COND_STATUS = 1 ; (Ref page 5-23)
+SPEC_COND_FRAMING_ERR = %01000000
+SPEC_COND_OVERRUN_ERR = %00100000
+
+RR_IRQ_STATUS = 2 ; (Ref page 5-24)
+IRQ_MASQ = %01110000 ; ANDed
+IRQ_RX = %00100000
+IRQ_SPECIAL = %01100000
+
+RR_INTR_PENDING_STATUS = 3 ; (Ref page 5-25)
+INTR_IS_RX = %00100100 ; ANDed (RX IRQ, channel A or B)
+
+ .code
+
+; Read register value to A.
+; Input: X as channel
+; Y as register
+; Output: A
+readSSCReg:
+ cpx #0
+ bne ReadAreg
+ sty SCCBREG
+ lda SCCBREG
+ rts
+ReadAreg:
+ sty SCCAREG
+ lda SCCAREG
+ rts
+
+; Write value of A to a register.
+; Input: X as channel
+; Y as register
+writeSCCReg:
+ cpx #0
+ bne WriteAreg
+ sty SCCBREG
+ sta SCCBREG
+ rts
+WriteAreg:
+ sty SCCAREG
+ sta SCCAREG
+ rts
+
+;----------------------------------------------------------------------------
+; SER_INSTALL: Is called after the driver is loaded into memory. If possible,
+; check if the hardware is present. Must return an SER_ERR_xx code in a/x.
+;
+; Since we don't have to manage the IRQ vector on the Apple II, this is
+; actually the same as:
+;
+; SER_UNINSTALL: Is called before the driver is removed from memory.
+; No return code required (the driver is removed from memory on return).
+;
+; and:
+;
+; SER_CLOSE: Close the port and disable interrupts. Called without parameters.
+; Must return an SER_ERR_xx code in a/x.
+
+SER_INSTALL:
+SER_UNINSTALL:
+SER_CLOSE:
+ ; Check if this is a IIgs (Apple II Miscellaneous TechNote #7,
+ ; Apple II Family Identification)
+ sec
+ bit $C082
+ jsr $FE1F
+ bit $C080
+
+ bcc IIgs
+
+ lda #SER_ERR_NO_DEVICE ; Not a IIgs
+ ldx #$00 ; Promote char return value
+ rts
+
+IIgs:
+ ldx Opened ; Check for open port
+ beq :+
+
+ ldx Channel
+
+ ; Deactivate interrupts
+ sei
+ ldy #WR_MASTER_IRQ_RST
+ lda #MASTER_IRQ_SHUTDOWN
+ jsr writeSCCReg
+
+ ldy #WR_TX_RX_MODE_CTRL
+ lda #TX_RX_MODE_OFF
+ jsr writeSCCReg
+
+ ; Reset SerFlag to what it was
+ lda SerFlagOrig
+ sta SER_FLAG
+
+ lda SCCBDATA
+
+ ; Clear external interrupts (twice)
+ ldy #WR_INIT_CTRL
+ lda #INIT_CTRL_CLEAR_EIRQ
+ jsr writeSCCReg
+ jsr writeSCCReg
+
+ ; Reset MIE for firmware use
+ ldy #WR_MASTER_IRQ_RST
+ lda #MASTER_IRQ_MIE_RST
+ jsr writeSCCReg
+
+ ldx #$00
+ stx Opened ; Mark port as closed
+
+ cli
+: txa ; Promote char return value
+ rts
+
+getClockSource:
+ .assert SER_PARAMS::BAUDRATE = 0, error
+ lda (ptr1) ; Baudrate index - cc65 value
+ cmp #SER_BAUD_115200
+ lda #$00
+ adc #$00
+ sta CurClockSource ; 0 = BRG, 1 = RTxC
+ rts
+
+;----------------------------------------------------------------------------
+; SER_OPEN: A pointer to a ser_params structure is passed in ptr1.
+; Must return an SER_ERR_xx code in a/x.
+
+SER_OPEN:
+ sei
+
+ ; Check if the handshake setting is valid
+ ldy #SER_PARAMS::HANDSHAKE ; Handshake
+ lda (ptr1),y
+ cmp #SER_HS_SW ; Not supported
+ beq InvParam
+
+ sta HSType ; Store flow control type
+
+ ; Initialize buffers
+ ldy #$00
+ sty Stopped
+ sty RecvHead
+ sty RecvTail
+ sty SendHead
+ sty SendTail
+ dey ; Y = 255
+ sty RecvFreeCnt
+ sty SendFreeCnt
+
+ ldx Channel
+
+ ldy #RR_INIT_STATUS ; Hit rr0 once to sync up
+ jsr readSSCReg
+
+ ldy #WR_MISC_CTRL ; WR14: Turn everything off
+ lda #$00
+ jsr writeSCCReg
+
+ jsr getClockSource ; Should we use BRG or RTxC?
+
+ ldy #SER_PARAMS::STOPBITS ; WR4 setup: clock mult., stop & parity
+ lda (ptr1),y ; Stop bits
+ tay
+ lda StopTable,y ; Get value
+
+ pha
+ ldy #SER_PARAMS::PARITY
+ lda (ptr1),y ; Parity bits
+ tay
+ pla
+ ora ParityTable,y ; Get value
+ bmi InvParam
+
+ ldy CurClockSource ; Clock multiplier
+ ora ClockMultiplier,y
+
+ ldy #WR_TX_RX_CTRL
+ jsr writeSCCReg ; End of WR4 setup
+
+ ldy CurClockSource ; WR11 setup: clock source
+ cpx #CHANNEL_B
+ beq SetClock
+ iny ; Shift to get correct ClockSource val
+ iny ; depending on our channel
+
+SetClock:
+ lda ClockSource,y
+ ldy #WR_CLOCK_CTRL
+ jsr writeSCCReg ; End of WR11 setup
+
+ lda ChanIrqFlags,x ; Store which IRQ bits we'll check
+ sta CurChanIrqFlags
+
+SetBaud:
+ .assert SER_PARAMS::BAUDRATE = 0, error
+ lda (ptr1) ; Baudrate index - cc65 value
+ asl
+ tay
+
+ lda BaudTable,y ; Get low byte of register value
+ bpl BaudOK ; Verify baudrate is supported
+
+InvParam:
+ lda #SER_ERR_INIT_FAILED
+ ldy #$00 ; Mark port closed
+ bra SetupOut
+
+BaudOK:
+ phy ; WR12 setup: BRG time constant, low byte
+ ldy #WR_BAUDL_CTRL ; Setting WR12 & 13 is useless if we're using
+ jsr writeSCCReg ; RTxC, but doing it anyway makes code smaller
+ ply
+
+ iny
+ lda BaudTable,y ; WR13 setup: BRG time constant, high byte
+ ldy #WR_BAUDH_CTRL
+ jsr writeSCCReg
+
+ ldy CurClockSource ; WR14 setup: BRG enabling
+ lda BrgEnabled,y
+ ldy #WR_MISC_CTRL ; Time to turn this thing on
+ jsr writeSCCReg
+
+ ldy #SER_PARAMS::DATABITS ; WR3 setup: RX data bits
+ lda (ptr1),y
+ tay
+ lda RxBitTable,y
+ ora #RX_CTRL_ON ; and turn receiver on
+
+ phy
+ ldy #WR_RX_CTRL
+ jsr writeSCCReg ; End of WR3 setup
+ ply
+
+ lda TxBitTable,y ; WR5 setup: TX data bits
+ ora #TX_CTRL_ON ; and turn transmitter on
+ and #TX_DTR_ON ; and turn DTR on
+
+ sta RtsOff ; Save value for flow control
+
+ ora #TX_RTS_ON ; and turn RTS on
+
+ ldy #WR_TX_CTRL
+ jsr writeSCCReg ; End of WR5 setup
+
+ ldy #WR_IRQ_CTRL ; WR15 setup: IRQ
+ lda #IRQ_CLEANUP_EIRQ
+ jsr writeSCCReg
+
+ ldy #WR_INIT_CTRL ; WR0 setup: clear existing IRQs
+ lda #INIT_CTRL_CLEAR_EIRQ
+ jsr writeSCCReg ; Clear (write twice)
+ jsr writeSCCReg
+
+ ldy #WR_TX_RX_MODE_CTRL ; WR1 setup: Activate RX IRQ
+ lda #TX_RX_MODE_RXIRQ
+ jsr writeSCCReg
+
+ lda SCCBREG ; WR9 setup: Activate master IRQ
+ ldy #WR_MASTER_IRQ_RST
+ lda #MASTER_IRQ_SET
+ jsr writeSCCReg
+
+ lda SER_FLAG ; Get SerFlag's current value
+ sta SerFlagOrig ; and save it
+
+ ora ChanIrqMask,x ; Tell firmware which channel IRQs we want
+ sta SER_FLAG
+
+ ldy #$01 ; Mark port opened
+ lda #SER_ERR_OK
+
+SetupOut:
+ ldx #$00 ; Promote char return value
+ sty Opened
+ cli
+ rts
+
+;----------------------------------------------------------------------------
+; SER_GET: Will fetch a character from the receive buffer and store it into the
+; variable pointed to by ptr1. If no data is available, SER_ERR_NO_DATA is
+; returned.
+
+SER_GET:
+ ldx Channel
+
+ lda RecvFreeCnt ; Check for buffer empty
+ cmp #$FF
+ beq NoData
+
+ ldy Stopped ; Check for flow stopped
+ beq :+
+ cmp #63 ; Enough free?
+ bcc :+
+ stz Stopped ; Release flow control
+
+ lda RtsOff
+ ora #TX_RTS_ON
+
+ ldy #WR_TX_CTRL
+ jsr writeSCCReg
+
+: ldy RecvHead ; Get byte from buffer
+ lda RecvBuf,y
+ inc RecvHead
+ inc RecvFreeCnt
+ sta (ptr1)
+ lda #SER_ERR_OK
+ .assert SER_ERR_OK = 0, error
+ tax
+ rts
+NoData:
+ lda #SER_ERR_NO_DATA
+ ldx #$00 ; Promote char return value
+ rts
+
+;----------------------------------------------------------------------------
+; SER_PUT: Output character in A.
+; Must return an SER_ERR_xx code in a/x.
+
+SER_PUT:
+ ldx Channel
+
+ ldy SendFreeCnt ; Anything to send first?
+ iny ; Y = $FF?
+ beq :+
+ pha
+ lda #$00 ; TryHard = false
+ jsr TryToSend
+ pla
+
+: ldy SendFreeCnt ; Do we have room to store byte?
+ bne :+
+ lda #SER_ERR_OVERFLOW
+ ldx #$00
+ rts
+
+: ldy SendTail ; Put byte into send buffer & send
+ sta SendBuf,y
+ inc SendTail
+ dec SendFreeCnt
+ lda #$FF ; TryHard = true
+ jsr TryToSend
+ lda #SER_ERR_OK
+ .assert SER_ERR_OK = 0, error
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+; SER_STATUS: Return the status in the variable pointed to by ptr1.
+; Must return an SER_ERR_xx code in a/x.
+; We provide the read register 0, containing interesting info like
+; INIT_STATUS_READY (hardware handshake status) or INIT_STATUS_RTS
+; (ready to send).
+
+SER_STATUS:
+ ldx Channel
+ ldy #RR_INIT_STATUS
+ jsr readSSCReg
+ ldx #$00
+ sta (ptr1)
+ .assert SER_ERR_OK = 0, error
+ txa
+ rts
+
+;----------------------------------------------------------------------------
+; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
+; specific data in ptr1, and the ioctl code in A.
+; Sets communication channel A or B (A = 1, B = 0)
+; Must return an SER_ERR_xx code in a/x.
+
+SER_IOCTL:
+ ora ptr1+1 ; Check data msb and code to be 0
+ bne :+
+
+ ldx ptr1 ; Check data lsb to be 0 or 1
+ bmi :+
+ cpx #$02
+ bcs :+
+
+ stx Channel
+ .assert SER_ERR_OK = 0, error
+ tax
+ rts
+
+: lda #SER_ERR_INV_IOCTL
+ ldx #$00 ; Promote char return value
+ rts
+
+;----------------------------------------------------------------------------
+; SER_IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
+; registers are already saved, no parameters are passed, but the carry flag
+; is clear on entry. The routine must return with carry set if the interrupt
+; was handled, otherwise with carry clear.
+
+SER_IRQ:
+ ldy #RR_INTR_PENDING_STATUS ; IRQ status is always in A reg
+ sty SCCAREG
+ lda SCCAREG
+
+ and CurChanIrqFlags ; Is this ours?
+ beq Done
+
+ and #INTR_IS_RX ; Is this an RX irq?
+ beq CheckSpecial
+
+ ldx Channel
+ beq ReadBdata
+ lda SCCADATA
+ bra ReadDone
+ReadBdata:
+ lda SCCBDATA ; Get byte
+ReadDone:
+ ldx RecvFreeCnt ; Check if we have free space left
+ beq Flow ; Jump if no space in receive buffer
+ ldy RecvTail ; Load buffer pointer
+ sta RecvBuf,y ; Store received byte in buffer
+ inc RecvTail ; Increment buffer pointer
+ dec RecvFreeCnt ; Decrement free space counter
+ cpx #33
+ bcc Flow ; Assert flow control if buffer space low
+ rts ; Interrupt handled (carry already set)
+
+CheckSpecial:
+ ; Always check IRQ special flags from Channel B (Ref page 5-24)
+ ldy #RR_IRQ_STATUS
+ sty SCCBREG
+ lda SCCBREG
+
+ and #IRQ_MASQ
+ cmp #IRQ_SPECIAL
+ beq Special
+
+ ; Clear exint
+ ldx Channel
+ ldy #WR_INIT_CTRL
+ lda #INIT_CTRL_CLEAR_EIRQ
+ jsr writeSCCReg
+
+ sec
+ rts
+
+Flow: lda HSType ; Don't touch if no flow control
+ beq IRQDone
+
+ ldx Channel ; Assert flow control if buffer space too low
+ ldy #WR_TX_CTRL
+ lda RtsOff
+ jsr writeSCCReg
+
+ sta Stopped
+IRQDone:sec ; Interrupt handled
+Done: rts
+
+Special:ldx Channel
+ ldy #RR_SPEC_COND_STATUS
+ jsr readSSCReg
+
+ tax
+ and #SPEC_COND_FRAMING_ERR
+ bne BadChar
+ txa
+ and #SPEC_COND_OVERRUN_ERR
+ beq BadChar
+
+ ldy #WR_INIT_CTRL
+ lda #INIT_CTRL_CLEAR_ERR
+ jsr writeSCCReg
+
+ sec
+ rts
+
+BadChar:
+ cpx #CHANNEL_B
+ beq BadCharB
+ lda SCCADATA
+ bra BadCharDone
+BadCharB:
+ lda SCCBDATA ; Remove char in error
+BadCharDone:
+ sec
+ rts
+
+;----------------------------------------------------------------------------
+; Try to send a byte. Internal routine. A = TryHard, X = Channel
+
+TryToSend:
+ sta tmp1 ; Remember tryHard flag
+Again: lda SendFreeCnt ; Anything to send?
+ cmp #$FF
+ beq Quit ; No
+
+ lda Stopped ; Check for flow stopped
+ bne Quit ; Bail out if it is
+
+Wait:
+ ldy #RR_INIT_STATUS
+ jsr readSSCReg ; Check that we're ready to send
+ tay
+ and #INIT_STATUS_READY
+ beq NotReady
+
+ tya
+ and #INIT_STATUS_RTS ; Ready to send
+ bne Send
+
+NotReady:
+ bit tmp1 ; Keep trying if must try hard
+ bmi Wait
+Quit: rts
+
+Send: ldy SendHead ; Send byte
+ lda SendBuf,y
+
+ cpx #CHANNEL_B
+ beq WriteBdata
+ sta SCCADATA
+ bra WriteDone
+WriteBdata:
+ sta SCCBDATA
+WriteDone:
+ inc SendHead
+ inc SendFreeCnt
+ jmp Again ; Continue flushing TX buffer
diff --git a/libsrc/apple2/ser/a2.ssc.s b/libsrc/apple2/ser/a2.ssc.s
index e0cd94597..88dc4572c 100644
--- a/libsrc/apple2/ser/a2.ssc.s
+++ b/libsrc/apple2/ser/a2.ssc.s
@@ -26,6 +26,7 @@
.include "ser-error.inc"
.macpack module
+ .macpack cpu
; ------------------------------------------------------------------------
; Header. Includes jump table
@@ -37,8 +38,8 @@
.endif
; Driver signature
- .byte $73, $65, $72 ; "ser"
- .byte SER_API_VERSION ; Serial API version number
+ .byte $73, $65, $72 ; "ser"
+ .byte SER_API_VERSION ; Serial API version number
; Library reference
.addr $0000
@@ -57,13 +58,19 @@
;----------------------------------------------------------------------------
; I/O definitions
+.if (.cpu .bitand CPU_ISET_65C02)
+ACIA := $C088
+.else
Offset = $8F ; Move 6502 false read out of I/O to page $BF
+ACIA := $C088-Offset
+.endif
-ACIA = $C088-Offset
-ACIA_DATA = ACIA+0 ; Data register
-ACIA_STATUS = ACIA+1 ; Status register
-ACIA_CMD = ACIA+2 ; Command register
-ACIA_CTRL = ACIA+3 ; Control register
+ACIA_DATA := ACIA+0 ; Data register
+ACIA_STATUS := ACIA+1 ; Status register
+ACIA_CMD := ACIA+2 ; Command register
+ACIA_CTRL := ACIA+3 ; Control register
+
+SLTROMSEL := $C02D ; For Apple IIgs slot verification
;----------------------------------------------------------------------------
; Global variables
@@ -72,16 +79,18 @@ ACIA_CTRL = ACIA+3 ; Control register
RecvHead: .res 1 ; Head of receive buffer
RecvTail: .res 1 ; Tail of receive buffer
-RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
+RecvFreeCnt: .res 1 ; Number of free bytes in receive buffer
SendHead: .res 1 ; Head of send buffer
SendTail: .res 1 ; Tail of send buffer
-SendFreeCnt: .res 1 ; Number of bytes in send buffer
+SendFreeCnt: .res 1 ; Number of free bytes in send buffer
Stopped: .res 1 ; Flow-stopped flag
-RtsOff: .res 1 ;
+RtsOff: .res 1 ; Cached value of command register with
+ ; flow stopped
+HSType: .res 1 ; Flow-control type
-RecvBuf: .res 256 ; Receive buffers: 256 bytes
-SendBuf: .res 256 ; Send buffers: 256 bytes
+RecvBuf: .res 256 ; Receive buffer: 256 bytes
+SendBuf: .res 256 ; Send buffer: 256 bytes
Index: .res 1 ; I/O register index
@@ -91,8 +100,9 @@ Slot: .byte $02 ; Default to SSC in slot 2
.rodata
- ; Tables used to translate RS232 params into register values
-BaudTable: ; bit7 = 1 means setting is invalid
+BaudTable: ; Table used to translate RS232 baudrate param
+ ; into control register value
+ ; bit7 = 1 means setting is invalid
.byte $FF ; SER_BAUD_45_5
.byte $01 ; SER_BAUD_50
.byte $02 ; SER_BAUD_75
@@ -111,32 +121,44 @@ BaudTable: ; bit7 = 1 means setting is invalid
.byte $0F ; SER_BAUD_19200
.byte $FF ; SER_BAUD_38400
.byte $FF ; SER_BAUD_57600
- .byte $FF ; SER_BAUD_115200
+ .byte $00 ; SER_BAUD_115200
.byte $FF ; SER_BAUD_230400
-BitTable:
+
+BitTable: ; Table used to translate RS232 databits param
+ ; into control register value
.byte $60 ; SER_BITS_5
.byte $40 ; SER_BITS_6
.byte $20 ; SER_BITS_7
.byte $00 ; SER_BITS_8
-StopTable:
+
+StopTable: ; Table used to translate RS232 stopbits param
+ ; into control register value
.byte $00 ; SER_STOP_1
.byte $80 ; SER_STOP_2
-ParityTable:
+
+ParityTable: ; Table used to translate RS232 parity param
+ ; into command register value
.byte $00 ; SER_PAR_NONE
.byte $20 ; SER_PAR_ODD
.byte $60 ; SER_PAR_EVEN
.byte $A0 ; SER_PAR_MARK
.byte $E0 ; SER_PAR_SPACE
-IdOfsTable:
+
+IdOfsTable: ; Table of bytes positions, used to check four
+ ; specific bytes on the slot's firmware to make
+ ; sure this is a serial card.
.byte $05 ; Pascal 1.0 ID byte
.byte $07 ; Pascal 1.0 ID byte
.byte $0B ; Pascal 1.1 generic signature byte
.byte $0C ; Device signature byte
-IdValTable:
- .byte $38 ; Fixed
- .byte $18 ; Fixed
- .byte $01 ; Fixed
- .byte $31 ; Serial or parallel I/O card type 1
+
+IdValTable: ; Table of expected values for the four checked
+ ; bytes
+ .byte $38 ; ID Byte 0 (from Pascal 1.0), fixed
+ .byte $18 ; ID Byte 1 (from Pascal 1.0), fixed
+ .byte $01 ; Generic signature for Pascal 1.1, fixed
+ .byte $31 ; Device signature byte (serial or
+ ; parallel I/O card type 1)
IdTableLen = * - IdValTable
@@ -163,116 +185,167 @@ SER_CLOSE:
ldx Index ; Check for open port
beq :+
- ; Deactivate DTR and disable 6551 interrupts
- lda #%00001010
+ lda #%00001010 ; Deactivate DTR and disable 6551 interrupts
sta ACIA_CMD,x
- ; Done, return an error code
-: lda #$C000
ora Slot
sta ptr2+1
- ; Check Pascal 1.1 Firmware Protocol ID bytes
-: ldy IdOfsTable,x
+: ldy IdOfsTable,x ; Check Pascal 1.1 Firmware Protocol ID bytes
lda IdValTable,x
cmp (ptr2),y
- bne NoDevice
+ bne NoDev
inx
cpx #IdTableLen
bcc :-
- ; Convert slot to I/O register index
- lda Slot
+ lda Slot ; Convert slot to I/O register index
asl
asl
asl
asl
- adc Offset ; Assume carry to be clear
+.if .not (.cpu .bitand CPU_ISET_65C02)
+ adc #Offset ; Assume carry to be clear
+.endif
tax
- ; Check if the handshake setting is valid
- ldy #SER_PARAMS::HANDSHAKE ; Handshake
- lda (ptr1),y
- cmp #SER_HS_HW ; This is all we support
- bne InvParam
+ ; Check that this works like an ACIA 6551 is expected to work
- ; Initialize buffers
- ldy #$00
+ lda ACIA_STATUS,x ; Save current values in what we expect to be
+ sta tmp1 ; the ACIA status register
+ lda ACIA_CMD,x ; and command register. So we can restore them
+ sta tmp2 ; if this isn't a 6551.
+
+ ldy #%00000010 ; Disable TX/RX, disable IRQ
+: tya
+ sta ACIA_CMD,x
+ cmp ACIA_CMD,x ; Verify what we stored is there
+ bne NotAcia
+ iny ; Enable TX/RX, disable IRQ
+ cpy #%00000100
+ bne :-
+ sta ACIA_STATUS,x ; Reset ACIA
+ lda ACIA_CMD,x ; Check that RX/TX is disabled
+ lsr
+ bcc AciaOK
+
+NotAcia:lda tmp2 ; Restore original values
+ sta ACIA_CMD,x
+ lda tmp1
+ sta ACIA_STATUS,x
+
+NoDev: lda #SER_ERR_NO_DEVICE
+ bne Out
+
+ ; Check if the handshake setting is valid
+AciaOK: ldy #SER_PARAMS::HANDSHAKE
+ lda (ptr1),y
+ cmp #SER_HS_SW ; Not supported
+ bne HandshakeOK
+
+ lda #SER_ERR_INIT_FAILED
+ bne Out
+
+HandshakeOK:
+ sta HSType ; Store flow control type
+
+ ldy #$00 ; Initialize buffers
sty Stopped
sty RecvHead
sty RecvTail
sty SendHead
sty SendTail
- dey ; Y = 255
+ dey ; Y = 255
sty RecvFreeCnt
sty SendFreeCnt
; Set the value for the control register, which contains stop bits,
; word length and the baud rate.
ldy #SER_PARAMS::BAUDRATE
- lda (ptr1),y ; Baudrate index
+ lda (ptr1),y ; Baudrate index
tay
- lda BaudTable,y ; Get 6551 value
- bmi InvBaud ; Branch if rate not supported
- sta tmp1
+ lda BaudTable,y ; Get 6551 value
+ sta tmp2 ; Backup for IRQ setting
+ bpl BaudOK ; Check that baudrate is supported
- ldy #SER_PARAMS::DATABITS ; Databits
- lda (ptr1),y
+ lda #SER_ERR_BAUD_UNAVAIL
+ bne Out
+
+BaudOK: sta tmp1
+ ldy #SER_PARAMS::DATABITS
+ lda (ptr1),y ; Databits index
tay
- lda BitTable,y
+ lda BitTable,y ; Get 6551 value
ora tmp1
sta tmp1
- ldy #SER_PARAMS::STOPBITS ; Stopbits
- lda (ptr1),y
+ ldy #SER_PARAMS::STOPBITS
+ lda (ptr1),y ; Stopbits index
tay
- lda StopTable,y
+ lda StopTable,y ; Get 6551 value
ora tmp1
- ora #%00010000 ; Receiver clock source = baudrate
+ ora #%00010000 ; Set receiver clock source = baudrate
sta ACIA_CTRL,x
; Set the value for the command register. We remember the base value
; in RtsOff, since we will have to manipulate ACIA_CMD often.
- ldy #SER_PARAMS::PARITY ; Parity
- lda (ptr1),y
+ ldy #SER_PARAMS::PARITY
+ lda (ptr1),y ; Parity index
tay
- lda ParityTable,y
- ora #%00000001 ; DTR active
- sta RtsOff
- ora #%00001000 ; Enable receive interrupts
- sta ACIA_CMD,x
+ lda ParityTable,y ; Get 6551 value
+
+ ora #%00000001 ; Set DTR active
+ sta RtsOff ; Store value to easily handle flow control later
+
+ ora #%00001010 ; Disable interrupts and set RTS low
+
+ ldy tmp2 ; Don't enable IRQs if 115200bps
+ beq :+
+ and #%11111101 ; Enable receive IRQs
+: sta ACIA_CMD,x
; Done
- stx Index ; Mark port as open
- lda #SER_ERR_NO_DEVICE
- rts
-
- ; Invalid parameter
-InvParam:lda #SER_ERR_INIT_FAILED
- rts
-
- ; Baud rate not available
-InvBaud:lda #SER_ERR_BAUD_UNAVAIL
+ stx Index ; Mark port as open
+ lda #SER_ERR_OK
+Out:
+ ldx #$00 ; Promote char return value
rts
;----------------------------------------------------------------------------
@@ -282,38 +355,38 @@ InvBaud:lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #$00 ; Promote char return value
rts
- ; Check for flow stopped & enough free: release flow control
-: ldy Stopped ; (34)
+: ldy Stopped ; Check for flow stopped
beq :+
- cmp #63
+ cmp #63 ; Enough free?
bcc :+
+.if (.cpu .bitand CPU_ISET_65C02)
+ stz Stopped ; Release flow control
+.else
lda #$00
sta Stopped
+.endif
lda RtsOff
ora #%00001000
sta ACIA_CMD,x
- ; Get byte from buffer
-: ldy RecvHead ; (41)
+: ldy RecvHead ; Get byte from buffer
lda RecvBuf,y
inc RecvHead
inc RecvFreeCnt
- ldx #$00 ; (59)
+ ldx #$00
+.if (.cpu .bitand CPU_ISET_65C02)
+ sta (ptr1) ; Store it for caller
+.else
sta (ptr1,x)
+.endif
txa ; Return code = 0
rts
@@ -324,29 +397,28 @@ SER_GET:
SER_PUT:
ldx Index
- ; Try to send
- ldy SendFreeCnt
- iny ; Y = $FF?
+ ldy SendFreeCnt ; Anything to send first?
+ cpy #$FF ; No
beq :+
pha
lda #$00 ; TryHard = false
- jsr TryToSend
+ jsr TryToSend ; Try to flush send buffer
pla
- ; Put byte into send buffer & send
-: ldy SendFreeCnt
+ ldy SendFreeCnt ; Reload SendFreeCnt after TryToSend
bne :+
- lda #SER_ERR_OVERFLOW
+ lda #SER_ERR_OVERFLOW
+ ldx #$00 ; Promote char return value
rts
-: ldy SendTail
+: ldy SendTail ; Put byte into send buffer
sta SendBuf,y
inc SendTail
dec SendFreeCnt
lda #$FF ; TryHard = true
- jsr TryToSend
- lda #SER_ERR_INV_IOCTL
+: lda #SER_ERR_INV_IOCTL
+ ldx #$00 ; Promote char return value
rts
;----------------------------------------------------------------------------
@@ -399,22 +472,24 @@ SER_IRQ:
and #$08
beq Done ; Jump if no ACIA interrupt
lda ACIA_DATA,x ; Get byte from ACIA
- ldy RecvFreeCnt ; Check if we have free space left
+ ldx RecvFreeCnt ; Check if we have free space left
beq Flow ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
- ldy RecvFreeCnt ; Check for buffer space low
- cpy #33
+ cpx #33 ; Check for buffer space low
bcc Flow ; Assert flow control if buffer space low
rts ; Interrupt handled (carry already set)
- ; Assert flow control if buffer space too low
-Flow: lda RtsOff
+Flow: lda HSType ; Don't touch if no flow control
+ beq IRQDone
+
+ ldx Index ; Assert flow control if buffer space too low
+ lda RtsOff
sta ACIA_CMD,x
sta Stopped
- sec ; Interrupt handled
+IRQDone:sec ; Interrupt handled
Done: rts
;----------------------------------------------------------------------------
@@ -422,26 +497,24 @@ Done: rts
TryToSend:
sta tmp1 ; Remember tryHard flag
-Again: lda SendFreeCnt
- cmp #$FF
- beq Quit ; Bail out
+NextByte:
+ lda SendFreeCnt ; Is there anything to send? This can happen if
+ cmp #$FF ; we got interrupted by RX while sending, and
+ beq Quit ; flow control was asserted.
- ; Check for flow stopped
- lda Stopped
- bne Quit ; Bail out
+Again: lda Stopped ; Is flow stopped?
+ bne Quit ; Yes, Bail out
- ; Check that ACIA is ready to send
- lda ACIA_STATUS,x
+ lda ACIA_STATUS,x ; Check that ACIA is ready to send
and #$10
- bne Send
+ bne Send ; It is!
bit tmp1 ; Keep trying if must try hard
bmi Again
Quit: rts
- ; Send byte and try again
-Send: ldy SendHead
+Send: ldy SendHead ; Get first byte to send
lda SendBuf,y
- sta ACIA_DATA,x
+ sta ACIA_DATA,x ; Send it
inc SendHead
inc SendFreeCnt
- jmp Again
+ bne NextByte ; And try next one
diff --git a/libsrc/apple2/ser_stat_stddrv.s b/libsrc/apple2/ser_stat_stddrv.s
new file mode 100644
index 000000000..690fe4853
--- /dev/null
+++ b/libsrc/apple2/ser_stat_stddrv.s
@@ -0,0 +1,22 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .ifdef __APPLE2ENH__
+ .import _a2e_ssc_ser
+ .else
+ .import _a2_ssc_ser
+ .endif
+
+.rodata
+
+ .ifdef __APPLE2ENH__
+_ser_static_stddrv := _a2e_ssc_ser
+ .else
+_ser_static_stddrv := _a2_ssc_ser
+ .endif
diff --git a/libsrc/apple2/ser_stddrv.s b/libsrc/apple2/ser_stddrv.s
new file mode 100644
index 000000000..2e8361865
--- /dev/null
+++ b/libsrc/apple2/ser_stddrv.s
@@ -0,0 +1,18 @@
+;
+; Name of the standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const char ser_stddrv[];
+;
+
+ .export _ser_stddrv
+
+.rodata
+
+_ser_stddrv:
+ .ifdef __APPLE2ENH__
+ .asciiz "A2E.SSC.SER"
+ .else
+ .asciiz "A2.SSC.SER"
+ .endif
diff --git a/libsrc/apple2/set_iigs_speed.s b/libsrc/apple2/set_iigs_speed.s
new file mode 100644
index 000000000..5e2f2f722
--- /dev/null
+++ b/libsrc/apple2/set_iigs_speed.s
@@ -0,0 +1,29 @@
+;
+; Colin Leroy-Mira , 2024
+;
+; unsigned char __fastcall__ detect_iigs(unsigned char speed)
+;
+
+ .export _set_iigs_speed
+ .import ostype, return0
+
+ .include "apple2.inc"
+ .include "accelerator.inc"
+
+_set_iigs_speed:
+ tax ; Keep parameter
+ lda ostype ; Return if not IIgs
+ bmi :+
+ jmp return0
+
+: lda CYAREG
+ cpx #SPEED_SLOW
+ beq :+
+ ora #%10000000
+ bne set_speed
+: and #%01111111
+set_speed:
+ sta CYAREG
+ txa
+ ldx #$00
+ rts
diff --git a/libsrc/apple2/sleep.s b/libsrc/apple2/sleep.s
new file mode 100644
index 000000000..43873d9f4
--- /dev/null
+++ b/libsrc/apple2/sleep.s
@@ -0,0 +1,54 @@
+;
+; Colin Leroy-Mira , 2024
+;
+; void __fastcall__ sleep(unsigned s)
+;
+;
+
+ .export _sleep
+ .import _get_iigs_speed
+ .import _set_iigs_speed
+ .import WAIT
+ .importzp tmp1
+
+ .include "accelerator.inc"
+
+ ; This functions uses the Apple2 WAIT ROM routine to waste a certain
+ ; amount of cycles and returns approximately after the numbers of
+ ; seconds passed in AX.
+ ;
+ ; It takes 1023730 cycles when called with AX=1 (1,0007s),
+ ; 10236364 cycles when called with AX=10 (10,006 seconds),
+ ; 306064298 cycles with AX=300 (299.2 seconds).
+ ;
+ ; Caveat: IRQs firing during calls to sleep will make the sleep longer
+ ; by the amount of cycles it takes to handle the IRQ.
+ ;
+_sleep:
+ stx tmp1 ; High byte of s in X
+ tay ; Low byte in A
+ ora tmp1
+ bne :+
+ rts
+: jsr _get_iigs_speed ; Save current CPU speed
+ pha
+ lda #SPEED_SLOW ; Down to 1MHz for consistency around WAIT
+ jsr _set_iigs_speed
+sleep_1s:
+ ldx #$0A ; Loop 10 times
+sleep_100ms:
+ lda #$C7 ; Sleep about 99ms
+ jsr WAIT
+ lda #$0D ; About 1ms
+ jsr WAIT
+ dex
+ bne sleep_100ms
+ dey
+ bne sleep_1s
+ dec tmp1
+ bmi done
+ dey ; Down to #$FF
+ bne sleep_1s
+done:
+ pla ; Restore CPU speed
+ jmp _set_iigs_speed
diff --git a/libsrc/apple2/stat.s b/libsrc/apple2/stat.s
new file mode 100644
index 000000000..f655b3e3f
--- /dev/null
+++ b/libsrc/apple2/stat.s
@@ -0,0 +1,129 @@
+;
+; Colin Leroy-Mira, 2023
+;
+; int __fastcall__ stat(const char *pathname, struct stat *statbuf);
+;
+
+ .export _stat
+ .import __errno, _open,_close
+ .import mli_file_info
+ .import popax, pushax, pusha0, incsp2
+ .include "zeropage.inc"
+ .include "errno.inc"
+ .include "fcntl.inc"
+ .include "filedes.inc"
+ .include "mli.inc"
+ .include "stat.inc"
+
+_stat:
+ ; Store statbuf pointer
+ sta ptr4
+ sta stbuf
+ stx ptr4+1
+ stx stbuf+1
+
+ ; Clear statbuf
+ lda #$00
+ ldy #.sizeof(stat)-1
+: sta (ptr4),y
+ dey
+ bpl :-
+
+ ; Reset errno
+ sta ___errno
+
+ ; Store pathname
+ jsr popax
+ jsr pushax ; Push it back for mli_file_info
+ jsr pushax ; and for open
+
+ jsr mli_file_info
+
+ bcc got_info
+ jmp incsp2 ; Drop filename copy for open
+
+got_info:
+ ; st_dev
+ lda DEVNUM
+ lsr ; Shift right to cc65 representation
+ lsr
+ lsr
+ lsr
+ ldy #stat::st_dev
+ sta (ptr4),y
+
+ ; st_mode (S_IFDIR/S_IFREG only)
+ lda mliparam + MLI::INFO::FILE_TYPE
+ ldy #stat::st_mode
+ cmp #$0f
+ bne is_reg
+ lda #S_IFDIR
+ bne set_st_mode
+
+is_reg: lda #S_IFREG
+
+set_st_mode:
+ sta (ptr4),y
+
+ ; st_access through st_create_time
+ ldx #MLI::INFO::ACCESS
+ ldy #stat::st_access
+: lda mliparam,x
+ sta (ptr4),y
+ inx
+ iny
+ cpy #stat::st_create_time + .sizeof(stat::st_create_time)
+ bne :-
+
+ ; st_size
+ lda #O_RDONLY
+ jsr pusha0
+ ldy #$04
+ jsr _open
+ cmp #$FF
+ beq done
+ pha ; Save file descriptor for closing
+
+ ; Get ProDOS's REF_NUM from file descriptor
+ jsr getfd
+ ; Get file information
+ sta mliparam + MLI::EOF::REF_NUM
+ lda #GET_EOF_CALL
+ ldx #EOF_COUNT
+ jsr callmli
+ bcs eoferr
+
+ ; Get struct stat in ptr4 back, open destroyed it
+ lda stbuf
+ ldx stbuf+1
+ sta ptr4
+ stx ptr4+1
+
+ ; Store size
+ ldy #stat::st_size
+ lda mliparam + MLI::EOF::EOF
+ sta (ptr4),y
+ lda mliparam + MLI::EOF::EOF+1
+ iny
+ sta (ptr4),y
+ lda mliparam + MLI::EOF::EOF+2
+ iny
+ sta (ptr4),y
+
+ ; Close file
+eoferr:
+ pla
+ ldx #$00
+ jsr _close
+
+ ; Set return value if we had an error
+ lda ___errno
+ beq done
+ lda #$FF
+done:
+ tax
+ rts
+
+ .bss
+
+stbuf: .res 2
diff --git a/libsrc/apple2/statvfs.s b/libsrc/apple2/statvfs.s
new file mode 100644
index 000000000..8fcf46af8
--- /dev/null
+++ b/libsrc/apple2/statvfs.s
@@ -0,0 +1,123 @@
+;
+; Colin Leroy-Mira, 2023
+;
+; int __fastcall__ statvfs(const char *pathname, struct statvfs *statvfsbuf);
+;
+
+ .export _statvfs
+ .import _dio_query_sectsize
+ .import mli_file_info, pushax, popax, popptr1, pushptr1
+ .include "zeropage.inc"
+ .include "apple2.inc"
+ .include "errno.inc"
+ .include "mli.inc"
+ .include "statvfs.inc"
+
+_statvfs:
+ ; Store statbuf
+ sta ptr4
+ stx ptr4+1
+
+ ; Clear statbuf
+ lda #$00
+ ldy #.sizeof(statvfs)-1
+: sta (ptr4),y
+ dey
+ bpl :-
+
+ ; Store pathname, keeping only volume name
+ jsr popptr1
+ ldy #$00
+ sty vol_sep
+ lda (ptr1),y
+ cmp #'/' ; Is the path absolute?
+ beq :+
+ lda #EINVAL
+ jmp ___directerrno
+
+: iny
+ lda (ptr1),y
+ beq :+ ; End of string, no other /
+ cpy #FILENAME_MAX
+ beq :+ ; Max filename length reached
+ cmp #'/'
+ bne :- ; Not a slash, keep looking
+ sty vol_sep ; Register '/' index
+ lda #$00
+ sta (ptr1),y ; Cut pathname at first slash
+: jsr pushptr1
+
+ jsr mli_file_info
+
+ php
+ ldy vol_sep ; Put slash back in pathname
+ lda #'/'
+ sta (ptr1),y
+ plp
+
+ bcc got_info
+
+ jmp ___mappederrno
+
+got_info:
+ ; f_fsid
+ lda DEVNUM
+ lsr ; Shift right to cc65 representation
+ lsr
+ lsr
+ lsr
+ ldy #statvfs::f_fsid
+ sta (ptr4),y
+
+ ; total number of blocks
+ lda mliparam + MLI::INFO::AUX_TYPE
+ ldy #statvfs::f_blocks
+ sta (ptr4),y
+ lda mliparam + MLI::INFO::AUX_TYPE+1
+ iny
+ sta (ptr4),y
+
+ ; blocks free & avail
+ sec
+ lda mliparam + MLI::INFO::AUX_TYPE
+ sbc mliparam + MLI::INFO::BLOCKS
+ ldy #statvfs::f_bfree
+ sta (ptr4),y
+ ldy #statvfs::f_bavail
+ sta (ptr4),y
+
+ lda mliparam + MLI::INFO::AUX_TYPE+1
+ sbc mliparam + MLI::INFO::BLOCKS+1
+ iny
+ sta (ptr4),y
+ ldy #statvfs::f_bfree+1
+ sta (ptr4),y
+
+ ; block sizes
+ jsr _dio_query_sectsize
+ ; low bytes
+ ldy #statvfs::f_bsize
+ sta (ptr4),y
+ ldy #statvfs::f_frsize
+ sta (ptr4),y
+ ; f_frsize high byte
+ iny
+ txa
+ sta (ptr4),y
+ ; f_bsize high byte
+ ldy #statvfs::f_bsize+1
+ sta (ptr4),y
+
+ ; f_namemax
+ lda #FILENAME_MAX
+ ldy #statvfs::f_namemax
+ sta (ptr4),y
+
+ lda #$00
+ sta ___errno
+ tax
+ rts
+
+ .bss
+
+vol_sep:.res 1
diff --git a/libsrc/apple2/syschdir.s b/libsrc/apple2/syschdir.s
index 8afc3af0b..b3f81e2a5 100644
--- a/libsrc/apple2/syschdir.s
+++ b/libsrc/apple2/syschdir.s
@@ -29,7 +29,8 @@ __syschdir:
bcs cleanup
; Update current working directory
- jsr initcwd ; Returns with A = 0
+ jsr initcwd
+ lda #$00
; Cleanup name
cleanup:jsr popname ; Preserves A
diff --git a/libsrc/apple2/targetutil/convert.c b/libsrc/apple2/targetutil/convert.c
index ea9273fc3..52dffa745 100644
--- a/libsrc/apple2/targetutil/convert.c
+++ b/libsrc/apple2/targetutil/convert.c
@@ -108,7 +108,7 @@ static unsigned get_dir_entry(char* p_name)
}
/* Field header_pointer directly follows field last_mod */
- cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1);
+ cur_addr = *(unsigned*)(&dirent->d_mtime.time.hour + 1);
dhandle = dio_open(getcurrentdevice());
if (!dhandle) {
diff --git a/libsrc/apple2/wait.s b/libsrc/apple2/wait.s
new file mode 100644
index 000000000..3b569215b
--- /dev/null
+++ b/libsrc/apple2/wait.s
@@ -0,0 +1,20 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; WAIT routine
+;
+
+ .export WAIT
+
+ .include "apple2.inc"
+
+ .segment "LOWCODE"
+
+WAIT:
+ ; Switch in ROM and call WAIT
+ bit $C082
+ jsr $FCA8 ; Vector to WAIT routine
+
+ ; Switch in LC bank 2 for R/O and return
+ bit $C080
+ rts
diff --git a/libsrc/apple2/waitvsync.s b/libsrc/apple2/waitvsync.s
index a4ab5ebb3..1697622de 100644
--- a/libsrc/apple2/waitvsync.s
+++ b/libsrc/apple2/waitvsync.s
@@ -5,21 +5,11 @@
;
.ifdef __APPLE2ENH__
- .constructor initvsync
.export _waitvsync
- .import _get_ostype
+ .import ostype
.include "apple2.inc"
- .segment "ONCE"
-
-initvsync:
- jsr _get_ostype
- sta ostype
- rts
-
- .code
-
_waitvsync:
bit ostype
bmi iigs ; $8x
@@ -53,8 +43,4 @@ iic: sei
cli
rts
- .segment "INIT"
-
-ostype: .res 1
-
.endif ; __APPLE2ENH__
diff --git a/libsrc/atari/joy/atrmj8.s b/libsrc/atari/joy/atrmj8.s
index 3a26c381d..daf11651d 100644
--- a/libsrc/atari/joy/atrmj8.s
+++ b/libsrc/atari/joy/atrmj8.s
@@ -69,7 +69,8 @@ INSTALL:
lda #$34
sta PACTL
lda #JOY_ERR_OK
- ldx #0
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/atari/joy/atrstd.s b/libsrc/atari/joy/atrstd.s
index fd1d99d31..1a124192f 100644
--- a/libsrc/atari/joy/atrstd.s
+++ b/libsrc/atari/joy/atrstd.s
@@ -62,7 +62,8 @@ JOY_COUNT = 4 ; Number of joysticks we support
INSTALL:
lda #JOY_ERR_OK
- ldx #0
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/atari/mou/atrjoy.s b/libsrc/atari/mou/atrjoy.s
index 3ea428576..a93c7de13 100644
--- a/libsrc/atari/mou/atrjoy.s
+++ b/libsrc/atari/mou/atrjoy.s
@@ -137,9 +137,10 @@ INSTALL:
ldx YPos+1
jsr CMOVEY
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
diff --git a/libsrc/atari/mou/atrst.s b/libsrc/atari/mou/atrst.s
index 5d8a5cd12..626b7a8f7 100644
--- a/libsrc/atari/mou/atrst.s
+++ b/libsrc/atari/mou/atrst.s
@@ -268,9 +268,10 @@ INSTALL:
and #$0f
sta old_porta_vbi
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
diff --git a/libsrc/atari/mou/atrtt.s b/libsrc/atari/mou/atrtt.s
index 61963aa61..b1e53935e 100644
--- a/libsrc/atari/mou/atrtt.s
+++ b/libsrc/atari/mou/atrtt.s
@@ -132,9 +132,10 @@ INSTALL:
ldx YPos+1
jsr CMOVEY
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
diff --git a/libsrc/atari/open.s b/libsrc/atari/open.s
index ed3e40b2f..e7e55c54c 100644
--- a/libsrc/atari/open.s
+++ b/libsrc/atari/open.s
@@ -19,7 +19,7 @@
.import findfreeiocb
.import incsp4
.import ldaxysp,addysp
- .import ___oserror
+ .import ___oserror, returnFFFF
.ifdef UCASE_FILENAME
.import ucase_fn
.endif
@@ -39,9 +39,7 @@ parmok: jsr findfreeiocb
lda #SER_ERR_BAUD_UNAVAIL
+ lda #SER_ERR_BAUD_UNAVAIL
+ ldx #0 ; return value is char
openerr:
rts
@@ -229,8 +229,9 @@ SER_OPEN:
jsr my_CIOV
bmi cioerr
- lda #SER_ERR_OK
+@done: lda #SER_ERR_OK
+ .assert SER_ERR_OK = 0, error
+ tax
rts
;----------------------------------------------------------------------------
@@ -365,16 +367,16 @@ SER_GET:
rts
@nix_da:lda #SER_ERR_NO_DATA
- ldx #0
+ ldx #0 ; return value is char
rts
ser_error:
lda #SER_ERR_OVERFLOW ; there is no large selection of serial error codes... :-/
- ldx #0
+ ldx #0 ; return value is char
rts
ni_err: lda #SER_ERR_NOT_OPEN
- ldx #0
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -427,8 +429,8 @@ SER_STATUS:
;
SER_IOCTL:
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -456,8 +458,8 @@ search: lda HATABS,y ; get device name
; R: device not found, return error
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/atmos/joy/atmos-ijk.s b/libsrc/atmos/joy/atmos-ijk.s
index 6e75a3e0b..c2bdd67ab 100644
--- a/libsrc/atmos/joy/atmos-ijk.s
+++ b/libsrc/atmos/joy/atmos-ijk.s
@@ -55,11 +55,12 @@ INSTALL:
lda VIA::PRA
and #%00100000
bne ijkPresent
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/atmos/joy/atmos-pase.s b/libsrc/atmos/joy/atmos-pase.s
index fd64901c9..d9982cafe 100644
--- a/libsrc/atmos/joy/atmos-pase.s
+++ b/libsrc/atmos/joy/atmos-pase.s
@@ -58,7 +58,8 @@ temp2: .byte $00
INSTALL:
lda #JOY_ERR_OK
- ldx #0
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/atmos/ser/atmos-acia.s b/libsrc/atmos/ser/atmos-acia.s
index f84b66a0a..1509803d2 100644
--- a/libsrc/atmos/ser/atmos-acia.s
+++ b/libsrc/atmos/ser/atmos-acia.s
@@ -141,8 +141,9 @@ SER_CLOSE:
sta ACIA::CMD,x
; Done, return an error code
-: lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #0 ; return value is char
rts
; Check for flow stopped & enough free: release flow control
@@ -267,27 +263,29 @@ SER_GET:
SER_PUT:
; Try to send
ldy SendFreeCnt
- iny ; Y = $FF?
+ cpy #$FF ; Nothing to flush
beq :+
pha
lda #$00 ; TryHard = false
jsr TryToSend
pla
- ; Put byte into send buffer & send
-: ldy SendFreeCnt
+ ; Reload SendFreeCnt after TryToSend
+ ldy SendFreeCnt
bne :+
- lda #SER_ERR_OVERFLOW
+ lda #SER_ERR_OVERFLOW
+ ldx #0 ; return value is char
rts
+ ; Put byte into send buffer & send
: ldy SendTail
sta SendBuf,y
inc SendTail
dec SendFreeCnt
lda #$FF ; TryHard = true
jsr TryToSend
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -325,19 +324,19 @@ SER_IRQ:
and #$08
beq Done ; Jump if no ACIA interrupt
lda ACIA::DATA,x ; Get byte from ACIA
- ldy RecvFreeCnt ; Check if we have free space left
+ ldx RecvFreeCnt ; Check if we have free space left
beq Flow ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
- ldy RecvFreeCnt ; Check for buffer space low
- cpy #33
+ cpx #33
bcc Flow ; Assert flow control if buffer space low
rts ; Interrupt handled (carry already set)
; Assert flow control if buffer space too low
-Flow: lda RtsOff
+Flow: ldx Index ; Reload port
+ lda RtsOff
sta ACIA::CMD,x
sta Stopped
sec ; Interrupt handled
@@ -348,12 +347,13 @@ Done: rts
TryToSend:
sta tmp1 ; Remember tryHard flag
-Again: lda SendFreeCnt
+NextByte:
+ lda SendFreeCnt
cmp #$FF
beq Quit ; Bail out
; Check for flow stopped
- lda Stopped
+Again: lda Stopped
bne Quit ; Bail out
; Check that ACIA is ready to send
@@ -370,4 +370,4 @@ Send: ldy SendHead
sta ACIA::DATA
inc SendHead
inc SendFreeCnt
- jmp Again
+ jmp NextByte
diff --git a/libsrc/atmos/ser_stat_stddrv.s b/libsrc/atmos/ser_stat_stddrv.s
new file mode 100644
index 000000000..2b4373695
--- /dev/null
+++ b/libsrc/atmos/ser_stat_stddrv.s
@@ -0,0 +1,14 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .import _atmos_acia_ser
+
+.rodata
+
+_ser_static_stddrv := _atmos_acia_ser
diff --git a/libsrc/atmos/ser_stddrv.s b/libsrc/atmos/ser_stddrv.s
new file mode 100644
index 000000000..71e33115a
--- /dev/null
+++ b/libsrc/atmos/ser_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const char ser_stddrv[];
+;
+
+ .export _ser_stddrv
+
+.rodata
+
+_ser_stddrv: .asciiz "atmos-acia.ser"
diff --git a/libsrc/atmos/tgi/atmos-228-200-3.s b/libsrc/atmos/tgi/atmos-228-200-3.s
index 98d2cef96..466f6922a 100644
--- a/libsrc/atmos/tgi/atmos-228-200-3.s
+++ b/libsrc/atmos/tgi/atmos-228-200-3.s
@@ -215,7 +215,8 @@ SETPALETTE:
jsr PAPER
ldy #1
jsr flipcolor
- dey ; TGI_ERR_OK
+ .assert TGI_ERR_OK = 0, error
+ dey
sty ERROR
sty PARAM1+1
jmp INK
diff --git a/libsrc/c128/emd/c128-efnram.s b/libsrc/c128/emd/c128-efnram.s
index 788c73e0f..909c90048 100644
--- a/libsrc/c128/emd/c128-efnram.s
+++ b/libsrc/c128/emd/c128-efnram.s
@@ -87,16 +87,17 @@ INSTALL:
cli
cmp tmp1
beq @ram_present
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
@ram_present:
ldx #$FF
stx curpage
stx curpage+1 ; Invalidate the current page
+ .assert EM_ERR_OK = 0, error
inx
- txa ; A = X = EM_ERR_OK
+ txa
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c128/emd/c128-georam.s b/libsrc/c128/emd/c128-georam.s
index 7511c6841..ecf12f6cd 100644
--- a/libsrc/c128/emd/c128-georam.s
+++ b/libsrc/c128/emd/c128-georam.s
@@ -120,16 +120,16 @@ INSTALL:
bne @setok
@notpresent:
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
@setok:
lda #0
sta pagecount
stx pagecount+1
- lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
check:
diff --git a/libsrc/c128/emd/c128-ifnram.s b/libsrc/c128/emd/c128-ifnram.s
index 01a4fdf8e..c51b775b2 100644
--- a/libsrc/c128/emd/c128-ifnram.s
+++ b/libsrc/c128/emd/c128-ifnram.s
@@ -87,16 +87,17 @@ INSTALL:
cli
cmp tmp1
beq @ram_present
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
@ram_present:
ldx #$FF
stx curpage
stx curpage+1 ; Invalidate the current page
+ .assert EM_ERR_OK = 0, error
inx
- txa ; A = X = EM_ERR_OK
+ txa
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c128/emd/c128-ram.s b/libsrc/c128/emd/c128-ram.s
index 3fc52c9cc..0ae504b84 100644
--- a/libsrc/c128/emd/c128-ram.s
+++ b/libsrc/c128/emd/c128-ram.s
@@ -68,8 +68,9 @@ INSTALL:
ldx #$FF
stx curpage
stx curpage+1 ; Invalidate the current page
+ .assert EM_ERR_OK = 0, error
inx
- txa ; A = X = EM_ERR_OK
+ txa
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c128/emd/c128-ram2.s b/libsrc/c128/emd/c128-ram2.s
index 7d2703fa5..92e72700a 100644
--- a/libsrc/c128/emd/c128-ram2.s
+++ b/libsrc/c128/emd/c128-ram2.s
@@ -107,8 +107,9 @@ INSTALL:
ldx #$FF
stx curpage
stx curpage+1 ; Invalidate the current page
+ .assert EM_ERR_OK = 0, error
inx
- txa ; A = X = EM_ERR_OK
+ txa
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c128/emd/c128-ramcart.s b/libsrc/c128/emd/c128-ramcart.s
index e72d053ac..c58c1cd1b 100644
--- a/libsrc/c128/emd/c128-ramcart.s
+++ b/libsrc/c128/emd/c128-ramcart.s
@@ -97,13 +97,14 @@ INSTALL:
lda #0
sta pagecount
stx pagecount+1
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
@notpresent:
@readonly:
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c128/emd/c128-reu.s b/libsrc/c128/emd/c128-reu.s
index 84e7cb695..8228a0517 100644
--- a/libsrc/c128/emd/c128-reu.s
+++ b/libsrc/c128/emd/c128-reu.s
@@ -126,8 +126,9 @@ size_found:
pagecount_ok:
stx pagecount
sty pagecount+1
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
; common REU setup for size check
diff --git a/libsrc/c128/emd/c128-vdc.s b/libsrc/c128/emd/c128-vdc.s
index accb82154..8d0b77fd2 100644
--- a/libsrc/c128/emd/c128-vdc.s
+++ b/libsrc/c128/emd/c128-vdc.s
@@ -121,8 +121,9 @@ INSTALL:
lda vdc_cset_save
jsr vdcputreg
@keep64kBit:
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
test64k:
diff --git a/libsrc/c128/joy/c128-ptvjoy.s b/libsrc/c128/joy/c128-ptvjoy.s
index 180f7667d..0a1c53587 100644
--- a/libsrc/c128/joy/c128-ptvjoy.s
+++ b/libsrc/c128/joy/c128-ptvjoy.s
@@ -53,8 +53,9 @@ JOY_COUNT = 4 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c128/joy/c128-stdjoy.s b/libsrc/c128/joy/c128-stdjoy.s
index bf2e2fea7..ee04374ee 100644
--- a/libsrc/c128/joy/c128-stdjoy.s
+++ b/libsrc/c128/joy/c128-stdjoy.s
@@ -57,8 +57,9 @@ JOY_COUNT = 2 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c128/mou/c128-1351.s b/libsrc/c128/mou/c128-1351.s
index 79ccbe0de..76e28d9f7 100644
--- a/libsrc/c128/mou/c128-1351.s
+++ b/libsrc/c128/mou/c128-1351.s
@@ -194,9 +194,10 @@ INSTALL:
sta (ptr3),y
cli
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
diff --git a/libsrc/c128/mou/c128-inkwell.s b/libsrc/c128/mou/c128-inkwell.s
index b8e71bbb1..2aac7d32d 100644
--- a/libsrc/c128/mou/c128-inkwell.s
+++ b/libsrc/c128/mou/c128-inkwell.s
@@ -228,9 +228,10 @@ INSTALL:
jsr MoveX
cli
-; Done, return zero.
+; Done
lda #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
tax
rts
diff --git a/libsrc/c128/mou/c128-joy.s b/libsrc/c128/mou/c128-joy.s
index 065674dc0..d809db526 100644
--- a/libsrc/c128/mou/c128-joy.s
+++ b/libsrc/c128/mou/c128-joy.s
@@ -195,9 +195,10 @@ INSTALL:
sta (ptr3),y
cli
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
diff --git a/libsrc/c128/mou/c128-pot.s b/libsrc/c128/mou/c128-pot.s
index e582d64fb..1cbe4aa18 100644
--- a/libsrc/c128/mou/c128-pot.s
+++ b/libsrc/c128/mou/c128-pot.s
@@ -195,9 +195,10 @@ INSTALL:
sta (ptr3),y
cli
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
diff --git a/libsrc/c128/ser/c128-swlink.s b/libsrc/c128/ser/c128-swlink.s
index 3337e2668..b8f08159b 100644
--- a/libsrc/c128/ser/c128-swlink.s
+++ b/libsrc/c128/ser/c128-swlink.s
@@ -187,8 +187,9 @@ SetNMI: sta NMIVec
; Done, return an error code
- lda #SER_ERR_INIT_FAILED
+ lda #SER_ERR_INIT_FAILED
+ ldx #0 ; return value is char
rts
; Baud rate not available
InvBaud:
- lda #SER_ERR_BAUD_UNAVAIL
+ lda #SER_ERR_BAUD_UNAVAIL
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -300,8 +302,9 @@ SER_CLOSE:
; Return OK
- lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #0 ; return value is char
rts
; Check for flow stopped & enough free: release flow control
@@ -359,27 +357,30 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
- inx ; X = $ff?
+ cpx #$FF ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
-; Put byte into send buffer & send
+; Reload SendFreeCnt after TryToSend
-@L2: ldx SendFreeCnt
- bne @L3
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -461,25 +463,25 @@ NmiHandler:
sta tmp1 ; Remember tryHard flag
@L0: lda SendFreeCnt
cmp #$ff
- beq @L3 ; Bail out
+ beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
- bne @L3 ; Bail out
+ bne @L2 ; Bail out
; Check that swiftlink is ready to send
-@L2: lda ACIA_STATUS
+ lda ACIA_STATUS
and #$10
- bne @L4
+ bne @L3
bit tmp1 ;keep trying if must try hard
- bmi @L0
-@L3: rts
+ bmi @L1
+@L2: rts
; Send byte and try again
-@L4: ldx SendHead
+@L3: ldx SendHead
lda SendBuf,x
sta ACIA_DATA
inc SendHead
diff --git a/libsrc/c128/ser_stat_stddrv.s b/libsrc/c128/ser_stat_stddrv.s
new file mode 100644
index 000000000..8b0732703
--- /dev/null
+++ b/libsrc/c128/ser_stat_stddrv.s
@@ -0,0 +1,14 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .import _c128_swlink_ser
+
+.rodata
+
+_ser_static_stddrv := _c128_swlink_ser
diff --git a/libsrc/c128/ser_stddrv.s b/libsrc/c128/ser_stddrv.s
new file mode 100644
index 000000000..63f73cadd
--- /dev/null
+++ b/libsrc/c128/ser_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const char ser_stddrv[];
+;
+
+ .export _ser_stddrv
+
+.rodata
+
+_ser_stddrv: .asciiz "c128_swlink.ser"
diff --git a/libsrc/c16/emd/c16-ram.s b/libsrc/c16/emd/c16-ram.s
index a8083aca4..937019974 100644
--- a/libsrc/c16/emd/c16-ram.s
+++ b/libsrc/c16/emd/c16-ram.s
@@ -77,12 +77,13 @@ INSTALL:
ldx #$FF
stx curpage ; Invalidate the current page
- inx ; X = 0
- txa ; A = X = EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ inx
+ txa
rts
-nomem: ldx #>EM_ERR_NO_DEVICE
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
@not_present:
cli
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
; rts ; Run into UNINSTALL instead
diff --git a/libsrc/c64/emd/c64-c256k.s b/libsrc/c64/emd/c64-c256k.s
index 79706e8fb..5a4bc54c3 100644
--- a/libsrc/c64/emd/c64-c256k.s
+++ b/libsrc/c64/emd/c64-c256k.s
@@ -158,13 +158,14 @@ INSTALL:
jsr restore_data
cpy #$01
beq @present
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
@present:
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/emd/c64-dqbb.s b/libsrc/c64/emd/c64-dqbb.s
index 986c5939d..6a63b3baa 100644
--- a/libsrc/c64/emd/c64-dqbb.s
+++ b/libsrc/c64/emd/c64-dqbb.s
@@ -147,13 +147,14 @@ INSTALL:
jsr restore_data
cpy #$01
beq @present
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
@present:
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/emd/c64-georam.s b/libsrc/c64/emd/c64-georam.s
index 97f1a7cc4..0116fe8ea 100644
--- a/libsrc/c64/emd/c64-georam.s
+++ b/libsrc/c64/emd/c64-georam.s
@@ -121,16 +121,17 @@ INSTALL:
bne @setok
@notpresent:
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ .assert EM_ERR_OK = 0, error
+ tax
rts
@setok:
lda #0
sta pagecount
stx pagecount+1
- lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
check:
diff --git a/libsrc/c64/emd/c64-isepic.s b/libsrc/c64/emd/c64-isepic.s
index 3764443e2..2b7949757 100644
--- a/libsrc/c64/emd/c64-isepic.s
+++ b/libsrc/c64/emd/c64-isepic.s
@@ -76,13 +76,14 @@ INSTALL:
beq @setok
@notpresent:
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
@setok:
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/emd/c64-kerberos.s b/libsrc/c64/emd/c64-kerberos.s
index 30183362f..20be4e409 100644
--- a/libsrc/c64/emd/c64-kerberos.s
+++ b/libsrc/c64/emd/c64-kerberos.s
@@ -82,13 +82,14 @@ INSTALL:
cmp #$AA
bne @notpresent
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
@notpresent:
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
; use rts from UNINSTALL below
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/emd/c64-ram.s b/libsrc/c64/emd/c64-ram.s
index 5355b552d..cdd7b8965 100644
--- a/libsrc/c64/emd/c64-ram.s
+++ b/libsrc/c64/emd/c64-ram.s
@@ -65,8 +65,9 @@ window: .res 256 ; Memory "window"
INSTALL:
ldx #$FF
stx curpage ; Invalidate the current page
- inx ; X = 0
- txa ; A = X = EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ inx
+ txa
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/emd/c64-ramcart.s b/libsrc/c64/emd/c64-ramcart.s
index 8998bb6d6..a99f25b4f 100644
--- a/libsrc/c64/emd/c64-ramcart.s
+++ b/libsrc/c64/emd/c64-ramcart.s
@@ -98,13 +98,13 @@ INSTALL:
lda #0
sta pagecount
stx pagecount+1
- lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
@notpresent:
@readonly:
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/emd/c64-reu.s b/libsrc/c64/emd/c64-reu.s
index 07ac1fbed..832e66f51 100644
--- a/libsrc/c64/emd/c64-reu.s
+++ b/libsrc/c64/emd/c64-reu.s
@@ -127,8 +127,9 @@ size_found:
pagecount_ok:
stx pagecount
sty pagecount+1
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
; common REU setup for size check
@@ -152,6 +153,7 @@ reu_size_check_common:
nodevice:
lda #EM_ERR_NO_DEVICE
+ .assert EM_ERR_OK = 0, error
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/emd/c64-vdc.s b/libsrc/c64/emd/c64-vdc.s
index 2448f09d4..60fbccbbf 100644
--- a/libsrc/c64/emd/c64-vdc.s
+++ b/libsrc/c64/emd/c64-vdc.s
@@ -87,8 +87,8 @@ INSTALL:
bne @L0
iny
bne @L0
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+; ldx #0 ; return value is char
rts
@present:
@@ -131,8 +131,9 @@ INSTALL:
sta pagecount
stx pagecount+1
@endok:
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
test64k:
diff --git a/libsrc/c64/emd/dtv-himem.s b/libsrc/c64/emd/dtv-himem.s
index 6dde874f7..4d19b19d5 100644
--- a/libsrc/c64/emd/dtv-himem.s
+++ b/libsrc/c64/emd/dtv-himem.s
@@ -93,15 +93,16 @@ INSTALL:
; DTV not found
- lda #EM_ERR_NO_DEVICE
+ lda #EM_ERR_NO_DEVICE
+ ldx #0 ; return value is char
rts
@present:
ldx #$FF
stx curpage+1 ; Invalidate curpage
- inx ; X = 0
- txa ; A/X = EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ inx
+ txa
; rts ; Run into UNINSTALL instead
diff --git a/libsrc/c64/joy/c64-hitjoy.s b/libsrc/c64/joy/c64-hitjoy.s
index 3b4a0b909..a9d454fd0 100644
--- a/libsrc/c64/joy/c64-hitjoy.s
+++ b/libsrc/c64/joy/c64-hitjoy.s
@@ -59,8 +59,9 @@ temp4: .byte 0
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
diff --git a/libsrc/c64/joy/c64-numpad.s b/libsrc/c64/joy/c64-numpad.s
index 0ccdc4fcd..f6839d6cf 100644
--- a/libsrc/c64/joy/c64-numpad.s
+++ b/libsrc/c64/joy/c64-numpad.s
@@ -100,12 +100,14 @@ masktable:
;
INSTALL:
- lda #JOY_ERR_OK ; Assume we have a joystick
- ldx VIC_CLK_128 ; Test for a C128
- cpx #$FF
+ lda #JOY_ERR_OK ; Assume we have a "joystick"
+ .assert JOY_ERR_OK = 0, error
+ tax ; Set high byte
+ ldy VIC_CLK_128 ; Test for a C128
+ cpy #$FF
bne @C128 ; Jump if we have one
lda #JOY_ERR_NO_DEVICE ; No C128 -> no numpad
-@C128: ldx #0 ; Set high byte
+@C128:
; rts ; Run into UNINSTALL instead
diff --git a/libsrc/c64/joy/c64-ptvjoy.s b/libsrc/c64/joy/c64-ptvjoy.s
index a772fb5f6..30466b2c2 100644
--- a/libsrc/c64/joy/c64-ptvjoy.s
+++ b/libsrc/c64/joy/c64-ptvjoy.s
@@ -52,8 +52,9 @@ JOY_COUNT = 4 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/c64/joy/c64-stdjoy.s b/libsrc/c64/joy/c64-stdjoy.s
index d11093fba..511032507 100644
--- a/libsrc/c64/joy/c64-stdjoy.s
+++ b/libsrc/c64/joy/c64-stdjoy.s
@@ -56,8 +56,9 @@ JOY_COUNT = 2 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
diff --git a/libsrc/c64/mou/c64-1351.s b/libsrc/c64/mou/c64-1351.s
index a7d042c7b..ce0f18803 100644
--- a/libsrc/c64/mou/c64-1351.s
+++ b/libsrc/c64/mou/c64-1351.s
@@ -152,9 +152,10 @@ INSTALL:
jsr CMOVEY
cli
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
@@ -307,8 +308,8 @@ INFO: jsr POS
; Must return an error code in a/x.
;
-IOCTL: lda #MOUSE_ERR_INV_IOCTL
+IOCTL: lda #MOUSE_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
diff --git a/libsrc/c64/mou/c64-inkwell.s b/libsrc/c64/mou/c64-inkwell.s
index 9c876a7c8..d2f14a6f0 100644
--- a/libsrc/c64/mou/c64-inkwell.s
+++ b/libsrc/c64/mou/c64-inkwell.s
@@ -168,6 +168,7 @@ INSTALL:
; Done, return zero.
lda #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
tax
rts
@@ -319,8 +320,8 @@ INFO: jsr POS
; Must return an error code in .XA.
;
-IOCTL: lda #MOUSE_ERR_INV_IOCTL
+IOCTL: lda #MOUSE_ERR_INV_IOCTL ; We don't support ioctls, for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
diff --git a/libsrc/c64/mou/c64-joy.s b/libsrc/c64/mou/c64-joy.s
index f2a501000..5ee1b4f84 100644
--- a/libsrc/c64/mou/c64-joy.s
+++ b/libsrc/c64/mou/c64-joy.s
@@ -156,9 +156,10 @@ INSTALL:
jsr CMOVEY
cli
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
@@ -312,8 +313,8 @@ INFO: jsr POS
; Must return an error code in a/x.
;
-IOCTL: lda #MOUSE_ERR_INV_IOCTL
+IOCTL: lda #MOUSE_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
diff --git a/libsrc/c64/mou/c64-pot.s b/libsrc/c64/mou/c64-pot.s
index 102ca351c..9bdf24f62 100644
--- a/libsrc/c64/mou/c64-pot.s
+++ b/libsrc/c64/mou/c64-pot.s
@@ -139,9 +139,10 @@ INSTALL:
jsr CMOVEY
cli
-; Done, return zero (= MOUSE_ERR_OK)
+; Done
- ldx #$00
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
@@ -297,8 +298,8 @@ INFO: jsr POS
; Must return an error code in a/x.
;
-IOCTL: lda #MOUSE_ERR_INV_IOCTL
+IOCTL: lda #MOUSE_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
diff --git a/libsrc/c64/ser/c64-swlink.s b/libsrc/c64/ser/c64-swlink.s
index 597cf1dd6..067a7ca92 100644
--- a/libsrc/c64/ser/c64-swlink.s
+++ b/libsrc/c64/ser/c64-swlink.s
@@ -161,8 +161,9 @@ SetNMI: sta NMIVec
; Done, return an error code
- lda #SER_ERR_INIT_FAILED
+ lda #SER_ERR_INIT_FAILED
+ ldx #0 ; return value is char
rts
; Baud rate not available
InvBaud:
- lda #SER_ERR_BAUD_UNAVAIL
+ lda #SER_ERR_BAUD_UNAVAIL
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -274,8 +276,9 @@ SER_CLOSE:
; Return OK
- lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #0 ; return value is char
rts
; Check for flow stopped & enough free: release flow control
@@ -333,27 +331,30 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
- inx ; X = $ff?
+ cpx #$FF ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
-; Put byte into send buffer & send
+; Reload SendFreeCnt after TryToSend
-@L2: ldx SendFreeCnt
- bne @L3
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -438,25 +440,25 @@ NmiHandler:
sta tmp1 ; Remember tryHard flag
@L0: lda SendFreeCnt
cmp #$ff
- beq @L3 ; Bail out
+ beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
- bne @L3 ; Bail out
+ bne @L2 ; Bail out
; Check that swiftlink is ready to send
-@L2: lda ACIA_STATUS
+ lda ACIA_STATUS
and #$10
- bne @L4
+ bne @L3
bit tmp1 ;keep trying if must try hard
- bmi @L0
-@L3: rts
+ bmi @L1
+@L2: rts
; Send byte and try again
-@L4: ldx SendHead
+@L3: ldx SendHead
lda SendBuf,x
sta ACIA_DATA
inc SendHead
diff --git a/libsrc/c64/ser_stat_stddrv.s b/libsrc/c64/ser_stat_stddrv.s
new file mode 100644
index 000000000..327abbe5f
--- /dev/null
+++ b/libsrc/c64/ser_stat_stddrv.s
@@ -0,0 +1,14 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .import _c64_swlink_ser
+
+.rodata
+
+_ser_static_stddrv := _c64_swlink_ser
diff --git a/libsrc/c64/ser_stddrv.s b/libsrc/c64/ser_stddrv.s
new file mode 100644
index 000000000..5b00b7642
--- /dev/null
+++ b/libsrc/c64/ser_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const char ser_stddrv[];
+;
+
+ .export _ser_stddrv
+
+.rodata
+
+_ser_stddrv: .asciiz "c64_swlink.ser"
diff --git a/libsrc/cbm/cbm_read.s b/libsrc/cbm/cbm_read.s
index 8a9939eca..98e3c25c9 100644
--- a/libsrc/cbm/cbm_read.s
+++ b/libsrc/cbm/cbm_read.s
@@ -40,7 +40,7 @@
.export _cbm_read
.importzp ptr1, ptr2, ptr3, tmp1
- .import popax, popa
+ .import popax, popa, returnFFFF
.import ___oserror
@@ -107,7 +107,4 @@ _cbm_read:
; CHKIN failed
@E1: sta ___oserror
- lda #$FF
- tax
- rts ; return -1
-
+ jmp returnFFFF
diff --git a/libsrc/cbm/cbm_write.s b/libsrc/cbm/cbm_write.s
index 18c6f4684..a4ecfbe3f 100644
--- a/libsrc/cbm/cbm_write.s
+++ b/libsrc/cbm/cbm_write.s
@@ -32,7 +32,7 @@
.export _cbm_write
.importzp ptr1, ptr2, ptr3
- .import popax, popa
+ .import popax, popa, returnFFFF
.import ___oserror
@@ -88,7 +88,4 @@ _cbm_write:
; Error entry, error code is in A
@E2: sta ___oserror
- lda #$FF
- tax
- rts ; return -1
-
+ jmp returnFFFF
diff --git a/libsrc/cbm/initcwd.s b/libsrc/cbm/initcwd.s
index d5e5b9296..7064c16e1 100644
--- a/libsrc/cbm/initcwd.s
+++ b/libsrc/cbm/initcwd.s
@@ -9,8 +9,6 @@
.import pusha0, tosudiva0
.importzp sreg, ptr1, ptr2
- .macpack generic
-
initcwd:
lda #<__cwd
ldx #>__cwd
@@ -27,15 +25,20 @@ devicestr:
lda #10
jsr tosudiva0
ldy #0
- lda sreg
- beq @L0 ; >=10
- add #'0'
+ tax ; result of the division (lsb)
+ beq @L0 ; < 10
+
+ clc
+ adc #'0'
sta (ptr2),y
iny
-@L0: lda ptr1 ; rem
- add #'0'
+@L0:
+ lda sreg ; reminder of the division
+ clc
+ adc #'0'
sta (ptr2),y
iny
- lda #0
+
+ lda #0 ; terminating 0
sta (ptr2),y
rts
diff --git a/libsrc/cbm510/emd/cbm510-ram.s b/libsrc/cbm510/emd/cbm510-ram.s
index f724c7360..6cc319b7f 100644
--- a/libsrc/cbm510/emd/cbm510-ram.s
+++ b/libsrc/cbm510/emd/cbm510-ram.s
@@ -81,8 +81,9 @@ INSTALL:
sbc #$00
sta pagecount
-@L1: lda #EM_ERR_OK
+@L1: lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/cbm510/joy/cbm510-std.s b/libsrc/cbm510/joy/cbm510-std.s
index 4e47fc1a0..f7cbb2cdc 100644
--- a/libsrc/cbm510/joy/cbm510-std.s
+++ b/libsrc/cbm510/joy/cbm510-std.s
@@ -57,8 +57,9 @@ JOY_COUNT = 2 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/cbm510/mou/cbm510-inkwl.s b/libsrc/cbm510/mou/cbm510-inkwl.s
index 91bc52fcd..ea6d95934 100644
--- a/libsrc/cbm510/mou/cbm510-inkwl.s
+++ b/libsrc/cbm510/mou/cbm510-inkwl.s
@@ -175,6 +175,7 @@ INSTALL:
; Done, return zero.
lda #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
tax
rts
@@ -331,8 +332,8 @@ INFO: jsr POS
; Must return an error code in .XA.
;
-IOCTL: lda #MOUSE_ERR_INV_IOCTL
+IOCTL: lda #MOUSE_ERR_INV_IOCTL ; We don't support ioctls, for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
diff --git a/libsrc/cbm510/mou/cbm510-joy.s b/libsrc/cbm510/mou/cbm510-joy.s
index 8aa3a778e..4daa49272 100644
--- a/libsrc/cbm510/mou/cbm510-joy.s
+++ b/libsrc/cbm510/mou/cbm510-joy.s
@@ -140,7 +140,8 @@ INSTALL:
; Done, return zero.
- ldx #>MOUSE_ERR_OK
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
@@ -315,8 +316,8 @@ POS: ldy #MOUSE_POS::XCOORD ; Structure offset
; Must return an error code in .XA.
;
-IOCTL: lda #MOUSE_ERR_INV_IOCTL
+IOCTL: lda #MOUSE_ERR_INV_IOCTL ; We don't support ioctls, for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
diff --git a/libsrc/cbm510/ser/cbm510-std.s b/libsrc/cbm510/ser/cbm510-std.s
index 64f613cd5..800007492 100644
--- a/libsrc/cbm510/ser/cbm510-std.s
+++ b/libsrc/cbm510/ser/cbm510-std.s
@@ -148,8 +148,9 @@ SER_CLOSE:
; Done, return an error code
- lda #SER_ERR_INIT_FAILED
+ lda #SER_ERR_INIT_FAILED
+ ldx #0 ; return value is char
rts
; Baud rate not available
InvBaud:
- lda #SER_ERR_BAUD_UNAVAIL
+ lda #SER_ERR_BAUD_UNAVAIL
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -242,19 +244,14 @@ InvBaud:
;
SER_GET:
- ldx SendFreeCnt ; Send data if necessary
- inx ; X == $FF?
- beq @L1
- lda #$00
- jsr TryToSend
; Check for buffer empty
-@L1: lda RecvFreeCnt
+ lda RecvFreeCnt
cmp #$ff
bne @L2
- lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #0 ; return value is char
rts
; Check for flow stopped & enough free: release flow control
@@ -290,27 +287,30 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
- inx ; X = $ff?
+ cpx #$FF ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
-; Put byte into send buffer & send
+; Reload SendFreeCnt after TryToSend
-@L2: ldx SendFreeCnt
- bne @L3
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -391,31 +392,31 @@ SER_IRQ:
sta IndReg ; Switch to the system bank
@L0: lda SendFreeCnt
cmp #$ff
- beq @L3 ; Bail out
+ beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
- bne @L3 ; Bail out
+ bne @L2 ; Bail out
; Check that swiftlink is ready to send
-@L2: ldy #ACIA::STATUS
+ ldy #ACIA::STATUS
lda (acia),y
and #$10
- bne @L4
+ bne @L3
bit tmp1 ; Keep trying if must try hard
- bmi @L0
+ bmi @L1
; Switch back the bank and return
-@L3: lda ExecReg
+@L2: lda ExecReg
sta IndReg
rts
; Send byte and try again
-@L4: ldx SendHead
+@L3: ldx SendHead
lda SendBuf,x
ldy #ACIA::DATA
sta (acia),y
diff --git a/libsrc/cbm510/ser_stat_stddrv.s b/libsrc/cbm510/ser_stat_stddrv.s
new file mode 100644
index 000000000..a872f19b9
--- /dev/null
+++ b/libsrc/cbm510/ser_stat_stddrv.s
@@ -0,0 +1,14 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .import _cbm510_std_ser
+
+.rodata
+
+_ser_static_stddrv := _cbm510_std_ser
diff --git a/libsrc/cbm510/ser_stddrv.s b/libsrc/cbm510/ser_stddrv.s
new file mode 100644
index 000000000..ed785f914
--- /dev/null
+++ b/libsrc/cbm510/ser_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const char ser_stddrv[];
+;
+
+ .export _ser_stddrv
+
+.rodata
+
+_ser_stddrv: .asciiz "cbm510-std.ser"
diff --git a/libsrc/cbm610/emd/cbm610-ram.s b/libsrc/cbm610/emd/cbm610-ram.s
index 5c67df7a4..5aa43b0c2 100644
--- a/libsrc/cbm610/emd/cbm610-ram.s
+++ b/libsrc/cbm610/emd/cbm610-ram.s
@@ -81,8 +81,9 @@ INSTALL:
sbc #$00
sta pagecount
-@L1: lda #EM_ERR_OK
+@L1: lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/cbm610/ser/cbm610-std.s b/libsrc/cbm610/ser/cbm610-std.s
index 7cdb285bd..45b18eadf 100644
--- a/libsrc/cbm610/ser/cbm610-std.s
+++ b/libsrc/cbm610/ser/cbm610-std.s
@@ -149,8 +149,9 @@ SER_CLOSE:
; Done, return an error code
- lda #SER_ERR_INIT_FAILED
+ lda #SER_ERR_INIT_FAILED
+ ldx #0 ; return value is char
rts
; Baud rate not available
InvBaud:
- lda #SER_ERR_BAUD_UNAVAIL
+ lda #SER_ERR_BAUD_UNAVAIL
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -243,19 +245,14 @@ InvBaud:
;
SER_GET:
- ldx SendFreeCnt ; Send data if necessary
- inx ; X == $FF?
- beq @L1
- lda #$00
- jsr TryToSend
; Check for buffer empty
-@L1: lda RecvFreeCnt
+ lda RecvFreeCnt
cmp #$ff
bne @L2
- lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #0 ; return value is char
rts
; Check for flow stopped & enough free: release flow control
@@ -291,27 +288,30 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
- inx ; X = $ff?
+ cpx #$ff ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
-; Put byte into send buffer & send
+; Reload SendFreeCnt after TryToSend
-@L2: ldx SendFreeCnt
- bne @L3
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -392,31 +392,31 @@ SER_IRQ:
sta IndReg ; Switch to the system bank
@L0: lda SendFreeCnt
cmp #$ff
- beq @L3 ; Bail out
+ beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
- bne @L3 ; Bail out
+ bne @L2 ; Bail out
; Check that swiftlink is ready to send
-@L2: ldy #ACIA::STATUS
+ ldy #ACIA::STATUS
lda (acia),y
and #$10
- bne @L4
+ bne @L3
bit tmp1 ; Keep trying if must try hard
- bmi @L0
+ bmi @L1
; Switch back the bank and return
-@L3: lda ExecReg
+@L2: lda ExecReg
sta IndReg
rts
; Send byte and try again
-@L4: ldx SendHead
+@L3: ldx SendHead
lda SendBuf,x
ldy #ACIA::DATA
sta (acia),y
diff --git a/libsrc/cbm610/ser_stat_stddrv.s b/libsrc/cbm610/ser_stat_stddrv.s
new file mode 100644
index 000000000..643a74c7d
--- /dev/null
+++ b/libsrc/cbm610/ser_stat_stddrv.s
@@ -0,0 +1,14 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .import _cbm610_std_ser
+
+.rodata
+
+_ser_static_stddrv := _cbm610_std_ser
diff --git a/libsrc/cbm610/ser_stddrv.s b/libsrc/cbm610/ser_stddrv.s
new file mode 100644
index 000000000..83702c1ef
--- /dev/null
+++ b/libsrc/cbm610/ser_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const char ser_stddrv[];
+;
+
+ .export _ser_stddrv
+
+.rodata
+
+_ser_stddrv: .asciiz "cbm610-std.ser"
diff --git a/libsrc/common/_printf.s b/libsrc/common/_printf.s
index 840d42127..d7eeb072d 100644
--- a/libsrc/common/_printf.s
+++ b/libsrc/common/_printf.s
@@ -13,6 +13,7 @@
.import _strlower, _strlen
.macpack generic
+ .macpack cpu
; ----------------------------------------------------------------------------
; We will store variables into the register bank in the zeropage. Define
@@ -37,7 +38,11 @@ FCount = ptr2
GetFormatChar:
ldy #0
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ lda (Format)
+ .else
lda (Format),y
+ .endif
IncFormatPtr:
inc Format
bne @L1
@@ -110,7 +115,11 @@ GetIntArg:
lda (ArgList),y
tax
dey
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ lda (ArgList)
+ .else
lda (ArgList),y
+ .endif
rts
; ----------------------------------------------------------------------------
@@ -135,9 +144,9 @@ ReadInt:
pha ; Save digit value
lda ptr1
ldx ptr1+1
- asl ptr1
+ asl a
rol ptr1+1 ; * 2
- asl ptr1
+ asl a
rol ptr1+1 ; * 4, assume carry clear
adc ptr1
sta ptr1
@@ -265,10 +274,16 @@ Save: lda regbank,y
; Initialize the output counter in the output descriptor to zero
lda #0
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ sta (OutData)
+ ldy #$01
+ sta (OutData),y
+ .else
tay
sta (OutData),y
iny
sta (OutData),y
+ .endif
; Get the output function from the output descriptor and remember it
@@ -338,7 +353,11 @@ MainLoop:
sta (sp),y
dey
lda FCount
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ sta (sp)
+ .else
sta (sp),y
+ .endif
jsr CallOutFunc ; Call the output function
; We're back from out(), or we didn't call it. Check for end of string.
@@ -502,10 +521,10 @@ DoFormat:
; It is a character
jsr GetIntArg ; Get the argument (promoted to int)
- sta Buf ; Place it as zero terminated string...
- lda #0
- sta Buf+1 ; ...into the buffer
- jmp HaveArg ; Done
+ sta Buf ; Place it into the buffer
+ ldx #0
+ lda #1 ; Buffer length is 1
+ jmp HaveArg1
; Is it an integer?
@@ -551,10 +570,16 @@ CheckCount:
jsr GetIntArg
sta ptr1
stx ptr1+1 ; Get user supplied pointer
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ lda (OutData) ; Low byte of OutData->ccount
+ sta (ptr1)
+ ldy #1
+ .else
ldy #0
lda (OutData),y ; Low byte of OutData->ccount
sta (ptr1),y
iny
+ .endif
lda (OutData),y ; High byte of OutData->ccount
sta (ptr1),y
jmp MainLoop ; Done
@@ -671,6 +696,7 @@ HaveArg:
lda Str
ldx Str+1
jsr _strlen ; Get length of argument
+HaveArg1: ; Jumped into here from %c handling
sta ArgLen
stx ArgLen+1
diff --git a/libsrc/common/_time_t_to_tm.s b/libsrc/common/_time_t_to_tm.s
new file mode 100644
index 000000000..9bcf84184
--- /dev/null
+++ b/libsrc/common/_time_t_to_tm.s
@@ -0,0 +1,129 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; struct tm* __fastcall__ _time_t_to_tm (const time_t t)
+;
+; Helper to gmtime and localtime. Breaks down a number of
+; seconds since Jan 1, 1970 into days, hours and seconds,
+; so that each of them fits in 16 bits; passes the
+; result to _mktime which fixes all values in the struct,
+; and returns a pointer to the struct to callers.
+;
+
+ .export __time_t_to_tm
+ .import udiv32, _mktime
+ .importzp sreg, tmp3, ptr1, ptr2, ptr3, ptr4
+
+ .include "time.inc"
+
+ .macpack cpu
+
+__time_t_to_tm:
+ ; Divide number of seconds since epoch, in ptr1:sreg,
+ ; by 86400 to get the number of days since epoch, and
+ ; the number of seconds today in the remainder.
+
+ ; Load t as dividend (sreg is already set by the caller)
+ sta ptr1
+ stx ptr1+1
+
+ ; Load 86400 as divisor
+ lda #$80
+ sta ptr3
+ lda #$51
+ sta ptr3+1
+ lda #$01
+ sta ptr4
+ lda #$00
+ sta ptr4+1
+
+ ; Clear TM buf while we have zero in A
+ ldx #.sizeof(tm)-1
+: sta TM,x
+ dex
+ bpl :-
+
+ ; Divide t/86400
+ jsr udiv32
+
+ ; Store the quotient (the number of full days), and increment
+ ; by one as epoch starts at day 1.
+ clc
+ lda ptr1
+ adc #1
+ sta TM + tm::tm_mday
+ lda ptr1+1
+ adc #0
+ sta TM + tm::tm_mday+1
+
+ ; Now divide the number of remaining seconds by 3600,
+ ; to get the number of hours, and the seconds in the
+ ; current hour, in neat 16-bit integers.
+
+ ; Load the previous division's remainder (in ptr2:tmp3:tmp4)
+ ; as dividend
+ lda ptr2
+ sta ptr1
+ lda ptr2+1
+ sta ptr1+1
+ lda tmp3
+ sta sreg
+ ; We ignore the high byte stored in tmp4 because it will be
+ ; zero. We'll zero sreg+1 right below, when we'll have
+ ; a convenient zero already in A.
+
+ ; Load divisor
+ lda #<3600
+ sta ptr3
+ lda #>3600
+ sta ptr3+1
+
+ ; Zero the two high bytes of the divisor and the high byte
+ ; of the dividend.
+ .if .cpu .bitand CPU_ISET_65SC02
+ stz ptr4
+ stz ptr4+1
+ stz sreg+1
+ .else
+ lda #$00
+ sta ptr4
+ sta ptr4+1
+ sta sreg+1
+ .endif
+
+ ; Do the division
+ jsr udiv32
+
+ ; Store year
+ lda #70
+ sta TM + tm::tm_year
+
+ ; Store hours (the quotient of the last division)
+ lda ptr1
+ sta TM + tm::tm_hour
+ lda ptr1+1
+ sta TM + tm::tm_hour+1
+
+ ; Store seconds (the remainder of the last division)
+ lda ptr2
+ sta TM + tm::tm_sec
+ lda ptr2+1
+ sta TM + tm::tm_sec+1
+
+ ; The rest of the struct tm fields are zero. mktime
+ ; will take care of shifting extra seconds to minutes,
+ ; and extra days to months and years.
+
+ ; Call mktime
+ lda #TM
+ jsr _mktime
+
+ ; And return our pointer
+ lda #TM
+ rts
+
+ .bss
+
+TM: .tag tm
diff --git a/libsrc/common/asctime.s b/libsrc/common/asctime.s
new file mode 100644
index 000000000..efcf34b41
--- /dev/null
+++ b/libsrc/common/asctime.s
@@ -0,0 +1,81 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; char* __fastcall__ asctime (const struct tm* timep)
+;
+
+ .export _asctime
+ .import _strftime, pushax
+ .importzp ptr1
+ .include "time.inc"
+
+ .macpack cpu
+
+; ------------------------------------------------------------------------
+; Special values
+
+; We need to be able to store up to 38 bytes:
+; 1234567890123456789012345678901234567
+; "Wednesday September ..1 00:00:00 1970"
+MAX_BUF_LEN = 38
+
+; ------------------------------------------------------------------------
+; Code
+
+_asctime:
+ ; Backup timep
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ pha
+ phx
+ .else
+ sta ptr1
+ stx ptr1+1
+ .endif
+
+ ; Push buf
+ lda #buf
+ jsr pushax
+
+ ; Push sizeof(buf)
+ lda #MAX_BUF_LEN
+ jsr pushax
+
+ ; Push format string
+ lda #fmt
+ jsr pushax
+
+ ; Restore timep
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ plx
+ pla
+ .else
+ lda ptr1
+ ldx ptr1+1
+ .endif
+
+ ; Call formatter
+ jsr _strftime
+
+ ; Check return status
+ bne :+
+ cpx #$00
+ bne :+
+ rts
+
+: lda #buf
+ rts
+
+ .data
+
+fmt: .byte '%'
+ .byte 'c'
+ .byte $0A
+ .byte $00
+
+ .bss
+
+buf: .res MAX_BUF_LEN
diff --git a/libsrc/common/checkferror.s b/libsrc/common/checkferror.s
new file mode 100644
index 000000000..736fa3ccd
--- /dev/null
+++ b/libsrc/common/checkferror.s
@@ -0,0 +1,24 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; Helper to check for file opened, not eof, not ferror
+; Expects file pointer in ptr1,
+; Returns with Z flag set if everything is OK,
+; Destroys A, X, Y,
+; Sets file flags in A
+;
+
+ .export checkferror
+ .importzp ptr1
+
+ .include "_file.inc"
+
+checkferror:
+ ldy #_FILE::f_flags
+ lda (ptr1),y
+ tax
+ and #(_FOPEN|_FERROR|_FEOF); Check for file open, error/eof
+ tay
+ txa
+ cpy #_FOPEN
+ rts
diff --git a/libsrc/common/divt.s b/libsrc/common/divt.s
index 7f2b4e1bb..52b6efd04 100644
--- a/libsrc/common/divt.s
+++ b/libsrc/common/divt.s
@@ -3,7 +3,7 @@
; 2002-10-22, Greg King
;
; This signed-division function returns both the quotient and the remainder,
-; in this structure:
+; in this structure: (quotient in sreg, remainder in AX)
;
; typedef struct {
; int rem, quot;
diff --git a/libsrc/common/fclose.s b/libsrc/common/fclose.s
index 2368bf9f6..f6c57841e 100644
--- a/libsrc/common/fclose.s
+++ b/libsrc/common/fclose.s
@@ -7,7 +7,7 @@
.export _fclose
- .import _close
+ .import _close, ___directerrno
.importzp ptr1
.include "errno.inc"
@@ -31,10 +31,7 @@
; File is not open
lda #EINVAL
- jsr ___seterrno
- lda #$FF ; Return -1
- tax
- rts
+ jmp ___directerrno
; File is open. Reset the flags and close the file.
@@ -47,4 +44,3 @@
jmp _close ; Will set errno and return an error flag
.endproc
-
diff --git a/libsrc/common/fgetc.c b/libsrc/common/fgetc.c
deleted file mode 100644
index b4ba18d73..000000000
--- a/libsrc/common/fgetc.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-** fgetc.c
-**
-** (C) Copyright 1998, 2002 Ullrich von Bassewitz (uz@cc65.org)
-**
-*/
-
-
-
-#include
-#include
-#include "_file.h"
-
-
-
-/*****************************************************************************/
-/* Code */
-/*****************************************************************************/
-
-
-
-int __fastcall__ fgetc (register FILE* f)
-{
- unsigned char c;
-
- /* Check if the file is open or if there is an error condition */
- if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
- return EOF;
- }
-
- /* If we have a pushed back character, return it */
- if (f->f_flags & _FPUSHBACK) {
- f->f_flags &= ~_FPUSHBACK;
- return f->f_pushback;
- }
-
- /* Read one byte */
- switch (read (f->f_fd, &c, 1)) {
-
- case -1:
- /* Error */
- f->f_flags |= _FERROR;
- return EOF;
-
- case 0:
- /* EOF */
- f->f_flags |= _FEOF;
- return EOF;
-
- default:
- /* Char read */
- return c;
-
- }
-}
-
-
-
diff --git a/libsrc/common/fgetc.s b/libsrc/common/fgetc.s
new file mode 100644
index 000000000..34d4df3aa
--- /dev/null
+++ b/libsrc/common/fgetc.s
@@ -0,0 +1,94 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; int __fastcall__ fgetc (register FILE* f)
+;
+
+ .export _fgetc
+ .import _read, checkferror
+ .import pusha0, pushax, popptr1, incsp2, returnFFFF
+ .importzp ptr1
+
+ .include "stdio.inc"
+ .include "_file.inc"
+
+ .macpack cpu
+
+_fgetc:
+ sta ptr1
+ stx ptr1+1
+ jsr pushax ; Backup our ptr
+
+ jsr checkferror
+ bne ret_eof
+
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ bit #_FPUSHBACK ; Check for pushed back char
+ beq do_read
+ .else
+ tax
+ and #_FPUSHBACK ; Check for pushed back char
+ beq do_read
+ txa
+ .endif
+
+ and #<(~_FPUSHBACK) ; Reset flag
+ sta (ptr1),y
+
+ .assert _FILE::f_pushback = _FILE::f_flags+1, error
+ iny
+ jsr incsp2 ; Drop our ptr copy
+ lda (ptr1),y ; Return pushed back char
+ ldx #$00
+ rts
+
+do_read:
+ ; Push _read parameters
+ ldy #_FILE::f_fd
+ lda (ptr1),y
+ jsr pusha0
+
+ lda #c
+ jsr pushax
+
+ lda #$01
+ ldx #$00
+
+ ; Read
+ jsr _read
+
+ ; Check for errors
+ cmp #$00
+ beq set_feof
+
+ cmp #<(-1)
+ beq set_ferror
+
+ jsr incsp2
+ ; Return char
+ ldx #$00
+ lda c
+ rts
+
+ret_eof:
+ jsr incsp2
+ jmp returnFFFF
+
+set_ferror:
+ lda #_FERROR
+ bne set_err
+set_feof:
+ lda #_FEOF
+set_err:
+ pha
+ jsr popptr1
+ pla
+ ldy #_FILE::f_flags
+ ora (ptr1),y
+ sta (ptr1),y
+ jmp returnFFFF
+
+ .bss
+
+c: .res 1
diff --git a/libsrc/common/fgets.c b/libsrc/common/fgets.c
deleted file mode 100644
index 21a991fd6..000000000
--- a/libsrc/common/fgets.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-** Ullrich von Bassewitz, 11.08.1998
-**
-** char* fgets (char* s, int size, FILE* f);
-*/
-
-
-
-#include
-#include
-#include "_file.h"
-
-
-
-/*****************************************************************************/
-/* Code */
-/*****************************************************************************/
-
-
-
-char* __fastcall__ fgets (char* s, unsigned size, register FILE* f)
-{
- register char* p = s;
- unsigned i;
- int c;
-
- if (size == 0) {
- /* Invalid size */
- return (char*) _seterrno (EINVAL);
- }
-
- /* Read input */
- i = 0;
- while (--size) {
-
- /* Get next character */
- if ((c = fgetc (f)) == EOF) {
- /* Error or EOF */
- if ((f->f_flags & _FERROR) != 0 || i == 0) {
- /* ERROR or EOF on first char */
- *p = '\0';
- return 0;
- } else {
- /* EOF with data already read */
- break;
- }
- }
-
- /* One char more */
- *p = c;
- ++p;
- ++i;
-
- /* Stop at end of line */
- if ((char)c == '\n') {
- break;
- }
- }
-
- /* Terminate the string */
- *p = '\0';
-
- /* Done */
- return s;
-}
-
-
-
diff --git a/libsrc/common/fgets.s b/libsrc/common/fgets.s
new file mode 100644
index 000000000..172ca10dd
--- /dev/null
+++ b/libsrc/common/fgets.s
@@ -0,0 +1,117 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; char* __fastcall__ fgets (char* s, unsigned size, register FILE* f)
+;
+
+ .export _fgets
+ .import _fgetc, popptr1, pushptr1, popax, pushax, return0, ___errno
+ .importzp ptr1, ptr4
+
+ .include "errno.inc"
+ .include "stdio.inc"
+ .include "_file.inc"
+
+ .macpack cpu
+
+terminate_ptr:
+ lda #$00
+ tax
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ sta (ptr4)
+ .else
+ tay
+ sta (ptr4),y
+ .endif
+ rts
+
+_fgets:
+ sta ptr1
+ stx ptr1+1
+
+ jsr popax
+ sta size
+ stx size+1
+
+ jsr popax
+ sta ptr4
+ stx ptr4+1
+ sta buf
+ stx buf+1
+
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ stz didread
+ .else
+ lda #$00 ; We have read nothing yet
+ sta didread
+ .endif
+
+ ; Check size
+ lda size
+ ora size+1
+ bne read_loop
+ lda #EINVAL
+ sta ___errno
+ jmp return0
+
+read_loop:
+ lda size ; Dec size
+ bne :+
+ dec size+1
+: dec size
+
+ bne :+ ; Check bound
+ ldx size+1
+ beq done
+
+: jsr pushptr1 ; Push ptr1 for backup and load it to AX for fgetc
+ jsr _fgetc ; Read a char
+
+ pha
+ jsr popptr1 ; Get ptr1 back
+ pla
+
+ cpx #buf
+ lda #
-#include
-#include "_file.h"
-
-
-
-/*****************************************************************************/
-/* Code */
-/*****************************************************************************/
-
-
-
-int __fastcall__ fputc (int c, register FILE* f)
-{
- /* Check if the file is open or if there is an error condition */
- if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
- goto ReturnEOF;
- }
-
- /* Write the byte */
- if (write (f->f_fd, &c, 1) != 1) {
- /* Error */
- f->f_flags |= _FERROR;
-ReturnEOF:
- return EOF;
- }
-
- /* Return the byte written */
- return c & 0xFF;
-}
-
-
-
diff --git a/libsrc/common/fputc.s b/libsrc/common/fputc.s
new file mode 100644
index 000000000..358723538
--- /dev/null
+++ b/libsrc/common/fputc.s
@@ -0,0 +1,66 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; int __fastcall__ fputc (int c, FILE* f);
+;
+
+ .export _fputc
+ .importzp ptr1
+ .import _write, checkferror
+ .import pushax, pusha0, popax, incsp2
+ .import pushptr1, popptr1, returnFFFF
+
+ .include "stdio.inc"
+ .include "_file.inc"
+
+_fputc:
+ sta ptr1
+ stx ptr1+1
+
+ jsr popax ; Get char, as we'll have
+ sta c ; to return it anyway
+ stx c+1
+
+ jsr checkferror
+ bne ret_eof
+
+ jsr pushptr1 ; Backup fp pointer
+
+ ; Push _write parameters
+ ldy #_FILE::f_fd
+ lda (ptr1),y
+ jsr pusha0
+
+ lda #c
+ jsr pushax
+
+ lda #$01
+ ldx #$00
+
+ ; Write
+ jsr _write
+
+ ; Check for errors
+ cmp #$01
+ bne set_ferror
+
+ ; Return char
+ lda c
+ ldx #$00
+ jmp incsp2 ; Drop fp pointer copy
+
+ret_eof:
+ jmp returnFFFF
+
+set_ferror:
+ jsr popptr1
+ lda #_FERROR
+ ldy #_FILE::f_flags
+ ora (ptr1),y
+ sta (ptr1),y
+ jmp returnFFFF
+
+ .bss
+
+c: .res 2
diff --git a/libsrc/common/fputs.c b/libsrc/common/fputs.c
deleted file mode 100644
index be476a3f0..000000000
--- a/libsrc/common/fputs.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-** int fputs (const char* s, FILE* f);
-**
-** Ullrich von Bassewitz, 11.08.1998
-*/
-
-
-
-#include
-#include
-#include
-#include "_file.h"
-
-
-
-int __fastcall__ fputs (const char* s, register FILE* f)
-{
- /* Check if the file is open or if there is an error condition */
- if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
- return EOF;
- }
-
- /* Write the string */
- return write (f->f_fd, s, strlen (s));
-}
-
-
-
diff --git a/libsrc/common/fputs.s b/libsrc/common/fputs.s
new file mode 100644
index 000000000..b79a4707f
--- /dev/null
+++ b/libsrc/common/fputs.s
@@ -0,0 +1,36 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; int __fastcall__ fputs (const char* s, register FILE* f)
+;
+
+ .export _fputs
+ .importzp ptr1, ptr2
+ .import _write, _strlen, checkferror
+ .import swapstk, pushax, returnFFFF
+
+ .include "stdio.inc"
+ .include "_file.inc"
+
+_fputs:
+ sta ptr1
+ stx ptr1+1
+
+ jsr checkferror
+ bne ret_eof
+
+ ; Push _write parameters
+ ldy #_FILE::f_fd
+ lda (ptr1),y
+ ldx #$00
+ jsr swapstk ; Push fd, get s
+
+ jsr pushax ; Push s
+
+ jsr _strlen ; Get length
+
+ ; Write
+ jmp _write
+
+ret_eof:
+ jmp returnFFFF
diff --git a/libsrc/common/fread.s b/libsrc/common/fread.s
index 647a7f2c8..b39b9d748 100644
--- a/libsrc/common/fread.s
+++ b/libsrc/common/fread.s
@@ -20,6 +20,7 @@
.include "_file.inc"
.macpack generic
+ .macpack cpu
; ------------------------------------------------------------------------
; Code
@@ -47,13 +48,21 @@
ldy #_FILE::f_flags
lda (file),y
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ bit #_FOPEN ; Is the file open?
+ .else
and #_FOPEN ; Is the file open?
+ .endif
beq @L1 ; Branch if no
; Check if the stream is in an error state
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ bit #_FERROR
+ .else
lda (file),y ; get file->f_flags again
and #_FERROR
+ .endif
beq @L2
; File not open or in error state
@@ -65,11 +74,19 @@
; Remember if we have a pushed back character and reset the flag.
-@L2: tax ; X = 0
+@L2: .if (.cpu .bitand ::CPU_ISET_65SC02)
+ ldx #$00
+ bit #_FPUSHBACK
+ .else
+ tax ; X = 0
lda (file),y
and #_FPUSHBACK
+ .endif
beq @L3
+
+ .if (.not .cpu .bitand ::CPU_ISET_65SC02)
lda (file),y
+ .endif
and #<~_FPUSHBACK
sta (file),y ; file->f_flags &= ~_FPUSHBACK;
inx ; X = 1
@@ -118,12 +135,20 @@
; Copy the buffer pointer into ptr1, and increment the pointer value passed
; to read() by one, so read() starts to store data at buf+1.
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ lda (sp)
+ sta ptr1
+ add #1
+ sta (sp)
+ ldy #1
+ .else
ldy #0
lda (sp),y
sta ptr1
add #1
sta (sp),y
iny
+ .endif
lda (sp),y
sta ptr1+1
adc #0
@@ -134,8 +159,12 @@
ldy #_FILE::f_pushback
lda (file),y
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ sta (ptr1) ; *buf = file->f_pushback;
+ .else
ldy #0
sta (ptr1),y ; *buf = file->f_pushback;
+ .endif
; Restore the low byte of count and decrement count by one. This may result
; in count being zero, so check for that.
@@ -210,4 +239,3 @@
.bss
save: .res 2
pb: .res 1
-
diff --git a/libsrc/common/fwrite.s b/libsrc/common/fwrite.s
index 861feb120..e7151da95 100644
--- a/libsrc/common/fwrite.s
+++ b/libsrc/common/fwrite.s
@@ -8,7 +8,7 @@
.export _fwrite
.import _write
- .import pushax, incsp6, addysp, ldaxysp, pushwysp, return0
+ .import pushax, pusha0, incsp6, addysp, ldaxysp, pushwysp, return0
.import tosumulax, tosudivax
.importzp ptr1
@@ -16,6 +16,7 @@
.include "errno.inc"
.include "_file.inc"
+ .macpack cpu
; ------------------------------------------------------------------------
; Code
@@ -33,7 +34,11 @@
ldy #_FILE::f_flags
lda (ptr1),y
+ .if (.cpu .bitand ::CPU_ISET_65SC02)
+ bit #_FOPEN
+ .else
and #_FOPEN ; Is the file open?
+ .endif
bne @L2 ; Branch if yes
; File not open
@@ -45,7 +50,9 @@
; Check if the stream is in an error state
-@L2: lda (ptr1),y ; get file->f_flags again
+@L2: .if (.not .cpu .bitand ::CPU_ISET_65SC02)
+ lda (ptr1),y ; get file->f_flags again
+ .endif
and #_FERROR
bne @L1
@@ -53,8 +60,7 @@
ldy #_FILE::f_fd
lda (ptr1),y
- ldx #$00
- jsr pushax ; file->f_fd
+ jsr pusha0 ; file->f_fd
ldy #9
jsr pushwysp ; buf
@@ -123,4 +129,3 @@
.bss
file: .res 2
-
diff --git a/libsrc/common/gets.c b/libsrc/common/gets.c
deleted file mode 100644
index 2936c70de..000000000
--- a/libsrc/common/gets.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-** gets.c
-**
-** Ullrich von Bassewitz, 11.08.1998
-*/
-
-
-
-#include
-#include "_file.h"
-
-
-
-/*****************************************************************************/
-/* Code */
-/*****************************************************************************/
-
-
-
-char* __fastcall__ gets (char* s)
-{
- register char* p = s;
- int c;
- unsigned i = 0;
-
- while (1) {
-
- /* Get next character */
- if ((c = fgetc (stdin)) == EOF) {
- /* Error or EOF */
- *p = '\0';
- if (stdin->f_flags & _FERROR) {
- /* ERROR */
- return 0;
- } else {
- /* EOF */
- if (i) {
- return s;
- } else {
- return 0;
- }
- }
- }
-
- /* One char more. Newline ends the input */
- if ((char) c == '\n') {
- *p = '\0';
- break;
- } else {
- *p = c;
- ++p;
- ++i;
- }
-
- }
-
- /* Done */
- return s;
-}
-
-
-
-
diff --git a/libsrc/common/gets.s b/libsrc/common/gets.s
new file mode 100644
index 000000000..dfaf2def3
--- /dev/null
+++ b/libsrc/common/gets.s
@@ -0,0 +1,47 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; char* __fastcall__ gets (char* s)
+;
+
+ .export _gets
+ .import _fgets, _stdin, popax, pushax
+ .importzp ptr4
+
+_gets:
+ ; Push buffer
+ sta ptr4
+ stx ptr4+1
+ jsr pushax
+
+ ; Push size (there's no limit!)
+ lda #$FF
+ tax
+ jsr pushax
+
+ lda _stdin
+ ldx _stdin+1
+
+ jsr _fgets
+
+ ; Check return value
+ bne :+
+ cpx #$00
+ bne :+
+ rts
+
+: ; At least one byte written.
+ jsr pushax ; Store returned pointer
+
+ ; Remove \n if there is one.
+ lda ptr4 ; _fgets returns with ptr4 at
+ bne :+ ; end of buffer
+ dec ptr4+1
+: dec ptr4
+ lda (ptr4),y ; _fgets returns with Y=0
+ cmp #$0A
+ bne :+
+ tya
+ sta (ptr4),y ; Set terminator over \n
+
+: jmp popax
diff --git a/libsrc/common/gmtime.s b/libsrc/common/gmtime.s
new file mode 100644
index 000000000..288b285eb
--- /dev/null
+++ b/libsrc/common/gmtime.s
@@ -0,0 +1,20 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; struct tm* __fastcall__ gmtime (const time_t* timep);
+;
+
+ .export _gmtime
+ .import __time_t_to_tm
+ .import ldeaxi
+
+_gmtime:
+ cpx #$00 ; Check for null pointer
+ bne :+
+ cmp #$00
+ beq no_pointer
+: jsr ldeaxi ; Load value from pointer
+ jmp __time_t_to_tm ; Convert it
+
+no_pointer:
+ rts ; A/X already set
diff --git a/libsrc/common/localtime.s b/libsrc/common/localtime.s
new file mode 100644
index 000000000..279442c9d
--- /dev/null
+++ b/libsrc/common/localtime.s
@@ -0,0 +1,29 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; struct tm* __fastcall__ localtime (const time_t* timep);
+;
+
+ .export _localtime
+ .import __time_t_to_tm, __tz
+ .import ldeaxi, tosaddeax, pusheax
+ .importzp sreg
+
+_localtime:
+ cpx #$00 ; Check for null pointer
+ bne :+
+ cmp #$00
+ beq no_pointer
+: jsr ldeaxi ; Load value
+ jsr pusheax ; Push it
+ lda __tz+1+3
+ sta sreg+1
+ lda __tz+1+2
+ sta sreg
+ ldx __tz+1+1
+ lda __tz+1
+ jsr tosaddeax ; Add _tz.timezone
+ jmp __time_t_to_tm ; Convert to struct tm
+
+no_pointer:
+ rts ; A/X already set
diff --git a/libsrc/common/malloc.s b/libsrc/common/malloc.s
index 6872f1f2e..72c4aedaa 100644
--- a/libsrc/common/malloc.s
+++ b/libsrc/common/malloc.s
@@ -131,6 +131,7 @@ _malloc:
sta ptr1
bcc @L1
inc ptr1+1
+ beq OutOfHeapSpace ; if high byte's 0, we overflowed!
@L1: ldx ptr1+1
bne @L2
cmp #HEAP_MIN_BLOCKSIZE+1
@@ -336,4 +337,3 @@ RetUserPtr:
bcc @L9
inx
@L9: rts
-
diff --git a/libsrc/common/mktime.c b/libsrc/common/mktime.c
deleted file mode 100644
index 275589dbb..000000000
--- a/libsrc/common/mktime.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*****************************************************************************/
-/* */
-/* mktime.c */
-/* */
-/* Make calendar time from broken down time and cleanup */
-/* */
-/* */
-/* */
-/* (C) 2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
-/* */
-/* */
-/* This software is provided 'as-is', without any expressed or implied */
-/* warranty. In no event will the authors be held liable for any damages */
-/* arising from the use of this software. */
-/* */
-/* Permission is granted to anyone to use this software for any purpose, */
-/* including commercial applications, and to alter it and redistribute it */
-/* freely, subject to the following restrictions: */
-/* */
-/* 1. The origin of this software must not be misrepresented; you must not */
-/* claim that you wrote the original software. If you use this software */
-/* in a product, an acknowledgment in the product documentation would be */
-/* appreciated but is not required. */
-/* 2. Altered source versions must be plainly marked as such, and must not */
-/* be misrepresented as being the original software. */
-/* 3. This notice may not be removed or altered from any source */
-/* distribution. */
-/* */
-/*****************************************************************************/
-
-
-
-#include
-#include
-#include
-
-
-
-/*****************************************************************************/
-/* Data */
-/*****************************************************************************/
-
-
-
-#define JANUARY 0
-#define FEBRUARY 1
-#define DECEMBER 11
-#define JAN_1_1970 4 /* 1/1/1970 is a thursday */
-
-
-
-static const unsigned char MonthLength [] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-static const unsigned MonthDays [] = {
- 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
-};
-
-
-
-/*****************************************************************************/
-/* Code */
-/*****************************************************************************/
-
-
-
-static unsigned char __fastcall__ IsLeapYear (unsigned Year)
-/* Returns 1 if the given year is a leap year */
-{
- return (((Year % 4) == 0) && ((Year % 100) != 0 || (Year % 400) == 0));
-}
-
-
-
-time_t __fastcall__ mktime (register struct tm* TM)
-/* Make a time in seconds since 1/1/1970 from the broken down time in TM.
-** A call to mktime does also correct the time in TM to contain correct
-** values.
-*/
-{
- register div_t D;
- int Max;
- unsigned DayCount;
-
- /* Check if TM is valid */
- if (TM == 0) {
- /* Invalid data */
- goto Error;
- }
-
- /* Adjust seconds. */
- D = div (TM->tm_sec, 60);
- TM->tm_sec = D.rem;
-
- /* Adjust minutes */
- if (TM->tm_min + D.quot < 0) {
- goto Error;
- }
- TM->tm_min += D.quot;
- D = div (TM->tm_min, 60);
- TM->tm_min = D.rem;
-
- /* Adjust hours */
- if (TM->tm_hour + D.quot < 0) {
- goto Error;
- }
- TM->tm_hour += D.quot;
- D = div (TM->tm_hour, 24);
- TM->tm_hour = D.rem;
-
- /* Adjust days */
- if (TM->tm_mday + D.quot < 0) {
- goto Error;
- }
- TM->tm_mday += D.quot;
-
- /* Adjust month and year. This is an iterative process, since changing
- ** the month will change the allowed days for this month.
- */
- while (1) {
-
- /* Make sure, month is in the range 0..11 */
- D = div (TM->tm_mon, 12);
- TM->tm_mon = D.rem;
- if (TM->tm_year + D.quot < 0) {
- goto Error;
- }
- TM->tm_year += D.quot;
-
- /* Now check if mday is in the correct range, if not, correct month
- ** and eventually year and repeat the process.
- */
- if (TM->tm_mon == FEBRUARY && IsLeapYear (TM->tm_year + 1900)) {
- Max = 29;
- } else {
- Max = MonthLength[TM->tm_mon];
- }
- if (TM->tm_mday > Max) {
- /* Must correct month and eventually, year */
- if (TM->tm_mon == DECEMBER) {
- TM->tm_mon = JANUARY;
- ++TM->tm_year;
- } else {
- ++TM->tm_mon;
- }
- TM->tm_mday -= Max;
- } else {
- /* Done */
- break;
- }
- }
-
- /* Ok, all time/date fields are now correct. Calculate the days in this
- ** year.
- */
- TM->tm_yday = MonthDays[TM->tm_mon] + TM->tm_mday - 1;
- if (TM->tm_mon > FEBRUARY && IsLeapYear (TM->tm_year + 1900)) {
- ++TM->tm_yday;
- }
-
- /* Calculate days since 1/1/1970. In the complete epoch (1/1/1970 to
- ** somewhere in 2038) all years dividable by 4 are leap years, so
- ** dividing by 4 gives the days that must be added cause of leap years.
- ** (and the last leap year before 1970 was 1968)
- */
- DayCount = ((unsigned) (TM->tm_year-70)) * 365U +
- (((unsigned) (TM->tm_year-(68+1))) / 4) +
- TM->tm_yday;
-
- /* Calculate the weekday */
- TM->tm_wday = (JAN_1_1970 + DayCount) % 7;
-
- /* No (US) daylight saving (for now) */
- TM->tm_isdst = 0;
-
- /* Return seconds since 1970 */
- return DayCount * 86400UL +
- ((unsigned) TM->tm_hour) * 3600UL +
- ((unsigned) TM->tm_min) * 60U +
- ((unsigned) TM->tm_sec) -
- _tz.timezone;
-
-Error:
- /* Error exit */
- return (time_t) -1L;
-}
-
-
-
diff --git a/libsrc/common/mktime.s b/libsrc/common/mktime.s
new file mode 100644
index 000000000..ac5755a45
--- /dev/null
+++ b/libsrc/common/mktime.s
@@ -0,0 +1,476 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; time_t __fastcall__ mktime (register struct tm* TM)
+;
+; Converts a struct tm to a time_t timestamp, making sure
+; day, month, year, hour, minute and seconds are in the
+; correct range.
+;
+
+ .export _mktime
+ .import __tz
+ .import pushax, pusha0, pusheax
+ .import shrax2, _div, tosumulax, tosumodax, tossubeax, tosaddeax, tosumuleax
+ .importzp ptr2, tmp3, sreg
+
+ .include "time.inc"
+
+; ------------------------------------------------------------------------
+; Special values
+
+FEBRUARY = 1
+MARCH = 2
+JAN_1_1970 = 4
+N_SEC = 60
+N_MIN = 60
+N_HOUR = 24
+N_MON = 12
+N_DAY_YEAR = 365
+; ------------------------------------------------------------------------
+; Helpers
+
+ ; Helper to shift overflows from one field to the next
+ ; Current field in Y, divisor in A
+ ; Keeps remainder in current field, and adds the quotient
+ ; to the next one
+adjust_field:
+ pha ; Push divisor
+ iny ; Point to high byte of current field
+ lda (ptr2),y
+ tax
+ dey
+ sty tmp3 ; Store current field (_div will mess with
+ lda (ptr2),y ; tmp1 and tmp2)
+ jsr pushax
+ pla ; Load divisor
+ ldx #$00
+
+ jsr _div
+
+ ldy tmp3 ; Store remainder in current field
+ sta (ptr2),y
+ iny
+ txa
+ sta (ptr2),y
+
+ lda sreg ; Add quotient to next field
+ iny
+ clc
+ adc (ptr2),y
+ sta (ptr2),y
+ iny
+ lda sreg+1
+ adc (ptr2),y
+ sta (ptr2),y
+ rts
+
+ ; Returns 1 in A if the given year is a leap year. Expects a year
+ ; from 0 to 206, without 1900 added.
+is_leap_year:
+ cmp #$00 ; Y 0 (1900) is not a leap year
+ beq not_leap
+ cmp #$C8 ; Y 200 (2100) is not a leap year
+ beq not_leap
+ and #$03 ; Year % 4 == 0 means leap year
+ bne not_leap
+ lda #$01 ; Return 1
+ rts
+not_leap:
+ lda #$00 ; Return 0
+ rts
+
+ ; Returns the number of days in the current month/year in A
+get_days_in_month:
+ ldy #tm::tm_mon
+ lda (ptr2),y
+ tax
+ lda months_len,x
+ cpx #FEBRUARY
+ beq :+
+ rts
+: tax
+ ldy #tm::tm_year ; Adjust for leap years
+ lda (ptr2),y
+ jsr is_leap_year
+ beq :+
+ inx
+: txa
+ rts
+
+ ; Add AX to counter
+addaxcounter:
+ clc
+ adc Counter
+ sta Counter ; Store in Counter
+ txa
+ adc Counter+1
+ sta Counter+1
+ rts
+
+ ; Helpers for long chain of arithmetic on day counter.
+ ; Reload Counter and push it on the stack
+load_and_push_counter:
+ lda Counter+3
+ sta sreg+1
+ lda Counter+2
+ sta sreg
+ lda Counter
+ ldx Counter+1
+ jsr pusheax
+ rts
+
+ ; Store result in AX:sreg to Counter
+store_counter:
+ sta Counter
+ stx Counter+1
+ lda sreg
+ sta Counter+2
+ lda sreg+1
+ sta Counter+3
+ rts
+
+; ------------------------------------------------------------------------
+; Code
+
+_mktime:
+ sta ptr2 ; Store struct to ptr2, which arithmetic
+ stx ptr2+1 ; functions won't touch
+
+ ; Check pointer validity
+ ora ptr2+1
+ bne :+
+ lda #$FF
+ tax
+ sta sreg
+ sta sreg+1
+ rts
+
+ ; Adjust seconds
+: ldy #tm::tm_sec
+ lda #N_SEC
+ jsr adjust_field
+
+ ; Adjust minutes
+ ldy #tm::tm_min
+ lda #N_MIN
+ jsr adjust_field
+
+ ; Adjust hours
+ ldy #tm::tm_hour
+ lda #N_HOUR
+ jsr adjust_field
+
+ ;Shift one year as long as tm_mday is more than a year
+ ldy #tm::tm_year
+ lda (ptr2),y
+
+dec_by_year:
+ jsr is_leap_year ; Compute max numbers of days in year
+ clc
+ adc #N_DAY_YEAR
+ beq :+ ; High byte equal, check low byte
+ bcs do_year_dec ; High byte greater, decrement
+ bcc dec_by_month ; Low byte lower, we're done
+: dey
+ lda (ptr2),y
+ cmp Max
+ bcc dec_by_month
+ beq dec_by_month
+
+do_year_dec:
+ ; Decrement days
+ ldy #tm::tm_mday
+ lda (ptr2),y
+ sbc Max ; Carry already set
+ sta (ptr2),y
+ iny
+ lda (ptr2),y
+ sbc #>N_DAY_YEAR
+ sta (ptr2),y
+
+ ; Increment year
+ ldy #tm::tm_year
+ lda (ptr2),y
+ clc
+ adc #1
+ sta (ptr2),y ; No carry possible here either
+ bcc dec_by_year ; bra, go check next year
+
+dec_by_month:
+ ; We're done decrementing days by full years, now do it
+ ; month per month.
+ ldy #tm::tm_mon
+ lda #N_MON
+ jsr adjust_field
+
+ ; Get max day for this month
+ jsr get_days_in_month
+ sta Max
+
+ ; So, do we have more days than this month?
+ ldy #tm::tm_mday+1
+ lda (ptr2),y
+ bne do_month_dec ; High byte not zero, sure we do
+ dey
+ lda (ptr2),y
+ cmp Max
+ bcc calc_tm_yday ; No
+ beq calc_tm_yday
+
+do_month_dec:
+ ; Decrement days
+ ldy #tm::tm_mday
+ lda (ptr2),y
+ sec
+ sbc Max
+ sta (ptr2),y
+ iny
+ lda (ptr2),y
+ sbc #$00
+ sta (ptr2),y
+
+ ; Increment month
+ ldy #tm::tm_mon
+ lda (ptr2),y
+ clc
+ adc #1
+ sta (ptr2),y
+
+ bne dec_by_month ; Check next month
+
+calc_tm_yday:
+ ; We finished decrementing tm_mday and have put it in the correct
+ ; year/month range. Now compute the day of the year.
+ ldy #tm::tm_mday ; Get current day of month
+ lda (ptr2),y
+ sta Counter ; Store it in Counter
+
+ lda #$00 ; Init counter high bytes
+ sta Counter+1
+ sta Counter+2
+ sta Counter+3
+
+ ldy #tm::tm_mon ; Get current month
+ lda (ptr2),y
+ asl
+ tax
+ clc
+ lda yday_by_month,x ; Get yday for this month's start
+ adc Counter ; Add it to counter
+ sta Counter
+ inx
+ lda yday_by_month,x
+ adc Counter+1
+ sta Counter+1
+
+ ldy #tm::tm_year ; Adjust for leap years (if after feb)
+ lda (ptr2),y
+ jsr is_leap_year
+ beq dec_counter
+ ldy #tm::tm_mon ; Leap year, get current month
+ lda (ptr2),y
+ cmp #MARCH
+ bcs store_yday
+
+dec_counter:
+ lda Counter ; Decrease counter by one (yday starts at 0),
+ bne :+ ; unless we're after february in a leap year
+ dec Counter+1
+: dec Counter
+
+store_yday:
+ ldy #tm::tm_yday ; Store tm_yday
+ lda Counter
+ sta (ptr2),y
+ iny
+ lda Counter+1
+ sta (ptr2),y
+
+ ; Now calculate total day count since epoch with the formula:
+ ; ((unsigned) (TM->tm_year-70)) * 365U + (number of days per year since 1970)
+ ; (((unsigned) (TM->tm_year-(68+1))) / 4) + (one extra day per leap year since 1970)
+ ; TM->tm_yday (number of days in this year)
+
+ ldy #tm::tm_year ; Get full years
+ lda (ptr2),y
+ sec
+ sbc #70
+ ldx #0
+ jsr pushax
+ lda #N_DAY_YEAR
+
+ jsr tosumulax
+ jsr addaxcounter
+
+ ; Add one day per leap year
+ ldy #tm::tm_year ; Get full years
+ lda (ptr2),y
+ sec
+ sbc #69
+ ldx #0
+ jsr shrax2 ; Divide by 4
+
+ jsr addaxcounter
+
+ ; Handle the 2100 exception (which was considered leap by "Add one day
+ ; per leap year" just before)
+ ldy #tm::tm_year ; Get full years
+ lda (ptr2),y
+ cmp #201
+ bcc finish_calc ; <= 200, nothing to do
+
+ lda Counter
+ bne :+
+ dec Counter+1
+: dec Counter
+
+finish_calc:
+ ; Now we can compute the weekday.
+ lda Counter
+ clc
+ adc #JAN_1_1970
+ pha
+ lda Counter+1
+ adc #0
+ tax
+ pla
+ jsr pushax
+
+ lda #7 ; Modulo 7
+ ldx #0
+ jsr tosumodax
+
+ ldy #tm::tm_wday ; Store tm_wday
+ sta (ptr2),y
+ iny
+ txa
+ sta (ptr2),y
+
+ ; DST
+ lda #$00 ; Store tm_isdst
+ ldy #tm::tm_isdst
+ sta (ptr2),y
+ iny
+ sta (ptr2),y
+
+ ; Our struct tm is all fixed and every field calculated.
+ ; We can finally count seconds according to this formula:
+ ; seconds = (full days since epoch) * 86400UL +
+ ; ((unsigned) TM->tm_hour) * 3600UL +
+ ; ((unsigned) TM->tm_min) * 60U +
+ ; ((unsigned) TM->tm_sec) -
+ ; _tz.timezone;
+
+ ; We already have the number of days since epoch in our counter,
+ ; from just before when we computed tm_wday. Reuse it.
+ jsr load_and_push_counter
+ lda #$00 ; Multiply by 86400
+ sta sreg+1
+ lda #$01
+ sta sreg
+ lda #$80
+ ldx #$51
+ jsr tosumuleax
+ jsr store_counter ; Store into counter
+
+ ; Push counter to add 3600 * hours to it
+ jsr load_and_push_counter
+
+ ldx #$00 ; Load hours
+ stx sreg
+ stx sreg+1
+ ldy #tm::tm_hour
+ lda (ptr2),y
+ jsr pusheax ; Push
+ ldx #$00 ; Load 3600
+ stx sreg
+ stx sreg+1
+ lda #<3600
+ ldx #>3600
+ jsr tosumuleax ; Multiply (pops the pushed hours)
+ jsr tosaddeax ; Add to counter (pops the pushed counter)
+ jsr store_counter ; Store counter
+
+ ; Push counter to add 60 * min to it
+ jsr load_and_push_counter
+
+ ldy #tm::tm_min ; Load minutes
+ lda (ptr2),y
+ jsr pusha0 ; Push
+ lda #N_MIN
+ ldx #0
+ stx sreg
+ stx sreg+1
+ jsr tosumulax ; Multiply
+ jsr tosaddeax ; Add to pushed counter
+ jsr store_counter ; Store
+
+ ; Add seconds
+ jsr load_and_push_counter
+
+ ldy #tm::tm_sec ; Load seconds
+ lda (ptr2),y
+ ldx #0
+ stx sreg
+ stx sreg+1
+ jsr tosaddeax ; Simple addition there
+
+ ; No need to store/load/push the counter here, simply to push it
+ ; for the last substraction
+ jsr pusheax
+
+ ; Substract timezone
+ lda __tz+1+3
+ sta sreg+1
+ lda __tz+1+2
+ sta sreg
+ ldx __tz+1+1
+ lda __tz+1
+ jsr tossubeax
+
+ ; And we're done!
+ rts
+
+ .data
+
+months_len:
+ .byte 31
+ .byte 28
+ .byte 31
+ .byte 30
+ .byte 31
+ .byte 30
+ .byte 31
+ .byte 31
+ .byte 30
+ .byte 31
+ .byte 30
+ .byte 31
+
+yday_by_month:
+ .word 0
+ .word 31
+ .word 59
+ .word 90
+ .word 120
+ .word 151
+ .word 181
+ .word 212
+ .word 243
+ .word 273
+ .word 304
+ .word 334
+
+
+ .bss
+
+Max: .res 1 ; We won't need a high byte
+Counter:
+ .res 4
diff --git a/libsrc/common/ntohl.s b/libsrc/common/ntohl.s
new file mode 100644
index 000000000..77adba253
--- /dev/null
+++ b/libsrc/common/ntohl.s
@@ -0,0 +1,32 @@
+;
+; Colin Leroy-Mira , 2023-09-06
+;
+; int __fastcall__ ntohl (long val);
+;
+
+.export _ntohl, _htonl
+.import popa
+.importzp tmp1, tmp2, sreg
+
+_htonl := _ntohl
+
+_ntohl:
+ ; The parts of our 32 bit word
+ ; are in sreg+1, sreg, X, A.
+
+ ; Save A and X
+ stx tmp1
+ sta tmp2
+
+ ; Invert high word
+ lda sreg+1
+ ldx sreg
+
+ ; Invert low word
+ ldy tmp1
+ sty sreg
+
+ ldy tmp2
+ sty sreg+1
+
+ rts
diff --git a/libsrc/common/ntohs.s b/libsrc/common/ntohs.s
new file mode 100644
index 000000000..042ddb005
--- /dev/null
+++ b/libsrc/common/ntohs.s
@@ -0,0 +1,16 @@
+;
+; Colin Leroy-Mira , 2023-09-06
+;
+; int __fastcall__ ntohs (int val);
+;
+
+.export _ntohs, _htons
+.importzp tmp1
+
+_htons := _ntohs
+
+_ntohs:
+ sta tmp1
+ txa
+ ldx tmp1
+ rts
diff --git a/libsrc/common/pmemalign.c b/libsrc/common/pmemalign.c
index 52adb240d..4499084d1 100644
--- a/libsrc/common/pmemalign.c
+++ b/libsrc/common/pmemalign.c
@@ -50,7 +50,6 @@
*/
-
int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size)
/* Allocate a block of memory with the given "size", which is aligned to a
** memory address that is a multiple of "alignment". "alignment" MUST NOT be
@@ -64,20 +63,27 @@ int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size)
size_t rawsize;
size_t uppersize;
size_t lowersize;
+ char err;
register struct usedblock* b; /* points to raw Block */
register struct usedblock* u; /* points to User block */
register struct usedblock* p; /* Points to upper block */
/* Handle requests for zero-sized blocks */
if (size == 0) {
+err_einval:
+ err = EINVAL;
+err_out:
*memptr = NULL;
- return EINVAL;
+ return err;
}
- /* Test alignment: is it a power of two? There must be only one bit set. */
- if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
- *memptr = NULL;
- return EINVAL;
+ /* Test alignment: is it a power of two? There must be one and only one bit set. */
+ if (alignment == 0) {
+ goto err_einval;
+ }
+
+ if (alignment & (alignment - 1)) {
+ goto err_einval;
}
/* Augment the block size up to the alignment, and allocate memory.
@@ -90,8 +96,8 @@ int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size)
/* Handle out-of-memory */
if (b == NULL) {
- *memptr = NULL;
- return ENOMEM;
+ err = ENOMEM;
+ goto err_out;
}
/* Create (and return) a new pointer that points to the user-visible
diff --git a/libsrc/common/putenv.s b/libsrc/common/putenv.s
index 5febcc71e..13f0e7dc4 100644
--- a/libsrc/common/putenv.s
+++ b/libsrc/common/putenv.s
@@ -10,7 +10,7 @@
.import _malloc, _free
.import searchenv, copyenvptr
.import __environ, __envcount, __envsize
- .import return0
+ .import return0, ___directerrno
.import ptr1:zp, ptr2:zp, ptr3:zp, tmp1:zp
.include "errno.inc"
@@ -169,10 +169,7 @@ addentry:
; Error entries
nomem: lda #ENOMEM
-error: jsr ___seterrno
- lda #$FF ; Return -1
- tax
- rts
+error: jmp ___directerrno
.endproc
@@ -184,5 +181,3 @@ error: jsr ___seterrno
name: .addr 0 ; Pointer to name
newsize: .byte 0 ; New environment size
-
-
diff --git a/libsrc/common/realloc.c b/libsrc/common/realloc.c
deleted file mode 100644
index eeb1eeea5..000000000
--- a/libsrc/common/realloc.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*****************************************************************************/
-/* */
-/* realloc.c */
-/* */
-/* Change the size of an allocated memory block */
-/* */
-/* */
-/* */
-/* (C) 1998-2004 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
-/* */
-/* */
-/* This software is provided 'as-is', without any expressed or implied */
-/* warranty. In no event will the authors be held liable for any damages */
-/* arising from the use of this software. */
-/* */
-/* Permission is granted to anyone to use this software for any purpose, */
-/* including commercial applications, and to alter it and redistribute it */
-/* freely, subject to the following restrictions: */
-/* */
-/* 1. The origin of this software must not be misrepresented; you must not */
-/* claim that you wrote the original software. If you use this software */
-/* in a product, an acknowledgment in the product documentation would be */
-/* appreciated but is not required. */
-/* 2. Altered source versions must be plainly marked as such, and must not */
-/* be misrepresented as being the original software. */
-/* 3. This notice may not be removed or altered from any source */
-/* distribution. */
-/* */
-/*****************************************************************************/
-
-
-
-#include
-#include
-#include <_heap.h>
-
-
-
-void* __fastcall__ realloc (void* block, register size_t size)
-{
- register struct usedblock* b;
- struct usedblock* newblock;
- unsigned oldsize;
- unsigned newhptr;
-
- /* Check the block parameter */
- if (!block) {
- /* Block is NULL, same as malloc */
- return malloc (size);
- }
-
- /* Check the size parameter */
- if (size == 0) {
- /* Block is not NULL, but size is: free the block */
- free (block);
- return 0;
- }
-
- /* Make the internal used size from the given size */
- size += HEAP_ADMIN_SPACE;
- if (size < sizeof (struct freeblock)) {
- size = sizeof (struct freeblock);
- }
-
- /* The word below the user block contains a pointer to the start of the
- ** raw memory block. The first word of this raw memory block is the full
- ** size of the block. Get a pointer to the real block, get the old block
- ** size.
- */
- b = (((struct usedblock*) block) - 1)->start;
- oldsize = b->size;
-
- /* Is the block at the current heap top? */
- if (((unsigned) b) + oldsize == ((unsigned) __heapptr)) {
- /* Check if we've enough memory at the heap top */
- newhptr = ((unsigned) __heapptr) - oldsize + size;
- if (newhptr <= ((unsigned) __heapend)) {
- /* Ok, there's space enough */
- __heapptr = (unsigned*) newhptr;
- b->size = size;
- b->start = b;
- return block;
- }
- }
-
- /* The given block was not located on top of the heap, or there's no
- ** room left. Try to allocate a new block and copy the data.
- */
- if (newblock = malloc (size)) {
-
- /* Adjust the old size to the user visible portion */
- oldsize -= HEAP_ADMIN_SPACE;
-
- /* If the new block is larger than the old one, copy the old
- ** data only
- */
- if (size > oldsize) {
- size = oldsize;
- }
-
- /* Copy the block data */
- memcpy (newblock, block, size);
- free (block);
- }
- return newblock;
-}
-
-
-
diff --git a/libsrc/common/realloc.s b/libsrc/common/realloc.s
new file mode 100644
index 000000000..925ac3d19
--- /dev/null
+++ b/libsrc/common/realloc.s
@@ -0,0 +1,213 @@
+;
+; Colin Leroy-Mira, 2024
+;
+; void* __fastcall__ realloc (void* block, register size_t size)
+;
+
+ .importzp ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3, tmp4, sp
+ .import _malloc, _memcpy, _free
+ .import pushax, popptr1, return0
+ .import incsp2, decsp2
+ .export _realloc
+
+ .include "_heap.inc"
+
+ .macpack generic
+
+;----------------------------------------------------------------------------
+; Aliases for clarity
+
+block = ptr1
+size = ptr2
+ublock = ptr3
+oldsize = ptr4
+newblock = tmp1 ; (and tmp2)
+orgblock = tmp3 ; (and tmp4)
+
+;----------------------------------------------------------------------------
+; Code
+
+_realloc:
+ sta size ; Store size
+ stx size+1
+
+ jsr popptr1 ; Pop block
+
+ lda block+1 ; Is block null?
+ tax
+ ora block
+ bne :+
+
+ lda size ; Block is null, just malloc
+ ldx size+1
+ jmp _malloc
+
+: lda size ; Is size 0?
+ ora size+1
+ bne :+
+
+ lda block ; It is: free block (high byte already in X)
+ jsr _free
+ jmp return0
+
+: clc ; Add internal used size
+ lda size
+ adc #HEAP_ADMIN_SPACE
+ sta size
+ bcc :+
+ inc size+1
+ bne :+
+
+ lda #$00 ; Size high byte now 0: We overflowed!
+ tax
+ rts
+
+: ldx size+1 ; Should we round size up?
+ bne :+
+ cmp #.sizeof (freeblock)
+ bcs :+
+
+ lda #.sizeof (freeblock)
+ sta size ; (we presuppose that sizeof (freeblock) is < 256)
+
+: lda block ; Get pointer to raw memory block
+ sta orgblock ; Store original pointer
+ sec
+ sbc #.sizeof(usedblock)
+ sta ublock
+ lda block+1
+ sta orgblock+1 ; Finish storing original pointer
+ sbc #0
+ sta ublock+1 ; We have our usedblock struct
+
+ ; Get block start
+ ldy #usedblock::start+1
+ lda (ublock),y
+ tax ; Backup ublock high
+ dey
+ lda (ublock),y
+
+ sta ublock ; Store ublock
+ stx ublock+1
+
+ ; Remember oldsize
+ ldy #usedblock::size+1
+ lda (ublock),y
+ sta oldsize+1
+ dey
+ lda (ublock),y
+ sta oldsize
+
+ clc ; Is the block at heap top?
+ adc ublock
+ tay
+ lda ublock+1
+ adc oldsize+1
+ cmp ___heapptr+1
+ bne must_malloc_new
+ cpy ___heapptr
+ bne must_malloc_new
+
+ tya ; Put ___heapptr back in A
+ sec ; Check if we have enough memory at heap top
+ sbc oldsize ; Substract oldsize
+ sta newblock
+ lda ___heapptr+1
+ sbc oldsize+1
+ sta newblock+1
+ clc
+ lda newblock ; And add size
+ adc size
+ sta newblock
+ lda newblock+1
+ adc size+1
+ sta newblock+1
+ bcs must_malloc_new ; If we have a carry there we overflowed
+
+ cmp ___heapend+1
+ bne :+
+ lda newblock
+ cmp ___heapend
+: bcc :+
+ bne must_malloc_new
+
+: lda newblock ; There is enough space
+ sta ___heapptr ; Update heapptr
+ lda newblock+1
+ sta ___heapptr+1
+
+ ldy #usedblock::start+1
+ lda ublock+1
+ sta (ublock),y ; Update block start
+ dey
+ lda ublock
+ sta (ublock),y
+ dey
+
+ .assert usedblock::size = usedblock::start-2, error
+ lda size+1
+ sta (ublock),y ; Update block size
+ dey
+ lda size
+ sta (ublock),y
+
+ lda orgblock ; Return original block
+ ldx orgblock+1
+ rts
+
+must_malloc_new: ; The block is not at heap top, or too big
+ lda size+1
+ pha ; Backup new size (at this point the only ptr
+ tax ; we'll need after malloc). tmp* are safe
+ lda size ; from malloc, memcpy and free.
+ pha
+ jsr _malloc
+
+ cmp #$00 ; Did malloc succeed?
+ bne :+
+ cpx #$00
+ bne :+
+ pla ; Pop size backup and return NULL
+ pla
+ txa ; X already 0
+ rts ; No
+
+: sta newblock ; Yes, store newblock
+ stx newblock+1
+ jsr pushax ; Push newblock for memcpy
+
+ lda orgblock ; Push orgblock for memcpy
+ ldx orgblock+1
+ jsr pushax
+
+ sec ; Remove admin space from oldsize
+ lda oldsize
+ sbc #HEAP_ADMIN_SPACE
+ sta oldsize+1
+
+ pla ; Restore new size to AX
+ tay
+ pla
+ tax
+ tya
+
+ cmp oldsize ; Find the smallest size
+ bcc :+
+ cpx oldsize+1
+ bcc :+
+
+ lda oldsize
+ ldx oldsize+1
+
+: jsr _memcpy ; And copy data
+
+ lda orgblock ; Free old block
+ ldx orgblock+1
+ jsr _free
+
+ lda newblock ; Return new block
+ ldx newblock+1
+ rts
diff --git a/libsrc/common/strcspn.s b/libsrc/common/strcspn.s
index 4bb01479a..418bf6ac2 100644
--- a/libsrc/common/strcspn.s
+++ b/libsrc/common/strcspn.s
@@ -7,13 +7,13 @@
.export _strcspn
.import popptr1, _strlen
- .importzp ptr1, ptr2, tmp1, tmp2
+ .importzp ptr1, ptr4, tmp1, tmp2
_strcspn:
- jsr _strlen ; get length in a/x and transfer s2 to ptr2
+ jsr _strlen ; get length in a/x and transfer s2 to ptr4
; Note: It does not make sense to
; have more than 255 test chars, so
- ; we don't support a high byte here! (ptr2+1 is
+ ; we don't support a high byte here! (ptr4+1 is
; also unchanged in strlen then (important!))
; -> the original implementation also
; ignored this case
@@ -38,7 +38,7 @@ checkNext:
iny
check: cpy tmp1 ; compare with length of test character string
beq endOfTestChars
- cmp (ptr2),y ; found matching char?
+ cmp (ptr4),y ; found matching char?
bne checkNext
leave: txa ; restore position of finding
diff --git a/libsrc/common/strdup.s b/libsrc/common/strdup.s
index 3ab07bda1..94f2cd338 100644
--- a/libsrc/common/strdup.s
+++ b/libsrc/common/strdup.s
@@ -1,85 +1,62 @@
;
; Ullrich von Bassewitz, 18.07.2000
+; Colin Leroy-Mira, 05.01.2024
;
; char* __fastcall__ strdup (const char* S);
;
-; Note: The code knowns which zero page locations are used by malloc.
+; Note: The code knowns which zero page locations are used by malloc,
+; memcpy and strlen.
;
- .importzp sp, tmp1, ptr4
- .import pushax, decsp4, incsp4
- .import _strlen, _malloc, _memcpy
+ .importzp ptr2, ptr3, ptr4, tmp1, tmp2, tmp3
+ .import _strlen_ptr4, _malloc, _memcpy, pushax
.export _strdup
.macpack cpu
- .macpack generic
_strdup:
+ ; Get length (and store source in ptr4)
+ sta ptr4
+ stx ptr4+1
+ stx tmp1 ; Backup high byte, which
+ jsr _strlen_ptr4 ; strlen may increment
-; Since we need some place to store the intermediate results, allocate a
-; stack frame. To make this somewhat more efficient, create the stackframe
-; as needed for the final call to the memcpy function.
-
- pha ; decsp will destroy A (but not X)
- jsr decsp4 ; Target/source
-
-; Store the pointer into the source slot
-
- ldy #1
- txa
- sta (sp),y
- pla
-.if (.cpu .bitand CPU_ISET_65SC02)
- sta (sp)
+ ; Add null byte for terminator
+.if (.cpu .bitand ::CPU_ISET_65SC02)
+ inc a
.else
- dey
- sta (sp),y
+ clc
+ adc #1
.endif
-
-; Get length of S (which is still in a/x)
-
- jsr _strlen
-
-; Calculate strlen(S)+1 (the space needed)
-
- add #1
- bcc @L1
+ bne :+
inx
-; Save the space we're about to allocate in ptr4
-
-@L1: sta ptr4
- stx ptr4+1
-
-; Allocate memory. _malloc will not use ptr4
+ ; Store length
+: sta tmp2
+ stx tmp3
+ ; Allocate memory
jsr _malloc
-; Store the result into the target stack slot
-
- ldy #2
- sta (sp),y ; Store low byte
- sta tmp1
- txa ; Get high byte
- iny
- sta (sp),y ; Store high byte
-
-; Check for a NULL pointer
-
- ora tmp1
+ ; Check for NULL
+ bne :+
+ cpx #$00
beq OutOfMemory
-; Copy the string. memcpy will return the target string which is exactly
-; what we need here. It will also drop the allocated stack frame.
+ ; Push dest
+: jsr pushax
+ ; Push source
lda ptr4
- ldx ptr4+1 ; Load size
- jmp _memcpy ; Copy string, drop stackframe
+ ldx tmp1
+ jsr pushax
-; Out of memory, return NULL (A = 0)
+ ; Push length
+ lda tmp2
+ ldx tmp3
+
+ ; Copy and return the dest pointer
+ jmp _memcpy
OutOfMemory:
- tax
- jmp incsp4 ; Drop stack frame
-
-
+ rts
diff --git a/libsrc/common/strlen.s b/libsrc/common/strlen.s
index 8d5bc20fc..c20ab78f9 100644
--- a/libsrc/common/strlen.s
+++ b/libsrc/common/strlen.s
@@ -2,19 +2,20 @@
; Ullrich von Bassewitz, 31.05.1998
;
; Note: strspn & strcspn call internally this function and rely on
-; the usage of only ptr2 here! Keep in mind when appling changes
+; the usage of only ptr4 here! Keep in mind when appling changes
; and check the other implementations too!
;
; size_t __fastcall__ strlen (const char* s);
;
- .export _strlen
- .importzp ptr2
+ .export _strlen, _strlen_ptr4
+ .importzp ptr4
.macpack cpu
_strlen:
- sta ptr2 ; Save s
- stx ptr2+1
+ sta ptr4 ; Save s
+ stx ptr4+1
+_strlen_ptr4:
.if (.cpu .bitand ::CPU_ISET_HUC6280)
clx
cly
@@ -27,11 +28,11 @@ _strlen:
.endif
.endif
-L1: lda (ptr2),y
+L1: lda (ptr4),y
beq L9
iny
bne L1
- inc ptr2+1
+ inc ptr4+1
inx
bne L1
diff --git a/libsrc/common/strspn.s b/libsrc/common/strspn.s
index 6fda716be..7e3f707d1 100644
--- a/libsrc/common/strspn.s
+++ b/libsrc/common/strspn.s
@@ -7,13 +7,13 @@
.export _strspn
.import popptr1, _strlen
- .importzp ptr1, ptr2, tmp1, tmp2
+ .importzp ptr1, ptr4, tmp1, tmp2
_strspn:
- jsr _strlen ; get length in a/x and transfer s2 to ptr2
+ jsr _strlen ; get length in a/x and transfer s2 to ptr4
; Note: It does not make sense to
; have more than 255 test chars, so
- ; we don't support a high byte here! (ptr2+1 is
+ ; we don't support a high byte here! (ptr4+1 is
; also unchanged in strlen then (important!))
; -> the original implementation also
; ignored this case
@@ -38,7 +38,7 @@ checkNext:
iny
check: cpy tmp1 ; compare with length of test character string
beq leave
- cmp (ptr2),y ; found matching char?
+ cmp (ptr4),y ; found matching char?
bne checkNext
foundTestChar:
diff --git a/libsrc/common/ungetc.s b/libsrc/common/ungetc.s
index 7e8c1f94f..c661600af 100644
--- a/libsrc/common/ungetc.s
+++ b/libsrc/common/ungetc.s
@@ -62,10 +62,6 @@
; File is not open or the character is invalid
error: lda #EINVAL
- jsr ___seterrno
- lda #$FF ; Return -1
- tax
- rts
+ jmp ___directerrno
.endproc
-
diff --git a/libsrc/conio/cputs.s b/libsrc/conio/cputs.s
index 41191a0b0..62e757b84 100644
--- a/libsrc/conio/cputs.s
+++ b/libsrc/conio/cputs.s
@@ -8,28 +8,46 @@
.export _cputsxy, _cputs
.import gotoxy, _cputc
.importzp ptr1, tmp1
+ .macpack cpu
_cputsxy:
sta ptr1 ; Save s for later
stx ptr1+1
jsr gotoxy ; Set cursor, pop x and y
+.if (.cpu .bitand CPU_ISET_65SC02)
+ bra L0 ; Same as cputs...
+.else
jmp L0 ; Same as cputs...
+.endif
_cputs: sta ptr1 ; Save s
stx ptr1+1
-L0: ldy #0
-L1: lda (ptr1),y
- beq L9 ; Jump if done
+
+.if (.cpu .bitand CPU_ISET_65SC02)
+
+L0: lda (ptr1) ; (5)
+ beq L9 ; (7) Jump if done
+ jsr _cputc ; (13) Output char, advance cursor
+ inc ptr1 ; (18) Bump low byte
+ bne L0 ; (20) Next char
+ inc ptr1+1 ; (25) Bump high byte
+ bne L0
+
+.else
+
+L0: ldy #0 ; (2)
+L1: lda (ptr1),y ; (7)
+ beq L9 ; (9) Jump if done
iny
- sty tmp1 ; Save offset
- jsr _cputc ; Output char, advance cursor
- ldy tmp1 ; Get offset
- bne L1 ; Next char
- inc ptr1+1 ; Bump high byte
+ sty tmp1 ; (14) Save offset
+ jsr _cputc ; (20) Output char, advance cursor
+ ldy tmp1 ; (23) Get offset
+ bne L1 ; (25) Next char
+ inc ptr1+1 ; (30) Bump high byte
bne L1
+.endif
+
; Done
L9: rts
-
-
diff --git a/libsrc/conio/vcprintf.s b/libsrc/conio/vcprintf.s
index 084efe089..595a2d2c5 100644
--- a/libsrc/conio/vcprintf.s
+++ b/libsrc/conio/vcprintf.s
@@ -10,7 +10,7 @@
.importzp sp, ptr1, ptr2, ptr3, tmp1
.macpack generic
-
+ .macpack cpu
.data
@@ -74,21 +74,40 @@ out: jsr popax ; count
; Loop outputting characters
+.if (.cpu .bitand CPU_ISET_65SC02)
+
@L1: dec outdesc+6
beq @L4
-@L2: ldy tmp1
- lda (ptr1),y
- iny
- bne @L3
- inc ptr1+1
-@L3: sty tmp1
- jsr _cputc
- jmp @L1
+@L2: lda (ptr1) ; (5)
+ inc ptr1 ; (10)
+ bne @L3 ; (12)
+ inc ptr1+1 ; (17)
+@L3: jsr _cputc ; (23)
+ bra @L1 ; (26)
@L4: dec outdesc+7
bne @L2
rts
+.else
+
+@L1: dec outdesc+6
+ beq @L4
+@L2: ldy tmp1 ; (3)
+ lda (ptr1),y ; (8)
+ iny ; (10)
+ bne @L3 ; (12)
+ inc ptr1+1 ; (17)
+@L3: sty tmp1 ; (20)
+ jsr _cputc ; (26)
+ jmp @L1 ; (32)
+
+@L4: dec outdesc+7
+ bne @L2
+ rts
+
+.endif
+
; ----------------------------------------------------------------------------
; vcprintf - formatted console i/o
;
diff --git a/libsrc/creativision/cputc.s b/libsrc/creativision/cputc.s
index 437b738b2..4389234c1 100644
--- a/libsrc/creativision/cputc.s
+++ b/libsrc/creativision/cputc.s
@@ -95,12 +95,6 @@ IS_UPPER:
BAD_CHAR:
jmp plot
-;-----------------------------------------------------------------------------
-; Initialize the conio subsystem. "INIT" segment is nothing special on the
-; Creativision, it is part of the "ROM" memory.
-
-.segment "INIT"
-
initconio:
lda #$0
sta SCREEN_PTR
diff --git a/libsrc/creativision/joy/creativision-stdjoy.s b/libsrc/creativision/joy/creativision-stdjoy.s
index 73b0c249f..43f9a2b40 100644
--- a/libsrc/creativision/joy/creativision-stdjoy.s
+++ b/libsrc/creativision/joy/creativision-stdjoy.s
@@ -59,7 +59,8 @@ JOY_RIGHT = $08
;
INSTALL: lda #JOY_ERR_OK
- ldx #>$0000
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Fall through
; ------------------------------------------------------------------------
diff --git a/libsrc/cx16/joy/cx16-std.s b/libsrc/cx16/joy/cx16-std.s
index a40fcb061..5def55511 100644
--- a/libsrc/cx16/joy/cx16-std.s
+++ b/libsrc/cx16/joy/cx16-std.s
@@ -55,8 +55,9 @@ JOY_COUNT = $05 ; Number of joysticks we support
; Must return a JOY_ERR_xx code in .XA .
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/cx16/mou/cx16-std.s b/libsrc/cx16/mou/cx16-std.s
index 3af7d2eb3..f211815de 100644
--- a/libsrc/cx16/mou/cx16-std.s
+++ b/libsrc/cx16/mou/cx16-std.s
@@ -139,7 +139,8 @@ INSTALL:
; Done, return zero
- ldx #>MOUSE_ERR_OK
+ ldx #MOUSE_ERR_OK
+ .assert MOUSE_ERR_OK = 0, error
txa
rts
@@ -300,8 +301,8 @@ INFO: jsr BUTTONS ; Will not touch ptr1
; specific data in ptr1, and the ioctl code in A.
; Must return an error code in .XA .
-IOCTL: lda #MOUSE_ERR_INV_IOCTL
+IOCTL: lda #MOUSE_ERR_INV_IOCTL ; We don't support ioctls, for now
+ ldx #0 ; return value is char
; rts ; Fall through
;----------------------------------------------------------------------------
diff --git a/libsrc/gamate/joy/gamate-stdjoy.s b/libsrc/gamate/joy/gamate-stdjoy.s
index 8f927cdf5..514f92db4 100644
--- a/libsrc/gamate/joy/gamate-stdjoy.s
+++ b/libsrc/gamate/joy/gamate-stdjoy.s
@@ -47,8 +47,9 @@ JOY_COUNT = 1 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
diff --git a/libsrc/geos-cbm/emd/geos-vdc.s b/libsrc/geos-cbm/emd/geos-vdc.s
index 27316e1a0..2e7d19c03 100644
--- a/libsrc/geos-cbm/emd/geos-vdc.s
+++ b/libsrc/geos-cbm/emd/geos-vdc.s
@@ -125,8 +125,9 @@ INSTALL:
pla
sta $01
plp
- lda #EM_ERR_OK
+ lda #EM_ERR_OK
+ .assert EM_ERR_OK = 0, error
+ tax
rts
test64k:
diff --git a/libsrc/geos-cbm/joy/geos-stdjoy.s b/libsrc/geos-cbm/joy/geos-stdjoy.s
index 2787cb594..a3fd4ffc8 100644
--- a/libsrc/geos-cbm/joy/geos-stdjoy.s
+++ b/libsrc/geos-cbm/joy/geos-stdjoy.s
@@ -53,8 +53,9 @@ JOY_COUNT = 2 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/geos-common/graph/bitotherclip.s b/libsrc/geos-common/graph/bitotherclip.s
index 020139da8..fba00d966 100644
--- a/libsrc/geos-common/graph/bitotherclip.s
+++ b/libsrc/geos-common/graph/bitotherclip.s
@@ -6,7 +6,7 @@
; void BitOtherClip (void *proc1, void* proc2, char skipl, char skipr, int skipy,
; struct iconpic *myGfx);
-; both proc1, proc2 should be: char __fastcall something (void);
+; both proc1, proc2 should be: char foo (void);
; proc1 is called before reading a byte (.A returns next data)
; proc2 is called before reading each byte which is not pattern (code >219)
diff --git a/libsrc/joystick/joy_unload.s b/libsrc/joystick/joy_unload.s
index 25d54ff02..f52b7a2c1 100644
--- a/libsrc/joystick/joy_unload.s
+++ b/libsrc/joystick/joy_unload.s
@@ -10,7 +10,7 @@
.include "modload.inc"
.import joy_clear_ptr
- .import return0
+ .import return0, return1
@@ -31,7 +31,6 @@ _joy_unload:
jmp return0 ; Return JOY_ERR_OK
no_driver:
- tax ; X = 0
pla ; Remove pushed junk
- lda #JOY_ERR_NO_DRIVER
- rts
+ .assert JOY_ERR_NO_DRIVER = 1, error
+ jmp return1 ; Return JOY_ERR_NO_DRIVER
diff --git a/libsrc/kim1/crt0.s b/libsrc/kim1/crt0.s
new file mode 100644
index 000000000..906b3b980
--- /dev/null
+++ b/libsrc/kim1/crt0.s
@@ -0,0 +1,45 @@
+;
+; Startup code for cc65 (KIM-1 version)
+;
+
+ .export _init, _exit
+ .export __STARTUP__ : absolute = 1 ; Mark as startup
+
+ .import _main
+ .import initlib, donelib, copydata, zerobss
+ .import __RAM_START__, __RAM_SIZE__ ; Linker generated
+ .import __STACKSIZE__ ; Linker generated
+
+ .include "zeropage.inc"
+ .include "kim1.inc"
+
+
+; Place the startup code in a special segment
+
+.segment "STARTUP"
+
+
+; A little light housekeeping
+
+_init: cld ; Clear decimal mode
+
+; Set cc65 argument stack pointer
+
+ lda #<(__RAM_START__ + __RAM_SIZE__)
+ sta sp
+ lda #>(__RAM_START__ + __RAM_SIZE__)
+ sta sp+1
+
+; Initialize memory storage
+
+ jsr zerobss ; Clear BSS segment
+ jsr copydata ; Initialize DATA segment
+ jsr initlib ; Run constructors
+
+; Call main()
+
+ jsr _main
+
+; Back from main (this is also the _exit entry). Jumps to the KIM-1 monitor.
+
+_exit: jmp START
diff --git a/libsrc/kim1/ctype.s b/libsrc/kim1/ctype.s
new file mode 100644
index 000000000..1301965eb
--- /dev/null
+++ b/libsrc/kim1/ctype.s
@@ -0,0 +1,5 @@
+; Character specification table.
+;
+; uses the "common" definition
+
+ .include "ctype_common.inc"
diff --git a/libsrc/kim1/getkey.s b/libsrc/kim1/getkey.s
new file mode 100644
index 000000000..b36cd4b4c
--- /dev/null
+++ b/libsrc/kim1/getkey.s
@@ -0,0 +1,18 @@
+;
+; int __fastcall__ getkey();
+;
+
+.include "kim1.inc"
+
+.import popa
+
+.export _getkey
+
+.proc _getkey
+
+ jsr KEYIN ; Open up keyboard channel
+ jsr GETKEY ; Get key code
+ ldx #0 ; MSB of return value is zero
+ rts
+
+.endproc
diff --git a/libsrc/kim1/read.s b/libsrc/kim1/read.s
new file mode 100644
index 000000000..dd178ee98
--- /dev/null
+++ b/libsrc/kim1/read.s
@@ -0,0 +1,46 @@
+;
+; int __fastcall__ read (int fd, void* buf, unsigned count);
+;
+
+.include "kim1.inc"
+
+.import popax, popptr1
+.importzp ptr1, ptr2, ptr3
+
+.export _read
+
+.proc _read
+
+ sta ptr3
+ stx ptr3+1 ; Count in ptr3
+ inx
+ stx ptr2+1 ; Increment and store in ptr2
+ tax
+ inx
+ stx ptr2
+ jsr popptr1 ; Buffer address in ptr1
+ jsr popax
+
+begin: dec ptr2
+ bne getch
+ dec ptr2+1
+ beq done ; If buffer full, return
+
+getch: jsr INTCHR ; Get character using Monitor ROM call
+ and #$7F ; Clear top bit
+ cmp #$0D ; Check for '\r'
+ bne putch ; ...if CR character
+ lda #$0A ; Replace with '\n'
+
+putch: ldy #$00 ; Put char into return buffer
+ sta (ptr1),y
+ inc ptr1 ; Increment pointer
+ bne begin
+ inc ptr1+1
+ bne begin
+
+done: lda ptr3
+ ldx ptr3+1
+ rts ; Return count
+
+.endproc
diff --git a/libsrc/kim1/scandisplay.s b/libsrc/kim1/scandisplay.s
new file mode 100644
index 000000000..768adb2b9
--- /dev/null
+++ b/libsrc/kim1/scandisplay.s
@@ -0,0 +1,20 @@
+;
+; void __fastcall__ scandisplay(unsigned char left, unsigned char middle, unsigned char right);
+;
+
+.include "kim1.inc"
+
+.import popa
+
+.export _scandisplay
+
+.proc _scandisplay
+
+ sta $F9 ; Rightmost display data
+ jsr popa
+ sta $FA ; Middle display data
+ jsr popa
+ sta $FB ; Leftmost display data
+ jmp SCANDS
+
+.endproc
diff --git a/libsrc/kim1/tapeio.s b/libsrc/kim1/tapeio.s
new file mode 100644
index 000000000..4a16d6b9c
--- /dev/null
+++ b/libsrc/kim1/tapeio.s
@@ -0,0 +1,39 @@
+;
+; int __fastcall__ loadt (unsigned char id);
+; int __fastcall__ dumpt (unsigned char id, void* start_addr, void* end_addr);
+;
+
+.include "kim1.inc"
+
+.import popa, popax, return0, return1
+
+.export _loadt, _dumpt
+
+.segment "CODE"
+
+.proc _loadt: near
+
+ sta ID ; Tape record ID to P1L
+ jsr LOADT ; Read data from tape
+ bcs error
+ jmp return0 ; Return 0 if sucessful
+error: jmp return1 ; or 1 if not
+
+.endproc
+
+.proc _dumpt: near
+
+ sta EAL ; End address
+ stx EAH
+ jsr popax
+ sta SAL ; Start address
+ stx SAH
+ jsr popa
+ sta ID ; Tape Record ID
+ ldx #$00
+ jsr DUMPT ; Write data to tape
+ bcs error
+ jmp return0 ; Return 0 if sucessful
+error: jmp return1 ; or 1 if not
+
+.endproc
diff --git a/libsrc/kim1/write.s b/libsrc/kim1/write.s
new file mode 100644
index 000000000..96bcc91d1
--- /dev/null
+++ b/libsrc/kim1/write.s
@@ -0,0 +1,48 @@
+;
+; int __fastcall__ write (int fd, const void* buf, int count);
+;
+
+.include "kim1.inc"
+
+.import popax, popptr1
+.importzp ptr1, ptr2, ptr3
+
+.export _write
+
+.proc _write
+
+ sta ptr3
+ stx ptr3+1 ; Count in ptr3
+ inx
+ stx ptr2+1 ; Increment and store in ptr2
+ tax
+ inx
+ stx ptr2
+ jsr popptr1 ; Buffer address in ptr1
+ jsr popax
+
+begin: dec ptr2
+ bne outch
+ dec ptr2+1
+ beq done
+
+outch: ldy #0
+ lda (ptr1),y
+ pha ; Save A (changed by OUTCHR)
+ jsr OUTCHR ; Send character using Monitor call
+ pla ; Restore A
+ cmp #$0A ; Check for '\n'
+ bne next ; ...if LF character
+ lda #$0D ; Add a carriage return
+ jsr OUTCHR
+
+next: inc ptr1
+ bne begin
+ inc ptr1+1
+ jmp begin
+
+done: lda ptr3
+ ldx ptr3+1
+ rts ; Return count
+
+.endproc
diff --git a/libsrc/lynx/crt0.s b/libsrc/lynx/crt0.s
index 238a2c99d..030f523e9 100644
--- a/libsrc/lynx/crt0.s
+++ b/libsrc/lynx/crt0.s
@@ -68,7 +68,7 @@ MikeyInitData: .byte $9e,$18,$68,$1f,$00,$00,$00,$00,$00,$ff,$1a,$1b,$04,$0d,$2
; Disable the TX/RX IRQ; set to 8E1.
- lda #%00011101
+ lda #PAREN|RESETERR|TXOPEN|PAREVEN ; #%00011101
sta SERCTL
; Clear all pending interrupts.
diff --git a/libsrc/lynx/extzp.inc b/libsrc/lynx/extzp.inc
index 2b0f68701..7103ff5b6 100644
--- a/libsrc/lynx/extzp.inc
+++ b/libsrc/lynx/extzp.inc
@@ -12,10 +12,6 @@
.global __iodir: zp
.global __viddma: zp
.global __sprsys: zp
- .global _abc_score_ptr0: zp
- .global _abc_score_ptr1: zp
- .global _abc_score_ptr2: zp
- .global _abc_score_ptr3: zp
.global _FileEntry: zp
.global _FileStartBlock: zp
.global _FileBlockOffset: zp
@@ -25,6 +21,3 @@
.global _FileCurrBlock: zp
.global _FileBlockByte: zp
.global _FileDestPtr: zp
-
-
-
diff --git a/libsrc/lynx/extzp.s b/libsrc/lynx/extzp.s
index f22cfaefb..df53c3d9a 100644
--- a/libsrc/lynx/extzp.s
+++ b/libsrc/lynx/extzp.s
@@ -16,13 +16,6 @@ __iodir: .res 1
__viddma: .res 1
__sprsys: .res 1
-; ------------------------------------------------------------------------
-; sound effect pointers for multitimbral Lynx music hardware
-_abc_score_ptr0: .res 2
-_abc_score_ptr1: .res 2
-_abc_score_ptr2: .res 2
-_abc_score_ptr3: .res 2
-
; ------------------------------------------------------------------------
; Filesystem variables needed for reading stuff from the Lynx cart
_FileEntry: ; The file directory entry is 8 bytes
@@ -35,4 +28,3 @@ _FileFileLen: .res 2
_FileCurrBlock: .res 1
_FileBlockByte: .res 2
_FileDestPtr: .res 2
-
diff --git a/libsrc/lynx/joy/lynx-stdjoy.s b/libsrc/lynx/joy/lynx-stdjoy.s
index c81a97dbf..45eb8ab4e 100644
--- a/libsrc/lynx/joy/lynx-stdjoy.s
+++ b/libsrc/lynx/joy/lynx-stdjoy.s
@@ -58,8 +58,9 @@ JOY_COUNT = 1 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/lynx/lseek.s b/libsrc/lynx/lseek.s
index 4b4f94d7c..04d816945 100644
--- a/libsrc/lynx/lseek.s
+++ b/libsrc/lynx/lseek.s
@@ -18,7 +18,7 @@
.import ldeaxysp, decsp2, pushax, incsp8
.import tosandeax,decax1,tosdiveax,axlong,ldaxysp
.import lynxskip0, lynxblock,tosasreax
- .import __BLOCKSIZE__
+ .import __BANK0BLOCKSIZE__
.importzp _FileCurrBlock
.segment "CODE"
@@ -32,15 +32,15 @@
jsr ldeaxysp
jsr pusheax
ldx #$00
- lda #<(__BLOCKSIZE__/1024 + 9)
+ lda #<(__BANK0BLOCKSIZE__/1024 + 9)
jsr tosasreax
sta _FileCurrBlock
jsr lynxblock
ldy #$05
jsr ldeaxysp
jsr pusheax
- lda #<(__BLOCKSIZE__-1)
- ldx #>(__BLOCKSIZE__-1)
+ lda #<(__BANK0BLOCKSIZE__-1)
+ ldx #>(__BANK0BLOCKSIZE__-1)
jsr axlong
jsr tosandeax
eor #$FF
diff --git a/libsrc/lynx/lynx-cart.s b/libsrc/lynx/lynx-cart.s
index 94edff677..d1f3e33eb 100644
--- a/libsrc/lynx/lynx-cart.s
+++ b/libsrc/lynx/lynx-cart.s
@@ -17,7 +17,7 @@
.include "extzp.inc"
.export lynxskip0, lynxread0
.export lynxblock
- .import __BLOCKSIZE__
+ .import __BANK0BLOCKSIZE__
.code
@@ -88,7 +88,7 @@ lynxblock:
lda __iodat
sta IODAT
stz _FileBlockByte
- lda #<($100-(>__BLOCKSIZE__))
+ lda #<($100-(>__BANK0BLOCKSIZE__))
sta _FileBlockByte+1
ply
plx
diff --git a/libsrc/lynx/ser/lynx-comlynx.s b/libsrc/lynx/ser/lynx-comlynx.s
index ded862eaa..c4ae3d5b6 100644
--- a/libsrc/lynx/ser/lynx-comlynx.s
+++ b/libsrc/lynx/ser/lynx-comlynx.s
@@ -73,10 +73,16 @@ SER_UNINSTALL:
; Must return an SER_ERR_xx code in a/x.
SER_CLOSE:
- ; Disable interrupts
+ ; Disable interrupts and stop timer 4 (serial)
+ lda #TXOPEN|RESETERR
+ sta SERCTL
+ stz TIM4CTLA ; Disable count and no reload
+ stz SerialStat ; Reset status
+
; Done, return an error code
- lda #SER_ERR_OK
+ lda #SER_ERR_OK
+ .assert SER_ERR_OK = 0, error
+ tax
rts
;----------------------------------------------------------------------------
@@ -107,17 +113,17 @@ SER_OPEN:
stz TxPtrIn
stz TxPtrOut
- ; clock = 8 * 15625
- lda #%00011000
- sta TIM4CTLA
ldy #SER_PARAMS::BAUDRATE
lda (ptr1),y
+ ; Source period is 1 us
+ ldy #%00011000 ; ENABLE_RELOAD|ENABLE_COUNT|AUD_1
+
ldx #1
cmp #SER_BAUD_62500
beq setbaudrate
- ldx #2
+ ldx #3
cmp #SER_BAUD_31250
beq setbaudrate
@@ -133,6 +139,10 @@ SER_OPEN:
cmp #SER_BAUD_2400
beq setbaudrate
+ ldx #68
+ cmp #SER_BAUD_1800
+ beq setbaudrate
+
ldx #103
cmp #SER_BAUD_1200
beq setbaudrate
@@ -141,65 +151,22 @@ SER_OPEN:
cmp #SER_BAUD_600
beq setbaudrate
- ; clock = 6 * 15625
- ldx #%00011010
- stx TIM4CTLA
+ ; Source period is 8 us
+ ldy #%00011011 ; ENABLE_RELOAD|ENABLE_COUNT|AUD_8
- ldx #12
- cmp #SER_BAUD_7200
- beq setbaudrate
-
- ldx #25
- cmp #SER_BAUD_3600
- beq setbaudrate
-
- ldx #207
- stx TIM4BKUP
-
- ; clock = 4 * 15625
- ldx #%00011100
+ ldx #51
cmp #SER_BAUD_300
- beq setprescaler
-
- ; clock = 6 * 15625
- ldx #%00011110
- cmp #SER_BAUD_150
- beq setprescaler
-
- ; clock = 1 * 15625
- ldx #%00011111
- stx TIM4CTLA
- cmp #SER_BAUD_75
- beq baudsuccess
-
- ldx #141
- cmp #SER_BAUD_110
beq setbaudrate
- ; clock = 2 * 15625
- ldx #%00011010
- stx TIM4CTLA
- ldx #68
- cmp #SER_BAUD_1800
- beq setbaudrate
-
- ; clock = 6 * 15625
- ldx #%00011110
- stx TIM4CTLA
- ldx #231
- cmp #SER_BAUD_134_5
- beq setbaudrate
-
- lda #SER_ERR_BAUD_UNAVAIL
+ lda #SER_ERR_BAUD_UNAVAIL
+ ldx #0 ; return value is char
rts
-setprescaler:
- stx TIM4CTLA
- bra baudsuccess
+
setbaudrate:
+ sty TIM4CTLA
stx TIM4BKUP
-baudsuccess:
- ldx #TxOpenColl|ParEven
+
+ ldx #TXOPEN|PAREVEN
stx contrl
ldy #SER_PARAMS::DATABITS ; Databits
lda (ptr1),y
@@ -217,15 +184,15 @@ baudsuccess:
beq checkhs
cmp #SER_PAR_SPACE
bne @L0
- ldx #TxOpenColl
+ ldx #TXOPEN
stx contrl
bra checkhs
@L0:
- ldx #TxParEnable|TxOpenColl|ParEven
+ ldx #PAREN|TXOPEN|PAREVEN
stx contrl
cmp #SER_PAR_EVEN
beq checkhs
- ldx #TxParEnable|TxOpenColl
+ ldx #PAREN|TXOPEN
stx contrl
checkhs:
ldx contrl
@@ -233,17 +200,30 @@ checkhs:
ldy #SER_PARAMS::HANDSHAKE ; Handshake
lda (ptr1),y
cmp #SER_HS_NONE
+ beq redeye_ok
+ cmp #SER_HS_SW ; Software handshake will check for connected redeye
bne invparameter
+
+ lda IODAT
+ and #NOEXP ; Check if redeye bit flag is unset
+ beq redeye_ok
+ lda #SER_ERR_NO_DEVICE ; ComLynx cable is not inserted
+ ldx #0
+ rts
+
+redeye_ok:
lda SERDAT
lda contrl
- ora #RxIntEnable|ResetErr
+ ora #RXINTEN|RESETERR ; Turn on interrupts for receive
sta SERCTL
- lda #SER_ERR_OK
+ lda #SER_ERR_OK
+ .assert SER_ERR_OK = 0, error
+ tax
rts
+
invparameter:
- lda #SER_ERR_INIT_FAILED
+ lda #SER_ERR_INIT_FAILED
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -255,15 +235,15 @@ SER_GET:
lda RxPtrIn
cmp RxPtrOut
bne GetByte
- lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #0 ; return value is char
rts
GetByte:
ldy RxPtrOut
lda RxBuffer,y
inc RxPtrOut
+ sta (ptr1)
ldx #$00
- sta (ptr1,x)
txa ; Return code = 0
rts
@@ -277,26 +257,29 @@ SER_PUT:
ina
cmp TxPtrOut
bne PutByte
- lda #SER_ERR_OVERFLOW
+
+ lda #SER_ERR_OVERFLOW
+ ldx #0 ; return value is char
rts
+
PutByte:
ldy TxPtrIn
txa
sta TxBuffer,y
inc TxPtrIn
- bit TxDone
- bmi @L1
+ bit TxDone ; Check bit 7 of TxDone (TXINTEN)
+ bmi @L1 ; Was TXINTEN already set?
php
sei
- lda contrl
- ora #TxIntEnable|ResetErr
- sta SERCTL ; Allow TX-IRQ to hang RX-IRQ
+ lda contrl ; contrl does not include RXINTEN setting
+ ora #TXINTEN|RESETERR
+ sta SERCTL ; Allow TX-IRQ to hang RX-IRQ (no receive while transmitting)
sta TxDone
- plp
+ plp ; Restore processor and interrupt enable
@L1:
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -339,48 +322,56 @@ SER_IRQ:
@L0:
bit TxDone
bmi @tx_irq ; Transmit in progress
- ldx SERDAT
- lda SERCTL
- and #RxParityErr|RxOverrun|RxFrameErr|RxBreak
- beq @rx_irq
+
+ ldx SERDAT ; Read received data
+ lda contrl
+ and #PAREN ; Parity enabled implies SER_PAR_EVEN or SER_PAR_ODD
+ tay
+ ora #OVERRUN|FRAMERR|RXBRK
+ and SERCTL ; Check presence of relevant error flags in SERCTL
+
+ beq @rx_irq ; No errors so far
+
tsb SerialStat ; Save error condition
- bit #RxBreak
+ bit #RXBRK ; Check for break signal
beq @noBreak
+
stz TxPtrIn ; Break received - drop buffers
stz TxPtrOut
stz RxPtrIn
stz RxPtrOut
@noBreak:
- lda contrl
- ora #RxIntEnable|ResetErr
- sta SERCTL
- lda #$10
- sta INTRST
- bra @IRQexit
+ bra @exit0
+
@rx_irq:
+ tya
+ bne @2 ; Parity was enabled so no marker bit check needed
+
lda contrl
- ora #RxIntEnable|ResetErr
- sta SERCTL
+ eor SERCTL ; Should match current parity bit
+ and #PARBIT ; Check for mark or space value
+ bne @exit0
+
+@2:
txa
ldx RxPtrIn
sta RxBuffer,x
txa
inx
-@cont0:
cpx RxPtrOut
beq @1
stx RxPtrIn
- lda #SERIAL_INTERRUPT
- sta INTRST
bra @IRQexit
@1:
sta RxPtrIn
lda #$80
tsb SerialStat
+ bra @exit0
+
@tx_irq:
- ldx TxPtrOut ; Has all bytes been sent?
+ ldx TxPtrOut ; Have all bytes been sent?
cpx TxPtrIn
beq @allSent
@@ -390,24 +381,24 @@ SER_IRQ:
@exit1:
lda contrl
- ora #TxIntEnable|ResetErr
+ ora #TXINTEN|RESETERR
sta SERCTL
- lda #SERIAL_INTERRUPT
- sta INTRST
bra @IRQexit
@allSent:
lda SERCTL ; All bytes sent
- bit #TxEmpty
+ bit #TXEMPTY
beq @exit1
bvs @exit1
stz TxDone
+
+@exit0:
lda contrl
- ora #RxIntEnable|ResetErr
+ ora #RXINTEN|RESETERR ; Re-enable receive interrupt
sta SERCTL
+@IRQexit:
lda #SERIAL_INTERRUPT
sta INTRST
-@IRQexit:
clc
rts
diff --git a/libsrc/lynx/ser_stat_stddrv.s b/libsrc/lynx/ser_stat_stddrv.s
new file mode 100644
index 000000000..37f481c47
--- /dev/null
+++ b/libsrc/lynx/ser_stat_stddrv.s
@@ -0,0 +1,14 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .import _lynx_comlynx_ser
+
+.rodata
+
+_ser_static_stddrv := _lynx_comlynx_ser
diff --git a/libsrc/lynx/uploader.s b/libsrc/lynx/uploader.s
index f16a1721a..5ce21b489 100644
--- a/libsrc/lynx/uploader.s
+++ b/libsrc/lynx/uploader.s
@@ -33,21 +33,21 @@ loop1:
cont1:
jsr read_byte
sta (load_ptr2),y
- sta PALETTE ; feedback ;-)
+ sta PALETTE + 1 ; feedback ;-)
iny
bne loop1
inc load_ptr2+1
bra loop1
read_byte:
- bit SERCTL
+ bit SERCTL ; Check for RXRDY ($40)
bvc read_byte
lda SERDAT
rts
_UpLoaderIRQ:
lda INTSET
- and #$10
+ and #SERIAL_INTERRUPT
bne @L0
clc
rts
@@ -69,6 +69,8 @@ again:
; last action : clear interrupt
;
exit:
+ lda #SERIAL_INTERRUPT
+ sta INTRST
clc
rts
diff --git a/libsrc/mouse/mouse_unload.s b/libsrc/mouse/mouse_unload.s
index 8c9018484..ecd7846ab 100644
--- a/libsrc/mouse/mouse_unload.s
+++ b/libsrc/mouse/mouse_unload.s
@@ -8,7 +8,7 @@
.include "mouse-kernel.inc"
.include "modload.inc"
- .import return0
+ .import return0, return1
@@ -29,7 +29,6 @@ _mouse_unload:
jmp return0 ; Return MOUSE_ERR_OK
no_driver:
- tax ; X = 0
pla ; Remove pushed junk
- lda #load_addr
sta load
@@ -57,9 +56,9 @@ LINEDIST = $20 ; Offset in video RAM between two lines
stx count+1 ; save size with each byte incremented separately
L1: dec count
- bnz L2
+ bne L2
dec count+1
- bze L3
+ beq L3
L2: jsr GETCHAR ; (doesn't change .Y)
sta (load),y
@@ -70,12 +69,12 @@ L2: jsr GETCHAR ; (doesn't change .Y)
lsr a
and #8 - 1
ora #$10 ; eight arrow characters
- sta SCRNBASE + FIRSTVISC + 2 * LINEDIST + 11
+ sta C1P_SCR_BASE + FIRSTVISC + 2 * LINEDIST + 11
iny
- bnz L1
+ bne L1
inc load+1
- bnz L1 ; branch always
+ bne L1 ; branch always
L3: jmp load_addr
@@ -112,18 +111,15 @@ CR = $0D
hex2 >load_addr
.byte CR, "85", CR, "08", CR
.byte "86", CR, "09", CR
- .byte "A9", CR
- hex2 load_size
- .byte CR, "49", CR, "FF", CR
- .byte "85", CR, "0B", CR
-
- .byte "E6", CR, "0A", CR
+ .byte "A2", CR
+ hex2 (load_size) + 1
+ .byte CR, "86", CR, "0B", CR
+ .byte "C6", CR, "0A", CR
.byte "D0", CR, "04", CR
- .byte "E6", CR, "0B", CR
+ .byte "C6", CR, "0B", CR
.byte "F0", CR, "16", CR
.byte "20", CR, "BF", CR, "FF", CR
.byte "91", CR, "08", CR
diff --git a/libsrc/osic1p/extra/screen-c1p-48x12.s b/libsrc/osic1p/extra/screen-c1p-48x12.s
new file mode 100644
index 000000000..91a61338b
--- /dev/null
+++ b/libsrc/osic1p/extra/screen-c1p-48x12.s
@@ -0,0 +1,16 @@
+;
+; Implementation of screen-layout related functions for Challenger 1P in 48x12 mode.
+;
+
+ .include "../osiscreen.inc"
+
+C1P_SCR_BASE := $D000 ; Base of C1P video RAM
+C1P_VRAM_SIZE = $0400 ; Size of C1P video RAM (1 kB)
+C1P_SCR_WIDTH = $30 ; Screen width
+C1P_SCR_HEIGHT = $0C ; Screen height
+C1P_SCR_FIRSTCHAR = $8B ; Offset of cursor position (0, 0) from base
+ ; of video RAM
+C1P_SCROLL_DIST = $40 ; Memory distance for scrolling by one line
+
+osi_screen_funcs C1P_SCR_BASE, C1P_VRAM_SIZE, C1P_SCR_FIRSTCHAR, \
+ C1P_SCR_WIDTH, C1P_SCR_HEIGHT, C1P_SCROLL_DIST
diff --git a/libsrc/pce/joy/pce-stdjoy.s b/libsrc/pce/joy/pce-stdjoy.s
index 2de3d0c4c..dc8576c87 100644
--- a/libsrc/pce/joy/pce-stdjoy.s
+++ b/libsrc/pce/joy/pce-stdjoy.s
@@ -50,8 +50,9 @@ padbuffer: .res JOY_COUNT
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
diff --git a/libsrc/pet/joy/pet-ptvjoy.s b/libsrc/pet/joy/pet-ptvjoy.s
index c098072fb..ee14c95c8 100644
--- a/libsrc/pet/joy/pet-ptvjoy.s
+++ b/libsrc/pet/joy/pet-ptvjoy.s
@@ -51,8 +51,9 @@ JOY_COUNT = 2 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/plus4/joy/plus4-stdjoy.s b/libsrc/plus4/joy/plus4-stdjoy.s
index e8e85fedc..86f080dae 100644
--- a/libsrc/plus4/joy/plus4-stdjoy.s
+++ b/libsrc/plus4/joy/plus4-stdjoy.s
@@ -58,8 +58,9 @@ JOY_COUNT = 2 ; Number of joysticks we support
;
INSTALL:
- lda #JOY_ERR_OK
+ lda #JOY_ERR_OK
+ .assert JOY_ERR_OK = 0, error
+ tax
; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
diff --git a/libsrc/plus4/ser/plus4-stdser.s b/libsrc/plus4/ser/plus4-stdser.s
index bb44a4cf9..77445c7a2 100644
--- a/libsrc/plus4/ser/plus4-stdser.s
+++ b/libsrc/plus4/ser/plus4-stdser.s
@@ -157,8 +157,9 @@ SER_CLOSE:
; Done, return an error code
- lda #SER_ERR_INIT_FAILED
+ lda #SER_ERR_INIT_FAILED
+ ldx #0 ; return value is char
rts
; Baud rate not available
InvBaud:
- lda #SER_ERR_BAUD_UNAVAIL
+ lda #SER_ERR_BAUD_UNAVAIL
+ ldx #0 ; return value is char
rts
;----------------------------------------------------------------------------
@@ -250,19 +252,14 @@ InvBaud:
;
SER_GET:
- ldx SendFreeCnt ; Send data if necessary
- inx ; X == $FF?
- beq @L1
- lda #$00
- jsr TryToSend
; Check for buffer empty
-@L1: lda RecvFreeCnt ; (25)
+ lda RecvFreeCnt ; (25)
cmp #$ff
bne @L2
- lda #SER_ERR_NO_DATA
+ lda #SER_ERR_NO_DATA
+ ldx #0 ; return value is char
rts
; Check for flow stopped & enough free: release flow control
@@ -298,27 +295,30 @@ SER_PUT:
; Try to send
ldx SendFreeCnt
- inx ; X = $ff?
+ cpx #$ff ; Nothing to flush
beq @L2
pha
lda #$00
jsr TryToSend
pla
-; Put byte into send buffer & send
+; Reload SendFreeCnt after TryToSend
-@L2: ldx SendFreeCnt
- bne @L3
- lda #SER_ERR_INV_IOCTL
+ lda #SER_ERR_INV_IOCTL ; We don't support ioclts for now
+ ldx #0 ; return value is char
rts ; Run into IRQ instead
;----------------------------------------------------------------------------
@@ -383,25 +384,25 @@ SER_IRQ:
sta tmp1 ; Remember tryHard flag
@L0: lda SendFreeCnt
cmp #$ff
- beq @L3 ; Bail out
+ beq @L2 ; Bail out
; Check for flow stopped
@L1: lda Stopped
- bne @L3 ; Bail out
+ bne @L2 ; Bail out
; Check that swiftlink is ready to send
-@L2: lda ACIA_STATUS
+ lda ACIA_STATUS
and #$10
- bne @L4
+ bne @L3
bit tmp1 ;keep trying if must try hard
- bmi @L0
-@L3: rts
+ bmi @L1
+@L2: rts
; Send byte and try again
-@L4: ldx SendHead
+@L3: ldx SendHead
lda SendBuf,x
sta ACIA_DATA
inc SendHead
diff --git a/libsrc/plus4/ser_stat_stddrv.s b/libsrc/plus4/ser_stat_stddrv.s
new file mode 100644
index 000000000..f35b09232
--- /dev/null
+++ b/libsrc/plus4/ser_stat_stddrv.s
@@ -0,0 +1,14 @@
+;
+; Address of the static standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const void ser_static_stddrv[];
+;
+
+ .export _ser_static_stddrv
+ .import _plus4_stdser_ser
+
+.rodata
+
+_ser_static_stddrv := _plus4_stdser_ser
diff --git a/libsrc/plus4/ser_stddrv.s b/libsrc/plus4/ser_stddrv.s
new file mode 100644
index 000000000..f308d5f40
--- /dev/null
+++ b/libsrc/plus4/ser_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard serial driver
+;
+; Oliver Schmidt, 2022-12-22
+;
+; const char ser_stddrv[];
+;
+
+ .export _ser_stddrv
+
+.rodata
+
+_ser_stddrv: .asciiz "plus4-stdser.ser"
diff --git a/libsrc/rp6502/close.c b/libsrc/rp6502/close.c
new file mode 100644
index 000000000..dd7e38115
--- /dev/null
+++ b/libsrc/rp6502/close.c
@@ -0,0 +1,8 @@
+#include
+#include
+
+int __fastcall__ close (int fd)
+{
+ ria_set_ax (fd);
+ return ria_call_int_errno (RIA_OP_CLOSE);
+}
diff --git a/libsrc/rp6502/codepage.c b/libsrc/rp6502/codepage.c
new file mode 100644
index 000000000..e28726f04
--- /dev/null
+++ b/libsrc/rp6502/codepage.c
@@ -0,0 +1,6 @@
+#include
+
+int __fastcall__ codepage (void)
+{
+ return ria_call_int (RIA_OP_CODEPAGE);
+}
diff --git a/libsrc/rp6502/crt0.s b/libsrc/rp6502/crt0.s
new file mode 100644
index 000000000..165ecf0a2
--- /dev/null
+++ b/libsrc/rp6502/crt0.s
@@ -0,0 +1,51 @@
+;
+; 2023, Rumbledethumps
+;
+; crt0.s
+
+.export _init, _exit
+.import _main
+
+.export __STARTUP__ : absolute = 1
+.import __RAM_START__, __RAM_SIZE__
+
+.import copydata, zerobss, initlib, donelib
+
+.include "rp6502.inc"
+.include "zeropage.inc"
+
+.segment "STARTUP"
+
+; Essential 6502 startup the CPU doesn't do
+_init:
+ ldx #$FF
+ txs
+ cld
+
+; Set cc65 argument stack pointer
+ lda #<(__RAM_START__ + __RAM_SIZE__)
+ sta sp
+ lda #>(__RAM_START__ + __RAM_SIZE__)
+ sta sp+1
+
+; Initialize memory storage
+ jsr zerobss ; Clear BSS segment
+ jsr copydata ; Initialize DATA segment
+ jsr initlib ; Run constructors
+
+; Call main()
+ jsr _main
+
+; Back from main() also the _exit entry
+; Stack the exit value in case destructors call OS
+_exit:
+ phx
+ pha
+ jsr donelib ; Run destructors
+ pla
+ sta RIA_A
+ plx
+ stx RIA_X
+ lda #$FF ; exit()
+ sta RIA_OP
+ stp
diff --git a/libsrc/rp6502/getres.c b/libsrc/rp6502/getres.c
new file mode 100644
index 000000000..394c32e76
--- /dev/null
+++ b/libsrc/rp6502/getres.c
@@ -0,0 +1,10 @@
+#include
+#include
+
+extern int __clock_gettimespec (struct timespec* ts, unsigned char op);
+
+int clock_getres (clockid_t clock_id, struct timespec* res)
+{
+ ria_set_ax (clock_id);
+ return __clock_gettimespec (res, RIA_OP_CLOCK_GETRES);
+}
diff --git a/libsrc/rp6502/gettime.c b/libsrc/rp6502/gettime.c
new file mode 100644
index 000000000..ee63c31ec
--- /dev/null
+++ b/libsrc/rp6502/gettime.c
@@ -0,0 +1,12 @@
+#include
+#include
+
+extern int __clock_gettimespec (struct timespec* ts, unsigned char op);
+
+int clock_gettime (clockid_t clock_id, struct timespec* tp)
+{
+ (void)clock_id;
+ /* time.s doesn't set the stack value for clock_id (bug?) */
+ ria_set_ax (CLOCK_REALTIME);
+ return __clock_gettimespec (tp, RIA_OP_CLOCK_GETTIME);
+}
diff --git a/libsrc/rp6502/gettimespec.c b/libsrc/rp6502/gettimespec.c
new file mode 100644
index 000000000..4dc3a0db3
--- /dev/null
+++ b/libsrc/rp6502/gettimespec.c
@@ -0,0 +1,13 @@
+#include
+#include
+
+int __clock_gettimespec (struct timespec* ts, unsigned char op)
+/* Internal method shared by clock_getres and clock_gettime. */
+{
+ int ax = ria_call_int_errno (op);
+ if (ax >= 0) {
+ ts->tv_sec = ria_pop_long ();
+ ts->tv_nsec = ria_pop_long ();
+ }
+ return ax;
+}
diff --git a/libsrc/rp6502/gettimezone.c b/libsrc/rp6502/gettimezone.c
new file mode 100644
index 000000000..f3cb2a061
--- /dev/null
+++ b/libsrc/rp6502/gettimezone.c
@@ -0,0 +1,16 @@
+#include
+#include
+
+int clock_gettimezone (clockid_t clock_id, struct _timezone* tz)
+{
+ int ax;
+ ria_set_ax (clock_id);
+ ax = ria_call_int_errno (RIA_OP_CLOCK_GETTIMEZONE);
+ if (ax >= 0) {
+ char i;
+ for (i = 0; i < sizeof (struct _timezone); i++) {
+ ((char*)tz)[i] = ria_pop_char ();
+ }
+ }
+ return ax;
+}
diff --git a/libsrc/rp6502/initenv.s b/libsrc/rp6502/initenv.s
new file mode 100644
index 000000000..180b25c67
--- /dev/null
+++ b/libsrc/rp6502/initenv.s
@@ -0,0 +1,14 @@
+;
+; 2023, Rumbledethumps
+;
+
+.constructor initenv, 24
+.import __environ, __envcount, __envsize
+
+.segment "ONCE"
+
+.proc initenv
+
+ rts
+
+.endproc
diff --git a/libsrc/rp6502/irq.s b/libsrc/rp6502/irq.s
new file mode 100644
index 000000000..d7d2e6ec5
--- /dev/null
+++ b/libsrc/rp6502/irq.s
@@ -0,0 +1,50 @@
+;
+; 2023, Rumbledethumps
+;
+; Enables the C IRQ tools
+
+.export initirq, doneirq
+.import callirq, _exit
+
+.include "rp6502.inc"
+
+.segment "ONCE"
+
+initirq:
+ lda #handler
+ sei
+ sta $FFFE
+ stx $FFFF
+ cli
+ rts
+
+.code
+
+doneirq:
+ sei
+ rts
+
+.segment "LOWCODE"
+
+handler:
+ cld
+ phx
+ tsx
+ pha
+ inx
+ inx
+ lda $100,X
+ and #$10
+ bne break
+ phy
+ jsr callirq
+ ply
+ pla
+ plx
+ rti
+
+break:
+ lda #$FF
+ sta RIA_A
+ jmp _exit
diff --git a/libsrc/rp6502/lrand.c b/libsrc/rp6502/lrand.c
new file mode 100644
index 000000000..6434425df
--- /dev/null
+++ b/libsrc/rp6502/lrand.c
@@ -0,0 +1,6 @@
+#include
+
+long __fastcall__ lrand (void)
+{
+ return ria_call_long (RIA_OP_LRAND);
+}
diff --git a/libsrc/rp6502/lseek.c b/libsrc/rp6502/lseek.c
new file mode 100644
index 000000000..29506612c
--- /dev/null
+++ b/libsrc/rp6502/lseek.c
@@ -0,0 +1,11 @@
+#include
+#include
+
+off_t __fastcall__ lseek (int fd, off_t offset, int whence)
+{
+ /* Modified argument order for short stacking offset */
+ ria_push_long (offset);
+ ria_push_char (whence);
+ ria_set_ax (fd);
+ return ria_call_long_errno (RIA_OP_LSEEK);
+}
diff --git a/libsrc/rp6502/mainargs.s b/libsrc/rp6502/mainargs.s
new file mode 100644
index 000000000..152020022
--- /dev/null
+++ b/libsrc/rp6502/mainargs.s
@@ -0,0 +1,15 @@
+;
+; 2023, Rumbledethumps
+;
+; No arguments
+
+.constructor initmainargs, 24
+.import __argc, __argv
+
+.segment "ONCE"
+
+.proc initmainargs
+
+ rts
+
+.endproc
diff --git a/libsrc/rp6502/open.c b/libsrc/rp6502/open.c
new file mode 100644
index 000000000..ab3a374a2
--- /dev/null
+++ b/libsrc/rp6502/open.c
@@ -0,0 +1,16 @@
+#include
+#include
+#include
+
+int __cdecl__ open (const char* name, int flags, ...)
+{
+ size_t namelen = strlen (name);
+ if (namelen > 255) {
+ return _mappederrno (EINVAL);
+ }
+ while (namelen) {
+ ria_push_char (name[--namelen]);
+ }
+ ria_set_ax (flags);
+ return ria_call_int_errno (RIA_OP_OPEN);
+}
diff --git a/libsrc/rp6502/oserrlist.s b/libsrc/rp6502/oserrlist.s
new file mode 100644
index 000000000..ef322e293
--- /dev/null
+++ b/libsrc/rp6502/oserrlist.s
@@ -0,0 +1,86 @@
+;
+; 2002-07-18, Ullrich von Bassewitz
+; 2022, ChaN
+; 2023, Rumbledethumps
+;
+; Defines the platform-specific error list.
+;
+; The table is built as a list of entries:
+;
+; .byte entrylen
+; .byte errorcode
+; .asciiz errormsg
+;
+; and, terminated by an entry with length zero that is returned if the
+; error code could not be found.
+;
+
+.export __sys_oserrlist
+
+.include "rp6502.inc"
+.include "errno.inc"
+
+;----------------------------------------------------------------------------
+; Macros used to generate the list (may get moved to an include file?)
+
+; Regular entry
+.macro sys_oserr_entry code, msg
+ .local Start, End
+Start:
+ .byte End - Start
+ .byte code
+ .asciiz msg
+End:
+.endmacro
+
+; Sentinel entry
+.macro sys_oserr_sentinel msg
+ .byte 0 ; Length is always zero
+ .byte 0 ; Code is unused
+ .asciiz msg
+.endmacro
+
+;----------------------------------------------------------------------------
+; The error message table
+
+.rodata
+__sys_oserrlist:
+
+ sys_oserr_entry ENOENT , "No such file or directory"
+ sys_oserr_entry ENOMEM , "Out of memory"
+ sys_oserr_entry EACCES , "Permission denied"
+ sys_oserr_entry ENODEV , "No such device"
+ sys_oserr_entry EMFILE , "Too many open files"
+ sys_oserr_entry EBUSY , "Device or resource busy"
+ sys_oserr_entry EINVAL , "Invalid argument"
+ sys_oserr_entry ENOSPC , "No space left on device"
+ sys_oserr_entry EEXIST , "File exists"
+ sys_oserr_entry EAGAIN , "Try again"
+ sys_oserr_entry EIO , "I/O error"
+ sys_oserr_entry EINTR , "Interrupted system call"
+ sys_oserr_entry ENOSYS , "Function not implemented"
+ sys_oserr_entry ESPIPE , "Illegal seek"
+ sys_oserr_entry ERANGE , "Range error"
+ sys_oserr_entry EBADF , "Bad file number"
+ sys_oserr_entry ENOEXEC , "Exec format error"
+ sys_oserr_entry EUNKNOWN , "Unknown OS specific error"
+ sys_oserr_entry FR_DISK_ERR , "A hard error occurred in the low level disk I/O layer"
+ sys_oserr_entry FR_INT_ERR , "Assertion failed"
+ sys_oserr_entry FR_NOT_READY , "The physical drive cannot work"
+ sys_oserr_entry FR_NO_FILE , "Could not find the file"
+ sys_oserr_entry FR_NO_PATH , "Could not find the path"
+ sys_oserr_entry FR_INVALID_NAME , "The path name format is invalid"
+ sys_oserr_entry FR_DENIED , "Access denied due to prohibited access or directory full"
+ sys_oserr_entry FR_EXIST , "Access denied due to prohibited access"
+ sys_oserr_entry FR_INVALID_OBJECT , "The file/directory object is invalid"
+ sys_oserr_entry FR_WRITE_PROTECTED , "The physical drive is write protected"
+ sys_oserr_entry FR_INVALID_DRIVE , "The logical drive number is invalid"
+ sys_oserr_entry FR_NOT_ENABLED , "The volume has no work area"
+ sys_oserr_entry FR_NO_FILESYSTEM , "There is no valid FAT volume"
+ sys_oserr_entry FR_MKFS_ABORTED , "The f_mkfs() aborted due to any problem"
+ sys_oserr_entry FR_TIMEOUT , "Could not get a grant to access the volume within defined period"
+ sys_oserr_entry FR_LOCKED , "The operation is rejected according to the file sharing policy"
+ sys_oserr_entry FR_NOT_ENOUGH_CORE , "LFN working buffer could not be allocated"
+ sys_oserr_entry FR_TOO_MANY_OPEN_FILES , "Number of open files > FF_FS_LOCK"
+ sys_oserr_entry FR_INVALID_PARAMETER , "Given parameter is invalid"
+ sys_oserr_sentinel "Unknown error"
diff --git a/libsrc/rp6502/oserror.s b/libsrc/rp6502/oserror.s
new file mode 100644
index 000000000..706bcfa65
--- /dev/null
+++ b/libsrc/rp6502/oserror.s
@@ -0,0 +1,66 @@
+;
+; 2000-05-17, Ullrich von Bassewitz
+; 2022, ChaN
+; 2023, Rumbledethumps
+;
+; int __fastcall__ __osmaperrno (unsigned char oserror);
+;
+; RP6502 will respond with a union of CC65 and FatFs errnos.
+; This will map FatFs errors into the CC65 range for portable code.
+
+EFATFS_START := 32
+
+.include "rp6502.inc"
+.include "errno.inc"
+
+.code
+
+___osmaperrno:
+ cmp #EFATFS_START
+ bmi @L2
+
+ ldx #ErrTabSize
+@L1:
+ cmp ErrTab-2,x ; Search for the error code
+ beq @L3 ; Jump if found
+ dex
+ dex
+ bne @L1 ; Next entry
+
+; Code not found, return EUNKNOWN
+ lda #EUNKNOWN
+@L2:
+ rts
+
+; Found the code
+@L3:
+ lda ErrTab-1,x
+ ldx #$00 ; High byte always zero
+ rts
+
+.rodata
+
+ErrTab:
+
+ .byte FR_DISK_ERR , EIO ; A hard error occurred in the low level disk I/O layer
+; .byte FR_INT_ERR , EUNKNOWN ; Assertion failed
+ .byte FR_NOT_READY , EBUSY ; The physical drive cannot work
+ .byte FR_NO_FILE , ENOENT ; Could not find the file
+ .byte FR_NO_PATH , ENOENT ; Could not find the path
+ .byte FR_INVALID_NAME , EINVAL ; The path name format is invalid
+ .byte FR_DENIED , EACCES ; Access denied due to prohibited access or directory full
+ .byte FR_EXIST , EEXIST ; Access denied due to prohibited access
+ .byte FR_INVALID_OBJECT , EINVAL ; The file/directory object is invalid
+ .byte FR_WRITE_PROTECTED , EACCES ; The physical drive is write protected
+ .byte FR_INVALID_DRIVE , ENODEV ; The logical drive number is invalid
+; .byte FR_NOT_ENABLED , EUNKNOWN ; The volume has no work area
+; .byte FR_NO_FILESYSTEM , EUNKNOWN ; There is no valid FAT volume
+; .byte FR_MKFS_ABORTED , EUNKNOWN ; The f_mkfs() aborted due to any problem
+; .byte FR_TIMEOUT , EUNKNOWN ; Could not get a grant to access the volume within defined period
+ .byte FR_LOCKED , EBUSY ; The operation is rejected according to the file sharing policy
+ .byte FR_NOT_ENOUGH_CORE , ENOMEM ; LFN working buffer could not be allocated
+ .byte FR_TOO_MANY_OPEN_FILES , EMFILE ; Number of open files > FF_FS_LOCK
+ .byte FR_INVALID_PARAMETER , EINVAL ; Given parameter is invalid
+
+ErrTabSize = (* - ErrTab)
diff --git a/libsrc/rp6502/phi2.c b/libsrc/rp6502/phi2.c
new file mode 100644
index 000000000..1275e256e
--- /dev/null
+++ b/libsrc/rp6502/phi2.c
@@ -0,0 +1,6 @@
+#include
+
+int __fastcall__ phi2 (void)
+{
+ return ria_call_int (RIA_OP_PHI2);
+}
diff --git a/libsrc/rp6502/randomize.c b/libsrc/rp6502/randomize.c
new file mode 100644
index 000000000..569387d14
--- /dev/null
+++ b/libsrc/rp6502/randomize.c
@@ -0,0 +1,7 @@
+#include
+#include
+
+void _randomize (void)
+{
+ srand (ria_call_int (RIA_OP_LRAND));
+}
diff --git a/libsrc/rp6502/read.c b/libsrc/rp6502/read.c
new file mode 100644
index 000000000..eb96f779c
--- /dev/null
+++ b/libsrc/rp6502/read.c
@@ -0,0 +1,20 @@
+#include
+#include
+
+int __fastcall__ read (int fildes, void* buf, unsigned count)
+{
+ int total = 0;
+ while (count) {
+ unsigned blockcount = (count > 256) ? 256 : count;
+ int bytes_read = read_xstack (&((char*)buf)[total], blockcount, fildes);
+ if (bytes_read < 0) {
+ return bytes_read;
+ }
+ total += bytes_read;
+ count -= bytes_read;
+ if (bytes_read < blockcount) {
+ break;
+ }
+ }
+ return total;
+}
diff --git a/libsrc/rp6502/read_xram.c b/libsrc/rp6502/read_xram.c
new file mode 100644
index 000000000..f88a036ee
--- /dev/null
+++ b/libsrc/rp6502/read_xram.c
@@ -0,0 +1,9 @@
+#include
+
+int __fastcall__ read_xram (unsigned buf, unsigned count, int fildes)
+{
+ ria_push_int (buf);
+ ria_push_int (count);
+ ria_set_ax (fildes);
+ return ria_call_int_errno (RIA_OP_READ_XRAM);
+}
diff --git a/libsrc/rp6502/read_xstack.c b/libsrc/rp6502/read_xstack.c
new file mode 100644
index 000000000..70eebad2f
--- /dev/null
+++ b/libsrc/rp6502/read_xstack.c
@@ -0,0 +1,13 @@
+#include
+
+int __fastcall__ read_xstack (void* buf, unsigned count, int fildes)
+{
+ int i, ax;
+ ria_push_int (count);
+ ria_set_ax (fildes);
+ ax = ria_call_int_errno (RIA_OP_READ_XSTACK);
+ for (i = 0; i < ax; i++) {
+ ((char*)buf)[i] = ria_pop_char ();
+ }
+ return ax;
+}
diff --git a/libsrc/rp6502/ria.s b/libsrc/rp6502/ria.s
new file mode 100644
index 000000000..a1b53efb1
--- /dev/null
+++ b/libsrc/rp6502/ria.s
@@ -0,0 +1,89 @@
+;
+; 2023, Rumbledethumps
+;
+; Helpers for building API shims
+
+.include "rp6502.inc"
+
+.export _ria_push_long, _ria_push_int
+.export _ria_pop_long, _ria_pop_int
+.export _ria_set_axsreg, _ria_set_ax
+.export _ria_call_int, _ria_call_long
+.export _ria_call_int_errno, _ria_call_long_errno
+
+.importzp sp, sreg
+.import ___mappederrno, incsp1
+
+.code
+
+; void __fastcall__ ria_push_long(unsigned long val);
+_ria_push_long:
+ ldy sreg+1
+ sty RIA_XSTACK
+ ldy sreg
+ sty RIA_XSTACK
+; void __fastcall__ ria_push_int(unsigned int val);
+_ria_push_int:
+ stx RIA_XSTACK
+ sta RIA_XSTACK
+ rts
+
+; long __fastcall__ ria_pop_long(void);
+_ria_pop_long:
+ jsr _ria_pop_int
+ ldy RIA_XSTACK
+ sty sreg
+ ldy RIA_XSTACK
+ sty sreg+1
+ rts
+
+; int __fastcall__ ria_pop_int(void);
+_ria_pop_int:
+ lda RIA_XSTACK
+ ldx RIA_XSTACK
+ rts
+
+; void __fastcall__ ria_set_axsreg(unsigned long axsreg);
+_ria_set_axsreg:
+ ldy sreg
+ sty RIA_SREG
+ ldy sreg+1
+ sty RIA_SREG+1
+; void __fastcall__ ria_set_ax(unsigned int ax);
+_ria_set_ax:
+ stx RIA_X
+ sta RIA_A
+ rts
+
+; int __fastcall__ ria_call_int(unsigned char op);
+_ria_call_int:
+ sta RIA_OP
+ jmp RIA_SPIN
+
+; long __fastcall__ ria_call_long(unsigned char op);
+_ria_call_long:
+ sta RIA_OP
+ jsr RIA_SPIN
+ ldy RIA_SREG
+ sty sreg
+ ldy RIA_SREG+1
+ sty sreg+1
+ rts
+
+; int __fastcall__ ria_call_int_errno(unsigned char op);
+_ria_call_int_errno:
+ sta RIA_OP
+ jsr RIA_SPIN
+ ldx RIA_X
+ bmi ERROR
+ rts
+
+; long __fastcall__ ria_call_long_errno(unsigned char op);
+_ria_call_long_errno:
+ jsr _ria_call_long
+ bmi ERROR
+ rts
+
+ERROR:
+ lda RIA_ERRNO
+ jmp ___mappederrno
diff --git a/libsrc/rp6502/settime.c b/libsrc/rp6502/settime.c
new file mode 100644
index 000000000..1ba1d2e3e
--- /dev/null
+++ b/libsrc/rp6502/settime.c
@@ -0,0 +1,10 @@
+#include
+#include