/*****************************************************************************/
-/* Code */
+/* Accessing the cart */
/*****************************************************************************/
+void __fastcall__ lynx_load (int fileno);
+/* Load a file into ram. The first entry is fileno=0. */
+
+void __fastcall__ lynx_exec (int fileno);
+/* Load a file into ram and execute it. */
+
+
+
/*****************************************************************************/
/* Accessing the EEPROM */
/*****************************************************************************/
/* Clear the word at the given address */
+
/*****************************************************************************/
/* TGI extras */
/*****************************************************************************/
+
+
#define tgi_sprite(spr) tgi_ioctl(0, spr)
#define tgi_flip() tgi_ioctl(1, (void*)0)
#define tgi_setbgcolor(bgcol) tgi_ioctl(2, (void*)(bgcol))
#define tgi_updatedisplay() tgi_ioctl(4, (void*)1)
#define tgi_setcollisiondetection(active) tgi_ioctl(5, (void*)(active))
+
+
/* End of lynx.h */
#endif
crt0.o \
ctype.o \
eeprom.o \
+ exec.o \
extzp.o \
kbhit.o \
+ load.o \
+ lseek.o \
+ lynx-cart.o \
mainargs.o \
+ open.o \
+ oserror.o \
+ read.o \
sysuname.o \
toascii.o
--- /dev/null
+;
+; Karri Kaksonen, 2010
+;
+; lynx_exec(fileno) loads a file into memory but after the read the CPU
+; does a jump into the loaded start address.
+;
+; lynx_exec is often used in compilation carts when you run small demos
+; created with various (non-cc65) compilers.
+;
+; void lynx_exec(int fileno)
+;
+ .importzp _FileDestAddr
+ .import pushax,ldax0sp,incsp2
+ .import _lynx_load
+ .export _lynx_exec
+
+; ---------------------------------------------------------------
+; void __near__ __fastcall__ lynx_exec (int)
+; ---------------------------------------------------------------
+
+.segment "CODE"
+
+.proc _lynx_exec: near
+
+.segment "CODE"
+
+ jsr pushax
+ jsr ldax0sp
+ jsr _lynx_load
+ jsr incsp2
+ jmp (_FileDestAddr)
+
+.endproc
+
--- /dev/null
+;
+; Karri Kaksonen, 2010
+;
+; lynx_load(fileno) is a convenience function that is widely used on the Lynx.
+; Basically this opens directory entry fileno and reads the content of the
+; file this points to into RAM.
+;
+; void lynx_load(int fileno)
+;
+ .importzp _FileFileLen
+ .importzp _FileDestAddr
+ .import pushax,ldax0sp,pusha0,incsp2
+ .import _openn
+ .import _read
+ .export _lynx_load
+
+; ---------------------------------------------------------------
+; void __near__ __fastcall__ lynx_load (int)
+; ---------------------------------------------------------------
+
+.segment "CODE"
+
+.proc _lynx_load: near
+
+.segment "CODE"
+
+ jsr pushax
+ jsr ldax0sp
+ jsr _openn
+ lda #$01
+ jsr pusha0
+ lda _FileDestAddr
+ ldx _FileDestAddr+1
+ jsr pushax
+ lda _FileFileLen
+ ldx _FileFileLen+1
+ jsr _read
+ jmp incsp2
+
+.endproc
+
--- /dev/null
+;
+; Karri Kaksonen, 2010
+;
+; This function is used to place the Lynx hardware to point to any byte in
+; the Lynx cart.
+;
+; This function supports all available block sizes (512, 1024 and 2048 bytes).
+; No other block sizes have been used afaik.
+;
+; Only SEEK_SET operation mode is implemented.
+;
+; off_t __fastcall__ lseek(int fd, off_t offset, int whence);
+
+ .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2
+ .macpack longbranch
+ .export _lseek
+ .import addysp, stax0sp, tosand0ax, pusheax, asreax2
+ .import ldeaxysp, decsp2, pushax, incsp8
+ .import tosandeax,decax1,tosdiveax,axlong,ldaxysp
+ .import lynxskip0, lynxblock,tosasreax
+ .import __BLOCKSIZE__
+ .importzp _FileCurrBlock
+
+.segment "CODE"
+
+.proc _lseek: near
+
+.segment "CODE"
+
+ jsr pushax
+ ldy #$05
+ jsr ldeaxysp
+ jsr pusheax
+ ldx #$00
+ lda #<(__BLOCKSIZE__/1024 + 9)
+ jsr tosasreax
+ sta _FileCurrBlock
+ jsr lynxblock
+ ldy #$05
+ jsr ldeaxysp
+ jsr pusheax
+ lda #<(__BLOCKSIZE__-1)
+ ldx #>(__BLOCKSIZE__-1)
+ jsr decax1
+ jsr axlong
+ jsr tosandeax
+ eor #$FF
+ pha
+ txa
+ eor #$FF
+ tay
+ plx
+ jsr lynxskip0
+ ldy #$05
+ jsr ldeaxysp
+ jmp incsp8
+
+.endproc
+
--- /dev/null
+; ***
+; CC65 Lynx Library
+;
+; Originally by Bastian Schick
+; http://www.geocities.com/SiliconValley/Byte/4242/lynx/
+;
+; Ported to cc65 (http://www.cc65.org) by
+; Shawn Jefferson, June 2004
+;
+; This version by Karri Kaksonen, December 2010
+;
+; Helper stuff for the cartridge file functions. This version can deal
+; with 1024 bytes/block carts that are using CART0 as a read strobe.
+; Also the default crt0.s supports this most common Lynx cart format.
+
+ .include "lynx.inc"
+ .include "extzp.inc"
+ .export lynxskip0, lynxread0
+ .export lynxblock
+
+__BLOCKSIZE0__ = 1024
+
+ .code
+
+;**********************************
+; Skip bytes on bank 0
+; X:Y count (EOR $FFFF)
+;**********************************
+lynxskip0:
+ inx
+ bne @0
+ iny
+ beq exit
+@0: jsr readbyte0
+ bra lynxskip0
+
+;**********************************
+; Read bytes from bank 0
+; X:Y count (EOR $ffff)
+;**********************************
+lynxread0:
+ inx
+ bne @1
+ iny
+ beq exit
+@1: jsr readbyte0
+ sta (_FileDestPtr)
+ inc _FileDestPtr
+ bne lynxread0
+ inc _FileDestPtr+1
+ bra lynxread0
+
+;**********************************
+; Read one byte from cartridge
+;**********************************
+readbyte0:
+ lda RCART0
+ inc _FileBlockByte
+ bne exit
+ inc _FileBlockByte+1
+ bne exit
+
+;**********************************
+; Select a block
+;**********************************
+lynxblock:
+ pha
+ phx
+ phy
+ lda __iodat
+ and #$fc
+ tay
+ ora #2
+ tax
+ lda _FileCurrBlock
+ inc _FileCurrBlock
+ sec
+ bra @2
+@0: bcc @1
+ stx IODAT
+ clc
+@1: inx
+ stx SYSCTL1
+ dex
+@2: stx SYSCTL1
+ rol
+ sty IODAT
+ bne @0
+ lda __iodat
+ sta IODAT
+ stz _FileBlockByte
+ lda #$100-(>__BLOCKSIZE0__)
+ sta _FileBlockByte+1
+ ply
+ plx
+ pla
+
+exit: rts
+
--- /dev/null
+;
+; Karri Kaksonen, 2010
+;
+; This function reads the directory entry for file "name".
+;
+; The name is actually plain ASCII string starting from
+; "0", "1", up to "4095" which is the largest file number we can handle.
+;
+; open() does not take part in what kind of cart we have. If it is RAM
+; you may also be able to write into it. Therefore we allow both reads
+; and writes in this routine.
+;
+; int open(const char *name, int flags, ...)
+;
+; As helper functions we also provide.
+; void openn(int fileno)
+;
+ .importzp sreg, tmp3
+ .macpack longbranch
+ .import _atoi
+ .import _read
+ .import _lseek
+ .import addysp,popax,pushax,decsp6,pusha0,pusheax,ldaxysp
+ .import aslax3,axlong,tosaddeax,steaxysp,stax0sp,incsp8
+ .import ldax0sp
+ .importzp _FileEntry
+ .importzp _FileStartBlock
+ .importzp _FileCurrBlock
+ .importzp _FileBlockOffset
+ .import __STARTOFDIRECTORY__
+ .export _open
+ .export _openn
+
+ .include "errno.inc"
+ .include "fcntl.inc"
+
+.segment "DATA"
+
+_startofdirectory:
+ .dword __STARTOFDIRECTORY__
+
+; ---------------------------------------------------------------
+; int __near__ open (__near__ const unsigned char*, int)
+; ---------------------------------------------------------------
+
+.segment "CODE"
+
+.proc _open
+
+.segment "CODE"
+
+ dey
+ dey
+ dey
+ dey
+ beq parmok
+ jsr addysp
+
+parmok: jsr popax
+ sta tmp3
+ and #(O_RDWR | O_CREAT)
+ cmp #O_RDONLY
+ beq flagsok
+ cmp #(O_WRONLY | O_CREAT)
+ beq flagsok
+ lda #EINVAL
+ ldx #0
+ jmp __directerrno
+
+flagsok:
+ jsr popax
+ jsr _atoi
+ jsr pushax
+ jsr ldax0sp
+ jsr _openn
+ ldx #$00
+ lda #$01
+ stx __oserror
+ rts
+
+.endproc
+
+; ---------------------------------------------------------------
+; void __near__ __fastcall__ openn (int)
+; ---------------------------------------------------------------
+
+.segment "CODE"
+
+.proc _openn: near
+
+.segment "CODE"
+
+ jsr pushax
+ jsr decsp6
+ lda #$01
+ jsr pusha0
+ lda _startofdirectory+3
+ sta sreg+1
+ lda _startofdirectory+2
+ sta sreg
+ ldx _startofdirectory+1
+ lda _startofdirectory
+ jsr pusheax
+ ldy #$0D
+ jsr ldaxysp
+ jsr aslax3
+ jsr axlong
+ jsr tosaddeax
+ jsr pusheax
+ ldx #$00
+ txa
+ jsr _lseek
+ ldy #$02
+ jsr steaxysp
+ lda #$01
+ jsr pusha0
+ lda _FileEntry
+ ldx _FileEntry+1
+ jsr pushax
+ ldx #$00
+ lda #$08
+ jsr _read
+ jsr stax0sp
+ jmp incsp8
+
+.endproc
+
--- /dev/null
+;
+; Karri Kaksonen, 2010
+;
+; int __fastcall__ _osmaperrno (unsigned char oserror);
+; /* Map a system specific error into a system independent code */
+;
+
+ .include "errno.inc"
+
+.code
+
+__osmaperrno:
+ rts
+
--- /dev/null
+;
+; Karri Kaksonen, 2010
+;
+; This function reads count bytes from the place where the address counter is.
+; Use lseek to place the address counter where you want to read from.
+;
+; The file descriptor is ignored in this implementation. The read operation
+; reads bytes from a raw cart and does not understand the concept of files.
+; So if you read over the end of file you get data from the next file.
+;
+; The count-parameter can be positive (Atari style) or negative (BLL style).
+; In any case the read routine will work correctly.
+;
+; int __fastcall__ read(int fd,void *buf,int count)
+;
+ .importzp _FileDestPtr
+ .import lynxread0
+ .import pushax,ldaxysp,ldax0sp,incsp6
+ .export _read
+
+.segment "CODE"
+
+.proc _read: near
+
+.segment "CODE"
+
+ jsr pushax
+ ldy #$03
+ jsr ldaxysp
+ sta _FileDestPtr
+ stx _FileDestPtr+1
+ jsr ldax0sp
+ phx ; The BLL kit uses negative counts
+ plx ; while the basic Lynx uses positive
+ bmi @1 ; make all counts negative
+ eor #$FF
+ pha
+ txa
+ eor #$FF
+ bra @2
+@1: pha
+ txa
+@2: tay
+ plx
+ jsr lynxread0
+ jsr ldax0sp
+ jmp incsp6
+
+.endproc
+
SYMBOLS {
__STACKSIZE__: type = weak, value = $0800; # 2k stack
+ __STARTOFDIRECTORY__: type = weak, value = $019A; # start just after loader
+ __BLOCKSIZE__: type = weak, value = 1024; # cart block size
}
MEMORY {
ZP: file = "", define = yes, start = $0000, size = $0100;