Merge branch 'master' into sane_makefile_output

This commit is contained in:
Gorilla Sapiens
2025-06-18 06:26:58 +00:00
102 changed files with 3395 additions and 265 deletions

View File

@@ -25,7 +25,8 @@ CBMS = c128 \
GEOS = geos-apple \
geos-cbm
TARGETS = apple2 \
TARGETS = agat \
apple2 \
apple2enh \
atari \
atarixl \

23
libsrc/agat/_scrsize.s Normal file
View File

@@ -0,0 +1,23 @@
;
; Ullrich von Bassewitz, 26.10.2000
; Konstantin Fedorov, 12.06.2025
;
; Screen size variables
;
.export screensize
.include "agat.inc"
screensize:
lda WNDWDTH
bit TATTR
bmi t64
lsr
t64:
tax
lda WNDBTM
sec
sbc WNDTOP
tay
rts

113
libsrc/agat/break.s Normal file
View File

@@ -0,0 +1,113 @@
;
; Ullrich von Bassewitz, 27.09.1998
; Oleg A. Odintsov, Moscow, 2024
;
; void __fastcall__ set_brk (unsigned Addr);
; void reset_brk (void);
;
.export _set_brk, _reset_brk
.destructor _reset_brk
; Be sure to export the following variables absolute
.export _brk_a: abs, _brk_x: abs, _brk_y: abs
.export _brk_sr: abs, _brk_pc: abs
.include "agat.inc"
_brk_a = $45
_brk_x = $46
_brk_y = $47
_brk_sr = $48
_brk_sp = $49
_brk_pc = $3A
.bss
oldvec: .res 2 ; Old vector
.data
uservec: jmp $FFFF ; Patched at runtime
.code
; Set the break vector
.proc _set_brk
sta uservec+1
stx uservec+2 ; Set the user vector
lda oldvec
ora oldvec+1 ; Did we save the vector already?
bne L1 ; Jump if we installed the handler already
lda BRKVec
sta oldvec
lda BRKVec+1
sta oldvec+1 ; Save the old vector
L1: lda #<brk_handler ; Set the break vector to our routine
ldx #>brk_handler
sta BRKVec
stx BRKVec+1
rts
.endproc
; Reset the break vector
.proc _reset_brk
lda oldvec
ldx oldvec+1
beq @L9 ; Jump if vector not installed
sta BRKVec
stx BRKVec+1
lda #$00
sta oldvec ; Clear the old vector
stx oldvec+1
@L9: rts
.endproc
; Break handler, called if a break occurs
.proc brk_handler
sec
lda _brk_pc
sbc #$02 ; Point to start of brk
sta _brk_pc
lda _brk_pc+1
sbc #$00
sta _brk_pc+1
clc
lda _brk_sp
adc #$04 ; Adjust stack pointer
sta _brk_sp
lda _brk_sr ; Clear brk
and #$EF
sta _brk_sr
jsr uservec ; Call the user's routine
lda _brk_pc+1
pha
lda _brk_pc
pha
lda _brk_sr
pha
ldx _brk_x
ldy _brk_y
lda _brk_a
rti ; Jump back...
.endproc

18
libsrc/agat/cclear.s Normal file
View File

@@ -0,0 +1,18 @@
;
; Oleg A. Odintsov, Moscow, 2024
;
; void __fastcall__ cclear (unsigned char length);
;
.export _cclear
.import COUT
.include "zeropage.inc"
_cclear:
sta ptr1
lda #$A0
next:
jsr COUT
dec ptr1
bne next
rts

23
libsrc/agat/cgetc.s Normal file
View File

@@ -0,0 +1,23 @@
;
; Oleg A. Odintsov, Moscow, 2024
;
; char cgetc (void);
;
.export _cgetc
.import cursor
.include "agat.inc"
_cgetc:
lda #$DF ; _
bit cursor
bne hascur
lda #$00
hascur:
sta CURSOR
jsr j1
cmp #$A0
bpl :+
and #$7F
: rts
j1: jmp (VCIN)

33
libsrc/agat/chline.s Normal file
View File

@@ -0,0 +1,33 @@
;
; Ullrich von Bassewitz, 08.08.1998
; Colin Leroy-Mira, 26.05.2025
; Konstantin Fedorov, 12.06.2025
;
; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
; void chline (unsigned char length);
;
.export _chlinexy, _chline, chlinedirect
.import gotoxy, putchar
.include "zeropage.inc"
_chlinexy:
pha ; Save the length
jsr gotoxy ; Call this one, will pop params
pla ; Restore the length and run into _chline
_chline:
ldx #$1B ; horizontal line character
chlinedirect:
stx tmp1
cmp #$00 ; Is the length zero?
beq done ; Jump if done
sta tmp2
: lda tmp1 ; Screen code
jsr putchar ; Direct output
dec tmp2
bne :-
done: rts

10
libsrc/agat/clrscr.s Normal file
View File

@@ -0,0 +1,10 @@
;
; Kevin Ruland
;
; void clrscr (void);
;
.export _clrscr
.import HOME
_clrscr := HOME

20
libsrc/agat/color.s Normal file
View File

@@ -0,0 +1,20 @@
;
; Oleg A. Odintsov, Moscow, 2024
;
; unsigned char __fastcall__ textcolor (unsigned char color);
;
.export _textcolor
.include "agat.inc"
_textcolor:
ldx TATTR
eor TATTR
and #$07
eor TATTR
sta TATTR
txa
and #$0F
rts

14
libsrc/agat/cout.s Normal file
View File

@@ -0,0 +1,14 @@
;
; Oleg A. Odintsov, Moscow, 2024
;
; COUT routine
;
.export COUT
.include "agat.inc"
COUT:
cmp #$10
bpl out
ora #$80
out: jmp (VCOUT)

60
libsrc/agat/cputc.s Normal file
View File

@@ -0,0 +1,60 @@
;
; Oleg A. Odintsov, Moscow, 2024
; Konstantin Fedorov, 12.06.2025
;
; void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c);
; void __fastcall__ cputc (char c);
;
.import COUT
.export _cputcxy, _cputc, newline, putchar,putchardirect
.import gotoxy, VTABZ
.include "agat.inc"
_cputcxy:
pha
jsr gotoxy
pla
_cputc:
cmp #$0D ; Test for \r = carriage return
bne notleft
ldy #$00
sty CH
rts
notleft:
cmp #$0A ; Test for \n = line feed
beq newline
putchar:
ldy CH
sta (BASL),Y
iny
lda TATTR
bmi wch ; Skip if t64
sta (BASL),Y
iny
wch:
sty CH
cpy WNDWDTH
bcc noend
ldy #$00
sty CH
newline:
inc CV
lda CV
cmp WNDBTM
bcc :+
lda WNDTOP
sta CV
: jmp VTABZ
noend:
rts
putchardirect:
ldy CH
sta (BASL),Y
lda TATTR
bmi :+
iny
sta (BASL),Y
: rts

78
libsrc/agat/crt0.s Normal file
View File

@@ -0,0 +1,78 @@
;
; Startup code for cc65 (Agat version)
;
.export __STARTUP__ : absolute = 1 ; Mark as startup
.export _exit
.import initlib, donelib
.import zerobss, callmain
.import __ONCE_LOAD__, __ONCE_SIZE__ ; Linker generated
.include "zeropage.inc"
.include "agat.inc"
; ------------------------------------------------------------------------
.segment "STARTUP"
jsr init
jsr zerobss
jsr callmain
_exit:
ldx #<exit
lda #>exit
jsr reset
jsr donelib
exit:
ldx #$02
: lda rvsave,x
sta SOFTEV,x
dex
bpl :-
ldx #zpspace-1
: lda zpsave,x
sta sp,x
dex
bpl :-
ldx #$FF
txs
jmp DOSWARM
.segment "ONCE"
init:
ldx #zpspace-1
: lda sp,x
sta zpsave,x
dex
bpl :-
ldx #$02
: lda SOFTEV,x
sta rvsave,x
dex
bpl :-
lda HIMEM
ldx HIMEM+1
sta sp
stx sp+1
ldx #<_exit
lda #>_exit
jsr reset
jmp initlib
.code
reset:
stx SOFTEV
sta SOFTEV+1
eor #$A5
sta PWREDUP
rts
.segment "INIT"
zpsave: .res zpspace
rvsave: .res 3

29
libsrc/agat/cvline.s Normal file
View File

@@ -0,0 +1,29 @@
;
; Ullrich von Bassewitz, 08.08.1998
; Colin Leroy-Mira, 26.05.2025
; Konstantin Fedorov, 12.06.2025
;
; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
; void cvline (unsigned char length);
;
.export _cvlinexy, _cvline
.import gotoxy, putchardirect, newline
.include "zeropage.inc"
_cvlinexy:
pha ; Save the length
jsr gotoxy ; Call this one, will pop params
pla ; Restore the length and run into _cvline
_cvline:
cmp #$00 ; Is the length zero?
beq done ; Jump if done
sta tmp2
: lda #$5C ; vertical line character
jsr putchardirect ; Write, no cursor advance
jsr newline ; Advance cursor to next line
dec tmp2
bne :-
done: rts

43
libsrc/agat/exehdr.s Normal file
View File

@@ -0,0 +1,43 @@
;
; Oliver Schmidt, 2012-06-10
;
; This module supplies an AppleSingle version 2 file header + entry with
; ID 11 according to https://tools.ietf.org/rfc/rfc1740.txt Appendix A.
;
; Agat target uses this header only for compatibility with Apple Commander
; because Agat's 140K disk filesystem is identical to Apple II DOS 3.3 and
; "ac.jar -as" option can be used to import binaries into disk images.
.export __EXEHDR__ : absolute = 1 ; Linker referenced
.import __FILETYPE__ ; Linker generated
.import __MAIN_START__, __MAIN_LAST__ ; Linker generated
; ------------------------------------------------------------------------
; Data Fork
ID01_LENGTH = __MAIN_LAST__ - __MAIN_START__
ID01_OFFSET = ID01 - START
; ProDOS File Info
ID11_LENGTH = ID01 - ID11
ID11_OFFSET = ID11 - START
; ------------------------------------------------------------------------
.segment "EXEHDR"
START: .byte $00, $05, $16, $00 ; Magic number
.byte $00, $02, $00, $00 ; Version number
.res 16 ; Filler
.byte 0, 2 ; Number of entries
.byte 0, 0, 0, 1 ; Entry ID 1 - Data Fork
.byte 0, 0, >ID01_OFFSET, <ID01_OFFSET ; Offset
.byte 0, 0, >ID01_LENGTH, <ID01_LENGTH ; Length
.byte 0, 0, 0, 11 ; Entry ID 11 - ProDOS File Info
.byte 0, 0, >ID11_OFFSET, <ID11_OFFSET ; Offset
.byte 0, 0, >ID11_LENGTH, <ID11_LENGTH ; Length
ID11: .byte 0, %11000011 ; Access - Destroy, Rename, Write, Read
.byte >__FILETYPE__, <__FILETYPE__ ; File Type
.byte 0, 0 ; Auxiliary Type high
.byte >__MAIN_START__, <__MAIN_START__ ; Auxiliary Type low
ID01:

28
libsrc/agat/gotoxy.s Normal file
View File

@@ -0,0 +1,28 @@
;
; Ullrich von Bassewitz, 06.08.1998
; Oleg A. Odintsov, Moscow, 2024
;
; void __fastcall__ gotoxy (unsigned char x, unsigned char y);
; void __fastcall__ gotox (unsigned char x);
;
.export gotoxy, _gotoxy, _gotox
.import popa, VTABZ
.include "agat.inc"
gotoxy:
jsr popa ; Get Y
_gotoxy:
clc
adc WNDTOP
sta CV ; Store Y
jsr VTABZ
jsr popa ; Get X
_gotox:
bit TATTR
bmi t64
asl
t64:
sta CH ; Store X
rts

16
libsrc/agat/gotoy.s Normal file
View File

@@ -0,0 +1,16 @@
;
; Ullrich von Bassewitz, 06.08.1998
; Oleg A. Odintsov, Moscow, 2024
;
; void __fastcall__ gotoy (unsigned char y);
;
.import VTABZ
.export _gotoy
.include "agat.inc"
_gotoy:
clc
adc WNDTOP
sta CV
jmp VTABZ

15
libsrc/agat/home.s Normal file
View File

@@ -0,0 +1,15 @@
;
; Oleg A. Odintsov, Moscow, 2024
;
; HOME routine
;
.export HOME
.import COUT
.include "agat.inc"
HOME:
lda #$8C
jmp COUT
rts

19
libsrc/agat/kbhit.s Normal file
View File

@@ -0,0 +1,19 @@
;
; Kevin Ruland
; Ullrich von Bassewitz, 2005-03-25
; Oleg A. Odintsov, Moscow, 2024
;
; unsigned char kbhit (void);
;
.export _kbhit
.include "agat.inc"
_kbhit:
lda KBD ; Reading KBD checks for keypress
rol ; if high bit is set, key was pressed
lda #$00
tax
rol
rts

18
libsrc/agat/randomize.s Normal file
View File

@@ -0,0 +1,18 @@
;
; Ullrich von Bassewitz, 07.11.2002
; Oleg A. Odintsov, Moscow, 2024
;
; void _randomize (void);
; /* Initialize the random number generator */
;
.export __randomize
.import _srand
.include "agat.inc"
__randomize:
ldx RNDH ; Use random value supplied by ROM
lda RNDL
jmp _srand ; Initialize generator

38
libsrc/agat/revers.s Normal file
View File

@@ -0,0 +1,38 @@
;
; Ullrich von Bassewitz, 2005-03-28
; Oleg A. Odintsov, Moscow, 2024
;
; unsigned char __fastcall__ revers (unsigned char onoff)
; unsigned char __fastcall__ flash (unsigned char onoff)
;
.export _revers, _flash
.include "agat.inc"
_revers:
tax
beq noinv
lda TATTR
and #$D7
sta TATTR
rts
noinv:
lda TATTR
ora #$20
sta TATTR
rts
_flash:
tax
beq noflash
lda TATTR
and #$DF
ora #$08
sta TATTR
rts
noflash:
lda TATTR
ora #$20
sta TATTR
rts

24
libsrc/agat/vtabz.s Normal file
View File

@@ -0,0 +1,24 @@
;
; Oleg A. Odintsov, Moscow, 2024
;
; VTABZ routine
;
.export VTABZ
.include "agat.inc"
VTABZ:
lda CV
ror
ror
ror
and #$C0
sta BASL
lda CV
lsr
lsr
eor BASH
and #$07
eor BASH
sta BASH
rts

19
libsrc/agat/wherex.s Normal file
View File

@@ -0,0 +1,19 @@
;
; Kevin Ruland
; Oleg A. Odintsov, Moscow, 2024
;
; unsigned char wherex (void);
;
.export _wherex
.include "agat.inc"
_wherex:
lda CH
bit TATTR
bmi t64
lsr
t64:
ldx #$00
rts

17
libsrc/agat/wherey.s Normal file
View File

@@ -0,0 +1,17 @@
;
; Kevin Ruland
; Oleg A. Odintsov, Moscow, 2024
;
; unsigned char wherey (void);
;
.export _wherey
.include "agat.inc"
_wherey:
lda CV
sec
sbc WNDTOP
ldx #$00
rts

50
libsrc/agat/write.s Normal file
View File

@@ -0,0 +1,50 @@
;
; Oleg A. Odintsov, Moscow, 2024
;
; int __fastcall__ write (int fd, const void* buf, unsigned count);
;
.export _write
.import popax, popptr1
.import COUT
.include "zeropage.inc"
_write:
sta ptr2
stx ptr2+1
jsr popptr1
jsr popax
; Check for zero count
ora ptr2
beq done
; Get char from buf
next: ldy #$00
lda (ptr1),y
; Replace '\n' with '\r'
cmp #$0A
bne output
lda #$8D
; Set hi bit and write to device
output:
jsr COUT ; Preserves X and Y
; Increment pointer
inc ptr1
bne :+
inc ptr1+1
; Decrement count
: dec ptr2
bne next
dec ptr2+1
bpl next
; Return success
done: lda #$00
rts

View File

@@ -58,6 +58,7 @@ init: ldx #zpspace-1
; Check for ProDOS.
ldy $BF00 ; MLI call entry point
cpy #$4C ; Is MLI present? (JMP opcode)
php ; Remember whether we're running ProDOS
bne basic
; Check the ProDOS system bit map.
@@ -99,7 +100,20 @@ basic: lda HIMEM
bit $C081
bit $C081
; Set the source start address.
plp ; Are we running ProDOS?
beq :+ ; Yes, no need to patch vectors
lda #<reset_6502
ldx #>reset_6502
sta ROM_RST
stx ROM_RST+1
lda #<irq_6502
ldx #>irq_6502
sta ROM_IRQ
stx ROM_IRQ+1
: ; Set the source start address.
; Aka __LC_LOAD__ iff segment LC exists.
lda #<(__ONCE_LOAD__ + __ONCE_SIZE__)
ldy #>(__ONCE_LOAD__ + __ONCE_SIZE__)
@@ -144,6 +158,14 @@ quit: jsr $BF00 ; MLI call entry point
.byte $65 ; Quit
.word q_param
reset_6502: ; Used with DOS3.3 programs
bit $C082 ; Switch in ROM
jmp (ROM_RST) ; Jump to ROM's RESET vector
irq_6502: ; Used with DOS3.3 programs
bit $C082 ; Switch in ROM
jmp (ROM_IRQ) ; Jump to ROM's IRQ/BRK vector
; ------------------------------------------------------------------------
.rodata

View File

@@ -18,11 +18,16 @@ _cgetc: lda KEY_COUNT ; Get number of characters
ora FKEY_COUNT ; Or with number of function key chars
bne L2 ; Jump if there are already chars waiting
lda #%00100000
bit $FF06
bne L2 ; always disable cursor if in bitmap mode
; Switch on the cursor if needed
ldy CURS_X
lda (CRAM_PTR),y ; Get current char
pha ; And save it
lda CHARCOLOR
sta (CRAM_PTR),y

View File

@@ -9,8 +9,7 @@
.import callirq_y, initlib, donelib
.import callmain, zerobss
.import __INTERRUPTOR_COUNT__
.import __MAIN_START__, __MAIN_SIZE__ ; Linker generated
.import __STACKSIZE__ ; Linker generated
.import __HIMEM__ ; Linker generated
.importzp ST
.include "zeropage.inc"
@@ -52,19 +51,28 @@ L1: lda sp,x
tsx
stx spsave ; Save system stk ptr
lda #<(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__)
ldx #>(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__)
lda #<__HIMEM__
ldx #>__HIMEM__
sta sp
stx sp+1
; Set up the IRQ vector in the banked RAM; and, switch off the ROM.
ldx #<IRQ
ldy #>IRQ
lda #<IRQ
ldx #>IRQ
sei ; No ints, handler not yet in place
sta ENABLE_RAM
stx $FFFE ; Install interrupt handler
sty $FFFF
sta $FFFE ; Install interrupt handler
stx $FFFF
lda IRQVec
ldx IRQVec+1
sta IRQInd+1
stx IRQInd+2
lda #<IRQStub
ldx #>IRQStub
sta IRQVec
stx IRQVec+1
cli ; Allow interrupts
; Clear the BSS data.
@@ -95,6 +103,13 @@ _exit: pha ; Save the return code
lda #0
sta irqcount ; Disable custom IRQ handlers
sei
ldx IRQInd+1
ldy IRQInd+2
stx IRQVec
sty IRQVec+1
cli
; Copy back the zero-page stuff.
ldx #zpspace-1
@@ -122,9 +137,13 @@ L2: lda zpsave,x
; IRQ handler. The handler in the ROM enables the Kernal, and jumps to
; $CE00, where the ROM code checks for a BRK or IRQ, and branches via the
; indirect vectors at $314/$316.
; To make our stub as fast as possible, we skip the whole part of the ROM
; handler, and jump to the indirect vectors directly. We do also call our
; own interrupt handlers if we have any; so, they need not use $314.
;
; When RAM is banked in, we skip the whole part of the ROM handler, and jump to
; the indirect vectors directly, after calling our own interrupt handlers.
;
; When ROM is banked in, a stub installed in the $314 indirect vector ensures
; that our interrupt handlers are still called (otherwise, interrupts that are
; not serviced by the ROM handler may cause a deadlock).
.segment "LOWCODE"
@@ -139,15 +158,6 @@ IRQ: cld ; Just to be sure
and #$10 ; Test for BRK bit
bne dobreak
; It's an IRQ; and, RAM is enabled. If we have handlers, call them. We will use
; a flag here instead of loading __INTERRUPTOR_COUNT__ directly, since the
; condes function is not reentrant. The irqcount flag will be set/reset from
; the main code, to avoid races.
ldy irqcount
beq @L1
jsr callirq_y ; Call the IRQ functions
; Since the ROM handler will end with an RTI, we have to fake an IRQ return
; on the stack, so that we get control of the CPU after the ROM handler,
; and can switch back to RAM.
@@ -161,7 +171,7 @@ IRQ: cld ; Just to be sure
pha ; Push faked X register
pha ; Push faked Y register
sta ENABLE_ROM ; Switch to ROM
jmp (IRQVec) ; Jump indirect to Kernal IRQ handler
jmp (IRQVec) ; Jump indirect to IRQ stub
irq_ret:
sta ENABLE_RAM ; Switch back to RAM
@@ -183,6 +193,22 @@ nohandler:
sta ENABLE_ROM
jmp (BRKVec) ; Jump indirect to the break vector
; IRQ stub installed at $314, called by our handler above if RAM is banked in,
; or the Kernal IRQ handler if ROM is banked in.
; If we have handlers, call them. We will use a flag here instead of loading
; __INTERRUPTOR_COUNT__ directly, since the condes function is not reentrant.
; The irqcount flag will be set/reset from the main code, to avoid races.
IRQStub:
cld ; Just to be sure
sta ENABLE_RAM
ldy irqcount
beq @L1
jsr callirq_y ; Call the IRQ functions
@L1: sta ENABLE_ROM
jmp (IRQInd+1) ; Jump to the saved IRQ vector
; ------------------------------------------------------------------------
; Data

View File

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

View File

@@ -64,15 +64,15 @@ ACIA_STATUS := ACIA+1 ; Status register
ACIA_CMD := ACIA+2 ; Command register
ACIA_CTRL := ACIA+3 ; Control register
RecvHead := $07D1 ; Head of receive buffer
RecvTail := $07D2 ; Tail of receive buffer
RecvFreeCnt := $07D3 ; Number of bytes in receive buffer
;----------------------------------------------------------------------------
;
; 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
@@ -88,7 +88,7 @@ SendBuf: .res 256
; Tables used to translate RS232 params into register values
BaudTable: ; bit7 = 1 means setting is invalid
BaudTable: ; Bit7 = 1 means setting is invalid
.byte $FF ; SER_BAUD_45_5
.byte $01 ; SER_BAUD_50
.byte $02 ; SER_BAUD_75
@@ -354,26 +354,27 @@ SER_IOCTL:
;
SER_IRQ:
lda ACIA_STATUS ; Check ACIA status for receive interrupt
and #$08
beq @L9 ; Jump if no ACIA interrupt (carry still clear)
lda ACIA_DATA ; Get byte from ACIA
ldx RecvFreeCnt ; Check if we have free space left
beq @L1 ; 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 ; Check for buffer space low
bcc @L1 ; Assert flow control if buffer space low
lda ACIA_STATUS ; (4) Check for byte received
and #$08 ; (2)
beq @L9 ; (2*)
lda ACIA_DATA ; (4) Get byte and put into receive buffer
ldy RecvTail ; (4)
ldx RecvFreeCnt ; (4)
beq @L3 ; (2*) Jump if no space in receive buffer
sta RecvBuf,y ; (5)
inc RecvTail ; (6)
dec RecvFreeCnt ; (6)
cpx #33 ; (2) Check for buffer space low
bcc @L2 ; (2*)
rts ; Return with carry set (interrupt handled)
; Assert flow control if buffer space too low
@L1: lda RtsOff
sta ACIA_CMD
sta Stopped
sec ; Interrupt handled
@L2: lda RtsOff ; (3)
sta ACIA_CMD ; (4)
sta Stopped ; (3)
@L3: sec ; Interrupt handled
@L9: rts
;----------------------------------------------------------------------------

860
libsrc/plus4/tgi/ted-hi.s Normal file
View File

@@ -0,0 +1,860 @@
;
; Graphics driver for the 320x200x2 mode on Commodore Plus/4 systems.
;
; Luminance/Chrominance matrices at $800/$C00, overwriting text-mode character
; and color data. Bitmap is at $C000-$DF3F. Programs using this driver should
; either be linked with the option '-D __HIMEM__=0xC000'.
;
; Based on the c64-hi TGI driver, which in turn was based on Stephen L. Judd's
; GRLIB code.
;
; 2017-01-13, Greg King
; 2018-03-13, Sven Klose
; 2019-10-23, Richard Halkyard
;
.include "zeropage.inc"
.include "tgi-kernel.inc"
.include "tgi-error.inc"
.include "cbm_kernal.inc"
.include "plus4.inc"
.macpack generic
.macpack module
; ------------------------------------------------------------------------
; Header. Includes jump table and constants.
module_header _ted_hi_tgi
; First part of the header is a structure that has a magic and defines the
; capabilities of the driver
.byte $74, $67, $69 ; "tgi"
.byte TGI_API_VERSION ; TGI API version number
.addr $0000 ; Library reference
.word 320 ; X resolution
.word 200 ; Y resolution
.byte 2 ; Number of drawing colors
.byte 1 ; Number of screens available
.byte 8 ; System font X size
.byte 8 ; System font Y size
.word $00D4 ; Aspect ratio (based on 4/3 display)
.byte 0 ; TGI driver flags
; Next comes the jump table. With the exception of IRQ, all entries must be
; valid and may point to an RTS for test versions (function not implemented).
.addr INSTALL
.addr UNINSTALL
.addr INIT
.addr DONE
.addr GETERROR
.addr CONTROL
.addr CLEAR
.addr SETVIEWPAGE
.addr SETDRAWPAGE
.addr SETCOLOR
.addr SETPALETTE
.addr GETPALETTE
.addr GETDEFPALETTE
.addr SETPIXEL
.addr GETPIXEL
.addr LINE
.addr BAR
.addr TEXTSTYLE
.addr OUTTEXT
; ------------------------------------------------------------------------
; Data.
; Variables mapped to the zero page segment variables. Some of these are
; used for passing parameters to the driver.
X1 := ptr1
Y1 := ptr2
X2 := ptr3
Y2 := ptr4
TEXT := ptr3
TEMP := tmp4
TEMP2 := sreg
POINT := regsave
CHUNK := X2 ; Used in the line routine
OLDCHUNK := X2+1 ; Dito
; Absolute variables used in the code
.bss
ERROR: .res 1 ; Error code
PALETTE: .res 2 ; The current palette
BITMASK: .res 1 ; $00 = clear, $FF = set pixels
; Line routine stuff
DX: .res 2
DY: .res 2
; BAR variables
X1SAVE: .res 2
Y1SAVE: .res 2
X2SAVE: .res 2
Y2SAVE: .res 2
; Text output stuff
TEXTMAGX: .res 1
TEXTMAGY: .res 1
TEXTDIR: .res 1
; Constants and tables
.rodata
DEFPALETTE: .byte $00, $71 ; White on black
PALETTESIZE = * - DEFPALETTE
BITTAB: .byte $80,$40,$20,$10,$08,$04,$02,$01
BITCHUNK: .byte $FF,$7F,$3F,$1F,$0F,$07,$03,$01
CHARROM := $D000 ; Character rom base address
; The TED uses the CPU's memory configuration to fetch color data! Although
; we run with ROMs banked out, putting color data in banked RAM (above $8000)
; will result in color artifacts appearing when we bank ROM back in for
; interrupts and Kernal calls. Bitmap data is not affected by this limitation,
; but since there is no way to access RAM under IO (FE00-FF40), we can't put the
; bitmap at $E000 like we do on the C64, and have to use the next lowest
; position at $C000.
LBASE := $0800 ; Luminance memory base address
VBASE := $C000 ; Bitmap base address
CBASE := LBASE + $400 ; Chrominance memory base address (fixed relative to LBASE)
CHRBASE := $0800 ; Base address of text mode data
.assert LBASE .mod $0800 = 0, error, "Luma/Chroma memory base address must be a multiple of 2K"
.assert VBASE .mod $2000 = 0, error, "Bitmap base address must be a multiple of 8K"
.assert LBASE + $800 < $8000, warning, "Luma/Chroma memory overlaps ROM. This will produce color artifacts."
.assert VBASE + $2000 < $FE00, error, "Bitmap overlaps IO space"
.code
; ------------------------------------------------------------------------
; INSTALL routine. Is called after the driver is loaded into memory. May
; initialize anything that has to be done just once. Is probably empty
; most of the time.
;
; Must set an error code: NO
;
INSTALL:
; rts ; Fall through
; ------------------------------------------------------------------------
; UNINSTALL routine. Is called before the driver is removed from memory. May
; clean up anything done by INSTALL but is probably empty most of the time.
;
; Must set an error code: NO
;
UNINSTALL:
rts
; ------------------------------------------------------------------------
; INIT: Changes an already installed device from text mode to graphics
; mode.
; Note that INIT/DONE may be called multiple times while the driver
; is loaded, while INSTALL is only called once, so any code that is needed
; to initializes variables and so on must go here. Setting palette and
; clearing the screen is not needed because this is called by the graphics
; kernel later.
; The graphics kernel will never call INIT when a graphics mode is already
; active, so there is no need to protect against that.
;
; Must set an error code: YES
;
INIT:
; Initialize variables
ldx #$FF
stx BITMASK
; Switch into graphics mode
lda $FF12 ; Set bitmap address and enable fetch from RAM
and #%00000011
ora #(>VBASE >> 2)
sta $FF12
.if LBASE <> CHRBASE
lda #>LBASE ; Set color memory address
sta $FF14
.endif
lda $FF06 ; Enable bitmap mode
ora #%00100000
sta $FF06
; Done, reset the error code
lda #TGI_ERR_OK
sta ERROR
rts
; ------------------------------------------------------------------------
; DONE: Will be called to switch the graphics device back into text mode.
; The graphics kernel will never call DONE when no graphics mode is active,
; so there is no need to protect against that.
;
; Must set an error code: NO
;
DONE: lda $FF12
ora #%00000100 ; Fetch from ROM
sta $FF12
.if LBASE <> CHRBASE
lda #>CHRBASE ; Reset character/color matrix address
sta $FF14
.else
sta ENABLE_ROM ; Clear text display since we clobbered it
jsr CLRSCR
sta ENABLE_RAM
.endif
lda $FF06
and #%11011111 ; Exit bitmap mode
sta $FF06
rts
; ------------------------------------------------------------------------
; GETERROR: Return the error code in A and clear it.
GETERROR:
ldx #TGI_ERR_OK
lda ERROR
stx ERROR
rts
; ------------------------------------------------------------------------
; CONTROL: Platform/driver specific entry point.
;
; Must set an error code: YES
;
CONTROL:
lda #TGI_ERR_INV_FUNC
sta ERROR
rts
; ------------------------------------------------------------------------
; CLEAR: Clears the screen.
;
; Must set an error code: NO
;
CLEAR: ldy #$00
tya
@L1: sta VBASE+$0000,y
sta VBASE+$0100,y
sta VBASE+$0200,y
sta VBASE+$0300,y
sta VBASE+$0400,y
sta VBASE+$0500,y
sta VBASE+$0600,y
sta VBASE+$0700,y
sta VBASE+$0800,y
sta VBASE+$0900,y
sta VBASE+$0A00,y
sta VBASE+$0B00,y
sta VBASE+$0C00,y
sta VBASE+$0D00,y
sta VBASE+$0E00,y
sta VBASE+$0F00,y
sta VBASE+$1000,y
sta VBASE+$1100,y
sta VBASE+$1200,y
sta VBASE+$1300,y
sta VBASE+$1400,y
sta VBASE+$1500,y
sta VBASE+$1600,y
sta VBASE+$1700,y
sta VBASE+$1800,y
sta VBASE+$1900,y
sta VBASE+$1A00,y
sta VBASE+$1B00,y
sta VBASE+$1C00,y
sta VBASE+$1D00,y
sta VBASE+$1E00,y
sta VBASE+$1E40,y
iny
bne @L1
rts
; ------------------------------------------------------------------------
; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
; The page number is already checked to be valid by the graphics kernel.
;
; Must set an error code: NO (will only be called if page ok)
;
SETVIEWPAGE:
; rts ; Fall through
; ------------------------------------------------------------------------
; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
; The page number is already checked to be valid by the graphics kernel.
;
; Must set an error code: NO (will only be called if page ok)
;
SETDRAWPAGE:
rts
; ------------------------------------------------------------------------
; SETCOLOR: Set the drawing color (in A). The new color is already checked
; to be in a valid range (0..maxcolor-1).
;
; Must set an error code: NO (will only be called if color ok)
;
SETCOLOR:
tax
beq @L1
lda #$FF
@L1: sta BITMASK
rts
; ------------------------------------------------------------------------
; SETPALETTE: Set the palette (not available with all drivers/hardware).
; A pointer to the palette is passed in ptr1. Must set an error if palettes
; are not supported
;
; Must set an error code: YES
;
SETPALETTE:
ldy #PALETTESIZE - 1
@L1: lda (ptr1),y ; Copy the palette
sta PALETTE,y
dey
bpl @L1
; Get luma values from the high nybble of the palette entries
lda PALETTE+1 ; Foreground luma
lsr a
lsr a
lsr a
lsr a
sta TEMP ; Foreground -> low nybble
lda PALETTE ; Background luma
and #$F0
ora TEMP ; Background -> high nybble
; Initialize the luma map with the new luma values
ldy #0
@L2: sta LBASE+$0000,y
sta LBASE+$0100,y
sta LBASE+$0200,y
sta LBASE+$02e8,y
iny
bne @L2
; Get chroma values from the low nybble of the palette entries
lda PALETTE+1 ; Foreground chroma
and #$0F
asl a
asl a
asl a
asl a
sta TEMP ; Foreground -> high nybble
lda PALETTE ; Background chroma
and #$0F
ora TEMP ; Background -> low nybble
; Initialize the chroma map with the new chroma values
ldy #0
@L3: sta CBASE+$0000,y
sta CBASE+$0100,y
sta CBASE+$0200,y
sta CBASE+$02e8,y
iny
bne @L3
; Done, reset the error code
lda #TGI_ERR_OK
sta ERROR
rts
; ------------------------------------------------------------------------
; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
; set the palette should return the default palette here, so there's no
; way for this function to fail.
;
; Must set an error code: NO
;
GETPALETTE:
lda #<PALETTE
ldx #>PALETTE
rts
; ------------------------------------------------------------------------
; GETDEFPALETTE: Return the default palette for the driver in A/X. All
; drivers should return something reasonable here, even drivers that don't
; support palettes, otherwise the caller has no way to determine the colors
; of the (not changeable) palette.
;
; Must set an error code: NO (all drivers must have a default palette)
;
GETDEFPALETTE:
lda #<DEFPALETTE
ldx #>DEFPALETTE
rts
; ------------------------------------------------------------------------
; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
; color. The coordinates passed to this function are never outside the
; visible screen area, so there is no need for clipping inside this function.
;
; Must set an error code: NO
;
SETPIXEL:
jsr CALC ; Calculate coordinates
lda (POINT),Y
eor BITMASK
and BITTAB,X
eor (POINT),Y
sta (POINT),Y
@L9: rts
; ------------------------------------------------------------------------
; GETPIXEL: Read the color value of a pixel and return it in A/X. The
; coordinates passed to this function are never outside the visible screen
; area, so there is no need for clipping inside this function.
GETPIXEL:
jsr CALC ; Calculate coordinates
lda (POINT),Y
ldy #$00
and BITTAB,X
beq @L1
iny
@L1:
tya ; Get color value into A
ldx #$00 ; Clear high byte
rts
; ------------------------------------------------------------------------
; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
; X2/Y2 = ptr3/ptr4 using the current drawing color.
;
; X1,X2 etc. are set up above (x2=LINNUM in particular)
; Format is LINE x2,y2,x1,y1
;
; Must set an error code: NO
;
LINE:
@CHECK: lda X2 ; Make sure x1<x2
sec
sbc X1
tax
lda X2+1
sbc X1+1
bpl @CONT
lda Y2 ; If not, swap P1 and P2
ldy Y1
sta Y1
sty Y2
lda Y2+1
ldy Y1+1
sta Y1+1
sty Y2+1
lda X1
ldy X2
sty X1
sta X2
lda X2+1
ldy X1+1
sta X1+1
sty X2+1
bcc @CHECK
@CONT: sta DX+1
stx DX
ldx #$C8 ; INY
lda Y2 ; Calculate dy
sec
sbc Y1
tay
lda Y2+1
sbc Y1+1
bpl @DYPOS ; Is y2>=y1?
lda Y1 ; Otherwise dy=y1-y2
sec
sbc Y2
tay
ldx #$88 ; DEY
@DYPOS: sty DY ; 8-bit DY -- FIX ME?
stx YINCDEC
stx XINCDEC
jsr CALC ; Set up .X, .Y, and POINT
lda BITCHUNK,X
sta OLDCHUNK
sta CHUNK
ldx DY
cpx DX ; Who's bigger: dy or dx?
bcc STEPINX ; If dx, then...
lda DX+1
bne STEPINX
;
; Big steps in Y
;
; To simplify my life, just use PLOT to plot points.
;
; No more!
; Added special plotting routine -- cool!
;
; X is now counter, Y is y-coordinate
;
; On entry, X=DY=number of loop iterations, and Y=
; Y1 AND #$07
STEPINY:
lda #00
sta OLDCHUNK ; So plotting routine will work right
lda CHUNK
lsr ; Strip the bit
eor CHUNK
sta CHUNK
txa
beq YCONT2 ; If dy=0, it's just a point
@CONT: lsr ; Init counter to dy/2
;
; Main loop
;
YLOOP: sta TEMP
lda (POINT),y
eor BITMASK
and CHUNK
eor (POINT),y
sta (POINT),y
YINCDEC:
iny ; Advance Y coordinate
cpy #8
bcc @CONT ; No prob if Y=0..7
jsr FIXY
@CONT: lda TEMP ; Restore A
sec
sbc DX
bcc YFIXX
YCONT: dex ; X is counter
bne YLOOP
YCONT2: lda (POINT),y ; Plot endpoint
eor BITMASK
and CHUNK
eor (POINT),y
sta (POINT),y
rts
YFIXX: ; X=x+1
adc DY
lsr CHUNK
bne YCONT ; If we pass a column boundary...
ror CHUNK ; Then reset CHUNK to $80
sta TEMP2
lda POINT ; And add 8 to POINT
adc #8
sta POINT
bcc @CONT
inc POINT+1
@CONT: lda TEMP2
dex
bne YLOOP
beq YCONT2
;
; Big steps in X direction
;
; On entry, X=DY=number of loop iterations, and Y=
; Y1 AND #$07
.bss
COUNTHI:
.byte $00 ; Temporary counter, only used once.
.code
STEPINX:
ldx DX
lda DX+1
sta COUNTHI
cmp #$80
ror ; Need bit for initialization
sta Y1 ; High byte of counter
txa
bne @CONT ; Could be $100
dec COUNTHI
@CONT: ror
;
; Main loop
;
XLOOP: lsr CHUNK
beq XFIXC ; If we pass a column boundary...
XCONT1: sbc DY
bcc XFIXY ; Time to step in Y?
XCONT2: dex
bne XLOOP
dec COUNTHI ; High bits set?
bpl XLOOP
lsr CHUNK ; Advance to last point
jmp LINEPLOT ; Plot the last chunk
;
; CHUNK has passed a column, so plot and increment pointer
; and fix up CHUNK, OLDCHUNK.
;
XFIXC: sta TEMP
jsr LINEPLOT
lda #$FF
sta CHUNK
sta OLDCHUNK
lda POINT
clc
adc #8
sta POINT
lda TEMP
bcc XCONT1
inc POINT+1
jmp XCONT1
;
; Check to make sure there isn't a high bit, plot chunk,
; and update Y-coordinate.
;
XFIXY: dec Y1 ; Maybe high bit set
bpl XCONT2
adc DX
sta TEMP
lda DX+1
adc #$FF ; Hi byte
sta Y1
jsr LINEPLOT ; Plot chunk
lda CHUNK
sta OLDCHUNK
lda TEMP
XINCDEC:
iny ; Y-coord
cpy #8 ; 0..7 is ok
bcc XCONT2
sta TEMP
jsr FIXY
lda TEMP
jmp XCONT2
;
; Subroutine to plot chunks/points (to save a little
; room, gray hair, etc.)
;
LINEPLOT: ; Plot the line chunk
lda (POINT),Y
eor BITMASK
ora CHUNK
and OLDCHUNK
eor CHUNK
eor (POINT),Y
sta (POINT),Y
rts
;
; Subroutine to fix up pointer when Y decreases through
; zero or increases through 7.
;
FIXY: cpy #255 ; Y=255 or Y=8
beq @DECPTR
@INCPTR: ; Add 320 to pointer
ldy #0 ; Y increased through 7
lda POINT
adc #<320
sta POINT
lda POINT+1
adc #>320
sta POINT+1
rts
@DECPTR: ; Okay, subtract 320 then
ldy #7 ; Y decreased through 0
lda POINT
sec
sbc #<320
sta POINT
lda POINT+1
sbc #>320
sta POINT+1
rts
; ------------------------------------------------------------------------
; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
; Contrary to most other functions, the graphics kernel will sort and clip
; the coordinates before calling the driver, so on entry the following
; conditions are valid:
; X1 <= X2
; Y1 <= Y2
; (X1 >= 0) && (X1 < XRES)
; (X2 >= 0) && (X2 < XRES)
; (Y1 >= 0) && (Y1 < YRES)
; (Y2 >= 0) && (Y2 < YRES)
;
; Must set an error code: NO
;
; Note: This function needs optimization. It's just a cheap translation of
; the original C wrapper and could be written much smaller (besides that,
; calling LINE is not a good idea either).
BAR: lda Y2
sta Y2SAVE
lda Y2+1
sta Y2SAVE+1
lda X2
sta X2SAVE
lda X2+1
sta X2SAVE+1
lda Y1
sta Y1SAVE
lda Y1+1
sta Y1SAVE+1
lda X1
sta X1SAVE
lda X1+1
sta X1SAVE+1
@L1: lda Y1
sta Y2
lda Y1+1
sta Y2+1
jsr LINE
lda Y1SAVE
cmp Y2SAVE
bne @L2
lda Y1SAVE
cmp Y2SAVE
beq @L4
@L2: inc Y1SAVE
bne @L3
inc Y1SAVE+1
@L3: lda Y1SAVE
sta Y1
lda Y1SAVE+1
sta Y1+1
lda X1SAVE
sta X1
lda X1SAVE+1
sta X1+1
lda X2SAVE
sta X2
lda X2SAVE+1
sta X2+1
jmp @L1
@L4: rts
; ------------------------------------------------------------------------
; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
; direction is passend in X/Y, the text direction is passed in A.
;
; Must set an error code: NO
;
TEXTSTYLE:
stx TEXTMAGX
sty TEXTMAGY
sta TEXTDIR
rts
; ------------------------------------------------------------------------
; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
; current text style. The text to output is given as a zero terminated
; string with address in ptr3.
;
; Must set an error code: NO
;
OUTTEXT:
rts
; ------------------------------------------------------------------------
; Calculate all variables to plot the pixel at X1/Y1.
CALC: lda Y1
sta TEMP2
and #7
tay
lda Y1+1
lsr ; Neg is possible
ror TEMP2
lsr
ror TEMP2
lsr
ror TEMP2
lda #00
sta POINT
lda TEMP2
cmp #$80
ror
ror POINT
cmp #$80
ror
ror POINT ; Row * 64
adc TEMP2 ; + Row * 256
clc
adc #>VBASE ; + Bitmap base
sta POINT+1
lda X1
tax
and #$F8
clc
adc POINT ; +(X AND #$F8)
sta POINT
lda X1+1
adc POINT+1
sta POINT+1
txa
and #7
tax
rts

View File

@@ -0,0 +1,14 @@
;
; Address of the static standard tgi driver
;
; Oliver Schmidt, 2012-11-01
;
; const void tgi_static_stddrv[];
;
.export _tgi_static_stddrv
.import _ted_hi_tgi
.rodata
_tgi_static_stddrv := _ted_hi_tgi

13
libsrc/plus4/tgi_stddrv.s Normal file
View File

@@ -0,0 +1,13 @@
;
; Name of the standard tgi driver
;
; Oliver Schmidt, 2011-05-02
;
; const char tgi_stddrv[];
;
.export _tgi_stddrv
.rodata
_tgi_stddrv: .asciiz "ted-hi.tgi"