Merge branch 'master' into feature/plus4-tgi-driver

This commit is contained in:
Bob Andrews
2025-06-01 23:12:27 +02:00
committed by GitHub
2213 changed files with 191473 additions and 27985 deletions

View File

@@ -21,21 +21,29 @@ TARGETS = apple2 \
atarixl \
atari2600 \
atari5200 \
atari7800 \
atmos \
creativision \
$(CBMS) \
$(GEOS) \
gamate \
kim1 \
lynx \
nes \
none \
osic1p \
pce \
rp6502 \
sim6502 \
sim65c02 \
supervision \
sym1 \
telestrat
TARGETTEST = none \
sim6502 \
sim65c02
DRVTYPES = emd \
joy \
mou \
@@ -50,7 +58,7 @@ OUTPUTDIRS := lib
$(subst ../,,$(wildcard ../target/*/drv/*)) \
$(subst ../,,$(wildcard ../target/*/util))
.PHONY: all mostlyclean clean install zip lib $(TARGETS)
.PHONY: all mostlyclean clean install zip lib libtest $(TARGETS)
.SUFFIXES:
@@ -78,6 +86,8 @@ datadir = $(PREFIX)/share/cc65
all lib: $(TARGETS)
libtest: $(TARGETTEST)
mostlyclean:
$(call RMDIR,../libwrk)
@@ -94,7 +104,6 @@ INSTALL = install
define INSTALL_recipe
$(if $(PREFIX),,$(error variable "PREFIX" must be set))
$(INSTALL) -d $(DESTDIR)$(datadir)/$(dir)
$(INSTALL) -m0644 ../$(dir)/*.* $(DESTDIR)$(datadir)/$(dir)
@@ -114,13 +123,17 @@ endef # ZIP_recipe
zip:
$(foreach dir,$(OUTPUTDIRS),$(ZIP_recipe))
$(TARGETS):
$(TARGETS): | ../lib
@$(MAKE) --no-print-directory $@
# ../lib must be created globally before doing lib targets in parallel
../lib:
@$(call MKDIR,$@)
else # TARGET
CA65FLAGS =
CC65FLAGS = -Or -W error
CA65FLAGS = -g
CC65FLAGS = -g -Or -W error
EXTZP = cbm510 \
cbm610 \
@@ -133,8 +146,7 @@ MKINC = $(GEOS) \
TARGETUTIL = apple2 \
apple2enh \
atari \
geos-apple
atari
GEOSDIRS = common \
conio \
@@ -286,10 +298,12 @@ $(EXTRA_OBJPAT): $(EXTRA_SRCPAT) | ../libwrk/$(TARGET) ../lib
@echo $(TARGET) - $(<F)
@$(CA65) -t $(TARGET) $(CA65FLAGS) --create-dep $(@:../lib/%.o=../libwrk/$(TARGET)/%.d) -o $@ $<
$(EXTRA_OBJS): | ../lib
../lib/$(TARGET).lib: $(OBJS) | ../lib
$(AR65) a $@ $?
../libwrk/$(TARGET) ../lib ../target/$(TARGET)/util:
../libwrk/$(TARGET) ../target/$(TARGET)/util:
@$(call MKDIR,$@)
$(TARGET): $(EXTRA_OBJS) ../lib/$(TARGET).lib

380
libsrc/NameClashes.md Normal file
View File

@@ -0,0 +1,380 @@
List of cc65 library name clashes
=================================
The following is a list of identifiers that might need
to be fixed, sorted by directory and identifier:
# common
## \_\_argc
* libsrc/runtime/callmain.s
* libsrc/cbm610/mainargs.s
* libsrc/cx16/mainargs.s
* libsrc/plus4/mainargs.s
* libsrc/lynx/mainargs.s
* libsrc/c16/mainargs.s
* libsrc/geos-common/system/mainargs.s
* libsrc/sim6502/mainargs.s
* libsrc/c128/mainargs.s
* libsrc/vic20/mainargs.s
* libsrc/nes/mainargs.s
* libsrc/atari/getargs.s
* libsrc/apple2/mainargs.s
* libsrc/cbm510/mainargs.s
* libsrc/telestrat/mainargs.s
* libsrc/c64/mainargs.s
* libsrc/pet/mainargs.s
* libsrc/atmos/mainargs.s
## \_\_argv
* libsrc/runtime/callmain.s
* libsrc/cbm610/mainargs.s
* libsrc/cx16/mainargs.s
* libsrc/plus4/mainargs.s
* libsrc/lynx/mainargs.s
* libsrc/c16/mainargs.s
* libsrc/geos-common/system/mainargs.s
* libsrc/sim6502/mainargs.s
* libsrc/c128/mainargs.s
* libsrc/vic20/mainargs.s
* libsrc/nes/mainargs.s
* libsrc/atari/getargs.s
* libsrc/apple2/mainargs.s
* libsrc/cbm510/mainargs.s
* libsrc/telestrat/mainargs.s
* libsrc/c64/mainargs.s
* libsrc/pet/mainargs.s
* libsrc/atmos/mainargs.s
## \_\_cos
* libsrc/common/sincos.s
## \_\_ctypeidx
* libsrc/common/ctype.s
* libsrc/common/ctypemask.s
* libsrc/geos-common/system/ctype.s
* libsrc/atari/ctype.s
* libsrc/cbm/ctype.s
* libsrc/atmos/ctype.s
* asminc/ctype\_common.inc
## \_\_cwd
* libsrc/common/getcwd.s
* libsrc/common/_cwd.s
* libsrc/atari/initcwd.s
* libsrc/apple2/initcwd.s
* libsrc/apple2/initcwd.s
* libsrc/telestrat/initcwd.s
* libsrc/cbm/initcwd.s
## \_\_cwd\_buf\_size
* libsrc/common/_cwd.s
## \_\_envcount
* libsrc/common/searchenv.s
* libsrc/common/_environ.s
* libsrc/common/putenv.s
* libsrc/common/getenv.s
## \_\_environ
* libsrc/common/searchenv.s
* libsrc/common/_environ.s
* libsrc/common/putenv.s
* libsrc/common/getenv.s
## \_\_envsize
* libsrc/common/_environ.s
* libsrc/common/putenv.s
## \_\_fdesc
* libsrc/common/_fdesc.s
* libsrc/common/fopen.s
## \_\_filetab
* libsrc/common/_fdesc.s
* libsrc/common/_file.s
* asminc/_file.inc
## \_\_fopen
* libsrc/common/fopen.s
* libsrc/common/_fopen.s
## \_\_printf
* libsrc/common/vsnprintf.s
* libsrc/common/_printf.s
* libsrc/common/vfprintf.s
* libsrc/conio/vcprintf.s
* libsrc/pce/_printf.s
## \_\_scanf
* libsrc/common/_scanf.inc
* libsrc/common/vsscanf.s
* libsrc/conio/vcscanf.s
## \_\_sin
* libsrc/common/sincos.s
## \_\_sys
* libsrc/common/_sys.s
* libsrc/apple2/_sys.s
## \_\_sys\_oserrlist
* libsrc/common/stroserr.s
* libsrc/geos-common/system/oserrlist.s
* libsrc/atari/oserrlist.s
* libsrc/apple2/oserrlist.s
* libsrc/cbm/oserrlist.s
* libsrc/atmos/oserrlist.s
## \_\_syschdir
* libsrc/common/chdir.s
* libsrc/atari/syschdir.s
* libsrc/apple2/syschdir.s
* libsrc/telestrat/syschdir.s
* libsrc/cbm/syschdir.s
## \_\_sysmkdir
* libsrc/common/mkdir.s
* libsrc/atari/sysmkdir.s
* libsrc/apple2/sysmkdir.s
* libsrc/telestrat/sysmkdir.s
## \_\_sysremove
* libsrc/common/remove.s
* libsrc/geos-common/file/sysremove.s
* libsrc/atari/sysremove.s
* libsrc/atari/sysrmdir.s
* libsrc/apple2/sysremove.s
* libsrc/apple2/sysrmdir.s
* libsrc/telestrat/sysremove.s
* libsrc/cbm/sysremove.s
## \_\_sysrename
* libsrc/common/rename.s
* libsrc/geos-common/file/sysrename.s
* libsrc/atari/sysrename.s
* libsrc/apple2/sysrename.s
* libsrc/cbm/sysrename.s
## \_\_sysrmdir
* libsrc/common/rmdir.s
* libsrc/atari/sysrmdir.s
* libsrc/apple2/sysrmdir.s
\_\_sysuname
* libsrc/common/uname.s
* libsrc/cbm610/sysuname.s
* libsrc/cx16/sysuname.s
* libsrc/plus4/sysuname.s
* libsrc/lynx/sysuname.s
* libsrc/c16/sysuname.s
* libsrc/geos-common/system/sysuname.s
* libsrc/c128/sysuname.s
* libsrc/creativision/sysuname.s
* libsrc/vic20/sysuname.s
* libsrc/nes/sysuname.s
* libsrc/atari/sysuname.s
* libsrc/apple2/sysuname.s
* libsrc/cbm510/sysuname.s
* libsrc/telestrat/sysuname.s
* libsrc/c64/sysuname.s
* libsrc/pet/sysuname.s
* libsrc/atari5200/sysuname.s
* libsrc/atmos/sysuname.s
# apple2
## \_\_auxtype
* libsrc/apple2/open.s
## \_\_datetime
* libsrc/apple2/open.s
## \_\_dos\_type
* libsrc/apple2/dioopen.s
* libsrc/apple2/curdevice.s
* libsrc/apple2/mainargs.s
* libsrc/apple2/settime.s
* libsrc/apple2/getdevice.s
* libsrc/apple2/dosdetect.s
* libsrc/apple2/irq.s
* libsrc/apple2/open.s
* libsrc/apple2/mli.s
* libsrc/apple2/getres.s
## \_\_filetype
* libsrc/apple2/open.s
* libsrc/apple2/exehdr.s
## atari
## \_\_defdev
* libsrc/atari/posixdirent.s
* libsrc/atari/ucase\_fn.s
* libsrc/atari/getdefdev.s
## \_\_dos\_type
* libsrc/atari/getargs.s
* libsrc/atari/exec.s
* libsrc/atari/settime.s
* libsrc/atari/syschdir.s
* libsrc/atari/dosdetect.s
* libsrc/atari/is\_cmdline\_dos.s
* libsrc/atari/sysrmdir.s
* libsrc/atari/gettime.s
* libsrc/atari/lseek.s
* libsrc/atari/getres.s
* libsrc/atari/getdefdev.s
## \_\_do\_oserror
* libsrc/atari/posixdirent.s
* libsrc/atari/do\_oserr.s
* libsrc/atari/serref.s
* libsrc/atari/read.s
* libsrc/atari/write.s
* libsrc/atari/close.s
## \_\_getcolor
* libsrc/atari/setcolor.s
## \_\_getdefdev
* libsrc/atari/getdefdev.s
## \_\_graphics
* libsrc/atari/graphics.s
## \_\_inviocb
* libsrc/atari/serref.s
* libsrc/atari/ser/atrrdev.s
* libsrc/atari/inviocb.s
* libsrc/atari/read.s
* libsrc/atari/write.s
* libsrc/atari/lseek.s
* libsrc/atari/close.s
## \_\_is\_cmdline\_dos
* libsrc/atari/is\_cmdline\_dos.s
* libsrc/atari/doesclrscr.s
## \_\_rest\_vecs
* libsrc/atari/savevec.s
## \_\_rwsetup
* libsrc/atari/rwcommon.s
* libsrc/atari/read.s
* libsrc/atari/write.s
## \_\_save\_vecs
* libsrc/atari/savevec.s
## \_\_scroll
* libsrc/atari/scroll.s
## \_\_setcolor
* libsrc/atari/setcolor.s
## \_\_setcolor\_low
* libsrc/atari/setcolor.s
## \_\_sio\_call
* libsrc/atari/diowritev.s
* libsrc/atari/diopncls.s
* libsrc/atari/siocall.s
* libsrc/atari/diowrite.s
* libsrc/atari/dioread.s
# cbm
## \_\_cbm\_filetype
* libsrc/cbm/cbm\_filetype.s
* asminc/cbm\_filetype.in
## \_\_dirread
* libsrc/cbm/dir.inc
* libsrc/cbm/dir.s
## \_\_dirread1
* libsrc/cbm/dir.inc
* libsrc/cbm/dir.s
# lynx
## \_\_iodat
* libsrc/lynx/lynx-cart.s
* libsrc/lynx/bootldr.s
* libsrc/lynx/extzp.s
* libsrc/lynx/crt0.s
* libsrc/lynx/extzp.inc
## \_\_iodir
* libsrc/lynx/extzp.s
* libsrc/lynx/crt0.s
* libsrc/lynx/extzp.inc
## \_\_sprsys
* libsrc/lynx/tgi/lynx-160-102-16.s
* libsrc/lynx/extzp.s
* libsrc/lynx/crt0.s
* libsrc/lynx/extzp.inc
## \_\_viddma
* libsrc/lynx/tgi/lynx-160-102-16.s
* libsrc/lynx/extzp.s
* libsrc/lynx/crt0.s
* libsrc/lynx/extzp.inc
# pce
## \_\_nmi
* libsrc/pce/irq.s
* libsrc/pce/crt0.s

View File

@@ -0,0 +1,28 @@
;
; Oliver Schmidt, 2024-08-06
;
; unsigned char __fastcall__ allow_lowercase (unsigned char onoff);
;
.ifndef __APPLE2ENH__
.export _allow_lowercase
.import return0
.import uppercasemask, return1
_allow_lowercase:
tax
lda values,x
ldx uppercasemask
sta uppercasemask
cpx #$FF
beq :+
jmp return0
: jmp return1
.rodata
values: .byte $DF ; Force uppercase
.byte $FF ; Keep lowercase
.endif

20
libsrc/apple2/beep.s Normal file
View File

@@ -0,0 +1,20 @@
;
; Colin Leroy-Mira, 2024
;
; void beep(void)
;
.export _beep
.include "apple2.inc"
.segment "LOWCODE"
_beep:
; Switch in ROM and call BELL
bit $C082
jsr $FF3A ; BELL
; Switch in LC bank 2 for R/O and return
bit $C080
rts

73
libsrc/apple2/boxchars.s Normal file
View File

@@ -0,0 +1,73 @@
;
; Colin Leroy-Mira and Oliver Schmidt, 26.05.2025
;
; Initialize box-drawing characters according to
; MouseText availability
;
.ifndef __APPLE2ENH__
.constructor initboxchars
.import machinetype
.export _CH_HLINE
.export _CH_VLINE
.export _CH_ULCORNER
.export _CH_URCORNER
.export _CH_LLCORNER
.export _CH_LRCORNER
.export _CH_TTEE
.export _CH_BTEE
.export _CH_LTEE
.export _CH_RTEE
.export _CH_CROSS
.segment "ONCE"
initboxchars:
bit machinetype ; IIe enhanced or newer?
bvs out
ldx #NUM_BOXCHARS ; No mousetext, patch characters
: lda std_boxchars,x
sta boxchars,x
dex
bpl :-
out: rts
; Replacement chars for when MouseText is not available
std_boxchars: .byte '!'
.byte '-'
.byte '+'
.byte '+'
.byte '+'
.byte '+'
.data
; MouseText-based box characters
boxchars:
VERT: .byte $DF
HORIZ: .byte $5F
ULCORNER: .byte $5F
URCORNER: .byte $20
LLCORNER: .byte $D4
LRCORNER: .byte $DF
NUM_BOXCHARS = *-boxchars
; exported symbols, referencing our 6 bytes
_CH_HLINE = HORIZ
_CH_VLINE = VERT
_CH_ULCORNER = ULCORNER
_CH_URCORNER = URCORNER
_CH_LLCORNER = LLCORNER
_CH_LRCORNER = LRCORNER
_CH_TTEE = ULCORNER
_CH_BTEE = LLCORNER
_CH_LTEE = LLCORNER
_CH_RTEE = LRCORNER
_CH_CROSS = LLCORNER
.endif ; not __APPLE2ENH__

75
libsrc/apple2/callmain.s Normal file
View File

@@ -0,0 +1,75 @@
;
; Ullrich von Bassewitz, 2003-03-07
;
; Push arguments and call main()
;
.export callmain, _exit
.export __argc, __argv
.import _main, pushax, done, donelib
.import zpsave, rvsave, reset
.include "zeropage.inc"
.include "apple2.inc"
;---------------------------------------------------------------------------
; Setup the stack for main(), then jump to it
callmain:
lda __argc
ldx __argc+1
jsr pushax ; Push argc
lda __argv
ldx __argv+1
jsr pushax ; Push argv
ldy #4 ; Argument size
jsr _main
; Avoid a re-entrance of donelib. This is also the exit() entry.
_exit: ldx #<exit
lda #>exit
jsr reset ; Setup RESET vector
; 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
sta SOFTEV,x
dex
bpl :-
; Copy back the zero-page stuff.
ldx #zpspace-1
: lda zpsave,x
sta sp,x
dex
bpl :-
; ProDOS TechRefMan, chapter 5.2.1:
; "System programs should set the stack pointer to $FF at the
; warm-start entry point."
ldx #$FF
txs ; Re-init stack pointer
; We're done
jmp done
;---------------------------------------------------------------------------
; Data
.data
__argc: .word 0
__argv: .addr 0

View File

@@ -7,8 +7,13 @@
;
.export _cgetc
.ifndef __APPLE2ENH__
.import machinetype
.endif
.import cursor, putchardirect
.include "zeropage.inc"
.include "apple2.inc"
_cgetc:
@@ -17,12 +22,15 @@ _cgetc:
beq :+
; Show caret.
.ifdef __APPLE2ENH__
lda #$7F | $80 ; Checkerboard, screen code
.else
.ifndef __APPLE2ENH__
lda #' ' | $40 ; Blank, flashing
bit machinetype
bpl put_caret
.endif
jsr putchardirect ; Returns old character in X
lda #$7F | $80 ; Checkerboard, screen code
put_caret:
jsr putchardirect ; Saves old character in tmp3
; Wait for keyboard strobe.
: inc RNDL ; Increment random counter low
@@ -37,16 +45,20 @@ _cgetc:
; Restore old character.
pha
txa
lda tmp3
jsr putchardirect
pla
; At this time, the high bit of the key pressed is set.
: bit KBDSTRB ; Clear keyboard strobe
.ifdef __APPLE2ENH__
.ifndef __APPLE2ENH__
bit machinetype ; Apple //e or more recent?
bpl clear
.endif
bit BUTN0 ; Check if OpenApple is down
bmi done
.endif
and #$7F ; If not down, then clear high bit
clear: and #$7F ; If not down, then clear high bit
done: ldx #>$0000
rts

View File

@@ -33,8 +33,8 @@ zerofd: lda #$00
; Return success
lda #$00
; Set __oserror
oserr: jmp __mappederrno
; Set ___oserror
oserr: jmp ___mappederrno
; Set __errno
errno: jmp __directerrno
errno: jmp ___directerrno

View File

@@ -1,57 +0,0 @@
/*****************************************************************************/
/* */
/* closedir.c */
/* */
/* Close a directory */
/* */
/* */
/* */
/* (C) 2005 Oliver Schmidt, <ol.sc@web.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 <fcntl.h>
#include <dirent.h>
#include "dir.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
int __fastcall__ closedir (DIR* dir)
{
int result;
/* Cleanup directory file */
result = close (dir->fd);
/* Cleanup DIR */
free (dir);
return result;
}

35
libsrc/apple2/closedir.s Normal file
View File

@@ -0,0 +1,35 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; int __fastcall__ closedir (DIR *dir)
;
.export _closedir, closedir_ptr1
.import _close
.import _free
.import pushax, popax, pushptr1, swapstk
.importzp ptr1
.include "apple2.inc"
.include "dir.inc"
.include "errno.inc"
.include "fcntl.inc"
.include "zeropage.inc"
_closedir:
sta ptr1
stx ptr1+1
closedir_ptr1:
; Close fd
jsr pushptr1 ; Backup ptr1
ldy #$00
lda (ptr1),y ; Get fd
ldx #$00
jsr _close
jsr swapstk ; Store result, pop ptr1
; Free dir structure
jsr _free
jmp popax ; Return result

View File

@@ -13,4 +13,4 @@ _textcolor := return1
_bgcolor := return0
_bordercolor := return0
_bordercolor := return0

42
libsrc/apple2/cpeekc.s Normal file
View File

@@ -0,0 +1,42 @@
;
; 2020-07-12, Oliver Schmidt
;
; char cpeekc (void);
;
.ifndef __APPLE2ENH__
.import machinetype
.endif
.export _cpeekc
.include "apple2.inc"
_cpeekc:
ldy CH
sec ; Assume main memory
.ifndef __APPLE2ENH__
bit machinetype
bpl peek
.endif
bit RD80VID ; In 80 column mode?
bpl peek ; No, just go ahead
lda OURCH
lsr ; Div by 2
tay
bcs peek ; Odd cols are in main memory
php
sei ; No valid MSLOT et al. in aux memory
bit HISCR ; Assume SET80COL
peek: lda (BASL),Y ; Get character
bcs :+ ; In main memory
bit LOWSCR
plp
: eor #$80 ; Invert high bit
ldx #>$0000
rts

View File

@@ -5,23 +5,33 @@
; void __fastcall__ cputc (char c);
;
.ifdef __APPLE2ENH__
.constructor initconio
.endif
.export _cputcxy, _cputc
.export cputdirect, newline, putchar, putchardirect
.import gotoxy, VTABZ
.ifndef __APPLE2ENH__
.import machinetype
.import uppercasemask
.endif
.include "zeropage.inc"
.include "apple2.inc"
.macpack cpu
.segment "ONCE"
.ifdef __APPLE2ENH__
initconio:
.ifndef __APPLE2ENH__
bit machinetype
bmi :+
rts
:
.endif
sta SETALTCHAR ; Switch in alternate charset
bit LORES ; Limit SET80COL-HISCR to text
rts
.endif
.code
@@ -33,7 +43,7 @@ _cputcxy:
pla ; Restore C and run into _cputc
_cputc:
cmp #$0D ; Test for \r = carrage return
cmp #$0D ; Test for \r = carriage return
beq left
cmp #$0A ; Test for \n = line feed
beq newline
@@ -41,19 +51,53 @@ _cputc:
.ifndef __APPLE2ENH__
cmp #$E0 ; Test for lowercase
bcc cputdirect
and #$DF ; Convert to uppercase
and uppercasemask
.endif
cputdirect:
jsr putchar
inc CH ; Bump to next column
.ifndef __APPLE2ENH__
bit machinetype
bpl :+
.endif
bit RD80VID ; In 80 column mode?
bpl :+
inc OURCH ; Bump to next column
lda OURCH
.ifdef __APPLE2ENH__
bra check ; Must leave CH alone
.else
jmp check
.endif
: inc CH ; Bump to next column
lda CH
cmp WNDWDTH
bcc :+
check: cmp WNDWDTH
bcc done
jsr newline
left: lda #$00 ; Goto left edge of screen
left:
.ifdef __APPLE2ENH__
stz CH ; Goto left edge of screen
.else
lda #$00
sta CH
: rts
.endif
.ifndef __APPLE2ENH__
bit machinetype
bpl done
.endif
bit RD80VID ; In 80 column mode?
bpl done
.ifdef __APPLE2ENH__
stz OURCH ; Goto left edge of screen
.else
sta OURCH
.endif
done: rts
newline:
inc CV ; Bump to next line
@@ -77,22 +121,32 @@ putchar:
mask: and INVFLG ; Apply normal, inverse, flash
putchardirect:
pha
tax
ldy CH
.ifdef __APPLE2ENH__
sec ; Assume main memory
.ifndef __APPLE2ENH__
bit machinetype
bpl put
.endif
bit RD80VID ; In 80 column mode?
bpl put ; No, just go ahead
tya
lda OURCH
lsr ; Div by 2
tay
bcs put ; Odd cols go in main memory
php
sei ; No valid MSLOT et al. in aux memory
bit HISCR ; Assume SET80COL
.endif
put: lda (BASL),Y ; Get current character
tax ; Return old character for _cgetc
pla
sta tmp3 ; Save old character for _cgetc
txa
sta (BASL),Y
.ifdef __APPLE2ENH__
bit LOWSCR ; Doesn't hurt in 40 column mode
.endif
rts
bcs :+ ; In main memory
bit LOWSCR
plp
: rts

View File

@@ -4,11 +4,13 @@
; Startup code for cc65 (Apple2 version)
;
.export _exit, done, return
.export done, return
.export zpsave, rvsave, reset
.export __STARTUP__ : absolute = 1 ; Mark as startup
.import initlib, donelib
.import initlib, _exit
.import zerobss, callmain
.import bltu2
.import __ONCE_LOAD__, __ONCE_SIZE__ ; Linker generated
.import __LC_START__, __LC_LAST__ ; Linker generated
@@ -33,41 +35,7 @@
jsr zerobss
; Push the command-line arguments; and, call main().
jsr callmain
; Avoid a re-entrance of donelib. This is also the exit() entry.
_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
; Call the module destructors.
jsr donelib
; Restore the original RESET vector.
exit: ldx #$02
: lda rvsave,x
sta SOFTEV,x
dex
bpl :-
; Copy back the zero-page stuff.
ldx #zpspace-1
: lda zpsave,x
sta sp,x
dex
bpl :-
; ProDOS TechRefMan, chapter 5.2.1:
; "System programs should set the stack pointer to $FF at the
; warm-start entry point."
ldx #$FF
txs ; Re-init stack pointer
; We're done
jmp done
jmp callmain
; ------------------------------------------------------------------------
@@ -126,6 +94,7 @@ basic: lda HIMEM
; Call the module constructors.
jsr initlib
; Copy the LC segment to its destination
; Switch in LC bank 2 for W/O.
bit $C081
bit $C081
@@ -153,7 +122,7 @@ basic: lda HIMEM
; Call into Applesoft Block Transfer Up -- which handles zero-
; sized blocks well -- to move the content of the LC memory area.
jsr $D39A ; BLTU2
jsr bltu2
; Switch in LC bank 2 for R/O and return.
bit $C080

View File

@@ -1,161 +0,0 @@
;
; Stefan Haubenthal with minor changes from Ullrich von Bassewitz, 2003-05-02
;
; Character specification table.
;
.include "ctype.inc"
; The tables are readonly, put them into the rodata segment
.rodata
; The following 256 byte wide table specifies attributes for the isxxx type
; of functions. Doing it by a table means some overhead in space, but it
; has major advantages:
;
; * It is fast. If it were'nt for the slow parameter passing of cc65, one
; could even define macros for the isxxx functions (this is usually
; done on other platforms).
;
; * It is highly portable. The only unportable part is the table itself,
; all real code goes into the common library.
;
; * We save some code in the isxxx functions.
__ctype:
.repeat 2
.byte CT_CTRL ; 0/00 ___ctrl_@___
.byte CT_CTRL ; 1/01 ___ctrl_A___
.byte CT_CTRL ; 2/02 ___ctrl_B___
.byte CT_CTRL ; 3/03 ___ctrl_C___
.byte CT_CTRL ; 4/04 ___ctrl_D___
.byte CT_CTRL ; 5/05 ___ctrl_E___
.byte CT_CTRL ; 6/06 ___ctrl_F___
.byte CT_CTRL ; 7/07 ___ctrl_G___
.byte CT_CTRL ; 8/08 ___ctrl_H___
.byte CT_CTRL | CT_OTHER_WS | CT_SPACE_TAB
; 9/09 ___ctrl_I___
.byte CT_CTRL | CT_OTHER_WS ; 10/0a ___ctrl_J___
.byte CT_CTRL | CT_OTHER_WS ; 11/0b ___ctrl_K___
.byte CT_CTRL | CT_OTHER_WS ; 12/0c ___ctrl_L___
.byte CT_CTRL | CT_OTHER_WS ; 13/0d ___ctrl_M___
.byte CT_CTRL ; 14/0e ___ctrl_N___
.byte CT_CTRL ; 15/0f ___ctrl_O___
.byte CT_CTRL ; 16/10 ___ctrl_P___
.byte CT_CTRL ; 17/11 ___ctrl_Q___
.byte CT_CTRL ; 18/12 ___ctrl_R___
.byte CT_CTRL ; 19/13 ___ctrl_S___
.byte CT_CTRL ; 20/14 ___ctrl_T___
.byte CT_CTRL ; 21/15 ___ctrl_U___
.byte CT_CTRL ; 22/16 ___ctrl_V___
.byte CT_CTRL ; 23/17 ___ctrl_W___
.byte CT_CTRL ; 24/18 ___ctrl_X___
.byte CT_CTRL ; 25/19 ___ctrl_Y___
.byte CT_CTRL ; 26/1a ___ctrl_Z___
.byte CT_CTRL ; 27/1b ___ctrl_[___
.byte CT_CTRL ; 28/1c ___ctrl_\___
.byte CT_CTRL ; 29/1d ___ctrl_]___
.byte CT_CTRL ; 30/1e ___ctrl_^___
.byte CT_CTRL ; 31/1f ___ctrl_____
.byte CT_SPACE | CT_SPACE_TAB ; 32/20 ___SPACE___
.byte CT_NONE ; 33/21 _____!_____
.byte CT_NONE ; 34/22 _____"_____
.byte CT_NONE ; 35/23 _____#_____
.byte CT_NONE ; 36/24 _____$_____
.byte CT_NONE ; 37/25 _____%_____
.byte CT_NONE ; 38/26 _____&_____
.byte CT_NONE ; 39/27 _____'_____
.byte CT_NONE ; 40/28 _____(_____
.byte CT_NONE ; 41/29 _____)_____
.byte CT_NONE ; 42/2a _____*_____
.byte CT_NONE ; 43/2b _____+_____
.byte CT_NONE ; 44/2c _____,_____
.byte CT_NONE ; 45/2d _____-_____
.byte CT_NONE ; 46/2e _____._____
.byte CT_NONE ; 47/2f _____/_____
.byte CT_DIGIT | CT_XDIGIT ; 48/30 _____0_____
.byte CT_DIGIT | CT_XDIGIT ; 49/31 _____1_____
.byte CT_DIGIT | CT_XDIGIT ; 50/32 _____2_____
.byte CT_DIGIT | CT_XDIGIT ; 51/33 _____3_____
.byte CT_DIGIT | CT_XDIGIT ; 52/34 _____4_____
.byte CT_DIGIT | CT_XDIGIT ; 53/35 _____5_____
.byte CT_DIGIT | CT_XDIGIT ; 54/36 _____6_____
.byte CT_DIGIT | CT_XDIGIT ; 55/37 _____7_____
.byte CT_DIGIT | CT_XDIGIT ; 56/38 _____8_____
.byte CT_DIGIT | CT_XDIGIT ; 57/39 _____9_____
.byte CT_NONE ; 58/3a _____:_____
.byte CT_NONE ; 59/3b _____;_____
.byte CT_NONE ; 60/3c _____<_____
.byte CT_NONE ; 61/3d _____=_____
.byte CT_NONE ; 62/3e _____>_____
.byte CT_NONE ; 63/3f _____?_____
.byte CT_NONE ; 64/40 _____@_____
.byte CT_UPPER | CT_XDIGIT ; 65/41 _____A_____
.byte CT_UPPER | CT_XDIGIT ; 66/42 _____B_____
.byte CT_UPPER | CT_XDIGIT ; 67/43 _____C_____
.byte CT_UPPER | CT_XDIGIT ; 68/44 _____D_____
.byte CT_UPPER | CT_XDIGIT ; 69/45 _____E_____
.byte CT_UPPER | CT_XDIGIT ; 70/46 _____F_____
.byte CT_UPPER ; 71/47 _____G_____
.byte CT_UPPER ; 72/48 _____H_____
.byte CT_UPPER ; 73/49 _____I_____
.byte CT_UPPER ; 74/4a _____J_____
.byte CT_UPPER ; 75/4b _____K_____
.byte CT_UPPER ; 76/4c _____L_____
.byte CT_UPPER ; 77/4d _____M_____
.byte CT_UPPER ; 78/4e _____N_____
.byte CT_UPPER ; 79/4f _____O_____
.byte CT_UPPER ; 80/50 _____P_____
.byte CT_UPPER ; 81/51 _____Q_____
.byte CT_UPPER ; 82/52 _____R_____
.byte CT_UPPER ; 83/53 _____S_____
.byte CT_UPPER ; 84/54 _____T_____
.byte CT_UPPER ; 85/55 _____U_____
.byte CT_UPPER ; 86/56 _____V_____
.byte CT_UPPER ; 87/57 _____W_____
.byte CT_UPPER ; 88/58 _____X_____
.byte CT_UPPER ; 89/59 _____Y_____
.byte CT_UPPER ; 90/5a _____Z_____
.byte CT_NONE ; 91/5b _____[_____
.byte CT_NONE ; 92/5c _____\_____
.byte CT_NONE ; 93/5d _____]_____
.byte CT_NONE ; 94/5e _____^_____
.byte CT_NONE ; 95/5f _UNDERLINE_
.byte CT_NONE ; 96/60 ___grave___
.byte CT_LOWER | CT_XDIGIT ; 97/61 _____a_____
.byte CT_LOWER | CT_XDIGIT ; 98/62 _____b_____
.byte CT_LOWER | CT_XDIGIT ; 99/63 _____c_____
.byte CT_LOWER | CT_XDIGIT ; 100/64 _____d_____
.byte CT_LOWER | CT_XDIGIT ; 101/65 _____e_____
.byte CT_LOWER | CT_XDIGIT ; 102/66 _____f_____
.byte CT_LOWER ; 103/67 _____g_____
.byte CT_LOWER ; 104/68 _____h_____
.byte CT_LOWER ; 105/69 _____i_____
.byte CT_LOWER ; 106/6a _____j_____
.byte CT_LOWER ; 107/6b _____k_____
.byte CT_LOWER ; 108/6c _____l_____
.byte CT_LOWER ; 109/6d _____m_____
.byte CT_LOWER ; 110/6e _____n_____
.byte CT_LOWER ; 111/6f _____o_____
.byte CT_LOWER ; 112/70 _____p_____
.byte CT_LOWER ; 113/71 _____q_____
.byte CT_LOWER ; 114/72 _____r_____
.byte CT_LOWER ; 115/73 _____s_____
.byte CT_LOWER ; 116/74 _____t_____
.byte CT_LOWER ; 117/75 _____u_____
.byte CT_LOWER ; 118/76 _____v_____
.byte CT_LOWER ; 119/77 _____w_____
.byte CT_LOWER ; 120/78 _____x_____
.byte CT_LOWER ; 121/79 _____y_____
.byte CT_LOWER ; 122/7a _____z_____
.byte CT_NONE ; 123/7b _____{_____
.byte CT_NONE ; 124/7c _____|_____
.byte CT_NONE ; 125/7d _____}_____
.byte CT_NONE ; 126/7e _____~_____
.byte CT_OTHER_WS ; 127/7f ____DEL____
.endrepeat

View File

@@ -23,5 +23,5 @@ _getcurrentdevice:
bne :+
lda #$FF ; INVALID_DEVICE
: ldx #$00
: ldx #>$0000
rts

View File

@@ -0,0 +1,56 @@
;
; Colin Leroy-Mira, 27/05/2025
;
; Verify the presence of a 80 columns card in slot 3,
; and publish a flag accordingly.
;
.export aux80col
.ifndef __APPLE2ENH__
.import machinetype
.endif
.constructor detect80cols
.include "apple2.inc"
.data
aux80col: .byte 0
.segment "ONCE"
IdOfsTable: ; Table of bytes positions, used to check four
; specific bytes on the slot's firmware to make
; sure this is a serial card.
.byte $05 ; Pascal 1.0 ID byte
.byte $07 ; Pascal 1.0 ID byte
.byte $0B ; Pascal 1.1 generic signature byte
.byte $0C ; Device signature byte
IdValTable: ; Table of expected values for the four checked
; bytes
.byte $38 ; ID Byte 0 (from Pascal 1.0), fixed
.byte $18 ; ID Byte 1 (from Pascal 1.0), fixed
.byte $01 ; Generic signature for Pascal 1.1, fixed
.byte $88 ; Device signature byte (80 columns card)
IdTableLen = * - IdValTable
detect80cols:
.ifndef __APPLE2ENH__
bit machinetype ; Check we're on a //e at least, otherwise we
bpl NoDev ; handle no 80cols hardware (like Videx)
.endif
ldx #IdTableLen-1
: ldy IdOfsTable,x ; Check Pascal 1.1 Firmware Protocol ID bytes
lda IdValTable,x
cmp $C300,y
bne NoDev
dex
bpl :-
dec aux80col ; We have an 80-columns card! Set flag to $FF
NoDev: rts

View 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

View File

@@ -45,9 +45,9 @@ _getdevicedir:
; Handle errors
erange: lda #<ERANGE
jsr __directerrno
jsr ___directerrno
bne :+ ; Branch always
oserr: jsr __mappederrno
oserr: jsr ___mappederrno
: lda #$00 ; Return NULL
tax
rts
@@ -73,7 +73,7 @@ oserr: jsr __mappederrno
iny
lda #$00
sta (ptr1),y
sta __oserror ; Clear _oserror
sta ___oserror ; Clear __oserror
; Success, return buf
lda ptr1

View File

@@ -30,6 +30,6 @@ diocommon:
dioepilog:
; Return success or error
sta __oserror
ldx #$00
sta ___oserror
ldx #>$0000
rts

View File

@@ -24,7 +24,7 @@ _dio_open:
lda #$28 ; "No device connected"
; Return oserror
oserr: sta __oserror
oserr: sta ___oserror
jmp return0
; Return success
@@ -34,5 +34,5 @@ oserr: sta __oserror
asl
asl
ldx #$00
stx __oserror
stx ___oserror
rts

View File

@@ -16,7 +16,7 @@ _dio_query_sectcount:
; Set handle
sta mliparam + MLI::ON_LINE::UNIT_NUM
; Get ProDOS 8 block size (clears __oserror)
; Get ProDOS 8 block size (clears ___oserror)
jsr _dio_query_sectsize
; Alloc buffer
@@ -74,7 +74,7 @@ done: lda ptr4
rts
nomem: lda #$FF ; Error code for sure not used by MLI
oserr: sta __oserror
oserr: sta ___oserror
; Save total blocks for failure
lda #$00
@@ -85,7 +85,7 @@ oserr: sta __oserror
; Check for non-ProDOS disk
check: cmp #$52 ; "Not a ProDOS volume"
bne oserr
sta __oserror
sta ___oserror
; Save total blocks for a 16-sector disk
lda #<280

View File

@@ -10,7 +10,7 @@
_dio_query_sectsize:
; Clear error
stx __oserror ; X = 0
stx ___oserror ; X = 0
; Return ProDOS 8 block size
txa ; X = 0

View File

@@ -1,62 +0,0 @@
/*****************************************************************************/
/* */
/* dir.h */
/* */
/* Apple ][ system specific DIR */
/* */
/* */
/* */
/* (C) 2005 Oliver Schmidt, <ol.sc@web.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. */
/* */
/*****************************************************************************/
#ifndef _DIR_H
#define _DIR_H
/*****************************************************************************/
/* Data */
/*****************************************************************************/
struct DIR {
int fd;
unsigned char entry_length;
unsigned char entries_per_block;
unsigned char current_entry;
union {
unsigned char bytes[512];
struct {
unsigned prev_block;
unsigned next_block;
unsigned char entries[1];
} content;
} block;
};
/* End of dir.h */
#endif

15
libsrc/apple2/dir.inc Normal file
View File

@@ -0,0 +1,15 @@
.struct DIR
FD .word
ENTRY_LENGTH .byte
ENTRIES_PER_BLOCK .byte
FILE_COUNT .word
CURRENT_ENTRY .byte
.union
BYTES .byte 512
.struct CONTENT
PREV_BLOCK .word
NEXT_BLOCK .word
ENTRIES .byte
.endstruct
.endunion
.endstruct

View File

@@ -0,0 +1,24 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; unsigned int __fastcall__ dir_entry_count(DIR *dir);
;
.export _dir_entry_count
.importzp ptr1
.include "apple2.inc"
.include "dir.inc"
.proc _dir_entry_count
sta ptr1
stx ptr1+1
ldy #DIR::FILE_COUNT + 1
lda (ptr1),y
tax
dey
lda (ptr1),y
rts
.endproc

View File

@@ -14,10 +14,11 @@
; ProDOS 8 1.6 - $16
; ProDOS 8 1.7 - $17
; ProDOS 8 1.8 - $18
; ProDOS 8 1.9 - $18
; ProDOS 8 1.9 - $18 (!)
; ProDOS 8 2.0.1 - $21
; ProDOS 8 2.0.2 - $22
; ProDOS 8 2.0.3 - $23
; ProDOS 8 2.4.x - $24
;
.constructor initdostype, 25

41
libsrc/apple2/dynchline.s Normal file
View File

@@ -0,0 +1,41 @@
;
; Ullrich von Bassewitz, 08.08.1998
; Colin Leroy-Mira, 26.05.2025
;
; void __fastcall__ dyn_chlinexy (unsigned char c, unsigned char x, unsigned char y, unsigned char length);
; void __fastcall__ dyn_chline (unsigned char c, unsigned char length);
;
.ifndef __APPLE2ENH__
.export _dyn_chlinexy, _dyn_chline, chlinedirect
.import gotoxy, cputdirect, popa
.import machinetype
.include "zeropage.inc"
.include "apple2.inc"
_dyn_chlinexy:
pha ; Save the length
jsr gotoxy ; Call this one, will pop params
pla ; Restore the length and run into _chline
_dyn_chline:
pha
jsr popa ; Get the character to draw
eor #$80 ; Invert high bit
tax
pla
chlinedirect:
stx tmp1
cmp #$00 ; Is the length zero?
beq done ; Jump if done
sta tmp2
: lda tmp1 ; Screen code
jsr cputdirect ; Direct output
dec tmp2
bne :-
done: rts
.endif

40
libsrc/apple2/dyncvline.s Normal file
View File

@@ -0,0 +1,40 @@
;
; Ullrich von Bassewitz, 08.08.1998
; Colin Leroy-Mira, 26.05.2025
;
; void __fastcall__ dyn_cvlinexy (unsigned char c, unsigned char x, unsigned char y, unsigned char length);
; void __fastcall__ dyn_cvline (unsigned char c, unsigned char length);
;
.ifndef __APPLE2ENH__
.export _dyn_cvlinexy, _dyn_cvline
.import gotoxy, putchar, newline, popa
.import machinetype
.include "zeropage.inc"
_dyn_cvlinexy:
pha ; Save the length
jsr gotoxy ; Call this one, will pop params
pla ; Restore the length and run into _cvline
_dyn_cvline:
pha
jsr popa ; Get the character to draw
eor #$80 ; Invert high bit
tax
pla
stx tmp1
cmp #$00 ; Is the length zero?
beq done ; Jump if done
sta tmp2
: lda tmp1 ; Screen code
jsr putchar ; Write, no cursor advance
jsr newline ; Advance cursor to next line
dec tmp2
bne :-
done: rts
.endif

View File

@@ -73,7 +73,8 @@ INSTALL:
and #$f0
cmp #$80
bne @L1
lda #EM_ERR_OK
.assert EM_ERR_OK = 0, error
txa
rts
@L1: lda #EM_ERR_NO_DEVICE
; rts

View File

@@ -5,8 +5,9 @@
;
.export _exec
.import pushname, popname
.import popax, done, _exit
.import mli_file_info_direct
.import aux80col
.import pushname, popname, popax, done, _exit
.include "zeropage.inc"
.include "errno.inc"
@@ -17,13 +18,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 +32,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 +49,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,37 +112,12 @@ setbuf: lda #$00 ; Low byte
dex
dex
; Set I/O buffer
sta mliparam + MLI::OPEN::IO_BUFFER
stx mliparam + MLI::OPEN::IO_BUFFER+1
; Set OPEN MLI call I/O buffer parameter
sta io_buffer
stx 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 libary 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
.ifdef __APPLE2ENH__
bit aux80col
bpl :+
; Calling the 80 column firmware needs the ROM switched
; in, otherwise it copies the F8 ROM to the LC (@ $CEF4)
bit $C082
@@ -164,9 +130,8 @@ setbuf: lda #$00 ; Low byte
; Switch in LC bank 2 for R/O
bit $C080
.endif
; Reset stack as we already passed
: ; Reset stack as we already passed
; the point of no return anyway
ldx #$FF
txs
@@ -185,23 +150,34 @@ setbuf: lda #$00 ; Low byte
lda #$00 ; '\0'
beq :- ; Branch always
; Call loader stub after C libary shutdown
; Call loader stub after C library shutdown
: lda #<target
ldx #>target
sta done+1
stx done+2
; Initiate C libary shutdown
; Initiate C library shutdown
jmp _exit
.bss
level : .res 1
.rodata
source:
; Open program file
; PATHNAME parameter is already set (we reuse
; the copy at $0280); IO_BUFFER has been setup
; before shutting down the C library
jsr $BF00
.byte OPEN_CALL
.word open_param
bcs error
; Copy REF_NUM to MLI READ and CLOSE parameters
lda open_ref
sta read_ref
sta close_ref
; Read whole program file
source: jsr $BF00
jsr $BF00
.byte READ_CALL
.word read_param
bcs error
@@ -213,8 +189,6 @@ source: jsr $BF00
bcs error
; Check for cmdline handling
lda $0100 ; Valid cmdline?
beq jump ; No, jump to program right away
ldx file_type ; SYS file?
bne system ; Yes, check for startup filename
@@ -256,6 +230,14 @@ jump: jmp (data_buffer)
file_type = * - source + target
.byte $00
open_param = * - source + target
.byte $03 ; PARAM_COUNT
.addr $0280 ; PATHNAME
io_buffer = * - source + target
.addr $0000 ; IO_BUFFER
open_ref = * - source + target
.byte $00 ; REF_NUM
read_param = * - source + target
.byte $04 ; PARAM_COUNT
read_ref = * - source + target
@@ -287,4 +269,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

View File

@@ -0,0 +1,33 @@
;
; Colin Leroy-Mira, 06.03.2025
;
; Copy the LC segment from the end of the binary to the Language Card
; using _memcpy. This allows running apple2 programs on the original
; Integer ROM Apple ][.
;
.export bltu2
.import _memcpy, pushax
.import __ONCE_LOAD__, __ONCE_SIZE__ ; Linker generated
.import __LC_START__, __LC_LAST__ ; Linker generated
.segment "ONCE"
bltu2:
; Get the destination start address.
lda #<__LC_START__
ldx #>__LC_START__
jsr pushax
; Get the source start address.
lda #<(__ONCE_LOAD__ + __ONCE_SIZE__)
ldx #>(__ONCE_LOAD__ + __ONCE_SIZE__)
jsr pushax
; Set the length
lda #<(__LC_LAST__ - __LC_START__)
ldx #>(__LC_LAST__ - __LC_START__)
; And do the copy
jmp _memcpy

View File

@@ -54,18 +54,20 @@ iobuf_alloc:
rts
; Mark table entry as used
: lda #$FF
sta table,x
: dec table,x
; Convert table index to address hibyte
txa
asl
asl
clc
; Skip clearing carry, it can't be set as long as MAX_FDS*4 is
; less than 64.
.assert MAX_FDS*4 < $40, error
adc #>$0800
; Store address in "memptr"
ldy #$01
; (Y still equals 0 from popptr1)
iny
sta (ptr1),y
dey
tya
@@ -82,8 +84,7 @@ iobuf_free:
; Mark table entry as free
tax
lda #$00
sta table,x
inc table,x
rts
; ------------------------------------------------------------------------

View File

@@ -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

View 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 #>$0000
rts
.assert SPEED_SLOW = 0, error
: jmp return0 ; SPEED_SLOW

View File

@@ -4,8 +4,10 @@
; unsigned char get_ostype (void)
;
.constructor initostype
.export _get_ostype
; Priority higher than the default one so that things depending
; on ostype can get ostype set when called at normal priority
.constructor initostype, 9
.export _get_ostype, ostype
; Identify machine according to:
; Apple II Miscellaneous TechNote #7, Apple II Family Identification
@@ -32,30 +34,30 @@ next: inx
bne :-
beq next ; Branch always
index: .byte $B3, $00 ; Apple ][
.byte $B3, $1E, $00 ; Apple ][+
.byte $B3, $1E, $00 ; Apple /// (emulation)
.byte $B3, $C0, $00 ; Apple //e
.byte $B3, $C0, $DD, $BE, $00 ; Apple //e Option Card
.byte $B3, $C0, $00 ; Apple //e (enhanced)
.byte $B3, $C0, $BF, $00 ; Apple //c
.byte $B3, $C0, $BF, $00 ; Apple //c (3.5 ROM)
.byte $B3, $C0, $BF, $00 ; Apple //c (Mem. Exp.)
.byte $B3, $C0, $BF, $00 ; Apple //c (Rev. Mem. Exp.)
.byte $B3, $C0, $BF, $00 ; Apple //c Plus
index: .byte $B3, $00 ; Apple ][
.byte $B3, $1E, $00 ; Apple ][+
.byte $B3, $1E, $00 ; Apple /// (emulation)
.byte $B3, $C0, $00 ; Apple //e
.byte $B3, $C0, $DD, $00 ; Apple //e Option Card
.byte $B3, $C0, $00 ; Apple //e (enhanced)
.byte $B3, $C0, $BF, $00 ; Apple //c
.byte $B3, $C0, $BF, $00 ; Apple //c (3.5 ROM)
.byte $B3, $C0, $BF, $00 ; Apple //c (Mem. Exp.)
.byte $B3, $C0, $BF, $00 ; Apple //c (Rev. Mem. Exp.)
.byte $B3, $C0, $BF, $00 ; Apple //c Plus
.byte $00
value: .byte $38, $10 ; Apple ][
.byte $EA, $AD, $11 ; Apple ][+
.byte $EA, $8A, $20 ; Apple /// (emulation)
.byte $06, $EA, $30 ; Apple //e
.byte $06, $E0, $02, $00, $40 ; Apple //e Option Card
.byte $06, $E0, $31 ; Apple //e (enhanced)
.byte $06, $00, $FF, $50 ; Apple //c
.byte $06, $00, $00, $51 ; Apple //c (3.5 ROM)
.byte $06, $00, $03, $53 ; Apple //c (Mem. Exp.)
.byte $06, $00, $04, $54 ; Apple //c (Rev. Mem. Exp.)
.byte $06, $00, $05, $55 ; Apple //c Plus
value: .byte $38, $10 ; Apple ][
.byte $EA, $AD, $11 ; Apple ][+
.byte $EA, $8A, $20 ; Apple /// (emulation)
.byte $06, $EA, $30 ; Apple //e
.byte $06, $E0, $02, $32 ; Apple //e Option Card
.byte $06, $E0, $31 ; Apple //e (enhanced)
.byte $06, $00, $FF, $40 ; Apple //c
.byte $06, $00, $00, $41 ; Apple //c (3.5 ROM)
.byte $06, $00, $03, $43 ; Apple //c (Mem. Exp.)
.byte $06, $00, $04, $44 ; Apple //c (Rev. Mem. Exp.)
.byte $06, $00, $05, $45 ; Apple //c Plus
.byte $00
.code

189
libsrc/apple2/get_tv.s Normal file
View File

@@ -0,0 +1,189 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2025
;
; unsigned char __fastcall__ get_tv(void)
;
.export _get_tv
.import _set_iigs_speed, _get_iigs_speed
.import ostype
.constructor calibrate_tv, 8 ; After ostype
.include "accelerator.inc"
.include "apple2.inc"
.include "get_tv.inc"
.segment "ONCE"
; Cycle wasters
waste_72:
jsr waste_36
waste_36:
jsr waste_12
waste_24:
jsr waste_12
waste_12:
rts
.proc calibrate_tv
lda ostype
bmi iigs
cmp #$20
bcc iip
cmp #$40
bcc iie
iic: jmp calibrate_iic
iigs: jmp calibrate_iigs
iie: jmp calibrate_iie
iip: rts ; Keep TV::OTHER.
.endproc
; Magic numbers
WASTE_LOOP_CYCLES = 92 ; The wait loop total cycles
NTSC_LOOP_COUNT = 17030/WASTE_LOOP_CYCLES ; How many loops expected on NTSC
PAL_LOOP_COUNT = 20280/WASTE_LOOP_CYCLES ; How many loops expected on PAL
STOP_PTRIG = 16500/WASTE_LOOP_CYCLES ; Stop PTRIG at 16.5ms
; Carry set at enter: wait for VBL +
; Carry clear at enter: wait for VBL -
; Increments X every 92 cycles.
.proc count_until_vbl_bit
lda #$10 ; BPL
bcc :+
lda #$30 ; BMI
: sta sign
; Wait for VBLsign change with 92 cycles loops.
; Hit PTRIG repeatedly so that accelerators will slow down.
; But stop hitting PTRIG after 16.5ms cycles, so that on the //c,
; the VBLINT will not be reset right before we get it. 16.5ms
; is a good value because it's far enough from 17ms for NTSC
; models, and close enough to 20.2ms for PAL models that accelerators
; will stay slow until there. (5ms usually).
: cpx #STOP_PTRIG ; 2 - see if we spent 16.5ms already
bcs notrig ; 4 / 5 - if so, stop hitting PTRIG
sta PTRIG ; 8 - otherwise hit it
bcc count ; 11
notrig:
nop ; 7 - keep cycle count constant when not
nop ; 9 - hitting PTRIG
nop ; 11
count:
inx ; 13
jsr waste_72 ; 85
bit RDVBLBAR ; 89 - Wait for VBL change
sign:
bpl :- ; 92 - patched with bpl/bmi
rts
.endproc
.proc calibrate_iic
php
sei
sta IOUDISOFF
lda RDVBLMSK
pha ; Back up for cleanup
bit ENVBL
bit PTRIG ; Reset VBL interrupt flag
: bit RDVBLBAR ; Wait for one VBL
bpl :-
bit PTRIG ; Reset VBL interrupt flag again
ldx #$00
clc
jsr count_until_vbl_bit
pla ; Cleanup
asl
bcs :+ ; VBL interrupts were already enabled
bit DISVBL
: sta IOUDISON ; IIc Tech Ref Man: The firmware normally leaves IOUDIS on.
plp
jmp calibrate_done
.endproc
.proc calibrate_iie
: bit RDVBLBAR ; Wait for bit 7 to be off (VBL start)
bmi :-
: bit RDVBLBAR ; Wait for bit 7 to be on (VBL end)
bpl :-
; Wait and count during a full cycle
ldx #$00
sec
jsr count_until_vbl_bit
clc
jsr count_until_vbl_bit
jmp calibrate_done
.endproc
.proc calibrate_iigs
; Backup speed and slow down
jsr _get_iigs_speed
pha
lda #SPEED_SLOW
jsr _set_iigs_speed
; The same as IIe, but reverted, because... something?
: bit RDVBLBAR ; Wait for bit 7 to be on (VBL start)
bpl :-
: bit RDVBLBAR ; Wait for bit 7 to be off (VBL end)
bmi :-
; Wait and count during a full cycle
ldx #$00
clc
jsr count_until_vbl_bit
sec
jsr count_until_vbl_bit
jsr calibrate_done
; Restore user speed
pla
jmp _set_iigs_speed
.endproc
.proc calibrate_done
; Consider X +/- 3 to be valid,
; anything else is unknown.
lda #TV::NTSC
cpx #NTSC_LOOP_COUNT-3
bcc unexpected
cpx #NTSC_LOOP_COUNT+3
bcc matched
lda #TV::PAL
cpx #PAL_LOOP_COUNT-3
bcc unexpected
cpx #PAL_LOOP_COUNT+3
bcs unexpected
matched:
sta tv
unexpected:
rts
.endproc
.code
; The only thing remaining from that code after init
.proc _get_tv
lda tv
ldx #>$0000
rts
.endproc
.segment "INIT"
tv: .byte TV::OTHER

View File

@@ -30,5 +30,5 @@ next: inx
bne next
done: txa
ldx #$00
ldx #>$0000
rts

View File

@@ -52,7 +52,7 @@ _clock_getres:
enosys: lda #ENOSYS
; Set __errno
jmp __directerrno
jmp ___directerrno
.rodata

View File

@@ -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
; Set ___oserror
jmp ___mappederrno

73
libsrc/apple2/gmtime_dt.s Normal file
View 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

View File

@@ -8,6 +8,10 @@
.export gotoxy, _gotoxy, _gotox
.import popa, VTABZ
.ifndef __APPLE2ENH__
.import machinetype
.endif
.include "apple2.inc"
gotoxy:
@@ -22,4 +26,13 @@ _gotoxy:
_gotox:
sta CH ; Store X
rts
.ifndef __APPLE2ENH__
bit machinetype
bpl :+
.endif
bit RD80VID ; In 80 column mode?
bpl :+
sta OURCH ; Store X
: rts

View File

@@ -3,22 +3,37 @@
;
.export initcwd
.import __cwd
.import __cwd, __dos_type
.include "zeropage.inc"
.include "apple2.inc"
.include "mli.inc"
initcwd:
; Set static prefix buffer
lda #<__cwd
ldx #>__cwd
sta mliparam + MLI::PREFIX::PATHNAME
stx mliparam + MLI::PREFIX::PATHNAME+1
; Check for ProDOS 8
lda __dos_type
beq done
; Get current working directory
lda #GET_PREFIX_CALL
ldx #PREFIX_COUNT
jsr callmli
; Save random counter
lda RNDL
pha
lda RNDH
pha
; Call MLI
; We're not using mli.s' callmli because its
; mliparam is in BSS and this will be called
; before LC code is moved to the Language Card.
jsr $BF00 ; MLI call entry point
.byte GET_PREFIX_CALL ; MLI command
.addr mli_parameters ; MLI parameter
; Restore random counter
pla
sta RNDH
pla
sta RNDL
; Check for null prefix
ldx __cwd
@@ -39,3 +54,9 @@ initcwd:
sta __cwd,x
done: rts
.rodata
mli_parameters:
.byte $01 ; Number of parameters
.addr __cwd ; Address of parameter

View File

@@ -2,7 +2,7 @@
; Oliver Schmidt, 10.9.2009
;
; Default ProDOS 8 I/O buffer management
;
;
.export iobuf_alloc, iobuf_free
.import _posix_memalign, _free

View File

@@ -19,13 +19,8 @@
; Constants
THRESHOLD = 20 ; Deviation from center triggering movement
; ------------------------------------------------------------------------
; ROM entry points
PREAD := $FB1E ; Read paddle in X, return AD conv. value in Y
LOWER_THRESHOLD = 05
UPPER_THRESHOLD = 85
; ------------------------------------------------------------------------
@@ -44,26 +39,41 @@ PREAD := $FB1E ; Read paddle in X, return AD conv. value in Y
; Library reference
.addr $0000
libref: .addr $0000
; Jump table
.addr INSTALL
.addr UNINSTALL
.addr COUNT
.addr READJOY
.addr READ
; ------------------------------------------------------------------------
.code
.bss
ostype: .res 1
value0: .res 1
value1: .res 1
; ------------------------------------------------------------------------
.data
; INSTALL routine. Is called after the driver is loaded into memory. If
; possible, check if the hardware is present and determine the amount of
; memory available.
; Must return an JOY_ERR_xx code in a/x.
INSTALL:
lda #<JOY_ERR_OK
ldx #>JOY_ERR_OK
lda libref
ldx libref+1
sta gettype+1
stx gettype+2
gettype:jsr $0000
sta ostype
lda #JOY_ERR_OK
.assert JOY_ERR_OK = 0, error
tax
; Fall through
; UNINSTALL routine. Is called before the driver is removed from memory.
@@ -71,57 +81,94 @@ INSTALL:
UNINSTALL:
rts
; COUNT: Return the total number of available joysticks in a/x.
; ------------------------------------------------------------------------
.code
; COUNT routine. Return the total number of available joysticks in a/x.
COUNT:
lda #$02 ; Number of joysticks we support
ldx #$00
ldx #$02
bit ostype
bvc noiic ; Not $4x
dex ; Only one joystick for the //c
noiic: txa ; Number of joysticks we support
ldx #>$0000
rts
; READ: Read a particular joystick passed in A.
READJOY:
bit $C082 ; Switch in ROM
and #$01 ; Restrict joystick number
; Read horizontal paddle
; READ routine. Read a particular joystick passed in A.
READ:
asl ; Joystick number -> paddle number
tax ; Set paddle number (0, 2)
jsr PREAD ; Read paddle value
lda #$00 ; 0 0 0 0 0 0 0 0
cpy #127 - THRESHOLD
ror ; !LEFT 0 0 0 0 0 0 0
cpy #127 + THRESHOLD
ror ; RIGHT !LEFT 0 0 0 0 0 0
tax
ldy #$00
sty value0
sty value1
; Read vertical paddle
; If IIgs -> set speed to normal
bit ostype
bpl nogs1 ; Not $8x
lda CYAREG
pha
inx ; Set paddle number (1, 3)
jsr PREAD ; Read paddle value
and #%01111111
sta CYAREG
; Read both paddles simultaneously according to:
; Apple IIe Technote #6, The Apple II Paddle Circuits
nogs1: lda PTRIG ; Trigger paddles
loop: lda PADDL0,x ; Read paddle (0 or 2)
bmi set0 ; Cycles: 2 3
nop ; Cycles: 2
bpl nop0 ; Cycles: 3
set0: sty value0 ; Cycles: 4
nop0: ; - -
; Cycles: 7 7
lda PADDL1,x ; Read paddle (1 or 3)
bmi set1 ; Cycles: 2 3
nop ; Cycles: 2
bpl nop1 ; Cycles: 3
set1: sty value1 ; Cycles: 4
nop1: ; - -
; Cycles: 7 7
iny
cpy #UPPER_THRESHOLD+1
bne loop
; If IIgs -> restore speed
bit ostype
bpl nogs2 ; Not $8x
pla
cpy #127 - THRESHOLD
sta CYAREG
; Transform paddle readings to directions
nogs2: lda #$00 ; 0 0 0 0 0 0 0 0
ldy value0
cpy #LOWER_THRESHOLD
ror ; !LEFT 0 0 0 0 0 0 0
cpy #UPPER_THRESHOLD
ror ; RIGHT !LEFT 0 0 0 0 0 0
ldy value1
cpy #LOWER_THRESHOLD
ror ; !UP RIGHT !LEFT 0 0 0 0 0
cpy #127 + THRESHOLD
cpy #UPPER_THRESHOLD
ror ; DOWN !UP RIGHT !LEFT 0 0 0 0
; Read primary button
tay
lda BUTN0-1,x ; Check button (1, 3)
lda BUTN0,x ; Check button (0 or 2)
asl
tya
ror ; BTN DOWN !UP RIGHT !LEFT 0 0 0
ror ; BTN_1 DOWN !UP RIGHT !LEFT 0 0 0
; Read secondary button
tay
inx
txa
and #$03 ; IIgs has fourth button at TAPEIN
eor #$02 ; IIgs has fourth button at TAPEIN
tax
lda BUTN0-1,x ; Check button (2, 0)
lda TAPEIN,x ; Check button (1 or 3)
asl
tya
ror ; BTN2 BTN DOWN !UP RIGHT !LEFT 0 0
ror ; BTN_2 BTN_1 DOWN !UP RIGHT !LEFT 0 0
; Finalize
eor #%00010100 ; BTN2 BTN DOWN UP RIGHT LEFT 0 0
ldx #$00
bit $C080 ; Switch in LC bank 2 for R/O
eor #%00010100 ; BTN_2 BTN_1 DOWN UP RIGHT LEFT 0 0
ldx #>$0000
rts

8
libsrc/apple2/joyref.s Normal file
View File

@@ -0,0 +1,8 @@
;
; Oliver Schmidt, 2020-06-04
;
.export joy_libref
.import _get_ostype
joy_libref := _get_ostype

View File

@@ -0,0 +1,9 @@
;
; Oliver Schmidt, 15.09.2009
;
; Copy the LC segment from the end of the binary to the Language Card
; using AppleSoft's BLTU2 routine.
;
.export bltu2
bltu2 := $D39A

View File

@@ -2,11 +2,8 @@
; Oliver Schmidt, 2013-05-31
;
.export em_libref, joy_libref, mouse_libref, ser_libref, tgi_libref
.export em_libref, ser_libref
.import _exit
em_libref := _exit
joy_libref := _exit
mouse_libref := _exit
ser_libref := _exit
tgi_libref := _exit

View File

@@ -107,13 +107,13 @@ seek_common:
einval: lda #EINVAL
; Set __errno
errno: jsr __directerrno ; leaves -1 in AX
errno: jsr ___directerrno ; leaves -1 in AX
stx sreg ; extend return value to 32 bits
stx sreg+1
rts
; Set __oserror
oserr: jsr __mappederrno ; leaves -1 in AX
; Set ___oserror
oserr: jsr ___mappederrno ; leaves -1 in AX
stx sreg ; extend return value to 32 bits
stx sreg+1
rts

View File

@@ -0,0 +1,24 @@
.ifndef __APPLE2ENH__
.constructor initmachinetype, 8
.import ostype
.export machinetype
.segment "ONCE"
initmachinetype:
ldx ostype
cpx #$31 ; Apple //e enhanced?
ror machinetype ; Carry to high bit
cpx #$30 ; Apple //e?
ror machinetype
rts
.data
; bit 7: Machine is a //e or newer
; bit 6: Machine is a //e enhanced or newer
machinetype: .byte 0
.endif

View File

@@ -8,13 +8,17 @@
;
.export _mouse_def_callbacks
.ifndef __APPLE2ENH__
.import machinetype
.endif
.include "apple2.inc"
; ------------------------------------------------------------------------
.bss
backup: .res 1
visible:.res 1
@@ -42,11 +46,14 @@ cursor = '+' | $40 ; Flashing crosshair
.endif
getcursor:
.ifdef __APPLE2ENH__
.ifndef __APPLE2ENH__
bit machinetype
bpl column
.endif
bit RD80VID ; In 80 column mode?
bpl column ; No, skip bank switching
switch: bit LOWSCR ; Patched at runtime
.endif
column: ldx #$00 ; Patched at runtime
getscr: lda $0400,x ; Patched at runtime
cmp #cursor
@@ -55,9 +62,7 @@ getscr: lda $0400,x ; Patched at runtime
setcursor:
lda #cursor
setscr: sta $0400,x ; Patched at runtime
.ifdef __APPLE2ENH__
bit LOWSCR ; Doesn't hurt in 40 column mode
.endif
rts
; ------------------------------------------------------------------------
@@ -65,9 +70,7 @@ setscr: sta $0400,x ; Patched at runtime
.code
done:
.ifdef __APPLE2ENH__
bit LOWSCR ; Doesn't hurt in 40 column mode
.endif
return: rts
; Hide the mouse cursor.
@@ -108,14 +111,14 @@ movex:
inx
bcs :-
stx column+1
.ifdef __APPLE2ENH__
; Patch switch anyway, it will just be skipped over if in 40-col mode
adc #7 / 2 ; Left or right half of 40-col column?
ldx #<LOWSCR ; Columns 1,3,5..79
bcs :+
.assert LOWSCR + 1 = HISCR, error
inx ; Columns 0,2,4..78
: stx switch+1
.endif
rts
; Move the mouse cursor y position to the value in A/X.

37
libsrc/apple2/mktime_dt.s Normal file
View 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

View File

@@ -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

View 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

View 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

View File

@@ -7,6 +7,7 @@
.include "zeropage.inc"
.include "mouse-kernel.inc"
.include "apple2.inc"
.include "get_tv.inc"
.macpack module
@@ -21,6 +22,7 @@ CLAMPMOUSE = $17 ; Sets mouse bounds in a window
HOMEMOUSE = $18 ; Sets mouse to upper-left corner of clamp win
INITMOUSE = $19 ; Resets mouse clamps to default values and
; sets mouse position to 0,0
TIMEDATA = $1C ; Set mousecard's interrupt rate
pos1_lo := $0478
pos1_hi := $0578
@@ -41,6 +43,7 @@ status := $0778
.byte MOUSE_API_VERSION ; Mouse driver API version number
; Library reference
libref:
.addr $0000
; Jump table
@@ -133,8 +136,8 @@ next: inc ptr1+1
bcc :+
; Mouse firmware not found
lda #<MOUSE_ERR_NO_DEVICE
ldx #>MOUSE_ERR_NO_DEVICE
lda #MOUSE_ERR_NO_DEVICE
ldx #0 ; return value is char
rts
; Check Pascal 1.1 Firmware Protocol ID bytes
@@ -152,9 +155,10 @@ next: inc ptr1+1
sta xparam+1
sta jump+2
; Disable interrupts now because setting the slot number makes
; Disable interrupts now because setting the slot number makes
; the IRQ handler (maybe called due to some non-mouse IRQ) try
; calling the firmware which isn't correctly set up yet
php
sei
; Convert to and save slot number
@@ -167,15 +171,39 @@ next: inc ptr1+1
asl
asl
sta yparam+1
; The AppleMouse II Card needs the ROM switched in
; Apple II technical notes "Varying VBL Interrupt Rate",
lda libref
ldx libref+1
sta ptr1
stx ptr1+1
.ifdef __APPLE2ENH__
lda (ptr1)
.else
ldy #$00
lda (ptr1),y
.endif
cmp #TV::OTHER
beq :+
; The TV values are aligned with the values the mousecard
; expect: 0 for 60Hz, 1 for 50Hz.
.assert TV::NTSC = 0, error
.assert TV::PAL = 1, error
ldx #TIMEDATA
jsr firmware
: ; The AppleMouse II Card needs the ROM switched in
; to be able to detect an Apple //e and use RDVBL
bit $C082
; Reset mouse hardware
ldx #INITMOUSE
jsr firmware
; Switch in LC bank 2 for R/O
bit $C080
@@ -211,7 +239,7 @@ next: inc ptr1+1
common: jsr firmware
; Enable interrupts and return success
cli
plp
lda #<MOUSE_ERR_OK
ldx #>MOUSE_ERR_OK
rts
@@ -220,6 +248,7 @@ common: jsr firmware
; No return code required (the driver is removed from memory on return).
UNINSTALL:
; Hide cursor
php
sei
jsr CHIDE
@@ -236,12 +265,12 @@ UNINSTALL:
SETBOX:
sta ptr1
stx ptr1+1
; Set x clamps
ldx #$00
ldy #MOUSE_BOX::MINX
jsr :+
; Set y clamps
ldx #$01
ldy #MOUSE_BOX::MINY
@@ -249,7 +278,8 @@ SETBOX:
; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
; "Disable interrupts before placing position information in the
; screen holes."
: sei
: php
sei
; Set low clamp
lda (ptr1),y
@@ -257,7 +287,7 @@ SETBOX:
sta pos1_lo
iny
lda (ptr1),y
sta box,y
sta box,y
sta pos1_hi
; Skip one word
@@ -267,11 +297,11 @@ SETBOX:
; Set high clamp
iny
lda (ptr1),y
sta box,y
sta box,y
sta pos2_lo
iny
lda (ptr1),y
sta box,y
sta box,y
sta pos2_hi
txa
@@ -298,6 +328,7 @@ GETBOX:
; the screen). No return code required.
MOVE:
ldy slot
php
sei
; Set y
@@ -328,9 +359,10 @@ MOVE:
; no special action is required besides hiding the mouse cursor.
; No return code required.
HIDE:
php
sei
jsr CHIDE
cli
plp
rts
; SHOW: Is called to show the mouse cursor. The mouse kernel manages a
@@ -339,15 +371,16 @@ HIDE:
; no special action is required besides enabling the mouse cursor.
; No return code required.
SHOW:
php
sei
jsr CSHOW
cli
plp
rts
; BUTTONS: Return the button mask in A/X.
BUTTONS:
lda info + MOUSE_INFO::BUTTONS
ldx #$00
ldx #>$0000
rts
; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
@@ -360,12 +393,13 @@ POS:
; struct pointed to by ptr1. No return code required.
INFO:
ldy #.sizeof(MOUSE_INFO)-1
copy: sei
copy: php
sei
: lda info,y
sta (ptr1),y
dey
bpl :-
cli
plp
rts
; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl

25
libsrc/apple2/mouseref.s Normal file
View File

@@ -0,0 +1,25 @@
;
; Colin Leroy-Mira, 2025-05-11
;
.export mouse_libref
.import _get_tv, ostype, return0
.constructor init_mousetv
.include "get_tv.inc"
.segment "ONCE"
.proc init_mousetv
lda ostype
cmp #$40 ; Technical notes say not to change
bcs :+ ; interrupt rate on IIc/IIgs, so...
jsr _get_tv
sta mouse_libref
: rts ; ...don't update "Other" on those machines
.endproc
.data
mouse_libref: .byte TV::OTHER

View File

@@ -1,27 +1,26 @@
;
; Ullrich von Bassewitz, 08.08.1998
; Colin Leroy-Mira, 26.05.2025
;
; void __fastcall__ chlinexy (unsigned char x, unsigned char y, unsigned char length);
; void __fastcall__ chline (unsigned char length);
; void __fastcall__ mt_chlinexy (unsigned char x, unsigned char y, unsigned char length);
; void __fastcall__ mt_chline (unsigned char length);
;
.export _chlinexy, _chline, chlinedirect
.ifdef __APPLE2ENH__
.export _mt_chlinexy, _mt_chline, chlinedirect
.import gotoxy, cputdirect
.include "zeropage.inc"
.include "apple2.inc"
_chlinexy:
_mt_chlinexy:
pha ; Save the length
jsr gotoxy ; Call this one, will pop params
pla ; Restore the length and run into _chline
_chline:
.ifdef __APPLE2ENH__
_mt_chline:
ldx #'_' | $80 ; Underscore, screen code
.else
ldx #'-' | $80 ; Minus, screen code
.endif
chlinedirect:
stx tmp1
@@ -33,3 +32,5 @@ chlinedirect:
dec tmp2
bne :-
done: rts
.endif

View File

@@ -1,34 +1,32 @@
;
; Ullrich von Bassewitz, 08.08.1998
; Colin Leroy-Mira, 26.05.2025
;
; void __fastcall__ cvlinexy (unsigned char x, unsigned char y, unsigned char length);
; void __fastcall__ cvline (unsigned char length);
; void __fastcall__ mt_cvlinexy (unsigned char x, unsigned char y, unsigned char length);
; void __fastcall__ mt_cvline (unsigned char length);
;
.export _cvlinexy, _cvline
.ifdef __APPLE2ENH__
.export _mt_cvlinexy, _mt_cvline
.import gotoxy, putchar, newline
.include "zeropage.inc"
_cvlinexy:
_mt_cvlinexy:
pha ; Save the length
jsr gotoxy ; Call this one, will pop params
pla ; Restore the length and run into _cvline
_cvline:
.ifdef __APPLE2ENH__
ldx #$5F ; Left vertical line MouseText character
.else
ldx #'!' | $80 ; Exclamation mark, screen code
.endif
stx tmp1
_mt_cvline:
cmp #$00 ; Is the length zero?
beq done ; Jump if done
sta tmp2
: lda tmp1 ; Screen code
: lda #$5F ; Left vertical line MouseText character
jsr putchar ; Write, no cursor advance
jsr newline ; Advance cursor to next line
dec tmp2
bne :-
done: rts
.endif

View File

@@ -18,6 +18,7 @@
.include "fcntl.inc"
.include "mli.inc"
.include "filedes.inc"
.include "time.inc"
.segment "ONCE"
@@ -64,7 +65,7 @@ _open:
errno: jsr incsp4 ; Preserves A
; Set __errno
jmp __directerrno
jmp ___directerrno
; Save fdtab slot
found: tya
@@ -147,8 +148,8 @@ oserr1: ldy tmp2 ; Restore fdtab slot
jsr freebuffer
pla ; Restore oserror code
; Set __oserror
jmp __mappederrno
; Set ___oserror
jmp ___mappederrno
open: ldy tmp2 ; Restore fdtab slot
@@ -208,8 +209,8 @@ done: lda tmp1 ; Restore fd
jsr popname ; Preserves A
; Return success
ldx #$00
stx __oserror
ldx #>$0000
stx ___oserror
rts
freebuffer:

View File

@@ -1,112 +0,0 @@
/*****************************************************************************/
/* */
/* opendir.h */
/* */
/* Open a directory */
/* */
/* */
/* */
/* (C) 2005 Oliver Schmidt, <ol.sc@web.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 <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include "dir.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
extern char _cwd[FILENAME_MAX];
/*****************************************************************************/
/* Code */
/*****************************************************************************/
DIR* __fastcall__ opendir (register const char* name)
{
register DIR* dir;
/* Alloc DIR */
if ((dir = malloc (sizeof (*dir))) == NULL) {
/* May not have been done by malloc() */
_directerrno (ENOMEM);
/* Return failure */
return NULL;
}
/* Interpret dot as current working directory */
if (*name == '.') {
name = _cwd;
}
/* Open directory file */
if ((dir->fd = open (name, O_RDONLY)) != -1) {
/* Read directory key block */
if (read (dir->fd,
dir->block.bytes,
sizeof (dir->block)) == sizeof (dir->block)) {
/* Get directory entry infos from directory header */
dir->entry_length = dir->block.bytes[0x23];
dir->entries_per_block = dir->block.bytes[0x24];
/* Skip directory header entry */
dir->current_entry = 1;
/* Return success */
return dir;
}
/* EOF: Most probably no directory file at all */
if (_oserror == 0) {
_directerrno (EINVAL);
}
/* Cleanup directory file */
close (dir->fd);
}
/* Cleanup DIR */
free (dir);
/* Return failure */
return NULL;
}

159
libsrc/apple2/opendir.s Normal file
View File

@@ -0,0 +1,159 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; DIR* __fastcall__ opendir (register const char* name)
;
.export _opendir, read_dir_block_ptr1
.import closedir_ptr1
.import _open, _read, _close
.import _malloc
.import ___directerrno
.import ___oserror, __cwd
.import pushptr1, popptr1
.import pushax, pusha0
.import return0, returnFFFF
.importzp ptr1
.include "apple2.inc"
.include "dir.inc"
.include "errno.inc"
.include "fcntl.inc"
.include "zeropage.inc"
.proc _opendir
sta ptr1
stx ptr1+1
ldy #$00
lda (ptr1),y
cmp #'.'
bne :+
lda #<__cwd
ldx #>__cwd
sta ptr1
stx ptr1+1
: ; Open directory
jsr pushptr1
lda #O_RDONLY
jsr pusha0
ldy #$04
jsr _open
cmp #$FF ; Did we succeed?
beq @return_null
pha ; Yes - Push fd for backup
; malloc the dir struct
lda #<.sizeof(DIR)
ldx #>.sizeof(DIR)
jsr _malloc
bne :+
; We failed to allocate
pla ; Get fd back
ldx #$00
jsr _close ; Close it
lda #ENOMEM ; Set error
jsr ___directerrno
@return_null:
jmp return0
: ; Store dir struct to pointer
sta ptr1
stx ptr1+1
; Save fd to dir struct
lda #$00
ldy #DIR::FD + 1
sta (ptr1),y
dey
pla ; Get fd back
sta (ptr1),y
jsr read_dir_block_ptr1
bcc @read_ok
; Close directory, free it
jsr closedir_ptr1
jmp return0 ; Return NULL
@read_ok:
; Read succeeded, populate dir struct
; Get file_count to entry_length from block
ldy #$26 + DIR::BYTES
: lda (ptr1),y
pha
dey
cpy #$23 + DIR::BYTES - 1
bne :-
; Set entry_length to file_count in struct
ldy #DIR::ENTRY_LENGTH
: pla
sta (ptr1),y
iny
cpy #DIR::CURRENT_ENTRY
bne :-
; Skip directory header entry
lda #$01
sta (ptr1),y
; Return pointer to dir struct
lda ptr1
ldx ptr1+1
rts
.endproc
; Read a directory for the DIR* pointer in ptr1
; Return with carry clear on success
read_dir_block_ptr1:
; Push ptr1, read will destroy it
jsr pushptr1
ldy #DIR::FD
lda (ptr1),y
jsr pusha0 ; Push fd for read
lda #<DIR::BYTES
clc
adc ptr1
pha
lda #>DIR::BYTES
adc ptr1+1
tax
pla
jsr pushax ; Push dir->block.bytes for read
lda #<.sizeof(DIR::BYTES)
ldx #>.sizeof(DIR::BYTES)
jsr _read ; Read directory block
cpx #>.sizeof(DIR::BYTES)
bne @read_err
cmp #<.sizeof(DIR::BYTES)
beq @read_ok
@read_err:
; Read failed, exit
lda ___oserror
bne :+
lda #EINVAL
jsr ___directerrno
: sec
bcs @out
@read_ok:
clc
@out:
jmp popptr1

View File

@@ -1,14 +1,14 @@
;
; Ullrich von Bassewitz, 17.05.2000
;
; int __fastcall__ _osmaperrno (unsigned char oserror);
; int __fastcall__ __osmaperrno (unsigned char oserror);
;
.export __osmaperrno
.export ___osmaperrno
.include "errno.inc"
__osmaperrno:
___osmaperrno:
ldx #ErrTabSize
: cmp ErrTab-2,x ; Search for the error code
beq :+ ; Jump if found
@@ -23,7 +23,7 @@ __osmaperrno:
; Found the code
: lda ErrTab-1,x
ldx #$00 ; High byte always zero
ldx #>$0000
rts
.rodata

View File

@@ -1,16 +1,16 @@
;
; Ullrich von Bassewitz, 07.11.2002
;
; void _randomize (void);
; void __randomize (void);
; /* Initialize the random number generator */
;
.export __randomize
.export ___randomize
.import _srand
.include "apple2.inc"
__randomize:
___randomize:
ldx RNDH ; Use random value supplied by ROM
lda RNDL
jmp _srand ; Initialize generator

View File

@@ -19,11 +19,14 @@
.segment "ONCE"
initprompt:
; Set prompt <> ']' to let DOS 3.3 know that we're
; not in Applesoft immediate mode and thus keep it
; from scanning our device I/O for DOS commands.
; Set prompt <> ']' and currently executed Applesoft
; line number hibyte <> $FF to let DOS 3.3 (at $A65E)
; know that we're not in Applesoft immediate mode and
; thus keep it from scanning our device I/O for DOS
; commands.
lda #$80 ; Same value used at $D52C
sta PROMPT
sta CURLIN+1 ; Any value <> $FF will do
rts
.code
@@ -49,7 +52,7 @@ _read:
; Device succeeds always
device: lda #$00
sta __oserror
sta ___oserror
; Set counter to zero
sta ptr3
@@ -104,4 +107,4 @@ check: lda ptr3
einval: lda #EINVAL
; Set __errno
errno: jmp __directerrno
errno: jmp ___directerrno

View File

@@ -1,90 +0,0 @@
/*****************************************************************************/
/* */
/* readdir.c */
/* */
/* Read directory entry */
/* */
/* */
/* */
/* (C) 2005 Oliver Schmidt, <ol.sc@web.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 <stddef.h>
#include <unistd.h>
#include <dirent.h>
#include "dir.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
struct dirent* __fastcall__ readdir (register DIR* dir)
{
register unsigned char* entry;
/* Search for the next active directory entry */
do {
/* Read next directory block if necessary */
if (dir->current_entry == dir->entries_per_block) {
if (read (dir->fd,
dir->block.bytes,
sizeof (dir->block)) != sizeof (dir->block)) {
/* Just return failure as read() has */
/* set errno if (and only if) no EOF */
return NULL;
}
/* Start with first entry in next block */
dir->current_entry = 0;
}
/* Compute pointer to current entry */
entry = dir->block.content.entries +
dir->current_entry * dir->entry_length;
/* Switch to next entry */
++dir->current_entry;
} while (entry[0x00] == 0);
/* Move creation date/time to allow for next step below */
*(unsigned long*)&entry[0x1A] = *(unsigned long*)&entry[0x18];
/* Feature unsigned long access to EOF by extension from 3 to 4 bytes */
entry[0x18] = 0;
/* Move file type to allow for next step below */
entry[0x19] = entry[0x10];
/* Zero-terminate file name */
entry[0x01 + (entry[0x00] & 0x0F)] = 0;
/* Return success */
return (struct dirent*)&entry[0x01];
}

113
libsrc/apple2/readdir.s Normal file
View File

@@ -0,0 +1,113 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; struct dirent * __fastcall__ readdir (DIR *dir)
;
.export _readdir
.import read_dir_block_ptr1
.import incax1, return0
.import tosaddax, tosumula0, incaxy
.import pushax, pusha0, pushptr1, popptr1
.importzp ptr1, ptr4
.include "dir.inc"
.proc _readdir
sta ptr1
stx ptr1+1
@next_entry:
; Do we need to read the next directory block?
ldy #DIR::CURRENT_ENTRY
lda (ptr1),y
ldy #DIR::ENTRIES_PER_BLOCK
cmp (ptr1),y
bne @read_entry ; We don't
jsr read_dir_block_ptr1
bcc @read_ok
; We had a read error
jmp return0
@read_ok:
ldy #DIR::CURRENT_ENTRY
lda #$00
sta (ptr1),y
@read_entry:
; Compute pointer to current entry:
; entry = dir->block.content.entries +
; dir->current_entry * dir->entry_length
jsr pushptr1 ; Backup ptr1
lda ptr1
ldx ptr1+1
ldy #DIR::BYTES + DIR::CONTENT::ENTRIES
jsr incaxy
jsr pushax
ldy #DIR::CURRENT_ENTRY
lda (ptr1),y
jsr pusha0
ldy #DIR::ENTRY_LENGTH
lda (ptr1),y
jsr tosumula0
jsr tosaddax
; Store pointer to current entry
sta ptr4
stx ptr4+1
jsr popptr1
; Switch to next entry
ldy #DIR::CURRENT_ENTRY
lda (ptr1),y
clc
adc #1
sta (ptr1),y
; Check if entry[0] == 0
ldy #$00
lda (ptr4),y
beq @next_entry ; Yes, skip entry
; Move creation date/time to allow for next step below
; 18-19-1A-1B => 1A-1B-1C-1D
ldy #$1B
: lda (ptr4),y
iny
iny
sta (ptr4),y
dey
dey
dey
cpy #$17
bne :-
; Feature unsigned long access to EOF by extension from 3 to 4 bytes
; entry[0x18] = 0
iny
lda #$00
sta (ptr4),y
; Move file type to allow for next step below
; entry[0x19] = entry[0x10]
ldy #$10
lda (ptr4),y
ldy #$19
sta (ptr4),y
; Zero-terminate file name
ldy #$00
lda (ptr4),y
and #$0F
tay
iny
lda #$00
sta (ptr4),y
; Return pointer to entry+1
lda ptr4
ldx ptr4+1
jmp incax1
.endproc

View File

@@ -18,5 +18,5 @@ normal: dex ; $00->$FF, $40->$3F
stx INVFLG ; Save new flag value
bmi :+ ; Jump if current value is $FF (normal)
lda #$01 ; Return "inverse"
: ldx #$00
: ldx #>$0000
rts

View File

@@ -1,69 +0,0 @@
/*****************************************************************************/
/* */
/* rewinddir.c */
/* */
/* Reset directory stream */
/* */
/* */
/* */
/* (C) 2005 Oliver Schmidt, <ol.sc@web.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 <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include "dir.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void __fastcall__ rewinddir (register DIR* dir)
{
/* Rewind directory file */
if (lseek (dir->fd, 0, SEEK_SET)) {
/* Read directory key block */
if (read (dir->fd,
dir->block.bytes,
sizeof (dir->block)) == sizeof (dir->block)) {
/* Skip directory header entry */
dir->current_entry = 1;
/* Return success */
return;
}
}
/* Assert that no subsequent readdir() finds an active entry */
memset (dir->block.bytes, 0, sizeof (dir->block));
/* Return failure */
}

70
libsrc/apple2/rewinddir.s Normal file
View File

@@ -0,0 +1,70 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; void __fastcall__ rewinddir (DIR* dir)
;
.export _rewinddir
.import read_dir_block_ptr1
.import pusha, pusha0, pushax
.import pushptr1, popptr1
.import incaxy
.import _lseek, _memset
.importzp ptr1, sreg
.include "dir.inc"
.include "stdio.inc"
.proc _rewinddir
sta ptr1
stx ptr1+1
jsr pushptr1 ; Backup ptr1, destroyed by _lseek
; Rewind directory file
ldy #DIR::FD
lda (ptr1),y
jsr pusha0 ; Push dir->fd
tya ; Y = 0 here
jsr pusha0
jsr pusha0 ; Push 0L
lda #SEEK_SET ; X = 0 here
jsr _lseek
ora sreg ; Check lseek returned 0L
ora sreg+1
bne @rewind_err
txa
bne @rewind_err
jsr popptr1 ; Restore ptr1
; Read directory key block
jsr read_dir_block_ptr1
bcs @rewind_err
; Skip directory header entry
lda #$01
ldy #DIR::CURRENT_ENTRY
sta (ptr1),y
rts
@rewind_err:
jsr popptr1 ; Restore ptr1
; Assert that no subsequent readdir() finds an active entry
lda ptr1
ldx ptr1+1
ldy #DIR::BYTES + DIR::CONTENT::ENTRIES
jsr incaxy
jsr pushax
lda #$00
jsr pusha
lda #<.sizeof(DIR::BYTES)
ldx #>.sizeof(DIR::BYTES)
jmp _memset
.endproc

View File

@@ -49,10 +49,10 @@ rwcommon:
rwepilog:
; Return success
sta __oserror ; A = 0
sta ___oserror ; A = 0
lda mliparam + MLI::RW::TRANS_COUNT
ldx mliparam + MLI::RW::TRANS_COUNT+1
rts
; Set __oserror
oserr: jmp __mappederrno
; Set ___oserror
oserr: jmp ___mappederrno

752
libsrc/apple2/ser/a2.gs.s Normal file
View File

@@ -0,0 +1,752 @@
;
; Serial driver for the Apple IIgs Zilog Z8530.
;
; Colin Leroy-Mira <colin@colino.net>, 2023
;
; This software is licensed under the same license as cc65,
; the zlib license (see LICENSE file).
;
; Documentation from http://www.applelogic.org/files/Z8530UM.pdf (pages
; referred to where applicable)
; and https://gswv.apple2.org.za/a2zine/Utils/Z8530_SCCsamples_info.txt
.setcpu "65816"
.include "zeropage.inc"
.include "ser-kernel.inc"
.include "ser-error.inc"
.macpack module
; ------------------------------------------------------------------------
; Header. Includes jump table
.ifdef __APPLE2ENH__
module_header _a2e_gs_ser
.else
module_header _a2_gs_ser
.endif
; Driver signature
.byte $73, $65, $72 ; "ser"
.byte SER_API_VERSION ; Serial API version number
; Library reference
.addr $0000
; Jump table
.addr SER_INSTALL
.addr SER_UNINSTALL
.addr SER_OPEN
.addr SER_CLOSE
.addr SER_GET
.addr SER_PUT
.addr SER_STATUS
.addr SER_IOCTL
.addr SER_IRQ
;----------------------------------------------------------------------------
; Global variables
.bss
RecvHead: .res 1 ; Head of receive buffer
RecvTail: .res 1 ; Tail of receive buffer
RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
SendHead: .res 1 ; Head of send buffer
SendTail: .res 1 ; Tail of send buffer
SendFreeCnt: .res 1 ; Number of bytes in send buffer
Stopped: .res 1 ; Flow-stopped flag
RtsOff: .res 1
HSType: .res 1 ; Flow-control type
RecvBuf: .res 256 ; Receive buffers: 256 bytes
SendBuf: .res 256 ; Send buffers: 256 bytes
CurClockSource: .res 1 ; Whether to use BRG or RTxC for clock
.data
Opened: .byte $00 ; 1 when opened
Channel: .byte $00 ; Channel B by default
CurChanIrqFlags:.byte $00
SerFlagOrig: .byte $00
RxBitTable: .byte %00000000 ; SER_BITS_5, in WR_RX_CTRL (WR3)
.byte %10000000 ; SER_BITS_6 (Ref page 5-7)
.byte %01000000 ; SER_BITS_7
.byte %11000000 ; SER_BITS_8
TxBitTable: .byte %00000000 ; SER_BITS_5, in WR_TX_CTRL (WR5)
.byte %01000000 ; SER_BITS_6 (Ref page 5-9)
.byte %00100000 ; SER_BITS_7
.byte %01100000 ; SER_BITS_8
.rodata
ClockMultiplier:.byte %01000000 ; Clock x16 (300-57600bps, WR4, ref page 5-8)
.byte %10000000 ; Clock x32 (115200bps, ref page 5-8)
ClockSource: .byte %01010000 ; Use baud rate generator (ch. B) (WR11, page 5-17)
.byte %00000000 ; Use RTxC (115200bps) (ch. B)
.byte %11010000 ; Use baud rate generator (ch. A)
.byte %10000000 ; Use RTxC (115200bps) (ch. A)
BrgEnabled: .byte %00000001 ; Baud rate generator on (WR14, page 5-19)
.byte %00000000 ; BRG Off
ChanIrqFlags: .byte %00000101 ; ANDed (RX/special IRQ, ch. B) (page 5-25)
.byte %00101000 ; ANDed (RX/special IRQ, ch. A)
ChanIrqMask: .byte %00000111 ; Ch. B IRQ flags mask
.byte %00111000 ; Ch. A IRQ flags mask
BaudTable: ; bit7 = 1 means setting is invalid
; Indexes cc65 RS232 SER_BAUD enum
; into WR12/13 register values
; (Ref page 5-18 and 5-19)
.word $FFFF ; SER_BAUD_45_5
.word $FFFF ; SER_BAUD_50
.word $FFFF ; SER_BAUD_75
.word $FFFF ; SER_BAUD_110
.word $FFFF ; SER_BAUD_134_5
.word $FFFF ; SER_BAUD_150
.word $017E ; SER_BAUD_300
.word $FFFF ; SER_BAUD_600
.word $005E ; SER_BAUD_1200
.word $FFFF ; SER_BAUD_1800
.word $002E ; SER_BAUD_2400
.word $FFFF ; SER_BAUD_3600
.word $0016 ; SER_BAUD_4800
.word $FFFF ; SER_BAUD_7200
.word $000A ; SER_BAUD_9600
.word $0004 ; SER_BAUD_19200
.word $0001 ; SER_BAUD_38400
.word $0000 ; SER_BAUD_57600
.word $0000 ; SER_BAUD_115200 (constant unused at that speed)
.word $FFFF ; SER_BAUD_230400
; About the speed selection: either we use the baud rate generator:
; - Load the time constants from BaudTable into WR12/WR13
; - Setup the TX/RX clock source to BRG (ClockSource into WR11)
; - Setup the clock multiplier (WR4)
; - Enable the baud rate generator (WR14)
; In this case, the baud rate will be:
; rate = crystal_clock/(2+BRG_time_constant))/(2*clock_multiplier)
; Example: (3686400/(2+0x0004)) / (2*16) = 19200 bps
;
; Or we don't use the baud rate generator:
; - Setup the TX/RX clock source to RTxC
; - Setup the clock multiplier
; - Disable the baud rate generator
; - WR12 and 13 are ignored
; In this case, the baud rate will be:
; rate = crystal_clock/clock_multiplier
; Example: 3686400/32 = 115200 bps
StopTable: .byte %00000100 ; SER_STOP_1, in WR_TX_RX_CTRL (WR4)
.byte %00001100 ; SER_STOP_2 (Ref page 5-8)
ParityTable: .byte %00000000 ; SER_PAR_NONE, in WR_TX_RX_CTRL (WR4)
.byte %00000001 ; SER_PAR_ODD (Ref page 5-8)
.byte %00000011 ; SER_PAR_EVEN
.byte $FF ; SER_PAR_MARK
.byte $FF ; SER_PAR_SPACE
; ------------------------------------------------------------------------
; Addresses
SCCAREG := $C039
SCCBREG := $C038
SCCADATA := $C03B
SCCBDATA := $C03A
; We're supposed to get SerFlag's address using GetAddr on ROMs 1 and 3.
; (https://archive.org/details/IIgs_2523018_SCC_Access, page 9)
; But, it's the same value as on ROM0. As we don't expect a ROM 4 anytime
; soon with a different value, let's keep it simple.
SER_FLAG := $E10104
; ------------------------------------------------------------------------
; Channels
CHANNEL_B = 0
CHANNEL_A = 1
; ------------------------------------------------------------------------
; Write registers, read registers, and values that interest us
WR_INIT_CTRL = 0
RR_INIT_STATUS = 0
INIT_CTRL_CLEAR_EIRQ = %00010000
INIT_CTRL_CLEAR_ERR = %00110000
INIT_STATUS_READY = %00000100
INIT_STATUS_RTS = %00100000
WR_TX_RX_MODE_CTRL = 1
TX_RX_MODE_OFF = %00000000
TX_RX_MODE_RXIRQ = %00010001
WR_RX_CTRL = 3 ; (Ref page 5-7)
RR_RX_STATUS = 9 ; Corresponding status register
RX_CTRL_ON = %00000001 ; ORed, Rx enabled
RX_CTRL_OFF = %11111110 ; ANDed,Rx disabled
WR_TX_RX_CTRL = 4
RR_TX_RX_STATUS = 4
WR_TX_CTRL = 5 ; (Ref page 5-9)
RR_TX_STATUS = 5 ; Corresponding status register
TX_CTRL_ON = %00001000 ; ORed, Tx enabled
TX_CTRL_OFF = %11110111 ; ANDed,Tx disabled
TX_DTR_ON = %01111111 ; ANDed,DTR ON (high)
TX_DTR_OFF = %10000000 ; ORed, DTR OFF
TX_RTS_ON = %00000010 ; ORed, RTS ON (low)
TX_RTS_OFF = %11111101 ; ANDed, RTS OFF
WR_MASTER_IRQ_RST = 9 ; (Ref page 5-14)
MASTER_IRQ_SHUTDOWN = %00000010 ; STA'd
MASTER_IRQ_MIE_RST = %00001010 ; STA'd
MASTER_IRQ_SET = %00011001 ; STA'd
WR_CLOCK_CTRL = 11 ; (Ref page 5-17)
WR_BAUDL_CTRL = 12 ; (Ref page 5-18)
WR_BAUDH_CTRL = 13 ; (Ref page 5-19)
WR_MISC_CTRL = 14 ; (Ref page 5-19)
WR_IRQ_CTRL = 15 ; (Ref page 5-20)
IRQ_CLEANUP_EIRQ = %00001000
RR_SPEC_COND_STATUS = 1 ; (Ref page 5-23)
SPEC_COND_FRAMING_ERR = %01000000
SPEC_COND_OVERRUN_ERR = %00100000
RR_IRQ_STATUS = 2 ; (Ref page 5-24)
IRQ_MASQ = %01110000 ; ANDed
IRQ_RX = %00100000
IRQ_SPECIAL = %01100000
RR_INTR_PENDING_STATUS = 3 ; (Ref page 5-25)
INTR_IS_RX = %00100100 ; ANDed (RX IRQ, channel A or B)
.code
; Read register value to A.
; Input: X as channel
; Y as register
; Output: A
readSSCReg:
cpx #0
bne ReadAreg
sty SCCBREG
lda SCCBREG
rts
ReadAreg:
sty SCCAREG
lda SCCAREG
rts
; Write value of A to a register.
; Input: X as channel
; Y as register
writeSCCReg:
cpx #0
bne WriteAreg
sty SCCBREG
sta SCCBREG
rts
WriteAreg:
sty SCCAREG
sta SCCAREG
rts
;----------------------------------------------------------------------------
; SER_INSTALL: Is called after the driver is loaded into memory. If possible,
; check if the hardware is present. Must return an SER_ERR_xx code in a/x.
;
; Since we don't have to manage the IRQ vector on the Apple II, this is
; actually the same as:
;
; SER_UNINSTALL: Is called before the driver is removed from memory.
; No return code required (the driver is removed from memory on return).
;
; and:
;
; SER_CLOSE: Close the port and disable interrupts. Called without parameters.
; Must return an SER_ERR_xx code in a/x.
SER_INSTALL:
SER_UNINSTALL:
SER_CLOSE:
; Check if this is a IIgs (Apple II Miscellaneous TechNote #7,
; Apple II Family Identification)
sec
bit $C082
jsr $FE1F
bit $C080
bcc IIgs
lda #SER_ERR_NO_DEVICE ; Not a IIgs
ldx #>$0000
rts
IIgs:
ldx Opened ; Check for open port
beq :+
ldx Channel
php ; Deactivate interrupts
sei ; if enabled
ldy #WR_MASTER_IRQ_RST
lda #MASTER_IRQ_SHUTDOWN
jsr writeSCCReg
ldy #WR_TX_RX_MODE_CTRL
lda #TX_RX_MODE_OFF
jsr writeSCCReg
; Reset SerFlag to what it was
lda SerFlagOrig
sta SER_FLAG
lda SCCBDATA
; Clear external interrupts (twice)
ldy #WR_INIT_CTRL
lda #INIT_CTRL_CLEAR_EIRQ
jsr writeSCCReg
jsr writeSCCReg
; Reset MIE for firmware use
ldy #WR_MASTER_IRQ_RST
lda #MASTER_IRQ_MIE_RST
jsr writeSCCReg
ldx #$00
stx Opened ; Mark port as closed
plp ; Reenable interrupts if needed
: txa ; Promote char return value
rts
getClockSource:
.assert SER_PARAMS::BAUDRATE = 0, error
lda (ptr1) ; Baudrate index - cc65 value
cmp #SER_BAUD_115200
lda #$00
adc #$00
sta CurClockSource ; 0 = BRG, 1 = RTxC
rts
;----------------------------------------------------------------------------
; SER_OPEN: A pointer to a ser_params structure is passed in ptr1.
; Must return an SER_ERR_xx code in a/x.
SER_OPEN:
php ; Deactivate interrupts
sei ; if enabled
; Check if the handshake setting is valid
ldy #SER_PARAMS::HANDSHAKE ; Handshake
lda (ptr1),y
cmp #SER_HS_SW ; Not supported
beq InvParam
sta HSType ; Store flow control type
; Initialize buffers
ldy #$00
sty Stopped
sty RecvHead
sty RecvTail
sty SendHead
sty SendTail
dey ; Y = 255
sty RecvFreeCnt
sty SendFreeCnt
ldx Channel
ldy #RR_INIT_STATUS ; Hit rr0 once to sync up
jsr readSSCReg
ldy #WR_MISC_CTRL ; WR14: Turn everything off
lda #$00
jsr writeSCCReg
jsr getClockSource ; Should we use BRG or RTxC?
ldy #SER_PARAMS::STOPBITS ; WR4 setup: clock mult., stop & parity
lda (ptr1),y ; Stop bits
tay
lda StopTable,y ; Get value
pha
ldy #SER_PARAMS::PARITY
lda (ptr1),y ; Parity bits
tay
pla
ora ParityTable,y ; Get value
bmi InvParam
ldy CurClockSource ; Clock multiplier
ora ClockMultiplier,y
ldy #WR_TX_RX_CTRL
jsr writeSCCReg ; End of WR4 setup
ldy CurClockSource ; WR11 setup: clock source
cpx #CHANNEL_B
beq SetClock
iny ; Shift to get correct ClockSource val
iny ; depending on our channel
SetClock:
lda ClockSource,y
ldy #WR_CLOCK_CTRL
jsr writeSCCReg ; End of WR11 setup
lda ChanIrqFlags,x ; Store which IRQ bits we'll check
sta CurChanIrqFlags
SetBaud:
.assert SER_PARAMS::BAUDRATE = 0, error
lda (ptr1) ; Baudrate index - cc65 value
asl
tay
lda BaudTable,y ; Get low byte of register value
bpl BaudOK ; Verify baudrate is supported
InvParam:
lda #SER_ERR_INIT_FAILED
ldy #$00 ; Mark port closed
bra SetupOut
BaudOK:
phy ; WR12 setup: BRG time constant, low byte
ldy #WR_BAUDL_CTRL ; Setting WR12 & 13 is useless if we're using
jsr writeSCCReg ; RTxC, but doing it anyway makes code smaller
ply
iny
lda BaudTable,y ; WR13 setup: BRG time constant, high byte
ldy #WR_BAUDH_CTRL
jsr writeSCCReg
ldy CurClockSource ; WR14 setup: BRG enabling
lda BrgEnabled,y
ldy #WR_MISC_CTRL ; Time to turn this thing on
jsr writeSCCReg
ldy #SER_PARAMS::DATABITS ; WR3 setup: RX data bits
lda (ptr1),y
tay
lda RxBitTable,y
ora #RX_CTRL_ON ; and turn receiver on
phy
ldy #WR_RX_CTRL
jsr writeSCCReg ; End of WR3 setup
ply
lda TxBitTable,y ; WR5 setup: TX data bits
ora #TX_CTRL_ON ; and turn transmitter on
and #TX_DTR_ON ; and turn DTR on
sta RtsOff ; Save value for flow control
ora #TX_RTS_ON ; and turn RTS on
ldy #WR_TX_CTRL
jsr writeSCCReg ; End of WR5 setup
ldy #WR_IRQ_CTRL ; WR15 setup: IRQ
lda #IRQ_CLEANUP_EIRQ
jsr writeSCCReg
ldy #WR_INIT_CTRL ; WR0 setup: clear existing IRQs
lda #INIT_CTRL_CLEAR_EIRQ
jsr writeSCCReg ; Clear (write twice)
jsr writeSCCReg
ldy #WR_TX_RX_MODE_CTRL ; WR1 setup: Activate RX IRQ
lda #TX_RX_MODE_RXIRQ
jsr writeSCCReg
lda SCCBREG ; WR9 setup: Activate master IRQ
ldy #WR_MASTER_IRQ_RST
lda #MASTER_IRQ_SET
jsr writeSCCReg
lda SER_FLAG ; Get SerFlag's current value
sta SerFlagOrig ; and save it
ora ChanIrqMask,x ; Tell firmware which channel IRQs we want
sta SER_FLAG
ldy #$01 ; Mark port opened
lda #SER_ERR_OK
SetupOut:
plp ; Reenable interrupts if needed
ldx #>$0000
sty Opened
rts
;----------------------------------------------------------------------------
; SER_GET: Will fetch a character from the receive buffer and store it into the
; variable pointed to by ptr1. If no data is available, SER_ERR_NO_DATA is
; returned.
SER_GET:
ldx Channel
lda RecvFreeCnt ; Check for buffer empty
cmp #$FF
beq NoData
ldy Stopped ; Check for flow stopped
beq :+
cmp #63 ; Enough free?
bcc :+
stz Stopped ; Release flow control
lda RtsOff
ora #TX_RTS_ON
ldy #WR_TX_CTRL
jsr writeSCCReg
: ldy RecvHead ; Get byte from buffer
lda RecvBuf,y
inc RecvHead
inc RecvFreeCnt
sta (ptr1)
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax
rts
NoData:
lda #SER_ERR_NO_DATA
ldx #>$0000
rts
;----------------------------------------------------------------------------
; SER_PUT: Output character in A.
; Must return an SER_ERR_xx code in a/x.
SER_PUT:
ldx Channel
ldy SendFreeCnt ; Anything to send first?
iny ; Y = $FF?
beq :+
pha
lda #$00 ; TryHard = false
jsr TryToSend
pla
: ldy SendFreeCnt ; Do we have room to store byte?
bne :+
lda #SER_ERR_OVERFLOW
ldx #>$0000
rts
: ldy SendTail ; Put byte into send buffer & send
sta SendBuf,y
inc SendTail
dec SendFreeCnt
lda #$FF ; TryHard = true
jsr TryToSend
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax ; Promote char return value
rts
;----------------------------------------------------------------------------
; SER_STATUS: Return the status in the variable pointed to by ptr1.
; Must return an SER_ERR_xx code in a/x.
; We provide the read register 0, containing interesting info like
; INIT_STATUS_READY (hardware handshake status) or INIT_STATUS_RTS
; (ready to send).
SER_STATUS:
ldx Channel
ldy #RR_INIT_STATUS
jsr readSSCReg
ldx #$00
sta (ptr1)
.assert SER_ERR_OK = 0, error
txa
rts
;----------------------------------------------------------------------------
; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
; specific data in ptr1, and the ioctl code in A.
; Sets communication channel A or B (A = 1, B = 0)
; Must return an SER_ERR_xx code in a/x.
SER_IOCTL:
ora ptr1+1 ; Check data msb and code to be 0
bne :+
ldx ptr1 ; Check data lsb to be 0 or 1
bmi :+
cpx #$02
bcs :+
stx Channel
.assert SER_ERR_OK = 0, error
tax ; Promote char return value
rts
: lda #SER_ERR_INV_IOCTL
ldx #>$0000
rts
;----------------------------------------------------------------------------
; SER_IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
; registers are already saved, no parameters are passed, but the carry flag
; is clear on entry. The routine must return with carry set if the interrupt
; was handled, otherwise with carry clear.
SER_IRQ:
ldy #RR_INTR_PENDING_STATUS ; IRQ status is always in A reg
sty SCCAREG
lda SCCAREG
and CurChanIrqFlags ; Is this ours?
beq Done
and #INTR_IS_RX ; Is this an RX irq?
beq CheckSpecial
ldx Channel
beq ReadBdata
lda SCCADATA
bra ReadDone
ReadBdata:
lda SCCBDATA ; Get byte
ReadDone:
ldx RecvFreeCnt ; Check if we have free space left
beq Flow ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
cpx #33
bcc Flow ; Assert flow control if buffer space low
rts ; Interrupt handled (carry already set)
CheckSpecial:
; Always check IRQ special flags from Channel B (Ref page 5-24)
ldy #RR_IRQ_STATUS
sty SCCBREG
lda SCCBREG
and #IRQ_MASQ
cmp #IRQ_SPECIAL
beq Special
; Clear exint
ldx Channel
ldy #WR_INIT_CTRL
lda #INIT_CTRL_CLEAR_EIRQ
jsr writeSCCReg
sec
rts
Flow: lda HSType ; Don't touch if no flow control
beq IRQDone
ldx Channel ; Assert flow control if buffer space too low
ldy #WR_TX_CTRL
lda RtsOff
jsr writeSCCReg
sta Stopped
IRQDone:sec ; Interrupt handled
Done: rts
Special:ldx Channel
ldy #RR_SPEC_COND_STATUS
jsr readSSCReg
tax
and #SPEC_COND_FRAMING_ERR
bne BadChar
txa
and #SPEC_COND_OVERRUN_ERR
beq BadChar
ldy #WR_INIT_CTRL
lda #INIT_CTRL_CLEAR_ERR
jsr writeSCCReg
sec
rts
BadChar:
cpx #CHANNEL_B
beq BadCharB
lda SCCADATA
bra BadCharDone
BadCharB:
lda SCCBDATA ; Remove char in error
BadCharDone:
sec
rts
;----------------------------------------------------------------------------
; Try to send a byte. Internal routine. A = TryHard, X = Channel
TryToSend:
sta tmp1 ; Remember tryHard flag
Again: lda SendFreeCnt ; Anything to send?
cmp #$FF
beq Quit ; No
lda Stopped ; Check for flow stopped
bne Quit ; Bail out if it is
Wait:
ldy #RR_INIT_STATUS
jsr readSSCReg ; Check that we're ready to send
tay
and #INIT_STATUS_READY
beq NotReady
tya
and #INIT_STATUS_RTS ; Ready to send
bne Send
NotReady:
bit tmp1 ; Keep trying if must try hard
bmi Wait
Quit: rts
Send: ldy SendHead ; Send byte
lda SendBuf,y
cpx #CHANNEL_B
beq WriteBdata
sta SCCADATA
bra WriteDone
WriteBdata:
sta SCCBDATA
WriteDone:
inc SendHead
inc SendFreeCnt
jmp Again ; Continue flushing TX buffer

View File

@@ -26,6 +26,7 @@
.include "ser-error.inc"
.macpack module
.macpack cpu
; ------------------------------------------------------------------------
; Header. Includes jump table
@@ -37,8 +38,8 @@
.endif
; Driver signature
.byte $73, $65, $72 ; "ser"
.byte SER_API_VERSION ; Serial API version number
.byte $73, $65, $72 ; "ser"
.byte SER_API_VERSION ; Serial API version number
; Library reference
.addr $0000
@@ -57,11 +58,19 @@
;----------------------------------------------------------------------------
; I/O definitions
ACIA = $C088
ACIA_DATA = ACIA+0 ; Data register
ACIA_STATUS = ACIA+1 ; Status register
ACIA_CMD = ACIA+2 ; Command register
ACIA_CTRL = ACIA+3 ; Control register
.if (.cpu .bitand CPU_ISET_65C02)
ACIA := $C088
.else
Offset = $8F ; Move 6502 false read out of I/O to page $BF
ACIA := $C088-Offset
.endif
ACIA_DATA := ACIA+0 ; Data register
ACIA_STATUS := ACIA+1 ; Status register
ACIA_CMD := ACIA+2 ; Command register
ACIA_CTRL := ACIA+3 ; Control register
SLTROMSEL := $C02D ; For Apple IIgs slot verification
;----------------------------------------------------------------------------
; Global variables
@@ -70,16 +79,18 @@ ACIA_CTRL = ACIA+3 ; Control register
RecvHead: .res 1 ; Head of receive buffer
RecvTail: .res 1 ; Tail of receive buffer
RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
RecvFreeCnt: .res 1 ; Number of free bytes in receive buffer
SendHead: .res 1 ; Head of send buffer
SendTail: .res 1 ; Tail of send buffer
SendFreeCnt: .res 1 ; Number of bytes in send buffer
SendFreeCnt: .res 1 ; Number of free bytes in send buffer
Stopped: .res 1 ; Flow-stopped flag
RtsOff: .res 1 ;
RtsOff: .res 1 ; Cached value of command register with
; flow stopped
HSType: .res 1 ; Flow-control type
RecvBuf: .res 256 ; Receive buffers: 256 bytes
SendBuf: .res 256 ; Send buffers: 256 bytes
RecvBuf: .res 256 ; Receive buffer: 256 bytes
SendBuf: .res 256 ; Send buffer: 256 bytes
Index: .res 1 ; I/O register index
@@ -89,8 +100,9 @@ Slot: .byte $02 ; Default to SSC in slot 2
.rodata
; Tables used to translate RS232 params into register values
BaudTable: ; bit7 = 1 means setting is invalid
BaudTable: ; Table used to translate RS232 baudrate param
; into control register value
; bit7 = 1 means setting is invalid
.byte $FF ; SER_BAUD_45_5
.byte $01 ; SER_BAUD_50
.byte $02 ; SER_BAUD_75
@@ -109,32 +121,44 @@ BaudTable: ; bit7 = 1 means setting is invalid
.byte $0F ; SER_BAUD_19200
.byte $FF ; SER_BAUD_38400
.byte $FF ; SER_BAUD_57600
.byte $FF ; SER_BAUD_115200
.byte $00 ; SER_BAUD_115200
.byte $FF ; SER_BAUD_230400
BitTable:
BitTable: ; Table used to translate RS232 databits param
; into control register value
.byte $60 ; SER_BITS_5
.byte $40 ; SER_BITS_6
.byte $20 ; SER_BITS_7
.byte $00 ; SER_BITS_8
StopTable:
StopTable: ; Table used to translate RS232 stopbits param
; into control register value
.byte $00 ; SER_STOP_1
.byte $80 ; SER_STOP_2
ParityTable:
ParityTable: ; Table used to translate RS232 parity param
; into command register value
.byte $00 ; SER_PAR_NONE
.byte $20 ; SER_PAR_ODD
.byte $60 ; SER_PAR_EVEN
.byte $A0 ; SER_PAR_MARK
.byte $E0 ; SER_PAR_SPACE
IdOfsTable:
IdOfsTable: ; Table of bytes positions, used to check four
; specific bytes on the slot's firmware to make
; sure this is a serial card.
.byte $05 ; Pascal 1.0 ID byte
.byte $07 ; Pascal 1.0 ID byte
.byte $0B ; Pascal 1.1 generic signature byte
.byte $0C ; Device signature byte
IdValTable:
.byte $38 ; Fixed
.byte $18 ; Fixed
.byte $01 ; Fixed
.byte $31 ; Serial or parallel I/O card type 1
IdValTable: ; Table of expected values for the four checked
; bytes
.byte $38 ; ID Byte 0 (from Pascal 1.0), fixed
.byte $18 ; ID Byte 1 (from Pascal 1.0), fixed
.byte $01 ; Generic signature for Pascal 1.1, fixed
.byte $31 ; Device signature byte (serial or
; parallel I/O card type 1)
IdTableLen = * - IdValTable
@@ -161,115 +185,167 @@ SER_CLOSE:
ldx Index ; Check for open port
beq :+
; Deactivate DTR and disable 6551 interrupts
lda #%00001010
lda #%00001010 ; Deactivate DTR and disable 6551 interrupts
sta ACIA_CMD,x
; Done, return an error code
: lda #<SER_ERR_OK
tax ; A is zero
: lda #SER_ERR_OK ; Done, return an error code
.assert SER_ERR_OK = 0, error
tax
stx Index ; Mark port as closed
rts
;----------------------------------------------------------------------------
; SER_OPEN: A pointer to a ser_params structure is passed in ptr1.
; Must return an SER_ERR_xx code in a/x.
; Note: Hardware checks are done in SER_OPEN instead of SER_INSTALL,
; because they depend on the selected slot, and we can't select the slot
; before SER_INSTALL.
SER_OPEN:
ldx #<$C000
; Check if this is a IIgs (Apple II Miscellaneous TechNote #7,
; Apple II Family Identification)
sec
bit $C082
jsr $FE1F
bit $C080
bcs NotIIgs
; We're on a IIgs. For every slot N, either bit N of $C02D is
; 0 for the internal ROM, or 1 for "Your Card". Let's make sure
; that slot N's bit is set to 1, otherwise, that can't be an SSC.
ldy Slot
lda SLTROMSEL
: lsr
dey
bpl :- ; Shift until slot's bit ends in carry
bcc NoDev
NotIIgs:ldx #<$C000
stx ptr2
lda #>$C000
ora Slot
sta ptr2+1
; Check Pascal 1.1 Firmware Protocol ID bytes
: ldy IdOfsTable,x
: ldy IdOfsTable,x ; Check Pascal 1.1 Firmware Protocol ID bytes
lda IdValTable,x
cmp (ptr2),y
bne NoDevice
bne NoDev
inx
cpx #IdTableLen
bcc :-
; Convert slot to I/O register index
lda Slot
lda Slot ; Convert slot to I/O register index
asl
asl
asl
asl
.if .not (.cpu .bitand CPU_ISET_65C02)
adc #Offset ; Assume carry to be clear
.endif
tax
; Check if the handshake setting is valid
ldy #SER_PARAMS::HANDSHAKE ; Handshake
lda (ptr1),y
cmp #SER_HS_HW ; This is all we support
bne InvParam
; Check that this works like an ACIA 6551 is expected to work
; Initialize buffers
ldy #$00
lda ACIA_STATUS,x ; Save current values in what we expect to be
sta tmp1 ; the ACIA status register
lda ACIA_CMD,x ; and command register. So we can restore them
sta tmp2 ; if this isn't a 6551.
ldy #%00000010 ; Disable TX/RX, disable IRQ
: tya
sta ACIA_CMD,x
cmp ACIA_CMD,x ; Verify what we stored is there
bne NotAcia
iny ; Enable TX/RX, disable IRQ
cpy #%00000100
bne :-
sta ACIA_STATUS,x ; Reset ACIA
lda ACIA_CMD,x ; Check that RX/TX is disabled
lsr
bcc AciaOK
NotAcia:lda tmp2 ; Restore original values
sta ACIA_CMD,x
lda tmp1
sta ACIA_STATUS,x
NoDev: lda #SER_ERR_NO_DEVICE
bne Out
; Check if the handshake setting is valid
AciaOK: ldy #SER_PARAMS::HANDSHAKE
lda (ptr1),y
cmp #SER_HS_SW ; Not supported
bne HandshakeOK
lda #SER_ERR_INIT_FAILED
bne Out
HandshakeOK:
sta HSType ; Store flow control type
ldy #$00 ; Initialize buffers
sty Stopped
sty RecvHead
sty RecvTail
sty SendHead
sty SendTail
dey ; Y = 255
dey ; Y = 255
sty RecvFreeCnt
sty SendFreeCnt
; Set the value for the control register, which contains stop bits,
; word length and the baud rate.
ldy #SER_PARAMS::BAUDRATE
lda (ptr1),y ; Baudrate index
lda (ptr1),y ; Baudrate index
tay
lda BaudTable,y ; Get 6551 value
bmi InvBaud ; Branch if rate not supported
sta tmp1
lda BaudTable,y ; Get 6551 value
sta tmp2 ; Backup for IRQ setting
bpl BaudOK ; Check that baudrate is supported
ldy #SER_PARAMS::DATABITS ; Databits
lda (ptr1),y
lda #SER_ERR_BAUD_UNAVAIL
bne Out
BaudOK: sta tmp1
ldy #SER_PARAMS::DATABITS
lda (ptr1),y ; Databits index
tay
lda BitTable,y
lda BitTable,y ; Get 6551 value
ora tmp1
sta tmp1
ldy #SER_PARAMS::STOPBITS ; Stopbits
lda (ptr1),y
ldy #SER_PARAMS::STOPBITS
lda (ptr1),y ; Stopbits index
tay
lda StopTable,y
lda StopTable,y ; Get 6551 value
ora tmp1
ora #%00010000 ; Receiver clock source = baudrate
ora #%00010000 ; Set receiver clock source = baudrate
sta ACIA_CTRL,x
; Set the value for the command register. We remember the base value
; in RtsOff, since we will have to manipulate ACIA_CMD often.
ldy #SER_PARAMS::PARITY ; Parity
lda (ptr1),y
ldy #SER_PARAMS::PARITY
lda (ptr1),y ; Parity index
tay
lda ParityTable,y
ora #%00000001 ; DTR active
sta RtsOff
ora #%00001000 ; Enable receive interrupts
sta ACIA_CMD,x
lda ParityTable,y ; Get 6551 value
ora #%00000001 ; Set DTR active
sta RtsOff ; Store value to easily handle flow control later
ora #%00001010 ; Disable interrupts and set RTS low
ldy tmp2 ; Don't enable IRQs if 115200bps
beq :+
and #%11111101 ; Enable receive IRQs
: sta ACIA_CMD,x
; Done
stx Index ; Mark port as open
lda #<SER_ERR_OK
tax ; A is zero
rts
; Device (hardware) not found
NoDevice:lda #<SER_ERR_NO_DEVICE
ldx #>SER_ERR_NO_DEVICE
rts
; Invalid parameter
InvParam:lda #<SER_ERR_INIT_FAILED
ldx #>SER_ERR_INIT_FAILED
rts
; Baud rate not available
InvBaud:lda #<SER_ERR_BAUD_UNAVAIL
ldx #>SER_ERR_BAUD_UNAVAIL
stx Index ; Mark port as open
lda #SER_ERR_OK
Out:
ldx #>$0000
rts
;----------------------------------------------------------------------------
@@ -279,38 +355,38 @@ InvBaud:lda #<SER_ERR_BAUD_UNAVAIL
SER_GET:
ldx Index
ldy SendFreeCnt ; Send data if necessary
iny ; Y == $FF?
beq :+
lda #$00 ; TryHard = false
jsr TryToSend
; Check for buffer empty
: lda RecvFreeCnt ; (25)
lda RecvFreeCnt ; Check for buffer empty
cmp #$FF
bne :+
lda #<SER_ERR_NO_DATA
ldx #>SER_ERR_NO_DATA
lda #SER_ERR_NO_DATA
ldx #>$0000
rts
; Check for flow stopped & enough free: release flow control
: ldy Stopped ; (34)
: ldy Stopped ; Check for flow stopped
beq :+
cmp #63
cmp #63 ; Enough free?
bcc :+
.if (.cpu .bitand CPU_ISET_65C02)
stz Stopped ; Release flow control
.else
lda #$00
sta Stopped
.endif
lda RtsOff
ora #%00001000
sta ACIA_CMD,x
; Get byte from buffer
: ldy RecvHead ; (41)
: ldy RecvHead ; Get byte from buffer
lda RecvBuf,y
inc RecvHead
inc RecvFreeCnt
ldx #$00 ; (59)
ldx #$00
.if (.cpu .bitand CPU_ISET_65C02)
sta (ptr1) ; Store it for caller
.else
sta (ptr1,x)
.endif
txa ; Return code = 0
rts
@@ -321,29 +397,28 @@ SER_GET:
SER_PUT:
ldx Index
; Try to send
ldy SendFreeCnt
iny ; Y = $FF?
ldy SendFreeCnt ; Anything to send first?
cpy #$FF ; No
beq :+
pha
lda #$00 ; TryHard = false
jsr TryToSend
jsr TryToSend ; Try to flush send buffer
pla
; Put byte into send buffer & send
: ldy SendFreeCnt
ldy SendFreeCnt ; Reload SendFreeCnt after TryToSend
bne :+
lda #<SER_ERR_OVERFLOW
ldx #>SER_ERR_OVERFLOW
lda #SER_ERR_OVERFLOW
ldx #>$0000
rts
: ldy SendTail
: ldy SendTail ; Put byte into send buffer
sta SendBuf,y
inc SendTail
dec SendFreeCnt
lda #$FF ; TryHard = true
jsr TryToSend
lda #<SER_ERR_OK
jsr TryToSend ; Flush send buffer
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax
rts
@@ -356,31 +431,32 @@ SER_STATUS:
lda ACIA_STATUS,x
ldx #$00
sta (ptr1,x)
txa ; SER_ERR_OK
.assert SER_ERR_OK = 0, error
txa
rts
;----------------------------------------------------------------------------
; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
; specific data in ptr1, and the ioctl code in A.
; The ioctl data is the slot number to open.
; Must return an SER_ERR_xx code in a/x.
SER_IOCTL:
; Check data msb and code to be 0
ora ptr1+1
ora ptr1+1 ; Check data msb and code to be 0
bne :+
; Check data lsb to be [1..7]
ldx ptr1
ldx ptr1 ; Check data lsb to be [1..7]
beq :+
cpx #7+1
bcs :+
stx Slot
tax ; SER_ERR_OK
stx Slot ; Store slot
.assert SER_ERR_OK = 0, error
tax
rts
: lda #<SER_ERR_INV_IOCTL
ldx #>SER_ERR_INV_IOCTL
: lda #SER_ERR_INV_IOCTL
ldx #>$0000
rts
;----------------------------------------------------------------------------
@@ -396,22 +472,24 @@ SER_IRQ:
and #$08
beq Done ; Jump if no ACIA interrupt
lda ACIA_DATA,x ; Get byte from ACIA
ldy RecvFreeCnt ; Check if we have free space left
ldx RecvFreeCnt ; Check if we have free space left
beq Flow ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
ldy RecvFreeCnt ; Check for buffer space low
cpy #33
cpx #33 ; Check for buffer space low
bcc Flow ; Assert flow control if buffer space low
rts ; Interrupt handled (carry already set)
; Assert flow control if buffer space too low
Flow: lda RtsOff
Flow: lda HSType ; Don't touch if no flow control
beq IRQDone
ldx Index ; Assert flow control if buffer space too low
lda RtsOff
sta ACIA_CMD,x
sta Stopped
sec ; Interrupt handled
IRQDone:sec ; Interrupt handled
Done: rts
;----------------------------------------------------------------------------
@@ -419,26 +497,24 @@ Done: rts
TryToSend:
sta tmp1 ; Remember tryHard flag
Again: lda SendFreeCnt
cmp #$FF
beq Quit ; Bail out
NextByte:
lda SendFreeCnt ; Is there anything to send? This can happen if
cmp #$FF ; we got interrupted by RX while sending, and
beq Quit ; flow control was asserted.
; Check for flow stopped
lda Stopped
bne Quit ; Bail out
Again: lda Stopped ; Is flow stopped?
bne Quit ; Yes, Bail out
; Check that ACIA is ready to send
lda ACIA_STATUS,x
lda ACIA_STATUS,x ; Check that ACIA is ready to send
and #$10
bne Send
bne Send ; It is!
bit tmp1 ; Keep trying if must try hard
bmi Again
Quit: rts
; Send byte and try again
Send: ldy SendHead
Send: ldy SendHead ; Get first byte to send
lda SendBuf,y
sta ACIA_DATA,x
sta ACIA_DATA,x ; Send it
inc SendHead
inc SendFreeCnt
jmp Again
bne NextByte ; And try next one

View File

@@ -0,0 +1,22 @@
;
; Address of the static standard serial driver
;
; Oliver Schmidt, 2022-12-22
;
; const void ser_static_stddrv[];
;
.export _ser_static_stddrv
.ifdef __APPLE2ENH__
.import _a2e_ssc_ser
.else
.import _a2_ssc_ser
.endif
.rodata
.ifdef __APPLE2ENH__
_ser_static_stddrv := _a2e_ssc_ser
.else
_ser_static_stddrv := _a2_ssc_ser
.endif

View File

@@ -0,0 +1,18 @@
;
; Name of the standard serial driver
;
; Oliver Schmidt, 2022-12-22
;
; const char ser_stddrv[];
;
.export _ser_stddrv
.rodata
_ser_stddrv:
.ifdef __APPLE2ENH__
.asciiz "A2E.SSC.SER"
.else
.asciiz "A2.SSC.SER"
.endif

View 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 #>$0000
rts

View File

@@ -68,4 +68,4 @@ enosys: lda #ENOSYS
erange: lda #ERANGE
; Set __errno
errno: jmp __directerrno
errno: jmp ___directerrno

54
libsrc/apple2/sleep.s Normal file
View 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
View 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 ; Promote char return value
rts
.bss
stbuf: .res 2

123
libsrc/apple2/statvfs.s Normal file
View 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

View File

@@ -29,7 +29,8 @@ __syschdir:
bcs cleanup
; Update current working directory
jsr initcwd ; Returns with A = 0
jsr initcwd
lda #$00
; Cleanup name
cleanup:jsr popname ; Preserves A

View File

@@ -1,9 +1,17 @@
DEPS += ../libwrk/$(TARGET)/loader.d
DEPS += ../libwrk/$(TARGET)/convert.d \
../libwrk/$(TARGET)/loader.d
../libwrk/$(TARGET)/convert.o: $(SRCDIR)/targetutil/convert.c | ../libwrk/$(TARGET)
$(COMPILE_recipe)
../libwrk/$(TARGET)/loader.o: $(SRCDIR)/targetutil/loader.s | ../libwrk/$(TARGET)
$(ASSEMBLE_recipe)
../target/$(TARGET)/util/convert.system: ../libwrk/$(TARGET)/convert.o ../lib/$(TARGET).lib | ../target/$(TARGET)/util
$(LD65) -o $@ -C $(TARGET)-system.cfg $^
../target/$(TARGET)/util/loader.system: ../libwrk/$(TARGET)/loader.o $(SRCDIR)/targetutil/loader.cfg | ../target/$(TARGET)/util
$(LD65) -o $@ -C $(filter %.cfg,$^) $(filter-out %.cfg,$^)
$(TARGET): ../target/$(TARGET)/util/loader.system
$(TARGET): ../target/$(TARGET)/util/convert.system \
../target/$(TARGET)/util/loader.system

View File

@@ -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) {

View File

@@ -83,7 +83,10 @@ Y2 := ptr4
.byte $74, $67, $69 ; "tgi"
.byte TGI_API_VERSION ; TGI API version number
libref:
.addr $0000 ; Library reference
.word 280 ; X resolution
.word 192 ; Y resolution
.byte 8 ; Number of drawing colors
@@ -120,6 +123,10 @@ pages: .byte 2 ; Number of screens available
.bss
.ifndef __APPLE2ENH__
machinetype: .res 1
.endif
; Absolute variables used in the code
ERROR: .res 1 ; Error code
@@ -146,13 +153,22 @@ FONT:
; most of the time.
; Must set an error code: NO
INSTALL:
.ifdef __APPLE2ENH__
.ifndef __APPLE2ENH__
lda libref
ldx libref+1
sta ptr1
stx ptr1+1
ldy #$0
lda (ptr1),y
sta machinetype
bpl :+
.endif
; No page switching if 80 column store is enabled
bit RD80COL
bpl :+
lda #$01
sta pages
: .endif
:
; Fall through
@@ -175,6 +191,16 @@ INIT:
; Switch into graphics mode
bit MIXCLR
bit HIRES
.ifndef __APPLE2ENH__
bit machinetype
bpl clr_txt
.endif
sta IOUDISON
bit DHIRESOFF
clr_txt:
bit TXTCLR
; Beagle Bros Shape Mechanic fonts don't
@@ -196,11 +222,14 @@ DONE:
bit TXTSET
bit LOWSCR
.ifdef __APPLE2ENH__
.ifndef __APPLE2ENH__
bit machinetype
bpl reset_wndtop
.endif
; Limit SET80COL-HISCR to text
bit LORES
.endif
reset_wndtop:
; Reset the text window top
lda #$00
sta WNDTOP
@@ -338,7 +367,7 @@ GETPIXEL:
lda #$03 ; 3 (white)
: bcc :+
adc #$03 ; += 4 (black -> black2, white -> white2)
: ldx #$00
: ldx #>$0000
bit $C080 ; Switch in LC bank 2 for R/O
rts

View File

@@ -53,7 +53,7 @@ Y2 := ptr4
.byte $74, $67, $69 ; "tgi"
.byte TGI_API_VERSION ; TGI API version number
.addr $0000 ; Library reference
libref: .addr $0000 ; Library reference
.word 40 ; X resolution
.word 48 ; Y resolution
.byte 16 ; Number of drawing colors
@@ -93,6 +93,10 @@ Y2 := ptr4
ERROR: .res 1 ; Error code
MIX: .res 1 ; 4 lines of text
.ifndef __APPLE2ENH__
machinetype: .res 1
.endif
; ------------------------------------------------------------------------
.rodata
@@ -126,7 +130,15 @@ INIT:
bit $C082 ; Switch in ROM
jsr SETGR
bit MIXCLR
bit $C080 ; Switch in LC bank 2 for R/O
.ifndef __APPLE2ENH__
bit machinetype
bpl lc_in
.endif
sta IOUDISON
bit DHIRESOFF
lc_in: bit $C080 ; Switch in LC bank 2 for R/O
; Done, reset the error code
lda #TGI_ERR_OK
@@ -140,6 +152,16 @@ INIT:
; most of the time.
; Must set an error code: NO
INSTALL:
.ifndef __APPLE2ENH__
lda libref
ldx libref+1
sta ptr1
stx ptr1+1
ldy #$0
lda (ptr1),y
sta machinetype
bpl :+
.endif
; Fall through
; UNINSTALL routine. Is called before the driver is removed from memory. May
@@ -317,7 +339,7 @@ GETPIXEL:
jsr SCRN
tax
lda COL2TGI,x
ldx #$00
ldx #>$0000
bit $C080 ; Switch in LC bank 2 for R/O
rts

18
libsrc/apple2/tgiref.s Normal file
View File

@@ -0,0 +1,18 @@
;
; Colin Leroy-Mira, 2025-05-10
;
.export tgi_libref
.import _exit
.ifndef __APPLE2ENH__
.import machinetype
tgi_libref := machinetype
.else
tgi_libref := _exit
.endif

View File

@@ -0,0 +1,27 @@
;
; Oliver Schmidt, 2024-08-06
;
.ifndef __APPLE2ENH__
.export uppercasemask
.import machinetype
.constructor detectlowercase
.segment "ONCE"
detectlowercase:
bit machinetype
bpl :+
lda #$FF
sta uppercasemask
: rts
.data
uppercasemask: .byte $DF ; Convert to uppercase
.endif

View File

@@ -1,68 +1,52 @@
;
; Oliver Schmidt, 07.09.2009
;
; unsigned __fastcall__ videomode (unsigned mode);
; signed char __fastcall__ videomode (unsigned mode);
;
.ifdef __APPLE2ENH__
.export _videomode
.import COUT
.import aux80col
.import returnFFFF
.include "apple2.inc"
VIDEOMODE_40x24 = $15
VIDEOMODE_80x24 = $00
.segment "LOWCODE"
_videomode:
bit aux80col
bmi set_mode
; No 80 column card, return error if requested mode is 80cols
cmp #VIDEOMODE_40x24
beq out
jmp returnFFFF
set_mode:
; Get and save current videomode flag
bit RD80VID
php
; If we are in 80 column mode then the 80 column firmware is
; known to be active so we can just print the ctrl-char code
; (even if this only means staying in the current videomode)
bpl :+
jsr COUT
bra done
; If we are in 40 column mode and want to set 40 column mode
; then we explicitly do nothing as we neither know about the
; current state of the 80 column firmware nor want to fix it
: cmp #$11 ; Ctrl-char code for 40 cols
beq done
; If we are in 40 column mode and want to set 80 column mode
; then we first presume the 80 column firmware being already
; active and print the ctrl-char code (this causes a garbage
; char to be printed on the screen if isn't already active)
jsr COUT
; If we successfully switched to 80 column mode then the 80
; column firmware was in fact already active and we're done
bit RD80VID
bmi done
; The 80 column firmware isn't already active so we need to
; initialize it - causing the screen to be cleared and thus
; the garbage char printed above to be erased (but for some
; reason the cursor horizontal position not to be zeroed)
stz CH
; Initializing the 80 column firmware needs the ROM switched
; in, otherwise it would copy the F8 ROM to the LC (@ $CEF4)
bit $C082
; Initialize 80 column firmware
jsr $C300 ; PR#3
; Call 80 column firmware with ctrl-char code
jsr $C300
; Switch in LC bank 2 for R/O
bit $C080
; Switch in alternate charset again
sta SETALTCHAR
; Return ctrl-char code for setting previous
; videomode using the saved videomode flag
done: lda #$11 ; Ctrl-char code for 40 cols
lda #VIDEOMODE_40x24
plp
bpl :+
lda #$12 ; Ctrl-char code for 80 cols
: rts ; X was preserved all the way
.endif ; __APPLE2ENH__
bpl out
lda #VIDEOMODE_80x24
out: rts ; X was preserved all the way

20
libsrc/apple2/wait.s Normal file
View 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

53
libsrc/apple2/waitvsync.s Normal file
View File

@@ -0,0 +1,53 @@
;
; Oliver Schmidt, 2020-06-14
;
; void waitvsync (void);
;
.export _waitvsync
.import ostype
.ifndef __APPLE2ENH__
.import machinetype
.endif
.include "apple2.inc"
_waitvsync:
.ifndef __APPLE2ENH__
bit machinetype ; IIe/enh?
bpl out ; No, silently fail
.endif
bit ostype
bmi iigs ; $8x
bvs iic ; $4x
; Apple IIe
: bit RDVBLBAR
bpl :- ; Blanking
: bit RDVBLBAR
bmi :- ; Drawing
rts
; Apple IIgs TechNote #40, VBL Signal
iigs: bit RDVBLBAR
bmi iigs ; Blanking
: bit RDVBLBAR
bpl :- ; Drawing
rts
; Apple IIc TechNote #9, Detecting VBL
iic: php
sei
sta IOUDISOFF
lda RDVBLMSK
bit ENVBL
bit PTRIG ; Reset VBL interrupt flag
: bit RDVBLBAR
bpl :-
asl
bcs :+ ; VBL interrupts were already enabled
bit DISVBL
: sta IOUDISON ; IIc Tech Ref Man: The firmware normally leaves IOUDIS on.
plp
out: rts

View File

@@ -4,11 +4,23 @@
; unsigned char wherex (void);
;
.ifndef __APPLE2ENH__
.import machinetype
.endif
.export _wherex
.include "apple2.inc"
_wherex:
lda CH
ldx #$00
.ifndef __APPLE2ENH__
bit machinetype
bpl :+
.endif
bit RD80VID ; In 80 column mode?
bpl :+
lda OURCH
: ldx #>$0000
rts

View File

@@ -12,5 +12,5 @@ _wherey:
lda CV
sec
sbc WNDTOP
ldx #$00
ldx #>$0000
rts

View File

@@ -7,6 +7,9 @@
.export _write
.import rwprolog, rwcommon, rwepilog
.import COUT
.ifndef __APPLE2ENH__
.import uppercasemask
.endif
.include "zeropage.inc"
.include "errno.inc"
@@ -84,7 +87,7 @@ next: lda (ptr1),y
.ifndef __APPLE2ENH__
cmp #$E0 ; Test for lowercase
bcc output
and #$DF ; Convert to uppercase
and uppercasemask
.endif
output: jsr COUT ; Preserves X and Y
@@ -107,8 +110,8 @@ done: lda #$00
einval: lda #EINVAL
; Set __errno
errno: jmp __directerrno
errno: jmp ___directerrno
; Set ___oserror
oserr: jmp ___mappederrno
; Set __oserror
oserr: jmp __mappederrno

View File

@@ -63,7 +63,7 @@ L1: lda #<brk_handler ; Set the break vector to our routine
lda #$00
sta oldvec ; Clear the old vector
stx oldvec+1
@L9: rts
@L9: rts
.endproc

View File

@@ -10,10 +10,10 @@
.include "atari.inc"
.import __BSS_RUN__, __STARTADDRESS__, _cas_init
.import __INIT_RUN__, __STARTADDRESS__, _cas_init
.export _cas_hdr
.assert ((__BSS_RUN__ - __STARTADDRESS__ + 127) / 128) < $101, error, "File to big to load from cassette"
.assert ((__INIT_RUN__ - __STARTADDRESS__ + 127) / 128) < $101, error, "File to big to load from cassette"
; for a description of the cassette header, see De Re Atari, appendix C
@@ -22,7 +22,7 @@
_cas_hdr:
.byte 0 ; ignored
.byte <((__BSS_RUN__ - __STARTADDRESS__ + 127) / 128) ; # of 128-byte records to read
.byte <((__INIT_RUN__ - __STARTADDRESS__ + 127) / 128) ; # of 128-byte records to read
.word __STARTADDRESS__ ; load address
.word _cas_init ; init address
@@ -31,6 +31,8 @@ _cas_hdr:
ldy #80
sta (SAVMSC),y
.endif
lda #$3c ; motor off
sta PACTL
clc
rts

View File

@@ -17,7 +17,7 @@ _cclearxy:
_cclear:
cmp #0 ; Is the length zero?
beq L9 ; Jump if done
sta tmp1
sta tmp1
L1: lda #0 ; Blank - screen code
jsr cputdirect ; Direct output
dec tmp1

View File

@@ -3,10 +3,10 @@
; originally by Ullrich von Bassewitz and Sidney Cadot
;
; clock_t clock (void);
; unsigned _clocks_per_sec (void);
; clock_t __clocks_per_sec (void);
;
.export _clock, __clocks_per_sec
.export _clock, ___clocks_per_sec
.importzp sreg
.include "atari.inc"
@@ -28,10 +28,12 @@
.endproc
.proc __clocks_per_sec
.proc ___clocks_per_sec
ldx #$00 ; Clear high byte of return value
lda PAL ; use hw register, PALNTS is only supported on XL/XE ROM
ldx #$00 ; Clear byte 1 of return value
stx sreg ; Clear byte 2 of return value
stx sreg+1 ; Clear byte 3 of return value
lda PAL ; Use hw register, PALNTS is only supported on XL/XE ROM
and #$0e
bne @NTSC
lda #50

View File

@@ -6,7 +6,7 @@
.include "atari.inc"
.export _close
.import __do_oserror,popax,__oserror
.import __do_oserror,popax,___oserror
.import fdtoiocb_down,__inviocb
.proc _close
@@ -18,7 +18,7 @@
jsr CIOV
bmi closerr
ok: ldx #0
stx __oserror ; clear system specific error code
stx ___oserror ; clear system specific error code
txa
rts

35
libsrc/atari/cpeekc.s Normal file
View File

@@ -0,0 +1,35 @@
;
; 2016-02-28, Groepaz
; 2017-06-21, Greg King
;
; char cpeekc (void);
;
.export _cpeekc
.include "atari.inc"
_cpeekc:
lda OLDCHR ; get char under cursor
and #<~$80 ; remove reverse bit
;; convert internal screen code to AtSCII
tay
and #%01100000
asl a
asl a
rol a
rol a
tax
tya
eor intats,x
ldx #>$0000
rts
.rodata
intats: .byte %00100000 ; -> %001xxxxx
.byte %01100000 ; -> %010xxxxx
.byte %01000000 ; -> %000xxxxx
.byte %00000000 ; -> %011xxxxx

View File

@@ -0,0 +1,8 @@
;
; 2017-06-03, Greg King
;
; unsigned char cpeekcolor (void);
;
.import return1
.export _cpeekcolor := return1 ; always COLOR_WHITE

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