mirror of
https://github.com/cc65/cc65.git
synced 2024-06-13 03:29:36 +00:00
Compare commits
225 Commits
1b93598de9
...
3f51fa383a
Author | SHA1 | Date | |
---|---|---|---|
|
3f51fa383a | ||
|
b993d88339 | ||
|
25967e65b5 | ||
|
a372ead4de | ||
|
081d18f7d7 | ||
|
a293920fb3 | ||
|
60c75bdb54 | ||
|
1fe12f112e | ||
|
a887b29ffb | ||
|
731f349b24 | ||
|
98767741ce | ||
|
9b2d27d1e1 | ||
|
23aa562094 | ||
|
5c3ff714ae | ||
|
86317711e0 | ||
|
8b71fafb84 | ||
|
3fd78208ba | ||
|
7a12399b39 | ||
|
294b034920 | ||
|
ab0eb4fe58 | ||
|
8d4946b3f4 | ||
|
3a7bd53956 | ||
|
8173c850fd | ||
|
4bde3afd80 | ||
|
7d6f3d24d4 | ||
|
8b172e05bc | ||
|
1deb9e52ae | ||
|
acff429eb8 | ||
|
6cf8ee8eb5 | ||
|
65bce9ecde | ||
|
014f85f226 | ||
|
788ae82d30 | ||
|
b04d79b1da | ||
|
3dfe033000 | ||
|
5acfb02794 | ||
|
934de685bc | ||
|
ce14f0f8ad | ||
|
a06431a8f9 | ||
|
eb503cc542 | ||
|
1fab179cb4 | ||
|
c4c6967e4a | ||
|
2a03e5d8c9 | ||
|
128f261c3a | ||
|
d5c84e7828 | ||
|
54b423a99e | ||
|
96d55e3703 | ||
|
a7ac9b7ef2 | ||
|
1e300bf768 | ||
|
ce606bb19e | ||
|
afd8ee627e | ||
|
2b97735d5d | ||
|
1a5a7d67a7 | ||
|
ba36071022 | ||
|
7594af553a | ||
|
7d7cf2d1e0 | ||
|
51b946bf25 | ||
|
0dd7b0c3a5 | ||
|
8682095f9f | ||
|
782dad23da | ||
|
aa6f850b8d | ||
|
a8b870555e | ||
|
65937684a0 | ||
|
ba6f9f5d3f | ||
|
4b9bf9bb98 | ||
|
f1d95f1f07 | ||
|
476591e8b7 | ||
|
f7388cfb79 | ||
|
ee3a542539 | ||
|
a2d722639f | ||
|
9ba270d97b | ||
|
34f37c873e | ||
|
ebf43ddb05 | ||
|
f0b5b02966 | ||
|
b87df9e1c6 | ||
|
1f820d0ae8 | ||
|
5d49fde788 | ||
|
3e01ac9b04 | ||
|
57e65a6bf6 | ||
|
13ddd734db | ||
|
2ba176372e | ||
|
6c7106c9d9 | ||
|
ea83b9fa53 | ||
|
ba75a2ac26 | ||
|
bea2e86210 | ||
|
998dfd6fa7 | ||
|
deaf27d6a8 | ||
|
01ee903cdf | ||
|
7a7e98d799 | ||
|
6a03fda453 | ||
|
b23a7ec407 | ||
|
83691f30c1 | ||
|
6bab3f921b | ||
|
ad90a3a421 | ||
|
a173428fab | ||
|
2e56dcc521 | ||
|
acce24fedc | ||
|
93f9cb6e48 | ||
|
d906748691 | ||
|
166a4b25f7 | ||
|
9471e128b5 | ||
|
10282a9b74 | ||
|
03d5e5fba0 | ||
|
348a9048b7 | ||
|
92ee03f9e9 | ||
|
0c53e7e0da | ||
|
5e267ccfca | ||
|
db8ac355cb | ||
|
dec65176f0 | ||
|
43c2239e94 | ||
|
2c4ebe812c | ||
|
8e25a7b376 | ||
|
b388ca0236 | ||
|
e9bd9330c0 | ||
|
07e349c517 | ||
|
afdf398a0b | ||
|
de3087a7e9 | ||
|
0b06c34dfc | ||
|
7e80e55b6d | ||
|
3d0dc58153 | ||
|
8c329dfd1a | ||
|
0f7d2dd818 | ||
|
6ab3c0c75f | ||
|
44b2e48e3e | ||
|
28f892bb3c | ||
|
17c2622382 | ||
|
38dac907e8 | ||
|
2682fc0b79 | ||
|
8e43c4706f | ||
|
94dfc08c0e | ||
|
2564aaa12c | ||
|
8aa59e4af3 | ||
|
773ed23cea | ||
|
2127778239 | ||
|
e1065d0c89 | ||
|
1e3b063b4a | ||
|
a71865f6ec | ||
|
fa7dca5fa3 | ||
|
df193c0947 | ||
|
3a439e0e1b | ||
|
7ce982cc68 | ||
|
29801a2fde | ||
|
82f01af6ec | ||
|
c379d03dfb | ||
|
169c9c0da0 | ||
|
1b5371b42d | ||
|
bcea5dfa8f | ||
|
726b70a534 | ||
|
dc9d2f0dbd | ||
|
075ece5faf | ||
|
75461e1319 | ||
|
7aab84628d | ||
|
acbd87b576 | ||
|
88246f852d | ||
|
4e820677ee | ||
|
0b7d9d8216 | ||
|
f734f43a35 | ||
|
f3199e4308 | ||
|
4343eebe67 | ||
|
9e3d1e1027 | ||
|
c262929a62 | ||
|
0ece9449d7 | ||
|
7297d2c8b6 | ||
|
d0903ba225 | ||
|
98b9814692 | ||
|
096bd0b633 | ||
|
66e354961c | ||
|
061d907a11 | ||
|
e5f9def572 | ||
|
b876a6b213 | ||
|
cd7c688dff | ||
|
9892c8f6c4 | ||
|
302c4f7409 | ||
|
0ff1b20f2a | ||
|
f6838be162 | ||
|
6cb8717c24 | ||
|
0d74b84ce4 | ||
|
103d4b82c5 | ||
|
269786a5ae | ||
|
08341aae30 | ||
|
1093d169ad | ||
|
a5746227dc | ||
|
1e4d1b4311 | ||
|
05aae60816 | ||
|
f8fe1d1560 | ||
|
bc97bce8c1 | ||
|
e90e7f46de | ||
|
b1c1502494 | ||
|
9985ee7f61 | ||
|
6b855d562a | ||
|
0b077f561f | ||
|
cc5e9c38ca | ||
|
b31a1c7c0c | ||
|
9634cc4d1e | ||
|
befc9533c6 | ||
|
bbd542fac7 | ||
|
07c71541f4 | ||
|
3215d377ea | ||
|
cadf8012f6 | ||
|
a1a060c291 | ||
|
79b4690077 | ||
|
a16a6298e2 | ||
|
92f869cdfb | ||
|
a956f6f9ed | ||
|
9e19a2e6a3 | ||
|
d805211002 | ||
|
b66682a05b | ||
|
2a2cc6cad6 | ||
|
d8e61552be | ||
|
d8a722b638 | ||
|
87f8893886 | ||
|
98ffc031d1 | ||
|
b7e7bb7489 | ||
|
519a52d92c | ||
|
66bfc31988 | ||
|
09735b26c5 | ||
|
c4575ec2c4 | ||
|
85a15007ec | ||
|
63861766e1 | ||
|
d8a3938f2b | ||
|
47e7ed2f56 | ||
|
c0a2021d9a | ||
|
6434176909 | ||
|
3b7af398a9 | ||
|
850007cb44 | ||
|
c8df241337 |
2
.github/checks/spaces.sh
vendored
2
.github/checks/spaces.sh
vendored
|
@ -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
|
||||
|
||||
|
|
2
.github/checks/tabs.sh
vendored
2
.github/checks/tabs.sh
vendored
|
@ -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
|
||||
|
||||
|
|
36
.github/workflows/build-on-pull-request.yml
vendored
36
.github/workflows/build-on-pull-request.yml
vendored
|
@ -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
|
||||
|
@ -44,7 +44,7 @@ jobs:
|
|||
shell: bash
|
||||
run: make -j2 doc
|
||||
- name: Upload a documents snapshot.
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docs
|
||||
path: ./html
|
||||
|
@ -54,7 +54,7 @@ jobs:
|
|||
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:
|
||||
|
@ -62,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
|
||||
|
|
14
.github/workflows/snapshot-on-push-master.yml
vendored
14
.github/workflows/snapshot-on-push-master.yml
vendored
|
@ -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,18 +86,18 @@ jobs:
|
|||
mv cc65.zip cc65-snapshot-win32.zip
|
||||
|
||||
- name: Upload a 32-bit Snapshot Zip
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cc65-snapshot-win32
|
||||
path: cc65-snapshot-win32.zip
|
||||
- name: Upload a 64-bit Snapshot Zip
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
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
|
||||
|
@ -120,7 +120,7 @@ jobs:
|
|||
- name: Package offline documents.
|
||||
run: 7z a cc65-snapshot-docs.zip ./html/*.*
|
||||
- name: Upload a Documents Snapshot Zip
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cc65-snapshot-docs
|
||||
path: cc65-snapshot-docs.zip
|
||||
|
|
6
.github/workflows/windows-test-scheduled.yml
vendored
6
.github/workflows/windows-test-scheduled.yml
vendored
|
@ -30,7 +30,7 @@ jobs:
|
|||
run: mkdir ~/.cache-sha
|
||||
|
||||
- name: Cache SHA
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: check-sha
|
||||
with:
|
||||
path: ~/.cache-sha
|
||||
|
@ -43,11 +43,11 @@ jobs:
|
|||
|
||||
- name: Checkout source
|
||||
if: steps.check-sha.outputs.cache-hit != 'true'
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
if: steps.check-sha.outputs.cache-hit != 'true'
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Build app (MSVC debug)
|
||||
if: steps.check-sha.outputs.cache-hit != 'true'
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
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.)
|
||||
|
||||
*this is work in progress and is constantly updated - if in doubt, please ask*
|
||||
|
|
|
@ -7,9 +7,13 @@ For details look at the [Website](https://cc65.github.io).
|
|||
|
||||
## People
|
||||
|
||||
Project founder:
|
||||
Project founders:
|
||||
|
||||
* Ullrich von Bassewitz
|
||||
* 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:
|
||||
|
||||
|
@ -28,6 +32,7 @@ External contributors:
|
|||
* [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)*
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ CPU_ISET_4510 = $0400
|
|||
CPU_NONE = CPU_ISET_NONE
|
||||
CPU_6502 = CPU_ISET_6502
|
||||
CPU_6502X = CPU_ISET_6502|CPU_ISET_6502X
|
||||
CPU_6502DTV = CPU_ISET_6502|CPU_ISET_6502X|CPU_ISET_6502DTV
|
||||
CPU_6502DTV = CPU_ISET_6502|CPU_ISET_6502DTV
|
||||
CPU_65SC02 = CPU_ISET_6502|CPU_ISET_65SC02
|
||||
CPU_65C02 = CPU_ISET_6502|CPU_ISET_65SC02|CPU_ISET_65C02
|
||||
CPU_65816 = CPU_ISET_6502|CPU_ISET_65SC02|CPU_ISET_65816
|
||||
|
|
|
@ -82,7 +82,41 @@ MATHJ = $FC6F
|
|||
; Suzy Misc
|
||||
|
||||
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
|
||||
; 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
|
||||
|
|
64
asminc/stat.inc
Normal file
64
asminc/stat.inc
Normal file
|
@ -0,0 +1,64 @@
|
|||
;****************************************************************************
|
||||
;* *
|
||||
;* stat.inc *
|
||||
;* *
|
||||
;* Stat struct *
|
||||
;* *
|
||||
;* *
|
||||
;* *
|
||||
;*(C) 2023 Colin Leroy-Mira <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 *
|
||||
;*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
|
46
asminc/statvfs.inc
Normal file
46
asminc/statvfs.inc
Normal file
|
@ -0,0 +1,46 @@
|
|||
;****************************************************************************
|
||||
;* *
|
||||
;* statvfs.inc *
|
||||
;* *
|
||||
;* Statvfs struct *
|
||||
;* *
|
||||
;* *
|
||||
;* *
|
||||
;*(C) 2023 Colin Leroy-Mira <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 *
|
||||
;*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
|
|
@ -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
|
||||
|
|
41
cfg/kim1-mtu60k.cfg
Normal file
41
cfg/kim1-mtu60k.cfg
Normal file
|
@ -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 <prog>.bin <prog>.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;
|
||||
}
|
||||
|
41
cfg/kim1-mtuE000.cfg
Normal file
41
cfg/kim1-mtuE000.cfg
Normal file
|
@ -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 <prog>.bin <prog>.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;
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
21
cfg/vic20-asm-32k.cfg
Normal file
21
cfg/vic20-asm-32k.cfg
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Assembly program configuration for expanded VICs (>= +8K).
|
||||
|
||||
FEATURES {
|
||||
STARTADDRESS: default = $1201;
|
||||
}
|
||||
SYMBOLS {
|
||||
__LOADADDR__: type = import;
|
||||
}
|
||||
MEMORY {
|
||||
ZP: file = "", start = $0002, size = $001A, define = yes;
|
||||
LOADADDR: file = %O, start = %S - 2, size = $0002;
|
||||
MAIN: file = %O, start = %S, size = $8000 - %S;
|
||||
}
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
LOADADDR: load = LOADADDR, type = ro;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
BSS: load = MAIN, type = bss, optional = yes, define = yes;
|
||||
}
|
21
cfg/vic20-asm-3k.cfg
Normal file
21
cfg/vic20-asm-3k.cfg
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Assembly program configuration for expanded VICs (+3K only).
|
||||
|
||||
FEATURES {
|
||||
STARTADDRESS: default = $0401;
|
||||
}
|
||||
SYMBOLS {
|
||||
__LOADADDR__: type = import;
|
||||
}
|
||||
MEMORY {
|
||||
ZP: file = "", start = $0002, size = $001A, define = yes;
|
||||
LOADADDR: file = %O, start = %S - 2, size = $0002;
|
||||
MAIN: file = %O, start = %S, size = $1E00 - %S;
|
||||
}
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
LOADADDR: load = LOADADDR, type = ro;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
BSS: load = MAIN, type = bss, optional = yes, define = yes;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
# Assembly program configuration for unexpanded VICs.
|
||||
|
||||
FEATURES {
|
||||
STARTADDRESS: default = $1001;
|
||||
}
|
||||
|
@ -7,7 +9,7 @@ SYMBOLS {
|
|||
MEMORY {
|
||||
ZP: file = "", start = $0002, size = $001A, define = yes;
|
||||
LOADADDR: file = %O, start = %S - 2, size = $0002;
|
||||
MAIN: file = %O, start = %S, size = $0DF3 - %S;
|
||||
MAIN: file = %O, start = %S, size = $1E00 - %S;
|
||||
}
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
|
|
|
@ -62,7 +62,7 @@ Special locations:
|
|||
</descrip><p>
|
||||
|
||||
While running <tt/main()/ the Language Card bank 2 is enabled for read access.
|
||||
However while running module constructors/destructors the Language Card is disabled.
|
||||
However while running module constructors the Language Card is disabled.
|
||||
|
||||
Enabling the Language Card allows to use it as additional memory for cc65
|
||||
generated code. However code is never automatically placed there. Rather code
|
||||
|
@ -321,21 +321,39 @@ Programs containing Apple ][ specific code may use the
|
|||
|
||||
<sect1>Apple ][ specific functions<p>
|
||||
|
||||
The functions listed below are special for the Apple ][. See
|
||||
the <url url="funcref.html" name="function reference"> for declaration and
|
||||
The functions and variables listed below are special for the Apple ][.
|
||||
See the <url url="funcref.html" name="function reference"> for declaration and
|
||||
usage.
|
||||
|
||||
<itemize>
|
||||
<item>_auxtype
|
||||
<item>_dos_type
|
||||
<item>_filetype
|
||||
<item>_datetime
|
||||
<item>beep
|
||||
<item>get_ostype
|
||||
<item>gmtime_dt
|
||||
<item>mktime_dt
|
||||
<item>rebootafterexit
|
||||
<item>ser_apple2_slot
|
||||
<item>tgi_apple2_mix
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1>Apple IIgs specific functions in accelerator.h<p>
|
||||
|
||||
In addition to those, the <tt/accelerator.h/ header file contains three functions
|
||||
to help determine whether the program is running on a IIgs, and change the IIgs
|
||||
CPU speed. See the <url url="funcref.html" name="function reference"> for declaration and
|
||||
usage.
|
||||
|
||||
<itemize>
|
||||
<item>detect_iigs
|
||||
<item>get_iigs_speed
|
||||
<item>set_iigs_speed
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1>Hardware access<p>
|
||||
|
||||
There's currently no support for direct hardware access. This does not mean
|
||||
|
@ -434,10 +452,15 @@ The names in the parentheses denote the symbols to be used for static linking of
|
|||
(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 <tt/ser_apple2_slot()/ prior to
|
||||
<tt/ser_open()/ in order to select a different slot. <tt/ser_apple2_slot()/
|
||||
succeeds for all Apple II slots, but <tt/ser_open()/ fails with
|
||||
|
@ -569,6 +592,28 @@ program. See the discussion of the <tt/.CONDES/ feature in the <url
|
|||
url="ca65.html" name="assembler manual">.
|
||||
|
||||
|
||||
<sect1>ProDOS date/time manipulation<p>
|
||||
|
||||
<descrip>
|
||||
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:
|
||||
|
||||
<tag/struct tm/
|
||||
<tt/struct tm* __fastcall__ gmtime_dt (const struct datetime* dt);/
|
||||
|
||||
Converts a <tt/struct datetime/ into a <tt/struct tm/. Returns NULL in case
|
||||
of error and sets errno.
|
||||
|
||||
<tag/time_t/
|
||||
<tt/time_t __fastcall__ mktime_dt (const struct datetime* dt);/
|
||||
|
||||
Parses a <tt/struct datetime/ and returns a UNIX timestamp. Returns 0 on error and
|
||||
sets errno.
|
||||
|
||||
</descrip>
|
||||
|
||||
|
||||
<sect1>DIO<p>
|
||||
|
||||
<descrip>
|
||||
|
@ -630,6 +675,16 @@ url="ca65.html" name="assembler manual">.
|
|||
that can be used to set these variables. It is included in
|
||||
<tt/apple2.h/.
|
||||
|
||||
The global variable <tt/_datetime/ allows the file creation date/time
|
||||
to be set before a call to <tt/fopen()/
|
||||
or <tt/open()/ that creates the file. It is defined in <tt/apple2.h/:
|
||||
|
||||
<tscreen>
|
||||
<verb>
|
||||
extern struct datetime _datetime;
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
<tag>Example</tag>
|
||||
|
||||
A text file cannot be created with just the
|
||||
|
|
|
@ -63,7 +63,7 @@ Special locations:
|
|||
</descrip><p>
|
||||
|
||||
While running <tt/main()/ the Language Card bank 2 is enabled for read access.
|
||||
However while running module constructors/destructors the Language Card is disabled.
|
||||
However while running module constructors the Language Card is disabled.
|
||||
|
||||
Enabling the Language Card allows to use it as additional memory for cc65
|
||||
generated code. However code is never automatically placed there. Rather code
|
||||
|
@ -322,15 +322,19 @@ Programs containing enhanced Apple //e specific code may use the
|
|||
|
||||
<sect1>Enhanced Apple //e specific functions<p>
|
||||
|
||||
The functions listed below are special for the enhanced Apple //e. See
|
||||
the <url url="funcref.html" name="function reference"> for declaration and
|
||||
The functions and variables listed below are special for the Apple ][.
|
||||
See the <url url="funcref.html" name="function reference"> for declaration and
|
||||
usage.
|
||||
|
||||
<itemize>
|
||||
<item>_auxtype
|
||||
<item>_dos_type
|
||||
<item>_filetype
|
||||
<item>_datetime
|
||||
<item>beep
|
||||
<item>get_ostype
|
||||
<item>gmtime_dt
|
||||
<item>mktime_dt
|
||||
<item>rebootafterexit
|
||||
<item>ser_apple2_slot
|
||||
<item>tgi_apple2_mix
|
||||
|
@ -339,6 +343,20 @@ usage.
|
|||
</itemize>
|
||||
|
||||
|
||||
<sect1>Apple IIgs specific functions in accelerator.h<p>
|
||||
|
||||
In addition to those, the <tt/accelerator.h/ header file contains three functions
|
||||
to help determine whether the program is running on a IIgs, and change the IIgs
|
||||
CPU speed. See the <url url="funcref.html" name="function reference"> for declaration and
|
||||
usage.
|
||||
|
||||
<itemize>
|
||||
<item>detect_iigs
|
||||
<item>get_iigs_speed
|
||||
<item>set_iigs_speed
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1>Hardware access<p>
|
||||
|
||||
There's currently no support for direct hardware access. This does not mean
|
||||
|
@ -435,10 +453,15 @@ The names in the parentheses denote the symbols to be used for static linking of
|
|||
(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 <tt/ser_apple2_slot()/ prior to
|
||||
<tt/ser_open()/ in order to select a different slot. <tt/ser_apple2_slot()/
|
||||
succeeds for all Apple II slots, but <tt/ser_open()/ fails with
|
||||
|
@ -575,6 +598,28 @@ program. See the discussion of the <tt/.CONDES/ feature in the <url
|
|||
url="ca65.html" name="assembler manual">.
|
||||
|
||||
|
||||
<sect1>ProDOS date/time manipulation<p>
|
||||
|
||||
<descrip>
|
||||
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:
|
||||
|
||||
<tag/struct tm/
|
||||
<tt/struct tm* __fastcall__ gmtime_dt (const struct datetime* dt);/
|
||||
|
||||
Converts a <tt/struct datetime/ into a <tt/struct tm/. Returns -1 in case
|
||||
of error and sets errno, 0 on success.
|
||||
|
||||
<tag/time_t/
|
||||
<tt/time_t __fastcall__ mktime_dt (const struct datetime* dt);/
|
||||
|
||||
Parses a <tt/struct datetime/ and returns a UNIX timestamp. Returns 0 on error and
|
||||
sets errno.
|
||||
|
||||
</descrip>
|
||||
|
||||
|
||||
<sect1>DIO<p>
|
||||
|
||||
<descrip>
|
||||
|
@ -619,7 +664,7 @@ url="ca65.html" name="assembler manual">.
|
|||
auxiliary type. Therefore, some additional mechanism for specifying
|
||||
the file types is needed.
|
||||
|
||||
<tag>Specifying the File Type and Auxiliary Type</tag>
|
||||
<tag>Specifying the File Type, Auxiliary Type and creation date</tag>
|
||||
|
||||
There are two global variables provided that allow the file type
|
||||
and auxiliary type to be specified before a call to <tt/fopen()/
|
||||
|
@ -636,6 +681,16 @@ url="ca65.html" name="assembler manual">.
|
|||
that can be used to set these variables. It is included in
|
||||
<tt/apple2.h/, which is in turn included in <tt/apple2enh.h/.
|
||||
|
||||
The global variable <tt/_datetime/ allows the file creation date/time
|
||||
to be set before a call to <tt/fopen()/
|
||||
or <tt/open()/ that creates the file. It is defined in <tt/apple2.h/:
|
||||
|
||||
<tscreen>
|
||||
<verb>
|
||||
extern struct datetime _datetime;
|
||||
</verb>
|
||||
</tscreen>
|
||||
|
||||
<tag>Example</tag>
|
||||
|
||||
A text file cannot be created with just the
|
||||
|
|
128
doc/ca65.sgml
128
doc/ca65.sgml
|
@ -2871,6 +2871,26 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
|
|||
overridden. When using this feature, you may also get into trouble if
|
||||
later versions of the assembler define new keywords starting with a dot.
|
||||
|
||||
<tag><tt>line_continuations</tt><label id="line_continuations"></tag>
|
||||
|
||||
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:
|
||||
|
||||
<tscreen><verb>
|
||||
.feature line_continuations + ; Allow line continuations
|
||||
|
||||
lda \
|
||||
#$20 ; This is legal now
|
||||
</verb></tscreen>
|
||||
|
||||
For backward compatibility reasons, the <tt>.LINECONT +</tt> control command
|
||||
is also supported and enables the same feature.
|
||||
|
||||
<tag><tt>long_jsr_jmp_rts</tt><label id="long_jsr_jmp_rts"></tag>
|
||||
|
||||
Affects 65816 mode only.
|
||||
|
@ -3375,26 +3395,6 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
|
|||
the feature in more detail.
|
||||
|
||||
|
||||
<sect1><tt>.LINECONT</tt><label id=".LINECONT"><p>
|
||||
|
||||
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 can be followed by a '+' or '-' character to switch the
|
||||
option on or off respectively.
|
||||
|
||||
Example:
|
||||
|
||||
<tscreen><verb>
|
||||
.linecont + ; Allow line continuations
|
||||
|
||||
lda \
|
||||
#$20 ; This is legal now
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
<sect1><tt>.LIST</tt><label id=".LIST"><p>
|
||||
|
||||
Enable output to the listing. The command can be followed by a boolean
|
||||
|
@ -4090,7 +4090,9 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".BYTE" name=".BYTE"
|
|||
|
||||
<sect1><tt>.TAG</tt><label id=".TAG"><p>
|
||||
|
||||
Allocate space for a struct or union.
|
||||
Allocate space for a struct or union. This is equivalent to
|
||||
<tt><ref id=".RES" name=".RES"></tt> with the
|
||||
<tt><ref id=".SIZEOF" name=".SIZEOF"></tt> of a struct.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -4104,6 +4106,7 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".BYTE" name=".BYTE"
|
|||
.tag Point ; Allocate 4 bytes
|
||||
</verb></tscreen>
|
||||
|
||||
See: <ref id="structs" name=""Structs and unions"">
|
||||
|
||||
<sect1><tt>.UNDEF, .UNDEFINE</tt><label id=".UNDEFINE"><p>
|
||||
|
||||
|
@ -4493,9 +4496,9 @@ different:
|
|||
|
||||
<item> Macros defined with <tt><ref id=".DEFINE" name=".DEFINE"></tt> may not
|
||||
span more than a line. You may use line continuation (see <tt><ref
|
||||
id=".LINECONT" name=".LINECONT"></tt>) 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"></tt>) to spread the
|
||||
definition over more than one line for increased readability, but the
|
||||
macro itself may not contain an end-of-line token.
|
||||
|
||||
<item> Macros defined with <tt><ref id=".DEFINE" name=".DEFINE"></tt> share
|
||||
the name space with classic macros, but they are detected and replaced
|
||||
|
@ -4869,10 +4872,15 @@ compiler, depending on the target system selected:
|
|||
|
||||
Structs and unions are special forms of <ref id="scopes" name="scopes">. 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
|
||||
<tt><ref id=".SIZEOF" name=".SIZEOF"></tt> operator. The struct or union itself
|
||||
also has a <tt/.SIZEOF/ indicating its total storage size.
|
||||
|
||||
<sect1>Declaration<p>
|
||||
|
||||
|
@ -4899,8 +4907,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:
|
||||
|
||||
<tscreen><verb>
|
||||
.struct Circle
|
||||
.struct Point
|
||||
|
@ -4909,7 +4918,8 @@ The storage allocators may contain a multiplier, as in the example below:
|
|||
Radius .word
|
||||
.endstruct
|
||||
</verb></tscreen>
|
||||
The size of the Circle struct is 6 (three words).
|
||||
|
||||
In this example the size of the Circle struct is 6 (three words).
|
||||
|
||||
|
||||
<sect1>The storage allocator keywords<p>
|
||||
|
@ -4919,7 +4929,7 @@ The size of the Circle struct is 6 (three words).
|
|||
<tag/.BYTE, .RES/
|
||||
Allocates multiples of 1 byte. <tt/.RES/ requires an operand.
|
||||
|
||||
<tag/.DBYTE, .WORD, .ADDR/
|
||||
<tag/.DBYT, .WORD, .ADDR/
|
||||
Allocates multiples of 2 bytes.
|
||||
|
||||
<tag/.FARADDR/
|
||||
|
@ -4928,6 +4938,15 @@ The size of the Circle struct is 6 (three words).
|
|||
<tag/.DWORD/
|
||||
Allocates multiples of 4 bytes.
|
||||
|
||||
<tag/.TAG/
|
||||
Allocates a previously defined struct.
|
||||
|
||||
<tag/.STRUCT, .UNION/
|
||||
Begins a nested .struct or .union definition, and allocates it.
|
||||
Note that its member offset values will begin at 0, unless this nested
|
||||
structure is anonymous, in which case they will instead become members of
|
||||
the enclosing scope.
|
||||
|
||||
</descrip>
|
||||
|
||||
|
||||
|
@ -4972,13 +4991,54 @@ name=".TAG"> directive.
|
|||
C: .tag Circle
|
||||
</verb></tscreen>
|
||||
|
||||
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:
|
||||
<tscreen><verb>
|
||||
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
|
||||
</verb></tscreen>
|
||||
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:
|
||||
|
||||
<tscreen><verb>
|
||||
.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
|
||||
</verb></tscreen>
|
||||
|
||||
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".
|
||||
|
||||
|
||||
<sect1>Limitations<p>
|
||||
|
|
|
@ -1613,13 +1613,13 @@ parameter with the <tt/#pragma/.
|
|||
|
||||
This pragma sets a wrapper for functions, often used for trampolines.
|
||||
|
||||
The name is a function returning <tt/void/, and taking no parameters.
|
||||
The <tt/name/ is a wrapper function returning <tt/void/, and taking no parameters.
|
||||
It must preserve the CPU's <tt/A/ and <tt/X/ registers if it wraps any
|
||||
<tt/__fastcall__/ functions that have parameters. It must preserve
|
||||
the <tt/Y/ register if it wraps any variadic functions (they have "<tt/.../"
|
||||
in their prototypes).
|
||||
|
||||
The identifier is an 8-bit number that's set into <tt/tmp4/. If the identifier
|
||||
The <tt/identifier/ is an 8-bit number that's set into <tt/tmp4/. If the <tt/identifier/
|
||||
is "bank", then ca65's <tt><url url="ca65.html#.BANK" name=".bank"></tt> function will be used
|
||||
to determine the number from the bank attribute defined in the linker config,
|
||||
see <url url="ld65.html#MEMORY" name="Other MEMORY area attributes">. Note that
|
||||
|
@ -1629,6 +1629,11 @@ parameter with the <tt/#pragma/.
|
|||
The address of a wrapped function is passed in <tt/ptr4/. The wrapper can
|
||||
call that function by using "<tt/jsr callptr4/".
|
||||
|
||||
All functions ever declared or defined when this pragma is in effect will be wrapped
|
||||
when they are called explicitly by their names later in the same translation unit.
|
||||
Invocation of these functions in any other ways, for example, that via a function
|
||||
pointer or in inline assembly code, will not be wrapped.
|
||||
|
||||
This feature is useful, for example, with banked memory, to switch banks
|
||||
automatically to where a wrapped function resides, and then to restore the
|
||||
previous bank when it returns.
|
||||
|
|
|
@ -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:
|
||||
|
||||
<itemize>
|
||||
|
|
246
doc/funcref.sgml
246
doc/funcref.sgml
|
@ -71,18 +71,21 @@ function.
|
|||
<item><ref id="detect_c64dtv" name="detect_c64dtv">
|
||||
<item><ref id="detect_c65" name="detect_c65">
|
||||
<item><ref id="detect_chameleon" name="detect_chameleon">
|
||||
<item><ref id="detect_iigs" name="detect_iigs">
|
||||
<item><ref id="detect_scpu" name="detect_scpu">
|
||||
<item><ref id="detect_turbomaster" name="detect_turbomaster">
|
||||
<item><ref id="get_c128_speed" name="get_c128_speed">
|
||||
<item><ref id="get_c64dtv_speed" name="get_c64dtv_speed">
|
||||
<item><ref id="get_c65_speed" name="get_c65_speed">
|
||||
<item><ref id="get_chameleon_speed" name="get_chameleon_speed">
|
||||
<item><ref id="get_iigs_speed" name="get_iigs_speed">
|
||||
<item><ref id="get_scpu_speed" name="get_scpu_speed">
|
||||
<item><ref id="get_turbomaster_speed" name="get_turbomaster_speed">
|
||||
<item><ref id="set_c128_speed" name="set_c128_speed">
|
||||
<item><ref id="set_c64dtv_speed" name="set_c64dtv_speed">
|
||||
<item><ref id="set_c65_speed" name="set_c65_speed">
|
||||
<item><ref id="set_chameleon_speed" name="set_chameleon_speed">
|
||||
<item><ref id="set_iigs_speed" name="set_iigs_speed">
|
||||
<item><ref id="set_scpu_speed" name="set_scpu_speed">
|
||||
<item><ref id="set_turbomaster_speed" name="set_turbomaster_speed">
|
||||
</itemize>
|
||||
|
@ -92,7 +95,10 @@ function.
|
|||
|
||||
<itemize>
|
||||
<item>_dos_type
|
||||
<item><ref id="beep" name="beep">
|
||||
<item><ref id="get_ostype" name="get_ostype">
|
||||
<item><ref id="gmtime_dt" name="gmtime_dt">
|
||||
<item><ref id="mktime_dt" name="mktime_dt">
|
||||
<item>rebootafterexit
|
||||
</itemize>
|
||||
|
||||
|
@ -101,7 +107,10 @@ function.
|
|||
|
||||
<itemize>
|
||||
<item>_dos_type
|
||||
<item><ref id="beep" name="beep">
|
||||
<item><ref id="get_ostype" name="get_ostype">
|
||||
<item><ref id="gmtime_dt" name="gmtime_dt">
|
||||
<item><ref id="mktime_dt" name="mktime_dt">
|
||||
<item>rebootafterexit
|
||||
<item><ref id="videomode" name="videomode">
|
||||
</itemize>
|
||||
|
@ -846,6 +855,20 @@ communication, see also <tt>testcode/lib/ser-test.c</tt>.
|
|||
(incomplete)
|
||||
|
||||
|
||||
<sect1><tt/stat.h/<label id="sys/stat.h"><p>
|
||||
|
||||
<itemize>
|
||||
<item><ref id="stat" name="stat">
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1><tt/statvfs.h/<label id="sys/statvfs.h"><p>
|
||||
|
||||
<itemize>
|
||||
<item><ref id="statvfs" name="statvfs">
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1><tt/vic20.h/<label id="vic20.h"><p>
|
||||
|
||||
(incomplete)
|
||||
|
@ -1750,10 +1773,11 @@ used in presence of a prototype.
|
|||
<descrip>
|
||||
<tag/Function/Beep sound.
|
||||
<tag/Header/<tt/<ref id="sym1.h" name="sym1.h">/
|
||||
<tag/Header/<tt/<ref id="apple2.h" name="apple2.h">/
|
||||
<tag/Declaration/<tt/void beep(void);/
|
||||
<tag/Description/<tt/beep/ makes a brief tone.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is specific to the Sym-1.
|
||||
<item>The function is specific to the Sym-1 and Apple2 platforms.
|
||||
</itemize>
|
||||
<tag/Availability/cc65
|
||||
<tag/See also/
|
||||
|
@ -2851,6 +2875,79 @@ setting the time may not work. See also the platform-specific information.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>gmtime_dt<label id="gmtime_dt"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Converts a ProDOS date to a struct tm.
|
||||
<tag/Header/<tt/<ref id="apple2.h" name="apple2.h">/
|
||||
<tag/Declaration/<tt/struct tm* __fastcall__ gmtime_dt (const struct datetime* dt);/
|
||||
<tag/Description/The <tt/gmtime_dt/ function converts the given
|
||||
proDOS date/time to a struct tm. On error, NULL is returned and <tt/errno/ is set
|
||||
to an error code describing the reason for the failure.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is only available as fastcall function, so it may only
|
||||
be used in presence of a prototype.
|
||||
<item>This function is only available on Apple II.
|
||||
<item>On Apple II, you can't stat() an opened file. stat() before opening.
|
||||
</itemize>
|
||||
<tag/Availability/cc65
|
||||
<tag/Example/
|
||||
<verb>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
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));
|
||||
}
|
||||
}
|
||||
</verb>
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>mktime_dt<label id="mktime_dt"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Converts a ProDOS date to a time_t.
|
||||
<tag/Header/<tt/<ref id="apple2.h" name="apple2.h">/
|
||||
<tag/Declaration/<tt/time_t __fastcall__ mktime_dt (const struct datetime* dt);/
|
||||
<tag/Description/The <tt/mktime_dt/ function parses the given
|
||||
proDOS date/time and returns a time_t timestamp. On error, 0 is returned,
|
||||
and errno is set.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is only available as fastcall function, so it may only
|
||||
be used in presence of a prototype.
|
||||
<item>This function is only available on Apple II.
|
||||
</itemize>
|
||||
<tag/Availability/cc65
|
||||
<tag/Example/
|
||||
<verb>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
int main(void)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat ("/disk/file", &st) == 0) {
|
||||
printf ("File created on %s\n",
|
||||
localtime (mktime_dt (&st.st_ctime)));
|
||||
}
|
||||
}
|
||||
</verb>
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>clrscr<label id="clrscr"><p>
|
||||
|
||||
<quote>
|
||||
|
@ -3364,6 +3461,26 @@ used in presence of a prototype.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>detect_iigs<label id="detect_iigs"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Check whether we are running on an Apple IIgs..
|
||||
<tag/Header/<tt/<ref id="accelerator.h" name="accelerator.h">/
|
||||
<tag/Declaration/<tt/unsigned char detect_iigs (void);/
|
||||
<tag/Description/The function returns a 1 if running on an Apple IIgs.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is specific to the Apple2 and Apple2enh platforms.
|
||||
</itemize>
|
||||
<tag/Availability/cc65 (not all platforms)
|
||||
<tag/See also/
|
||||
<ref id="get_iigs_speed" name="get_iigs_speed">,
|
||||
<ref id="set_iigs_speed" name="set_iigs_speed">,
|
||||
<tag/Example/None.
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>detect_scpu<label id="detect_scpu"><p>
|
||||
|
||||
<quote>
|
||||
|
@ -4078,6 +4195,27 @@ header files define constants that can be used to check the return code.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>get_iigs_speed<label id="get_iigs_speed"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Get the current speed of the Apple IIgs.
|
||||
<tag/Header/<tt/<ref id="accelerator.h" name="accelerator.h">/
|
||||
<tag/Declaration/<tt/unsigned char get_iigs_speed (void);/
|
||||
<tag/Description/The function returns the current speed of the Apple IIgs.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is specific to the Apple2 and Apple2enh platforms.
|
||||
<item>See the accelerator.h header for the speed definitions.
|
||||
</itemize>
|
||||
<tag/Availability/cc65 (not all platforms)
|
||||
<tag/See also/
|
||||
<ref id="detect_iigs" name="detect_iigs">,
|
||||
<ref id="set_iigs_speed" name="set_iigs_speed">,
|
||||
<tag/Example/None.
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>get_scpu_speed<label id="get_scpu_speed"><p>
|
||||
|
||||
<quote>
|
||||
|
@ -6229,6 +6367,9 @@ be used in presence of a prototype.
|
|||
<item>The returned pointer may point to a statically allocated instance of
|
||||
<tt/struct dirent/, so it may get overwritten by subsequent calls to
|
||||
<tt/readdir/.
|
||||
<item>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.
|
||||
<item>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
|
||||
|
@ -6893,6 +7034,30 @@ clean-up when exiting the program.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>set_iigs_speed<label id="set_iigs_speed"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Set the current speed of the Apple IIgs.
|
||||
<tag/Header/<tt/<ref id="accelerator.h" name="accelerator.h">/
|
||||
<tag/Declaration/<tt/unsigned char __fastcall__ set_iigs_speed (unsigned char speed);/
|
||||
<tag/Description/The function sets the speed of the Apple IIgs CPU (and returns
|
||||
the new speed).
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is specific to the Apple2 and Apple2enh platforms.
|
||||
<item>See the accelerator.h header for the speed definitions.
|
||||
<item>Accepted parameters are SPEED_SLOW and SPEED_FAST (all other values are
|
||||
considered SPEED_FAST).
|
||||
</itemize>
|
||||
<tag/Availability/cc65 (not all platforms)
|
||||
<tag/See also/
|
||||
<ref id="detect_iigs" name="detect_iigs">,
|
||||
<ref id="get_iigs_speed" name="get_iigs_speed">,
|
||||
<tag/Example/None.
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>set_scpu_speed<label id="set_scpu_speed"><p>
|
||||
|
||||
<quote>
|
||||
|
@ -7075,6 +7240,85 @@ be used in presence of a prototype.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>stat<label id="stat"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Get file status.
|
||||
<tag/Header/<tt/<ref id="sys/stat.h" name="sys/stat.h">/
|
||||
<tag/Declaration/<tt/int __fastcall__ stat (const char* pathname, struct stat* statbuf);/
|
||||
<tag/Description/<tt/stat/ gets information for the file with the given name. On success,
|
||||
zero is returned. On error, -1 is returned and <tt/errno/ is set to an error
|
||||
code describing the reason for the failure.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is only available as fastcall function, so it may only
|
||||
be used in presence of a prototype.
|
||||
<item>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 <url url="apple2.html#ss9.3" name="ProDOS datetime conversion functions">.
|
||||
</itemize>
|
||||
<tag/Availability/POSIX 1003.1
|
||||
<tag/See also/
|
||||
<ref id="statvfs" name="statvfs">
|
||||
<tag/Example/
|
||||
<verb>
|
||||
#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);
|
||||
}
|
||||
</verb>
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>statvfs<label id="statvfs"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Get filesystem statistics.
|
||||
<tag/Header/<tt/<ref id="sys/statvfs.h" name="sys/statvfs.h">/
|
||||
<tag/Declaration/<tt/int __fastcall__ statvfs (const char* pathname, struct statvfs* buf);/
|
||||
<tag/Description/<tt/statvfs/ gets information for the filesytem on which the given file
|
||||
resides. On success,
|
||||
zero is returned. On error, -1 is returned and <tt/errno/ is set to an error
|
||||
code describing the reason for the failure.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is only available as fastcall function, so it may only
|
||||
be used in presence of a prototype.
|
||||
<item>The function requires an absolute pathname.
|
||||
</itemize>
|
||||
<tag/Availability/POSIX 1003.1
|
||||
<tag/See also/
|
||||
<ref id="stat" name="stat">
|
||||
<tag/Example/
|
||||
<verb>
|
||||
#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);
|
||||
}
|
||||
</verb>
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>strcasecmp<label id="strcasecmp"><p>
|
||||
|
||||
<quote>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
# error This module may only be used when compiling for the Apple ][!
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <apple2_filetype.h>
|
||||
|
||||
|
||||
|
@ -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,20 +173,10 @@ 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__)
|
||||
|
@ -185,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. */
|
||||
|
||||
|
@ -211,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 */
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#ifndef _DIRENT_H
|
||||
#define _DIRENT_H
|
||||
|
||||
#include <target.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -51,26 +53,10 @@ struct dirent {
|
|||
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;
|
||||
struct datetime 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;
|
||||
struct datetime d_mtime;
|
||||
};
|
||||
|
||||
#define _DE_ISREG(t) ((t) != 0x0F)
|
||||
|
|
|
@ -72,8 +72,8 @@ 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 __fastcall__ ria_pop_long (void);
|
||||
int __fastcall__ ria_pop_int (void);
|
||||
long ria_pop_long (void);
|
||||
int ria_pop_int (void);
|
||||
#define ria_pop_char() RIA.xstack
|
||||
|
||||
/* Set the RIA fastcall register */
|
||||
|
@ -118,9 +118,9 @@ long __fastcall__ ria_call_long_errno (unsigned char op);
|
|||
/* C API for the operating system. */
|
||||
|
||||
int __cdecl__ xreg (char device, char channel, unsigned char address, ...);
|
||||
int __fastcall__ phi2 (void);
|
||||
int __fastcall__ codepage (void);
|
||||
long __fastcall__ lrand (void);
|
||||
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);
|
||||
|
|
|
@ -86,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
|
||||
|
|
|
@ -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 <time.h>
|
||||
#include <target.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -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
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* asctime.c */
|
||||
/* statvfs.h */
|
||||
/* */
|
||||
/* Convert a broken down time into a string */
|
||||
/* 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,8 +31,32 @@
|
|||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#ifndef _STATVFS_H
|
||||
#define _STATVFS_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -42,18 +64,11 @@
|
|||
/* 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];
|
||||
int __fastcall__ statvfs (const char* pathname, struct statvfs* buf);
|
||||
|
||||
/* Format into given buffer and return the result */
|
||||
return strftime (buf, sizeof (buf), "%c\n", timep)? buf : 0;
|
||||
}
|
||||
|
||||
|
||||
/* End of statvfs.h */
|
||||
#endif
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
#define _TIME_H
|
||||
|
||||
|
||||
/* Forward declaration for target.h */
|
||||
typedef unsigned long time_t;
|
||||
typedef unsigned long clock_t;
|
||||
|
||||
|
||||
|
||||
/* NULL pointer */
|
||||
#ifndef NULL
|
||||
|
@ -49,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;
|
||||
|
|
20
libsrc/apple2/beep.s
Normal file
20
libsrc/apple2/beep.s
Normal file
|
@ -0,0 +1,20 @@
|
|||
;
|
||||
; Colin Leroy-Mira, 2024
|
||||
;
|
||||
; void beep(void)
|
||||
;
|
||||
|
||||
.export _beep
|
||||
.import BELL
|
||||
|
||||
.include "apple2.inc"
|
||||
|
||||
.segment "LOWCODE"
|
||||
|
||||
_beep:
|
||||
lda CH ; Bell scrambles CH in 80col mode on IIgs, storing
|
||||
pha ; it in OURCH and resetting CH to 0. Save it.
|
||||
jsr BELL
|
||||
pla
|
||||
sta CH ; Restore CH
|
||||
rts
|
20
libsrc/apple2/bell.s
Normal file
20
libsrc/apple2/bell.s
Normal file
|
@ -0,0 +1,20 @@
|
|||
;
|
||||
; Colin Leroy-Mira, 2024
|
||||
;
|
||||
; BELL routine
|
||||
;
|
||||
|
||||
.export BELL
|
||||
|
||||
.include "apple2.inc"
|
||||
|
||||
.segment "LOWCODE"
|
||||
|
||||
BELL:
|
||||
; Switch in ROM and call BELL
|
||||
bit $C082
|
||||
jsr $FF3A ; BELL
|
||||
|
||||
; Switch in LC bank 2 for R/O and return
|
||||
bit $C080
|
||||
rts
|
|
@ -40,12 +40,15 @@ _exit: ldx #<exit
|
|||
lda #>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
|
||||
|
|
17
libsrc/apple2/detect_iigs.s
Normal file
17
libsrc/apple2/detect_iigs.s
Normal file
|
@ -0,0 +1,17 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 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
|
|
@ -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
|
||||
|
@ -254,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
|
||||
|
@ -285,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
|
||||
|
|
|
@ -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
|
||||
|
|
22
libsrc/apple2/get_iigs_speed.s
Normal file
22
libsrc/apple2/get_iigs_speed.s
Normal file
|
@ -0,0 +1,22 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
ldx #>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
|
||||
ldx #>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
|
||||
|
|
73
libsrc/apple2/gmtime_dt.s
Normal file
73
libsrc/apple2/gmtime_dt.s
Normal file
|
@ -0,0 +1,73 @@
|
|||
;
|
||||
; Oliver Schmidt, 14.08.2018
|
||||
; Colin Leroy-Mira, 2023 <colin@colino.net>
|
||||
;
|
||||
; 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 ; Return pointer to tm_buf
|
||||
ldx #>tm_buf
|
||||
rts
|
||||
|
||||
; Load errno code and return NULL
|
||||
erange: lda #ERANGE
|
||||
sta ___errno
|
||||
lda #$00
|
||||
tax
|
||||
rts
|
||||
|
||||
.bss
|
||||
|
||||
tm_buf:
|
||||
.tag tm
|
37
libsrc/apple2/mktime_dt.s
Normal file
37
libsrc/apple2/mktime_dt.s
Normal file
|
@ -0,0 +1,37 @@
|
|||
;
|
||||
; Oliver Schmidt, 14.08.2018
|
||||
; Colin Leroy-Mira, 2023 <colin@colino.net>
|
||||
;
|
||||
; 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
|
||||
ldx #>tm_buf
|
||||
jmp _mktime
|
||||
|
||||
err: lda #$00
|
||||
tax
|
||||
sta sreg
|
||||
sta sreg+1
|
||||
rts
|
|
@ -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
|
||||
|
|
33
libsrc/apple2/mli_file_info.s
Normal file
33
libsrc/apple2/mli_file_info.s
Normal file
|
@ -0,0 +1,33 @@
|
|||
;
|
||||
; Colin Leroy-Mira, 2023 <colin@colino.net>
|
||||
;
|
||||
|
||||
.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
|
22
libsrc/apple2/mli_file_info_direct.s
Normal file
22
libsrc/apple2/mli_file_info_direct.s
Normal file
|
@ -0,0 +1,22 @@
|
|||
;
|
||||
; Colin Leroy-Mira, 2023 <colin@colino.net>
|
||||
;
|
||||
|
||||
.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
|
|
@ -18,6 +18,7 @@
|
|||
.include "fcntl.inc"
|
||||
.include "mli.inc"
|
||||
.include "filedes.inc"
|
||||
.include "time.inc"
|
||||
|
||||
.segment "ONCE"
|
||||
|
||||
|
|
|
@ -66,34 +66,16 @@ 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 INTR_PENDING_RX_EXT_B
|
||||
CurChanIrqFlags:.byte $00
|
||||
|
||||
SerFlagOrig: .byte $00
|
||||
|
||||
; Tables used to translate cc65 RS232 params into register values
|
||||
; (Ref page 5-18 and 5-19)
|
||||
BaudLowTable: .byte $7E ; SER_BAUD_300
|
||||
.byte $5E ; SER_BAUD_1200
|
||||
.byte $2E ; SER_BAUD_2400
|
||||
.byte $16 ; SER_BAUD_4800
|
||||
.byte $0A ; SER_BAUD_9600
|
||||
.byte $04 ; SER_BAUD_19200
|
||||
.byte $01 ; SER_BAUD_38400
|
||||
.byte $00 ; SER_BAUD_57600
|
||||
|
||||
BaudHighTable: .byte $01 ; SER_BAUD_300
|
||||
.byte $00 ; SER_BAUD_1200
|
||||
.byte $00 ; SER_BAUD_2400
|
||||
.byte $00 ; SER_BAUD_4800
|
||||
.byte $00 ; SER_BAUD_9600
|
||||
.byte $00 ; SER_BAUD_19200
|
||||
.byte $00 ; SER_BAUD_38400
|
||||
.byte $00 ; SER_BAUD_57600
|
||||
|
||||
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
|
||||
|
@ -106,29 +88,65 @@ TxBitTable: .byte %00000000 ; SER_BITS_5, in WR_TX_CTRL (WR5)
|
|||
|
||||
.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
|
||||
; Otherwise refers to the index in
|
||||
; Baud(Low/High)Table
|
||||
.byte $FF ; SER_BAUD_45_5
|
||||
.byte $FF ; SER_BAUD_50
|
||||
.byte $FF ; SER_BAUD_75
|
||||
.byte $FF ; SER_BAUD_110
|
||||
.byte $FF ; SER_BAUD_134_5
|
||||
.byte $FF ; SER_BAUD_150
|
||||
.byte $00 ; SER_BAUD_300
|
||||
.byte $FF ; SER_BAUD_600
|
||||
.byte $01 ; SER_BAUD_1200
|
||||
.byte $FF ; SER_BAUD_1800
|
||||
.byte $02 ; SER_BAUD_2400
|
||||
.byte $FF ; SER_BAUD_3600
|
||||
.byte $03 ; SER_BAUD_4800
|
||||
.byte $FF ; SER_BAUD_7200
|
||||
.byte $04 ; SER_BAUD_9600
|
||||
.byte $05 ; SER_BAUD_19200
|
||||
.byte $06 ; SER_BAUD_38400
|
||||
.byte $07 ; SER_BAUD_57600
|
||||
.byte $FF ; SER_BAUD_115200
|
||||
.byte $FF ; SER_BAUD_230400
|
||||
; 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)
|
||||
|
@ -156,6 +174,7 @@ SER_FLAG := $E10104
|
|||
|
||||
; ------------------------------------------------------------------------
|
||||
; Channels
|
||||
|
||||
CHANNEL_B = 0
|
||||
CHANNEL_A = 1
|
||||
|
||||
|
@ -180,7 +199,6 @@ RX_CTRL_OFF = %11111110 ; ANDed,Rx disabled
|
|||
|
||||
WR_TX_RX_CTRL = 4
|
||||
RR_TX_RX_STATUS = 4
|
||||
TX_RX_CLOCK_MUL = %01000000 ; Clock x16 (Ref page 5-8)
|
||||
|
||||
WR_TX_CTRL = 5 ; (Ref page 5-9)
|
||||
RR_TX_STATUS = 5 ; Corresponding status register
|
||||
|
@ -197,15 +215,11 @@ MASTER_IRQ_MIE_RST = %00001010 ; STA'd
|
|||
MASTER_IRQ_SET = %00011001 ; STA'd
|
||||
|
||||
WR_CLOCK_CTRL = 11 ; (Ref page 5-17)
|
||||
CLOCK_CTRL_CH_A = %11010000
|
||||
CLOCK_CTRL_CH_B = %01010000
|
||||
|
||||
WR_BAUDL_CTRL = 12 ; (Ref page 5-18)
|
||||
WR_BAUDH_CTRL = 13 ; (Ref page 5-19)
|
||||
|
||||
WR_MISC_CTRL = 14 ; (Ref page 5-19)
|
||||
MISC_CTRL_RATE_GEN_ON = %00000001 ; ORed
|
||||
MISC_CTRL_RATE_GEN_OFF = %11111110 ; ANDed
|
||||
|
||||
WR_IRQ_CTRL = 15 ; (Ref page 5-20)
|
||||
IRQ_CLEANUP_EIRQ = %00001000
|
||||
|
@ -220,13 +234,8 @@ IRQ_RX = %00100000
|
|||
IRQ_SPECIAL = %01100000
|
||||
|
||||
RR_INTR_PENDING_STATUS = 3 ; (Ref page 5-25)
|
||||
INTR_PENDING_RX_EXT_A = %00101000 ; ANDed (RX or special IRQ)
|
||||
INTR_PENDING_RX_EXT_B = %00000101 ; ANDed (RX or special IRQ)
|
||||
INTR_IS_RX = %00100100 ; ANDed (RX IRQ, channel A or B)
|
||||
|
||||
SER_FLAG_CH_A = %00111000
|
||||
SER_FLAG_CH_B = %00000111
|
||||
|
||||
.code
|
||||
|
||||
; Read register value to A.
|
||||
|
@ -329,6 +338,15 @@ IIgs:
|
|||
: 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.
|
||||
|
@ -360,11 +378,13 @@ SER_OPEN:
|
|||
ldy #RR_INIT_STATUS ; Hit rr0 once to sync up
|
||||
jsr readSSCReg
|
||||
|
||||
ldy #WR_MISC_CTRL ; Turn everything off
|
||||
ldy #WR_MISC_CTRL ; WR14: Turn everything off
|
||||
lda #$00
|
||||
jsr writeSCCReg
|
||||
|
||||
ldy #SER_PARAMS::STOPBITS
|
||||
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
|
||||
|
@ -377,36 +397,33 @@ SER_OPEN:
|
|||
ora ParityTable,y ; Get value
|
||||
bmi InvParam
|
||||
|
||||
ora #TX_RX_CLOCK_MUL
|
||||
ldy CurClockSource ; Clock multiplier
|
||||
ora ClockMultiplier,y
|
||||
|
||||
ldy #WR_TX_RX_CTRL ; Setup stop & parity bits
|
||||
jsr writeSCCReg
|
||||
ldy #WR_TX_RX_CTRL
|
||||
jsr writeSCCReg ; End of WR4 setup
|
||||
|
||||
ldy CurClockSource ; WR11 setup: clock source
|
||||
cpx #CHANNEL_B
|
||||
bne ClockA
|
||||
ClockB:
|
||||
beq SetClock
|
||||
iny ; Shift to get correct ClockSource val
|
||||
iny ; depending on our channel
|
||||
|
||||
SetClock:
|
||||
lda ClockSource,y
|
||||
ldy #WR_CLOCK_CTRL
|
||||
lda #CLOCK_CTRL_CH_B
|
||||
jsr writeSCCReg
|
||||
jsr writeSCCReg ; End of WR11 setup
|
||||
|
||||
lda #INTR_PENDING_RX_EXT_B ; Store which IRQ bits we'll check
|
||||
sta CurChanIrqFlags
|
||||
|
||||
bra SetBaud
|
||||
ClockA:
|
||||
ldy #WR_CLOCK_CTRL
|
||||
lda #CLOCK_CTRL_CH_A
|
||||
jsr writeSCCReg
|
||||
|
||||
lda #INTR_PENDING_RX_EXT_A ; Store which IRQ bits we'll check
|
||||
lda ChanIrqFlags,x ; Store which IRQ bits we'll check
|
||||
sta CurChanIrqFlags
|
||||
|
||||
SetBaud:
|
||||
ldy #SER_PARAMS::BAUDRATE
|
||||
lda (ptr1),y ; Baudrate index - cc65 value
|
||||
.assert SER_PARAMS::BAUDRATE = 0, error
|
||||
lda (ptr1) ; Baudrate index - cc65 value
|
||||
asl
|
||||
tay
|
||||
|
||||
lda BaudTable,y ; Get chip value from Low/High tables
|
||||
lda BaudTable,y ; Get low byte of register value
|
||||
bpl BaudOK ; Verify baudrate is supported
|
||||
|
||||
InvParam:
|
||||
|
@ -415,59 +432,57 @@ InvParam:
|
|||
bra SetupOut
|
||||
|
||||
BaudOK:
|
||||
tay
|
||||
|
||||
lda BaudLowTable,y ; Get low byte
|
||||
|
||||
phy
|
||||
ldy #WR_BAUDL_CTRL
|
||||
jsr writeSCCReg
|
||||
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
|
||||
|
||||
lda BaudHighTable,y ; Get high byte
|
||||
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
|
||||
lda #MISC_CTRL_RATE_GEN_ON
|
||||
jsr writeSCCReg
|
||||
|
||||
ldy #SER_PARAMS::DATABITS
|
||||
lda (ptr1),y ; Data bits
|
||||
ldy #SER_PARAMS::DATABITS ; WR3 setup: RX data bits
|
||||
lda (ptr1),y
|
||||
tay
|
||||
lda RxBitTable,y ; Data bits for RX
|
||||
ora #RX_CTRL_ON ; and turn RX on
|
||||
lda RxBitTable,y
|
||||
ora #RX_CTRL_ON ; and turn receiver on
|
||||
|
||||
phy
|
||||
ldy #WR_RX_CTRL
|
||||
jsr writeSCCReg
|
||||
jsr writeSCCReg ; End of WR3 setup
|
||||
ply
|
||||
|
||||
lda TxBitTable,y ; Data bits for TX
|
||||
ora #TX_CTRL_ON ; and turn TX on
|
||||
and #TX_DTR_ON
|
||||
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
|
||||
ora #TX_RTS_ON ; and turn RTS on
|
||||
|
||||
ldy #WR_TX_CTRL
|
||||
jsr writeSCCReg
|
||||
jsr writeSCCReg ; End of WR5 setup
|
||||
|
||||
ldy #WR_IRQ_CTRL
|
||||
ldy #WR_IRQ_CTRL ; WR15 setup: IRQ
|
||||
lda #IRQ_CLEANUP_EIRQ
|
||||
jsr writeSCCReg
|
||||
|
||||
ldy #WR_INIT_CTRL ; Clear ext status (write twice)
|
||||
ldy #WR_INIT_CTRL ; WR0 setup: clear existing IRQs
|
||||
lda #INIT_CTRL_CLEAR_EIRQ
|
||||
jsr writeSCCReg
|
||||
jsr writeSCCReg ; Clear (write twice)
|
||||
jsr writeSCCReg
|
||||
|
||||
ldy #WR_TX_RX_MODE_CTRL ; Activate RX IRQ
|
||||
ldy #WR_TX_RX_MODE_CTRL ; WR1 setup: Activate RX IRQ
|
||||
lda #TX_RX_MODE_RXIRQ
|
||||
jsr writeSCCReg
|
||||
|
||||
lda SCCBREG ; Activate master IRQ
|
||||
lda SCCBREG ; WR9 setup: Activate master IRQ
|
||||
ldy #WR_MASTER_IRQ_RST
|
||||
lda #MASTER_IRQ_SET
|
||||
jsr writeSCCReg
|
||||
|
@ -475,14 +490,7 @@ BaudOK:
|
|||
lda SER_FLAG ; Get SerFlag's current value
|
||||
sta SerFlagOrig ; and save it
|
||||
|
||||
cpx #CHANNEL_B
|
||||
bne IntA
|
||||
IntB:
|
||||
ora #SER_FLAG_CH_B ; Inform firmware we want channel B IRQs
|
||||
bra StoreFlag
|
||||
IntA:
|
||||
ora #SER_FLAG_CH_A ; Inform firmware we want channel A IRQs
|
||||
StoreFlag:
|
||||
ora ChanIrqMask,x ; Tell firmware which channel IRQs we want
|
||||
sta SER_FLAG
|
||||
|
||||
ldy #$01 ; Mark port opened
|
||||
|
|
|
@ -121,7 +121,7 @@ BaudTable: ; Table used to translate RS232 baudrate param
|
|||
.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: ; Table used to translate RS232 databits param
|
||||
|
@ -302,6 +302,7 @@ HandshakeOK:
|
|||
lda (ptr1),y ; Baudrate index
|
||||
tay
|
||||
lda BaudTable,y ; Get 6551 value
|
||||
sta tmp2 ; Backup for IRQ setting
|
||||
bpl BaudOK ; Check that baudrate is supported
|
||||
|
||||
lda #SER_ERR_BAUD_UNAVAIL
|
||||
|
@ -332,8 +333,13 @@ BaudOK: sta tmp1
|
|||
|
||||
ora #%00000001 ; Set DTR active
|
||||
sta RtsOff ; Store value to easily handle flow control later
|
||||
ora #%00001000 ; Enable receive interrupts (RTS low)
|
||||
sta ACIA_CMD,x
|
||||
|
||||
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
|
||||
|
|
29
libsrc/apple2/set_iigs_speed.s
Normal file
29
libsrc/apple2/set_iigs_speed.s
Normal file
|
@ -0,0 +1,29 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 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
|
54
libsrc/apple2/sleep.s
Normal file
54
libsrc/apple2/sleep.s
Normal file
|
@ -0,0 +1,54 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 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
|
129
libsrc/apple2/stat.s
Normal file
129
libsrc/apple2/stat.s
Normal file
|
@ -0,0 +1,129 @@
|
|||
;
|
||||
; Colin Leroy-Mira, 2023 <colin@colino.net>
|
||||
;
|
||||
; 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
|
123
libsrc/apple2/statvfs.s
Normal file
123
libsrc/apple2/statvfs.s
Normal file
|
@ -0,0 +1,123 @@
|
|||
;
|
||||
; Colin Leroy-Mira, 2023 <colin@colino.net>
|
||||
;
|
||||
; 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
|
|
@ -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) {
|
||||
|
|
20
libsrc/apple2/wait.s
Normal file
20
libsrc/apple2/wait.s
Normal file
|
@ -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
|
|
@ -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__
|
||||
|
|
|
@ -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 #<EMFILE ; "too many open files"
|
||||
seterr: jsr ___directerrno
|
||||
jsr incsp4 ; clean up stack
|
||||
lda #$FF
|
||||
tax
|
||||
rts ; return -1
|
||||
jmp returnFFFF
|
||||
|
||||
; process the mode argument
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
@ -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
|
||||
|
|
129
libsrc/common/_time_t_to_tm.s
Normal file
129
libsrc/common/_time_t_to_tm.s
Normal file
|
@ -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
|
||||
ldx #>TM
|
||||
jsr _mktime
|
||||
|
||||
; And return our pointer
|
||||
lda #<TM
|
||||
ldx #>TM
|
||||
rts
|
||||
|
||||
.bss
|
||||
|
||||
TM: .tag tm
|
81
libsrc/common/asctime.s
Normal file
81
libsrc/common/asctime.s
Normal file
|
@ -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
|
||||
ldx #>buf
|
||||
jsr pushax
|
||||
|
||||
; Push sizeof(buf)
|
||||
lda #<MAX_BUF_LEN
|
||||
ldx #>MAX_BUF_LEN
|
||||
jsr pushax
|
||||
|
||||
; Push format string
|
||||
lda #<fmt
|
||||
ldx #>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
|
||||
ldx #>buf
|
||||
rts
|
||||
|
||||
.data
|
||||
|
||||
fmt: .byte '%'
|
||||
.byte 'c'
|
||||
.byte $0A
|
||||
.byte $00
|
||||
|
||||
.bss
|
||||
|
||||
buf: .res MAX_BUF_LEN
|
24
libsrc/common/checkferror.s
Normal file
24
libsrc/common/checkferror.s
Normal file
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
** fgetc.c
|
||||
**
|
||||
** (C) Copyright 1998, 2002 Ullrich von Bassewitz (uz@cc65.org)
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
94
libsrc/common/fgetc.s
Normal file
94
libsrc/common/fgetc.s
Normal file
|
@ -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
|
||||
ldx #>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
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
** Ullrich von Bassewitz, 11.08.1998
|
||||
**
|
||||
** char* fgets (char* s, int size, FILE* f);
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
117
libsrc/common/fgets.s
Normal file
117
libsrc/common/fgets.s
Normal file
|
@ -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 #<EOF
|
||||
beq got_eof
|
||||
|
||||
ldy #$01
|
||||
sty didread ; We read at least one char
|
||||
|
||||
.if (.cpu .bitand ::CPU_ISET_65SC02)
|
||||
sta (ptr4)
|
||||
.else
|
||||
dey
|
||||
sta (ptr4),y
|
||||
.endif
|
||||
|
||||
inc ptr4
|
||||
bne :+
|
||||
inc ptr4+1
|
||||
|
||||
: cmp #$0A ; Stop at \n
|
||||
beq done
|
||||
bne read_loop
|
||||
|
||||
got_eof:
|
||||
lda didread
|
||||
beq stopped_at_first_char
|
||||
ldy #_FILE::f_flags
|
||||
lda (ptr1),y
|
||||
and #_FERROR
|
||||
bne stopped_at_first_char
|
||||
|
||||
done:
|
||||
jsr terminate_ptr
|
||||
ldx #>buf
|
||||
lda #<buf
|
||||
rts
|
||||
|
||||
stopped_at_first_char:
|
||||
jmp terminate_ptr
|
||||
|
||||
.bss
|
||||
|
||||
c: .res 1
|
||||
buf: .res 2
|
||||
size: .res 2
|
||||
didread:.res 1
|
|
@ -5,7 +5,7 @@
|
|||
;
|
||||
|
||||
.export _clearerr, _feof, _ferror, _fileno, _fflush
|
||||
.import return0
|
||||
.import return0, ___directerrno
|
||||
.importzp ptr1
|
||||
|
||||
.include "_file.inc"
|
||||
|
@ -78,10 +78,7 @@ err: rts
|
|||
; If the file is not valid, fileno must set errno and return -1
|
||||
|
||||
error: lda #<EBADF
|
||||
jsr ___seterrno
|
||||
lda #$FF
|
||||
tax
|
||||
rts
|
||||
jmp ___directerrno
|
||||
.endproc
|
||||
|
||||
;
|
||||
|
@ -89,5 +86,3 @@ error: lda #<EBADF
|
|||
;
|
||||
|
||||
_fflush = return0
|
||||
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
** fputc.c
|
||||
**
|
||||
** Ullrich von Bassewitz, 02.06.1998
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
66
libsrc/common/fputc.s
Normal file
66
libsrc/common/fputc.s
Normal file
|
@ -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
|
||||
ldx #>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
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
** int fputs (const char* s, FILE* f);
|
||||
**
|
||||
** Ullrich von Bassewitz, 11.08.1998
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#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));
|
||||
}
|
||||
|
||||
|
||||
|
36
libsrc/common/fputs.s
Normal file
36
libsrc/common/fputs.s
Normal file
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
** gets.c
|
||||
**
|
||||
** Ullrich von Bassewitz, 11.08.1998
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
47
libsrc/common/gets.s
Normal file
47
libsrc/common/gets.s
Normal file
|
@ -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
|
|
@ -1,73 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* gmtime.c */
|
||||
/* */
|
||||
/* Convert calendar time into broken down time in UTC */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 <time.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
struct tm* __fastcall__ gmtime (const time_t* timep)
|
||||
{
|
||||
static struct tm timebuf;
|
||||
time_t t;
|
||||
|
||||
/* 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;
|
||||
}
|
20
libsrc/common/gmtime.s
Normal file
20
libsrc/common/gmtime.s
Normal file
|
@ -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
|
29
libsrc/common/localtime.s
Normal file
29
libsrc/common/localtime.s
Normal file
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
|
476
libsrc/common/mktime.s
Normal file
476
libsrc/common/mktime.s
Normal file
|
@ -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 ; No care about carry,
|
||||
sta Max ; 365+1 doesn't overflow low byte
|
||||
|
||||
ldy #tm::tm_mday+1 ; Do we have more days in store?
|
||||
lda (ptr2),y
|
||||
cmp #>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
|
||||
ldx #>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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
213
libsrc/common/realloc.s
Normal file
213
libsrc/common/realloc.s
Normal file
|
@ -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
|
||||
lda oldsize+1
|
||||
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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -73,7 +73,12 @@ 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
|
||||
.assert SER_ERR_OK = 0, error
|
||||
|
@ -108,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
|
||||
|
||||
|
@ -134,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
|
||||
|
@ -142,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
|
||||
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
|
||||
|
@ -218,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
|
||||
|
@ -234,15 +200,27 @@ 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
|
||||
.assert SER_ERR_OK = 0, error
|
||||
tax
|
||||
rts
|
||||
|
||||
invparameter:
|
||||
lda #SER_ERR_INIT_FAILED
|
||||
ldx #0 ; return value is char
|
||||
|
@ -264,8 +242,8 @@ GetByte:
|
|||
ldy RxPtrOut
|
||||
lda RxBuffer,y
|
||||
inc RxPtrOut
|
||||
sta (ptr1)
|
||||
ldx #$00
|
||||
sta (ptr1,x)
|
||||
txa ; Return code = 0
|
||||
rts
|
||||
|
||||
|
@ -279,24 +257,26 @@ SER_PUT:
|
|||
ina
|
||||
cmp TxPtrOut
|
||||
bne PutByte
|
||||
|
||||
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_OK
|
||||
.assert SER_ERR_OK = 0, error
|
||||
|
@ -308,9 +288,9 @@ PutByte:
|
|||
; Must return an SER_ERR_xx code in a/x.
|
||||
|
||||
SER_STATUS:
|
||||
ldy SerialStat
|
||||
lda SerialStat
|
||||
sta (ptr1)
|
||||
ldx #$00
|
||||
sta (ptr1,x)
|
||||
txa ; Return code = 0
|
||||
rts
|
||||
|
||||
|
@ -342,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
|
||||
|
||||
|
@ -393,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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user