From d993b332a4391b13c987e97a2cef796a73f2a1c6 Mon Sep 17 00:00:00 2001 From: uz Date: Wed, 29 Dec 2010 10:37:57 +0000 Subject: [PATCH] Lynx update including file routines that access a file system on a cartridge by Karri Kaksonen. git-svn-id: svn://svn.cc65.org/cc65/trunk@4892 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- include/lynx.h | 15 ++++- libsrc/lynx/Makefile | 7 +++ libsrc/lynx/exec.s | 34 +++++++++++ libsrc/lynx/load.s | 41 +++++++++++++ libsrc/lynx/lseek.s | 59 +++++++++++++++++++ libsrc/lynx/lynx-cart.s | 99 +++++++++++++++++++++++++++++++ libsrc/lynx/open.s | 127 ++++++++++++++++++++++++++++++++++++++++ libsrc/lynx/oserror.s | 14 +++++ libsrc/lynx/read.s | 50 ++++++++++++++++ src/ld65/cfg/lynx.cfg | 2 + 10 files changed, 447 insertions(+), 1 deletion(-) create mode 100644 libsrc/lynx/exec.s create mode 100644 libsrc/lynx/load.s create mode 100644 libsrc/lynx/lseek.s create mode 100644 libsrc/lynx/lynx-cart.s create mode 100644 libsrc/lynx/open.s create mode 100644 libsrc/lynx/oserror.s create mode 100644 libsrc/lynx/read.s diff --git a/include/lynx.h b/include/lynx.h index 985c33fe9..b127b2825 100644 --- a/include/lynx.h +++ b/include/lynx.h @@ -73,11 +73,19 @@ /*****************************************************************************/ -/* 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 */ /*****************************************************************************/ @@ -94,10 +102,13 @@ void __fastcall__ lynx_eeprom_erase (unsigned char cell); /* 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)) @@ -106,6 +117,8 @@ void __fastcall__ lynx_eeprom_erase (unsigned char cell); #define tgi_updatedisplay() tgi_ioctl(4, (void*)1) #define tgi_setcollisiondetection(active) tgi_ioctl(5, (void*)(active)) + + /* End of lynx.h */ #endif diff --git a/libsrc/lynx/Makefile b/libsrc/lynx/Makefile index 7225ebddb..07cf5c20c 100644 --- a/libsrc/lynx/Makefile +++ b/libsrc/lynx/Makefile @@ -49,9 +49,16 @@ OBJS = cgetc.o \ 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 diff --git a/libsrc/lynx/exec.s b/libsrc/lynx/exec.s new file mode 100644 index 000000000..44550fd7b --- /dev/null +++ b/libsrc/lynx/exec.s @@ -0,0 +1,34 @@ +; +; 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 + diff --git a/libsrc/lynx/load.s b/libsrc/lynx/load.s new file mode 100644 index 000000000..2e6baa9cb --- /dev/null +++ b/libsrc/lynx/load.s @@ -0,0 +1,41 @@ +; +; 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 + diff --git a/libsrc/lynx/lseek.s b/libsrc/lynx/lseek.s new file mode 100644 index 000000000..1d9d93b24 --- /dev/null +++ b/libsrc/lynx/lseek.s @@ -0,0 +1,59 @@ +; +; 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 + diff --git a/libsrc/lynx/lynx-cart.s b/libsrc/lynx/lynx-cart.s new file mode 100644 index 000000000..f740614ee --- /dev/null +++ b/libsrc/lynx/lynx-cart.s @@ -0,0 +1,99 @@ +; *** +; 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 + diff --git a/libsrc/lynx/open.s b/libsrc/lynx/open.s new file mode 100644 index 000000000..9e22f62a5 --- /dev/null +++ b/libsrc/lynx/open.s @@ -0,0 +1,127 @@ +; +; 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 + diff --git a/libsrc/lynx/oserror.s b/libsrc/lynx/oserror.s new file mode 100644 index 000000000..f3643a525 --- /dev/null +++ b/libsrc/lynx/oserror.s @@ -0,0 +1,14 @@ +; +; 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 + diff --git a/libsrc/lynx/read.s b/libsrc/lynx/read.s new file mode 100644 index 000000000..c461e378f --- /dev/null +++ b/libsrc/lynx/read.s @@ -0,0 +1,50 @@ +; +; 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 + diff --git a/src/ld65/cfg/lynx.cfg b/src/ld65/cfg/lynx.cfg index e756395d5..d94b1fa90 100644 --- a/src/ld65/cfg/lynx.cfg +++ b/src/ld65/cfg/lynx.cfg @@ -1,5 +1,7 @@ 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; -- 2.39.5