Added old lib and two examples
This commit is contained in:
parent
040c03467b
commit
312f724971
21 changed files with 4615 additions and 0 deletions
20
examples/hires/cm.sh
Executable file
20
examples/hires/cm.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/sh
|
||||
# Define filename as variable
|
||||
PROGNAME="hires"
|
||||
# Only set C65LIBPATH if not already defined
|
||||
if [ -z "$C65LIBPATH" ]; then
|
||||
export C65LIBPATH=$(readlink -f "../../lib")
|
||||
fi
|
||||
# Compile
|
||||
c65gm -in ${PROGNAME}.c65 -out ${PROGNAME}.s
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compilation terminated"
|
||||
exit 1
|
||||
fi
|
||||
echo assemble.
|
||||
acme ${PROGNAME}.s
|
||||
if [ -f ${PROGNAME}.prg ]; then
|
||||
rm ${PROGNAME}.prg
|
||||
fi
|
||||
# main.bin ${PROGNAME}.prg
|
||||
mv main.bin main.prg
|
||||
57
examples/hires/hires.c65
Normal file
57
examples/hires/hires.c65
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#INCLUDE <c64start.c65>
|
||||
#INCLUDE <c64defs.c65>
|
||||
|
||||
GOTO start
|
||||
|
||||
|
||||
FUNC sethires
|
||||
BYTE b
|
||||
b = PEEK $d011
|
||||
b = b | 32 //enable bitmap mode
|
||||
POKE $d011 , b
|
||||
|
||||
b = PEEK $d018
|
||||
b = b & %11110000
|
||||
b = b | 8 //enable bitmap mode
|
||||
POKE $d018 , b
|
||||
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
FUNC fillmem({WORD start_addr @ $fa} {WORD end_addr @ $fc} {BYTE value})
|
||||
|
||||
WHILE start_addr <= end_addr
|
||||
POKE start_addr , value
|
||||
start_addr++
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
FUNC main
|
||||
|
||||
sethires()
|
||||
|
||||
WORD CONST screen = $0400
|
||||
|
||||
fillmem(screen, screen+1000, $cf)
|
||||
|
||||
WHILE 1
|
||||
|
||||
fillmem($2000, $3fff, %00000001)
|
||||
fillmem($2000, $3fff, %00000010)
|
||||
fillmem($2000, $3fff, %00000100)
|
||||
fillmem($2000, $3fff, %00001000)
|
||||
fillmem($2000, $3fff, %00010000)
|
||||
fillmem($2000, $3fff, %00100000)
|
||||
fillmem($2000, $3fff, %01000000)
|
||||
fillmem($2000, $3fff, %10000000)
|
||||
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
LABEL start
|
||||
|
||||
main()
|
||||
1
examples/hires/start_in_vice.sh
Normal file
1
examples/hires/start_in_vice.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
x64 -autostartprgmode 1 main.prg
|
||||
20
examples/multicolorbm/cm.sh
Executable file
20
examples/multicolorbm/cm.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/sh
|
||||
# Define filename as variable
|
||||
PROGNAME="multicolorbm"
|
||||
# Only set C65LIBPATH if not already defined
|
||||
if [ -z "$C65LIBPATH" ]; then
|
||||
export C65LIBPATH=$(readlink -f "../../lib")
|
||||
fi
|
||||
# Compile
|
||||
c65gm -in ${PROGNAME}.c65 -out ${PROGNAME}.s
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compilation terminated"
|
||||
exit 1
|
||||
fi
|
||||
echo assemble.
|
||||
acme ${PROGNAME}.s
|
||||
if [ -f ${PROGNAME}.prg ]; then
|
||||
rm ${PROGNAME}.prg
|
||||
fi
|
||||
# main.bin ${PROGNAME}.prg
|
||||
mv main.bin main.prg
|
||||
58
examples/multicolorbm/multicolorbm.c65
Normal file
58
examples/multicolorbm/multicolorbm.c65
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#INCLUDE <c64start.c65>
|
||||
#INCLUDE <c64defs.c65>
|
||||
|
||||
GOTO start
|
||||
|
||||
|
||||
FUNC setmulti
|
||||
BYTE b
|
||||
b = PEEK $d011
|
||||
b = b | 32
|
||||
POKE $d011 , b
|
||||
|
||||
b = PEEK $d016
|
||||
b = b | 16
|
||||
POKE $d016 , b
|
||||
|
||||
b = PEEK $d018
|
||||
b = b & %11110000
|
||||
b = b | 8
|
||||
POKE $d018 , b
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
FUNC fillmem({WORD start_addr @ $fa} {WORD end_addr @ $fc} {BYTE value})
|
||||
|
||||
WHILE start_addr <= end_addr
|
||||
POKE start_addr , value
|
||||
start_addr++
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
FUNC main
|
||||
|
||||
setmulti()
|
||||
|
||||
WORD CONST screen = $0400
|
||||
|
||||
fillmem(screen, screen+999, $12)
|
||||
fillmem(colorram, colorram+999, $03)
|
||||
|
||||
POKE $d021 , 0
|
||||
|
||||
WHILE 1
|
||||
fillmem($2000, $3fff, %00011011)
|
||||
fillmem($2000, $3fff, %01101100)
|
||||
fillmem($2000, $3fff, %10110001)
|
||||
fillmem($2000, $3fff, %11000110)
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
LABEL start
|
||||
|
||||
main()
|
||||
1
examples/multicolorbm/start_in_vice.sh
Normal file
1
examples/multicolorbm/start_in_vice.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
x64 -autostartprgmode 1 main.prg
|
||||
40
lib/c64defs.c65
Normal file
40
lib/c64defs.c65
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//-----------------------------------------------------------
|
||||
//
|
||||
// Commodore 64 definitions library
|
||||
//
|
||||
//
|
||||
// Author: Mattias Hansson, Mikael Hansson
|
||||
// Copyright (c) : 2000-2005 Mattias Hansson
|
||||
// License: GNU LGPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies:
|
||||
// Target: Commodore 64
|
||||
//
|
||||
// Purpose: Define accessor constants to various resources
|
||||
// in the C64.
|
||||
//-----------------------------------------------------------
|
||||
#IFNDEF __C64DEFS
|
||||
#DEFINE __C64DEFS = 1
|
||||
WORD CONST vic2 = $d000
|
||||
WORD CONST cia1 = $dc00
|
||||
WORD CONST cia2 = $dd00
|
||||
WORD CONST colorram = $d800
|
||||
WORD CONST sid = $d400
|
||||
|
||||
BYTE CONST color_black = 0
|
||||
BYTE CONST color_white = 1
|
||||
BYTE CONST color_red = 2
|
||||
BYTE CONST color_cyan = 3
|
||||
BYTE CONST color_purple = 4
|
||||
BYTE CONST color_green = 5
|
||||
BYTE CONST color_blue = 6
|
||||
BYTE CONST color_yellow = 7
|
||||
BYTE CONST color_orange = 8
|
||||
BYTE CONST color_brown = 9
|
||||
BYTE CONST color_pink = 10
|
||||
BYTE CONST color_dark_grey = 11
|
||||
BYTE CONST color_grey = 12
|
||||
BYTE CONST color_light_green = 13
|
||||
BYTE CONST color_light_blue = 14
|
||||
BYTE CONST color_light_grey = 15
|
||||
#IFEND
|
||||
52
lib/c64kernal.c65
Normal file
52
lib/c64kernal.c65
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//-----------------------------------------------------------
|
||||
//
|
||||
// Commodore 64 kernal definitions
|
||||
//
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2025 Mattias Hansson
|
||||
// License: GNU LGPL 2
|
||||
// Language: 65CM v0.6+
|
||||
// Dependencies:
|
||||
// Target: Commodore 64
|
||||
//
|
||||
// Purpose: Define accessor constants to various kernal
|
||||
// routines in the C64.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
#IFNDEF __C64KERNAL
|
||||
#DEFINE __C64KERNAL = 1
|
||||
|
||||
WORD CONST CINT = $FF81
|
||||
WORD CONST IOINIT = $FF84
|
||||
WORD CONST RAMTAS = $FF87
|
||||
WORD CONST RESTOR = $FF8A
|
||||
WORD CONST VECTOR = $FF8D
|
||||
WORD CONST SETMSG = $FF90
|
||||
WORD CONST SECOND = $FF93
|
||||
WORD CONST TKSA = $FF96
|
||||
WORD CONST MEMTOP = $FF99
|
||||
WORD CONST MEMBOT = $FF9C
|
||||
WORD CONST SCNKEY = $FF9F
|
||||
WORD CONST SETTMO = $FFA2
|
||||
WORD CONST ACPTR = $FFA5
|
||||
WORD CONST CIOUT = $FFA8
|
||||
WORD CONST UNTLK = $FFAB
|
||||
WORD CONST UNLSN = $FFAE
|
||||
WORD CONST LISTEN = $FFB1
|
||||
WORD CONST TALK = $FFB4
|
||||
WORD CONST READST = $FFB7
|
||||
WORD CONST SETLFS = $FFBA
|
||||
WORD CONST SETNAM = $FFBD
|
||||
WORD CONST OPEN = $FFC0
|
||||
WORD CONST CLOSE = $FFC3
|
||||
WORD CONST LOAD = $FFD5
|
||||
WORD CONST SAVE = $FFD8
|
||||
WORD CONST SETTIM = $FFDB
|
||||
WORD CONST RDTIM = $FFDE
|
||||
WORD CONST CLRSCR = $E544 // Clear the screen
|
||||
WORD CONST KBDREAD = $E5B4 // Get Character From Keyboard Buffer
|
||||
WORD CONST NMIEXIT = $FEBC
|
||||
WORD CONST UPDCRAMPTR = $EA24 // Update color ram pointer
|
||||
|
||||
#IFEND
|
||||
25
lib/c64scr.c65
Normal file
25
lib/c64scr.c65
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
#IFNDEF __C64_SCR
|
||||
#DEFINE __C64_SCR = 1
|
||||
GOTO lib_c64scr_skip
|
||||
|
||||
LABEL lib_c64scr_blank
|
||||
ASM
|
||||
lda $d011
|
||||
and #($ff-$10)
|
||||
sta $d011
|
||||
ENDASM
|
||||
|
||||
SUBEND
|
||||
|
||||
LABEL lib_c64scr_show
|
||||
ASM
|
||||
lda $d011
|
||||
ora #$10
|
||||
sta $d011
|
||||
ENDASM
|
||||
SUBEND
|
||||
|
||||
LABEL lib_c64scr_skip
|
||||
|
||||
#IFEND
|
||||
34
lib/c64start.c65
Normal file
34
lib/c64start.c65
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//-------------------------------------------------------
|
||||
//
|
||||
// C64 START LIB
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// License: LGPL
|
||||
// Compiler version: c65cm, v.04+
|
||||
//
|
||||
// Purpose:
|
||||
// When loaded into CBM memory this source generates
|
||||
// a valid basic line that starts the program.
|
||||
//
|
||||
// Note: Include this first before any own written code,
|
||||
// and other libraries.
|
||||
//-------------------------------------------------------
|
||||
|
||||
ORIGIN $0801
|
||||
|
||||
#IFNDEF __C64_BASIC_START
|
||||
#DEFINE __C64_BASIC_START = 1
|
||||
#DEFINE MACHINE_C64 = 1
|
||||
|
||||
ASM
|
||||
!to "main.bin", cbm ; The output file definition (add CBM starting address)
|
||||
!sl "main.sym" ; save the symbols to separate file
|
||||
!cpu 6502 ; The processor definition
|
||||
; basic line "0 sys 2064"
|
||||
!8 $0c, $08, $00, $00, $9e, $20, $32, $30, $36, $34, $0, $0, $0
|
||||
|
||||
ENDASM
|
||||
|
||||
ORIGIN $0810
|
||||
|
||||
#IFEND
|
||||
136
lib/cbmiolib.c65
Normal file
136
lib/cbmiolib.c65
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
//------------------------------------------------------------------------
|
||||
// Library CBM I/O
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2005 Mattias Hansson
|
||||
// License: GNU LGPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies: (all libs might be included, selectively)
|
||||
// Target: CBM computers.
|
||||
//
|
||||
// Purpose: To shorten lib names to normal usage length
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFNDEF __LIB_CBMIO
|
||||
#DEFINE __LIB_CBMIO = 1
|
||||
|
||||
|
||||
GOTO lib_cbmio_skip
|
||||
|
||||
WORD lib_cbmio_to_txtptr
|
||||
FUNC lib_cbmio_print ( lib_cbmio_to_txtptr )
|
||||
//On c64 we "borrow" the undocumented "print zero-terminated string" routine
|
||||
#IFDEF MACHINE_C64
|
||||
ASM
|
||||
lda lib_cbmio_to_txtptr
|
||||
ldy lib_cbmio_to_txtptr+1
|
||||
jsr $ab1e ; strout kernal routine
|
||||
ENDASM
|
||||
#IFEND
|
||||
#IFNDEF MACHINE_C64
|
||||
BYTE lib_cbmio_to_char
|
||||
PEEK lib_cbmio_to_txtptr -> lib_cbmio_to_char
|
||||
WHILE lib_cbmio_to_char
|
||||
GOSUB $ffd2 PASSING lib_cbmio_to_char AS ACC
|
||||
INC lib_cbmio_to_txtptr
|
||||
PEEK lib_cbmio_to_txtptr -> lib_cbmio_to_char
|
||||
WEND
|
||||
#IFEND
|
||||
FEND
|
||||
|
||||
WORD lib_cbmio_tl_txtptr
|
||||
FUNC lib_cbmio_printlf ( lib_cbmio_tl_txtptr )
|
||||
|
||||
CALL lib_cbmio_print ( lib_cbmio_tl_txtptr )
|
||||
CALL lib_cbmio_print ( @lib_cbmio_tl_linefeed )
|
||||
|
||||
FEND
|
||||
|
||||
FUNC lib_cbmio_lf
|
||||
|
||||
CALL lib_cbmio_print ( @lib_cbmio_tl_linefeed )
|
||||
|
||||
FEND
|
||||
|
||||
FUNC lib_cbmio_home
|
||||
|
||||
CALL lib_cbmio_print ( @lib_cbmio_tl_home )
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
ASM
|
||||
lib_cbmio_tl_home
|
||||
!8 19, 0
|
||||
lib_cbmio_tl_linefeed
|
||||
!8 13, 0
|
||||
lib_cbmio_text_nullstr
|
||||
!8 0
|
||||
ENDASM
|
||||
|
||||
|
||||
BYTE lib_cbmio_hb_value
|
||||
FUNC lib_cbmio_hexoutb ( lib_cbmio_hb_value )
|
||||
ASM
|
||||
;ldy #0
|
||||
;lda (lib_cbmio_ho_varaddress),y
|
||||
lda lib_cbmio_hb_value
|
||||
and #$0f
|
||||
tax
|
||||
lda lib_cbmio_ho_hexdigits,x
|
||||
sta lib_cbmio_ho_hextxt+1
|
||||
;lda (lib_cbmio_ho_varaddress),y
|
||||
lda lib_cbmio_hb_value
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
lda lib_cbmio_ho_hexdigits,x
|
||||
sta lib_cbmio_ho_hextxt
|
||||
ENDASM
|
||||
CALL lib_cbmio_print ( @lib_cbmio_ho_hextxt )
|
||||
|
||||
FEND
|
||||
|
||||
WORD lib_cbmio_lib_cbmio_ho_value
|
||||
FUNC lib_cbmio_hexoutw ( lib_cbmio_lib_cbmio_ho_value )
|
||||
ASM
|
||||
lda lib_cbmio_lib_cbmio_ho_value+1
|
||||
sta lib_cbmio_hb_value
|
||||
jsr lib_cbmio_hexoutb
|
||||
lda lib_cbmio_lib_cbmio_ho_value
|
||||
sta lib_cbmio_hb_value
|
||||
jsr lib_cbmio_hexoutb
|
||||
ENDASM
|
||||
FEND
|
||||
|
||||
WORD lib_cbmio_i_ptr
|
||||
FUNC lib_cbmio_input ( lib_cbmio_i_ptr )
|
||||
BYTE char
|
||||
|
||||
LET char = 0
|
||||
WHILE char <> 13
|
||||
ASM
|
||||
jsr $ffcf
|
||||
sta |char|
|
||||
ENDASM
|
||||
POKE lib_cbmio_i_ptr WITH char
|
||||
INC lib_cbmio_i_ptr
|
||||
WEND
|
||||
DEC lib_cbmio_i_ptr //replace ending #13 with #0
|
||||
POKE lib_cbmio_i_ptr WITH 0
|
||||
FEND
|
||||
|
||||
ASM
|
||||
|
||||
lib_cbmio_ho_hextxt
|
||||
!8 0,0,0
|
||||
|
||||
lib_cbmio_ho_hexdigits
|
||||
!pet "0123456789abcdef"
|
||||
ENDASM
|
||||
|
||||
|
||||
LABEL lib_cbmio_skip
|
||||
#IFEND
|
||||
1566
lib/fat16/fat16lib.c65
Normal file
1566
lib/fat16/fat16lib.c65
Normal file
File diff suppressed because it is too large
Load diff
686
lib/fat16/fat16lowlib.c65
Normal file
686
lib/fat16/fat16lowlib.c65
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
//------------------------------------------------------------------------
|
||||
// FAT16 Library Low Level
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Target: Commodore 64 with MMC64 interface
|
||||
// (possible future conversions for other platforms possible)
|
||||
//
|
||||
// Purpose: To provide lowlevel access routines for the FAT16 Library
|
||||
//
|
||||
// Routines:
|
||||
// lib_fat16_int_read_cluster_sector (INTERNAL)
|
||||
//
|
||||
//
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
#IFNDEF __LIB_FAT16LOW
|
||||
#DEFINE __LIB_FAT16LOW = 1
|
||||
|
||||
GOTO lib_fat16low_skip
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// FAT16 constants
|
||||
//------------------------------------------------------------------------
|
||||
WORD CONST LIB_FAT16_CLUSTER_FREE = $0000
|
||||
WORD CONST LIB_FAT16_CLUSTER_END = $fff0 //this value or above = clusterchain ended
|
||||
BYTE CONST LIB_FAT16_DIRENTRY_SIZE = $20
|
||||
BYTE CONST LIB_FAT16_DELETED_FILE = $e5
|
||||
BYTE CONST LIB_FAT16_END_OF_DIR = $00
|
||||
WORD CONST LIB_FAT16_SECTOR_SIZE = 512
|
||||
|
||||
//******Do NOT EVER access this var as a regular variable***********
|
||||
//special: this is NOT a regular variable for usage!!!!!!!!!!!!!!!!!
|
||||
//The "Address" defines how many files may be open simultainously!!!
|
||||
//If you want to change the number of open files, change the!!!!!!!!
|
||||
//address to the number you of files you want open!!!!!!!!!!!!!!!!!!
|
||||
BYTE lib_fat16_max_open_files @ __LIB_FAT16_MAX_OPEN_FILES
|
||||
//******Do NOT EVER access this var as a regular variable***********
|
||||
|
||||
BYTE CONST LIB_FAT16_FILEMODE_READ = 0
|
||||
BYTE CONST LIB_FAT16_FILEMODE_WRITE = 1
|
||||
//This filemode is special as it's only valid for fclose()
|
||||
//This file gets set when blockwriting another size then $512
|
||||
//as further writes would not be alligned with the sectors.
|
||||
BYTE CONST LIB_FAT16_FILEMODE_WRITE_ENDED = 2
|
||||
//BYTE CONST LIB_FAT16_FILEMODE_READWRITE = 2 //future expansion
|
||||
|
||||
#IFDEF __LIB_FAT16_WRITESUPPORT
|
||||
//This constant controls how many consecutive clusters will be controlled
|
||||
//for beeing free when mounting a partition for read/write access.
|
||||
//Generally speaking this is good when having an unfragmented disk/card
|
||||
//with just a little data on it, as i shortens the mount time.
|
||||
|
||||
//However if you'll be writing much data (like several megabytes) you'll
|
||||
//probably want to set this to $ffff (no limit) since this will not add
|
||||
//any performance penalty (for searching new free clusters) when you've
|
||||
//reached the limit.
|
||||
|
||||
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
||||
WORD CONST LIB_FAT16_WRITE_CLUSTERS_MAX = $400
|
||||
#IFEND
|
||||
#IFNDEF __LIB_MMC64_OPTIMIZE_SPEED
|
||||
//Explanation: if we don't cache the reads, every single cluster
|
||||
//we search (in fat) will force the lib to re-read the sector again
|
||||
//which will take painfully much time
|
||||
#PRINT __LIB_MMC64_OPTIMIZE_SPEED combined with __LIB_FAT16_WRITESUPPORT is catastrophic performance-wise.
|
||||
WORD CONST LIB_FAT16_WRITE_CLUSTERS_MAX = $10
|
||||
#IFEND
|
||||
|
||||
|
||||
#IFEND
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// FAT16 common variables
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
//Info for developers: the lib_fat16_buffer_ptr must point out an 512 byte area
|
||||
//You can choose to do so by a constant or variable.
|
||||
//Default is a variable that points out an area reserved inside this library
|
||||
//called "lib_fat16_fatbuffer". If you change this to a constant, remark
|
||||
//the "lib_fat16_fatbuffer" area to save the unused filler.
|
||||
|
||||
//WORD CONST lib_fat16_buffer_ptr = $c800 //change this for your particular usage
|
||||
// //(size needed is "one sector" = 512 bytes )
|
||||
|
||||
WORD lib_fat16_buffer_ptr
|
||||
BYTE lib_fat16_sectors_per_cluster // needed for cluster reading routine
|
||||
WORD lib_fat16_reserved_sectors // offset from FAT16 boot record to FATs (file allocation tables)
|
||||
BYTE lib_fat16_nr_of_fats // self*sectors_per_fat = offset from FATs to the root directory
|
||||
WORD lib_fat16_sectors_per_fat // (see above)
|
||||
WORD lib_fat16_rootdir_entries // Max file-entries in the ROOT directory
|
||||
// ( self * size of directory entry (32) ) / 512 =
|
||||
// offset from ROOT directory to DATA area (where clusters begin.
|
||||
// N.B. First cluster here is #2 (!))
|
||||
WORD lib_fat16_rootdir_sectors // calculated size of rootdir measured in sectors.
|
||||
|
||||
#IFDEF __LIB_FAT16_WRITESUPPORT
|
||||
|
||||
WORD lib_fat16_total_clusters = 0 // ( sectors_per_fat * bytes_per_sector ($200) ) / 2 == ( sectors_per_fat * $100 ).
|
||||
|
||||
WORD lib_fat16_first_write_cluster = $ffff //these two are used internally by lib_fat16_int_find_unused_clusters and
|
||||
WORD lib_fat16_last_write_cluster = $0000 //lib_fat16_fwriteblock to find new areas for writing bit by bit (as needed)
|
||||
WORD lib_fat16_total_sectors_lo
|
||||
WORD lib_fat16_total_sectors_hi
|
||||
|
||||
#IFEND
|
||||
|
||||
//Temp ZP-variables for usage in the lib.
|
||||
WORD lib_fat16_tempw @ $3f
|
||||
WORD lib_fat16_tempw2 @ $4b
|
||||
BYTE lib_fat16_tempb @ $41
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// 512 byte internal buffer for FAT16 operations.
|
||||
//------------------------------------------------------------------------
|
||||
LABEL lib_fat16_fatbuffer
|
||||
ASM
|
||||
!fill 512
|
||||
ENDASM
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_fat16_int_read_cluster_sector (INTERNAL)
|
||||
//
|
||||
// Purpose:
|
||||
// 1. To read out a specific sector in a specific cluster
|
||||
// or
|
||||
// 2. To read out a sector in the root-dir
|
||||
//
|
||||
// Parameters:
|
||||
// lib_fat16_int_rc_cluster - cluster to read. special: 0 = root-dir
|
||||
// lib_fat16_int_rc_sector - sector # inside the cluster (0..lib_fat16_sectors_per_cluster-1)
|
||||
// special: if in root-dir (0..lib_fat16_rootdir_sectors-1)
|
||||
// lib_fat16_int_rc_buffer_ptr - pointer, where to put the read sector in memory
|
||||
// lib_fat16_int_rc_status - 0 = OK. !0 = error.
|
||||
//
|
||||
// Preparation: lib_fat16_mount_partition
|
||||
//
|
||||
// Usage of lib temp variables:
|
||||
// lib_fat16_tempw2
|
||||
// lib_fat16_tempb
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
WORD lib_fat16_int_rc_cluster
|
||||
WORD lib_fat16_int_rc_sector
|
||||
WORD lib_fat16_int_rc_buffer_ptr
|
||||
BYTE lib_fat16_int_rc_status
|
||||
|
||||
FUNC lib_fat16_int_read_cluster_sector ( lib_fat16_int_rc_cluster lib_fat16_int_rc_sector lib_fat16_int_rc_buffer_ptr out:lib_fat16_int_rc_status )
|
||||
WORD first_pos // in bytes
|
||||
WORD read_count
|
||||
|
||||
LET first_pos = 0
|
||||
LET read_count = LIB_FAT16_SECTOR_SIZE
|
||||
|
||||
FUNC lib_fat16_int_read_cluster_sector_part ( lib_fat16_int_rc_cluster lib_fat16_int_rc_sector lib_fat16_int_rc_buffer_ptr first_pos read_count out:lib_fat16_int_rc_status )
|
||||
|
||||
BYTE spc_count
|
||||
WORD csect_offset_lo
|
||||
BYTE csect_offset_hi
|
||||
BYTE callstat //status for internal calls
|
||||
|
||||
|
||||
LET lib_fat16_int_rc_status = 1 //indicate an error at first (we SUBEND out if things go wrong)
|
||||
|
||||
IF lib_fat16_int_rc_cluster == 0 //the root directory
|
||||
IF lib_fat16_int_rc_sector >= lib_fat16_rootdir_sectors
|
||||
SUBEND // caller tried to make us read past the root-dir region. probably an internal error.
|
||||
ENDIF
|
||||
//Now we must add the start sector for the rootdir with the sector requested inside it, to get the right one
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_rootdir_sector_lo
|
||||
adc lib_fat16_int_rc_sector
|
||||
sta lib_fat16_tempw2
|
||||
lda lib_fat16_rootdir_sector_lo+1
|
||||
adc lib_fat16_int_rc_sector+1
|
||||
sta lib_fat16_tempw2+1
|
||||
lda lib_fat16_rootdir_sector_hi
|
||||
adc #0
|
||||
sta lib_fat16_tempb
|
||||
ENDASM
|
||||
CALL lib_mmc64_readsector ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_rc_buffer_ptr callstat )
|
||||
IF callstat != 0
|
||||
SUBEND
|
||||
ENDIF
|
||||
GOTO lib_fat16_int_rc_exit_success
|
||||
ENDIF
|
||||
|
||||
//Else this is a real cluster in the dataarea that's about to be read
|
||||
IF lib_fat16_int_rc_sector >= lib_fat16_sectors_per_cluster
|
||||
SUBEND // caller passed a sector offset beyond the end of the cluster. probably an internal error
|
||||
ENDIF
|
||||
|
||||
//Adjust for data-area starting with cluster #2
|
||||
SUBT lib_fat16_int_rc_cluster - 2 -> lib_fat16_int_rc_cluster
|
||||
|
||||
//Now we must multiply the clusternr with "nr of sectors per cluster" to
|
||||
//get a valid sector-offset into the data-area
|
||||
LET csect_offset_lo = lib_fat16_int_rc_cluster
|
||||
LET csect_offset_hi = 0
|
||||
LET spc_count = lib_fat16_sectors_per_cluster
|
||||
//First bit unimportant (1 sector per cluster and we're done here!)
|
||||
ASM
|
||||
lsr |spc_count|
|
||||
ENDASM
|
||||
WHILE spc_count
|
||||
ASM
|
||||
clc
|
||||
rol |csect_offset_lo|
|
||||
rol |csect_offset_lo|+1
|
||||
rol |csect_offset_hi|
|
||||
|
||||
lsr |spc_count|
|
||||
ENDASM
|
||||
WEND
|
||||
|
||||
// "real sector to access" = "start of data area" + "cluster sector offset" + lib_fat16_int_rc_sector (sector # in cluster)
|
||||
//first we do "start of data area" + "cluster sector offset"
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_data_sector_lo
|
||||
adc |csect_offset_lo|
|
||||
sta lib_fat16_tempw2
|
||||
lda lib_fat16_data_sector_lo+1
|
||||
adc |csect_offset_lo|+1
|
||||
sta lib_fat16_tempw2+1
|
||||
lda lib_fat16_data_sector_hi
|
||||
adc |csect_offset_hi|
|
||||
sta lib_fat16_tempb
|
||||
ENDASM
|
||||
//now we add the lib_fat16_int_rc_sector
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_tempw2
|
||||
adc |lib_fat16_int_rc_sector|
|
||||
sta lib_fat16_tempw2
|
||||
lda lib_fat16_tempw2+1
|
||||
adc #0 ; we know that "sectors per cluster" cannot exceed 128.
|
||||
sta lib_fat16_tempw2+1
|
||||
lda lib_fat16_tempb
|
||||
adc #0
|
||||
sta lib_fat16_tempb
|
||||
ENDASM
|
||||
|
||||
//Mostly we read whole sectors. However if the file ends in (( size % 0x200 )!=0) the file ends someplace inside
|
||||
//a sector, and we must read the last sector partly.
|
||||
CALL lib_mmc64_readsector_part ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_rc_buffer_ptr first_pos read_count callstat )
|
||||
IF callstat != 0
|
||||
SUBEND
|
||||
ENDIF
|
||||
|
||||
|
||||
LABEL lib_fat16_int_rc_exit_success
|
||||
|
||||
LET lib_fat16_int_rc_status = 0
|
||||
FEND
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_fat16_int_write_cluster_sector (INTERNAL)
|
||||
//
|
||||
// Purpose:
|
||||
// 1. To write a specific sector in a specific cluster
|
||||
// or
|
||||
// 2. To write a sector in the root-dir
|
||||
//
|
||||
// Parameters:
|
||||
// lib_fat16_int_wc_cluster - cluster to write. special: 0 = root-dir
|
||||
// lib_fat16_int_wc_sector - sector # inside the cluster (0..lib_fat16_sectors_per_cluster-1)
|
||||
// special: if in root-dir (0..lib_fat16_rootdir_sectors-1)
|
||||
// lib_fat16_int_wc_buffer_ptr - pointer, sector-data in memory to write
|
||||
// lib_fat16_int_wc_status - 0 = OK. !0 = error.
|
||||
//
|
||||
// Preparation: lib_fat16_mount_partition
|
||||
//
|
||||
// Usage of lib temp variables:
|
||||
// lib_fat16_tempw2
|
||||
// lib_fat16_tempb
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFDEF __LIB_FAT16_WRITESUPPORT
|
||||
|
||||
WORD lib_fat16_int_wc_cluster
|
||||
WORD lib_fat16_int_wc_sector
|
||||
WORD lib_fat16_int_wc_buffer_ptr
|
||||
BYTE lib_fat16_int_wc_status
|
||||
|
||||
FUNC lib_fat16_int_write_cluster_sector ( lib_fat16_int_wc_cluster lib_fat16_int_wc_sector lib_fat16_int_wc_buffer_ptr out:lib_fat16_int_wc_status )
|
||||
WORD first_pos // in bytes
|
||||
WORD write_count
|
||||
|
||||
LET first_pos = 0
|
||||
LET write_count = LIB_FAT16_SECTOR_SIZE
|
||||
|
||||
FUNC lib_fat16_int_write_cluster_sector_part ( lib_fat16_int_wc_cluster lib_fat16_int_wc_sector lib_fat16_int_wc_buffer_ptr first_pos write_count out:lib_fat16_int_wc_status )
|
||||
|
||||
BYTE spc_count
|
||||
WORD csect_offset_lo
|
||||
BYTE csect_offset_hi
|
||||
BYTE callstat //status for internal calls
|
||||
|
||||
|
||||
LET lib_fat16_int_wc_status = 1 //indicate an error at first (we SUBEND out if things go wrong)
|
||||
|
||||
IF lib_fat16_int_wc_cluster == 0 //the root directory
|
||||
IF lib_fat16_int_wc_sector >= lib_fat16_rootdir_sectors
|
||||
SUBEND // caller tried to make us read past the root-dir region. probably an internal error.
|
||||
ENDIF
|
||||
//Now we must add the start sector for the rootdir with the sector requested inside it, to get the right one
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_rootdir_sector_lo
|
||||
adc lib_fat16_int_wc_sector
|
||||
sta lib_fat16_tempw2
|
||||
lda lib_fat16_rootdir_sector_lo+1
|
||||
adc lib_fat16_int_wc_sector+1
|
||||
sta lib_fat16_tempw2+1
|
||||
lda lib_fat16_rootdir_sector_hi
|
||||
adc #0
|
||||
sta lib_fat16_tempb
|
||||
ENDASM
|
||||
CALL lib_mmc64_writesector ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_wc_buffer_ptr callstat )
|
||||
IF callstat != 0
|
||||
SUBEND
|
||||
ENDIF
|
||||
GOTO lib_fat16_int_wc_exit_success
|
||||
ENDIF
|
||||
|
||||
//Else this is a real cluster in the dataarea that's about to be read
|
||||
IF lib_fat16_int_wc_sector >= lib_fat16_sectors_per_cluster
|
||||
SUBEND // caller passed a sector offset beyond the end of the cluster. probably an internal error
|
||||
ENDIF
|
||||
|
||||
//Adjust for data-area starting with cluster #2
|
||||
SUBT lib_fat16_int_wc_cluster - 2 -> lib_fat16_int_wc_cluster
|
||||
|
||||
//Now we must multiply the clusternr with "nr of sectors per cluster" to
|
||||
//get a valid sector-offset into the data-area
|
||||
LET csect_offset_lo = lib_fat16_int_wc_cluster
|
||||
LET csect_offset_hi = 0
|
||||
LET spc_count = lib_fat16_sectors_per_cluster
|
||||
//First bit unimportant (1 sector per cluster and we're done here!)
|
||||
ASM
|
||||
lsr |spc_count|
|
||||
ENDASM
|
||||
WHILE spc_count
|
||||
ASM
|
||||
clc
|
||||
rol |csect_offset_lo|
|
||||
rol |csect_offset_lo|+1
|
||||
rol |csect_offset_hi|
|
||||
|
||||
lsr |spc_count|
|
||||
ENDASM
|
||||
WEND
|
||||
|
||||
// "real sector to access" = "start of data area" + "cluster sector offset" + lib_fat16_int_wc_sector (sector # in cluster)
|
||||
//first we do "start of data area" + "cluster sector offset"
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_data_sector_lo
|
||||
adc |csect_offset_lo|
|
||||
sta lib_fat16_tempw2
|
||||
lda lib_fat16_data_sector_lo+1
|
||||
adc |csect_offset_lo|+1
|
||||
sta lib_fat16_tempw2+1
|
||||
lda lib_fat16_data_sector_hi
|
||||
adc |csect_offset_hi|
|
||||
sta lib_fat16_tempb
|
||||
ENDASM
|
||||
//now we add the lib_fat16_int_wc_sector
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_tempw2
|
||||
adc |lib_fat16_int_wc_sector|
|
||||
sta lib_fat16_tempw2
|
||||
lda lib_fat16_tempw2+1
|
||||
adc #0 ; we know that "sectors per cluster" cannot exceed 128.
|
||||
sta lib_fat16_tempw2+1
|
||||
lda lib_fat16_tempb
|
||||
adc #0
|
||||
sta lib_fat16_tempb
|
||||
ENDASM
|
||||
|
||||
//Mostly we read whole sectors. However if the file ends in (( size % 0x200 )!=0) the file ends someplace inside
|
||||
//a sector, and we must read the last sector partly.
|
||||
CALL lib_mmc64_writesector_part ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_wc_buffer_ptr first_pos write_count callstat )
|
||||
IF callstat != 0
|
||||
SUBEND
|
||||
ENDIF
|
||||
|
||||
|
||||
LABEL lib_fat16_int_wc_exit_success
|
||||
|
||||
LET lib_fat16_int_wc_status = 0
|
||||
FEND
|
||||
|
||||
#IFEND
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_fat16_int_get_cluster_link (INTERNAL)
|
||||
//
|
||||
// Purpose:
|
||||
// Return the next cluster nr for a given cluster.
|
||||
// In the FAT the position for the current cluster holds the link
|
||||
// to the next cluster in the "chain".
|
||||
// special values are: $0000 unallocated, $ffef-$ffff end-of-cluster-chain
|
||||
//
|
||||
// Parameters:
|
||||
// lib_fat16_int_nc_cluster_nr - we send in our current cluster number
|
||||
// and we get the next returned in the
|
||||
// same param
|
||||
// lib_fat16_int_nc_status - the status operation. 0 = success
|
||||
// !0 = failure (probably internal)
|
||||
//
|
||||
// Preparation: lib_fat16_dirnext (caller)
|
||||
// (unfinished) lib_fat16_fopen
|
||||
//
|
||||
// Usage of lib temp variables:
|
||||
// lib_fat16_tempw2
|
||||
// lib_fat16_tempb
|
||||
//
|
||||
//
|
||||
// lib_fat16_int_set_cluster_link (INTERNAL)
|
||||
//
|
||||
// Purpose: to update the two FAT's with a new value for the cluster-link
|
||||
//
|
||||
// Additional parameter:
|
||||
// lib_fat16_int_nc_target_cluster_nr = the new cluster-link to write
|
||||
//
|
||||
// Sorry for the clutter, but this way saves a whole lot of code to
|
||||
// support write-access //Mattias
|
||||
//
|
||||
// A note on caching: Since a fat-sector is read, updated and written back
|
||||
// at once we don't need to invalidate the "caching" of the FAT-buffer.
|
||||
// (a later cached read will still be valid)
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
WORD lib_fat16_int_nc_cluster_nr
|
||||
BYTE lib_fat16_int_nc_status
|
||||
|
||||
#IFDEF __LIB_FAT16_WRITESUPPORT
|
||||
|
||||
BYTE lib_fat16_int_nc_writeflag
|
||||
WORD lib_fat16_int_nc_target_cluster_nr
|
||||
FUNC lib_fat16_int_set_cluster_link ( lib_fat16_int_nc_cluster_nr lib_fat16_int_nc_target_cluster_nr out:lib_fat16_int_nc_status )
|
||||
|
||||
LET lib_fat16_int_nc_writeflag = 1
|
||||
|
||||
#IFEND
|
||||
|
||||
FUNC lib_fat16_int_get_cluster_link ( io:lib_fat16_int_nc_cluster_nr out:lib_fat16_int_nc_status )
|
||||
|
||||
BYTE sect_offset
|
||||
BYTE callstat
|
||||
WORD sector_lo
|
||||
BYTE sector_hi
|
||||
|
||||
//MHTAG 20050927 - this internal variable was replaced internally for lib_fat16_tempw2 (ZP-vars == better code)
|
||||
//WORD lib_fat16_int_nc_link_offset_bytes
|
||||
|
||||
LET lib_fat16_int_nc_status = 1
|
||||
|
||||
//Clusters in the data-area are numbered from 2 (i.e. 2 = offset 0 )
|
||||
IF lib_fat16_int_nc_cluster_nr < 2
|
||||
SUBEND
|
||||
ENDIF
|
||||
|
||||
//Values from $fff0 are "bad", reserved or cluster-chain end markers. (endmark>=$fff8)
|
||||
//We don't care here, since we cannot follow longer anyhow.
|
||||
IF lib_fat16_int_nc_cluster_nr >= LIB_FAT16_CLUSTER_END
|
||||
SUBEND
|
||||
ENDIF
|
||||
|
||||
// exp for the sector offset on disk for requested cluster entry:
|
||||
// "first FAT sector" + ( (cluster_nr * "sizeof cluster entry (2 bytes in FAT16 )") / 512 )
|
||||
// simplified = "first FAT sector" + ( cluster_nr / 256 ) i.e. the high byte of "cluster nr"
|
||||
// div 256 = shift left 8 bits, so we simply take the highbyte and move it to the lowbyte (see below)
|
||||
ASM
|
||||
lda lib_fat16_int_nc_cluster_nr+1
|
||||
sta |sect_offset|
|
||||
ENDASM
|
||||
//and now we add the "first FAT sector"
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_fat1_sector_lo
|
||||
adc |sect_offset|
|
||||
sta lib_fat16_tempw2
|
||||
lda lib_fat16_fat1_sector_lo+1
|
||||
adc #0
|
||||
sta lib_fat16_tempw2+1
|
||||
lda lib_fat16_fat1_sector_hi
|
||||
adc #0
|
||||
sta lib_fat16_tempb
|
||||
ENDASM
|
||||
|
||||
LET sector_lo = lib_fat16_tempw2
|
||||
LET sector_hi = lib_fat16_tempb
|
||||
|
||||
//read up the sector
|
||||
CALL lib_mmc64_readsector ( sector_lo sector_hi lib_fat16_buffer_ptr callstat )
|
||||
IF callstat != 0
|
||||
SUBEND //pass the read error on to the caller.
|
||||
ENDIF
|
||||
|
||||
//calculate the position of the link
|
||||
//Following the logic above the offset the the position of the link in the sector must be in the low-byte
|
||||
//However since every entry is 2 bytes long, we must multiply the lowbyte with 2 to get the offset in bytes
|
||||
//
|
||||
//MHTAG 20050927 - all usage of lib_fat16_tempw2 below in this func is replacement for lib_fat16_int_nc_link_offset_bytes
|
||||
ASM
|
||||
clc
|
||||
lda lib_fat16_int_nc_cluster_nr
|
||||
rol
|
||||
sta lib_fat16_tempw2
|
||||
lda #0
|
||||
rol
|
||||
sta lib_fat16_tempw2+1
|
||||
ENDASM
|
||||
|
||||
ADD lib_fat16_tempw2 + lib_fat16_buffer_ptr -> lib_fat16_tempw2
|
||||
|
||||
#IFDEF __LIB_FAT16_WRITESUPPORT
|
||||
//if readaccess - skit this section
|
||||
IF lib_fat16_int_nc_writeflag == 1
|
||||
//this section updates the cluster link value and writes the fat-sector back to disk
|
||||
PUTASWORD@ lib_fat16_tempw2 VALUE lib_fat16_int_nc_target_cluster_nr
|
||||
|
||||
CALL lib_mmc64_writesector ( sector_lo sector_hi lib_fat16_buffer_ptr callstat )
|
||||
IF callstat != 0
|
||||
SUBEND //pass the read error on to the caller.
|
||||
ENDIF
|
||||
|
||||
//now we must update the second FAT.
|
||||
//change here to support more than 2 FATs
|
||||
//reason for decision to support only 2 = VERY standard. Even linux vfat driver relies on two FATs
|
||||
//24-bit addition of the size of one fat to get right offset
|
||||
ASM
|
||||
clc
|
||||
lda |sector_lo|
|
||||
adc lib_fat16_sectors_per_fat
|
||||
sta |sector_lo|
|
||||
lda |sector_lo|+1
|
||||
adc lib_fat16_sectors_per_fat+1
|
||||
sta |sector_lo|+1
|
||||
lda |sector_hi|
|
||||
adc #0
|
||||
sta |sector_hi|
|
||||
ENDASM
|
||||
//and finally the actual write.
|
||||
CALL lib_mmc64_writesector ( sector_lo sector_hi lib_fat16_buffer_ptr callstat )
|
||||
IF callstat != 0
|
||||
SUBEND //pass the read error on to the caller.
|
||||
ENDIF
|
||||
|
||||
GOTO lib_fat16_int_nc_skipread
|
||||
ENDIF
|
||||
#IFEND
|
||||
|
||||
//return it
|
||||
GETASWORD@ lib_fat16_tempw2 -> lib_fat16_int_nc_cluster_nr
|
||||
|
||||
#IFDEF __LIB_FAT16_WRITESUPPORT
|
||||
LABEL lib_fat16_int_nc_skipread
|
||||
LET lib_fat16_int_nc_writeflag = 0 //reset for next access of this function
|
||||
#IFEND
|
||||
|
||||
LET lib_fat16_int_nc_status = 0
|
||||
FEND
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_fat16_int_search_free_clusters
|
||||
//
|
||||
// Purpose: To find clusters on the mounted drive that are free to allocate
|
||||
// for new filedata.
|
||||
//
|
||||
// Usage: When mounting a partition for R/W access this routine is called
|
||||
// to find unused clusters, in the event that a write is issued. The
|
||||
// routine searches for a "cluster hole" of max LIB_FAT16_WRITE_CLUSTERS_MAX
|
||||
// continous clusters (to reduce search time). It updates the variables
|
||||
// lib_fat16_first_write_cluster and lib_fat16_last_write_cluster with
|
||||
// the limits of the found "cluster hole" (range of unallocated clusters)
|
||||
//
|
||||
// If writing has completely filled previously discovered "cluster hole"
|
||||
// the write routines may call this routine again to try to find more
|
||||
// unclaimed disc space to fill.
|
||||
//
|
||||
// Method:
|
||||
// Space for writing is searched from the end of the FAT (last clusters)
|
||||
// and backwards until we find free clusters. When we find a free cluster
|
||||
// we set the "lib_fat16_last_write_cluster" marker and continue backwards
|
||||
// for a while (until we reach a count or until we hit data again. This is
|
||||
// where we set the "lib_fat16_first_write_cluster" marker.
|
||||
// After this operation we know about an area between the two markers that
|
||||
// consists of free clusters, ready to use for writing file-data
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFDEF __LIB_FAT16_WRITESUPPORT
|
||||
|
||||
BYTE lib_fat16_int_fu_status
|
||||
|
||||
FUNC lib_fat16_int_search_free_clusters ( out:lib_fat16_int_fu_status )
|
||||
|
||||
WORD active_cluster
|
||||
WORD active_link
|
||||
WORD cluster_search_max
|
||||
BYTE callstat
|
||||
|
||||
LET lib_fat16_int_fu_status = 1 //default = error exit
|
||||
|
||||
//-----------------------------------------------------
|
||||
//TASK1 - find out where to start the search
|
||||
LET active_cluster = lib_fat16_first_write_cluster
|
||||
IF active_cluster == $ffff //if free area is uninitialized yet
|
||||
LET active_cluster = lib_fat16_total_clusters //start the search at the end of the fat
|
||||
ENDIF
|
||||
|
||||
//-----------------------------------------------------
|
||||
//TASK2 - rewind until we reach:
|
||||
// a) free clusters
|
||||
// b) start of fat
|
||||
|
||||
WHILE 1
|
||||
LET active_link = active_cluster
|
||||
CALL lib_fat16_int_get_cluster_link ( active_link callstat )
|
||||
IF callstat != 0
|
||||
SUBEND //internal error
|
||||
ENDIF
|
||||
IF active_link == 0
|
||||
BREAK
|
||||
ENDIF
|
||||
DEC active_cluster
|
||||
WEND
|
||||
|
||||
IF active_cluster < 2 //disk is full. Unable to find a single free cluster!
|
||||
SUBEND
|
||||
ENDIF
|
||||
|
||||
LET lib_fat16_last_write_cluster = active_cluster
|
||||
|
||||
//-----------------------------------------------------
|
||||
//TASK3 - rewind until we reach the end of the free area.
|
||||
|
||||
//LET active_link = active_cluster
|
||||
LET cluster_search_max = LIB_FAT16_WRITE_CLUSTERS_MAX
|
||||
WHILE active_link == LIB_FAT16_CLUSTER_FREE
|
||||
DEC cluster_search_max
|
||||
IF cluster_search_max == 0
|
||||
BREAK
|
||||
ENDIF
|
||||
DEC active_cluster
|
||||
LET active_link = active_cluster
|
||||
CALL lib_fat16_int_get_cluster_link ( active_link callstat )
|
||||
IF callstat != 0
|
||||
SUBEND //internal error
|
||||
ENDIF
|
||||
WEND
|
||||
|
||||
IF active_cluster < 2
|
||||
LET active_cluster = 1
|
||||
ENDIF
|
||||
|
||||
INC active_cluster //this one was used so we need the next one (the first free)
|
||||
LET lib_fat16_first_write_cluster = active_cluster
|
||||
|
||||
//now we should have found a area free for writing.
|
||||
|
||||
//MHTAG 20051114 - debug writes out the free area to the screen
|
||||
//CALL lib_dbg_hexoutw ( lib_fat16_first_write_cluster )
|
||||
//CALL lib_dbg_outlf
|
||||
//CALL lib_dbg_hexoutw ( lib_fat16_last_write_cluster )
|
||||
//CALL lib_dbg_outlf
|
||||
|
||||
|
||||
|
||||
LET lib_fat16_int_fu_status = 0 //if we got this far it's a success
|
||||
|
||||
FEND
|
||||
|
||||
#IFEND
|
||||
|
||||
LABEL lib_fat16low_skip
|
||||
|
||||
#IFEND
|
||||
709
lib/fat16/mmc64lib.c65
Normal file
709
lib/fat16/mmc64lib.c65
Normal file
|
|
@ -0,0 +1,709 @@
|
|||
//------------------------------------------------------------------------
|
||||
// MMC64 ReadWrite Library
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2005 Mattias Hansson
|
||||
// License: GNU GPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies:
|
||||
// ZP usage: $fb-$fc (pointer to buffer)
|
||||
// Target: Commodore 64 with MMC64 interface
|
||||
//
|
||||
// functions:
|
||||
// ( MMC cartridge level )
|
||||
// lib_mmc64_enable
|
||||
// lib_mmc64_status
|
||||
// ( MMC-card or SD-card level )
|
||||
// lib_mmc64_cardinit
|
||||
// lib_mmc64_readsector
|
||||
//
|
||||
// External compiler directive support:
|
||||
// __LIB_MMC64_OPTIMIZE_SIZE - define this to build lib smaller
|
||||
// but slower (default UNDEFINED)
|
||||
// __LIB_MMC64_READONLY - define this to build the lib to support
|
||||
// only read operations (decreasing it's size)
|
||||
// (default UNDEFINED)
|
||||
//
|
||||
// Note: Some of the code is copied from Olivers Achtens democode.
|
||||
// I havent removed any comments or anything and it's very clear to
|
||||
// see, what comes from his paper caller "mmc64prog.txt". These
|
||||
// parts of the code are, if I understand it right, in the public domain
|
||||
// as just code-snippets to demonstrate how the MMC64 can be accessed.
|
||||
// Just want to clarify everything, and give credit where credit due.
|
||||
//
|
||||
// Note2: Communication with MMC/SD in this lib is implemented to always
|
||||
// Align with sectorsizes i.e. $200. i.e. AccessAddress % $200 is always
|
||||
// zero(!). Every single read or write access is always $200 long.
|
||||
// (Reason: This seams to keep all MMC/SD iv'e tried happy and provides
|
||||
// realiable communications.)
|
||||
//
|
||||
// Mattias Hansson
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFNDEF __LIB_MMC64
|
||||
#DEFINE __LIB_MMC64 = 1
|
||||
|
||||
//Define __LIB_MMC64_OPTIMIZE_SIZE externally to optimize for size instead of speed.
|
||||
#IFNDEF __LIB_MMC64_OPTIMIZE_SIZE
|
||||
#DEFINE __LIB_MMC64_OPTIMIZE_SPEED = 1
|
||||
#IFEND
|
||||
|
||||
//This define is needed to include the code needed for writesupport.
|
||||
#IFNDEF __LIB_MMC64_READONLY
|
||||
#PRINT Write access in mmc65lib.c65 is experimental!!!
|
||||
#DEFINE __LIB_MMC64_WRITESUPPORT = 1
|
||||
#IFEND
|
||||
|
||||
GOTO lib_mmc64_skip
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// buffer pointer zeropage variable used for data transfer function
|
||||
//------------------------------------------------------------------------
|
||||
WORD lib_mmc64_buffer_ptr @ $fb
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// MMC64 reader status constants
|
||||
//
|
||||
// Everything except LIB_MMC64_R_OK
|
||||
// is an error.
|
||||
// Constants in order of importance.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
BYTE CONST LIB_MMC64_R_OK = 0
|
||||
BYTE CONST LIB_MMC64_R_BUSY = 1
|
||||
BYTE CONST LIB_MMC64_R_NOCARD = 2
|
||||
BYTE CONST LIB_MMC64_R_FLASH_ENABLED = 3
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_mmc64_enable
|
||||
//
|
||||
// Purpose: Enables the MMC64 cartridge
|
||||
// Params: none.
|
||||
// Preparation: none.
|
||||
//------------------------------------------------------------------------
|
||||
FUNC lib_mmc64_enable
|
||||
ASM
|
||||
;(re)enable MMC64
|
||||
lda #$0A
|
||||
sta $df13
|
||||
lda #$1C
|
||||
sta $df13
|
||||
|
||||
;enable MMC64 with initial settings
|
||||
lda $df11 ;get contents of MMC64 control register
|
||||
and #%10111011 ;set 250khz & write trigger mode
|
||||
ora #%00000010 ;disable card select
|
||||
sta $df11 ;update control register
|
||||
ENDASM
|
||||
FEND
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_mmc64_status
|
||||
//
|
||||
// Purpose:
|
||||
// To get actual status codes from the reader controller.
|
||||
// Parameters:
|
||||
// out:lib_mmc64_st_value - Value of one of the
|
||||
// "MMC64 reader status constants" defined
|
||||
// above.
|
||||
//
|
||||
// Preparation: lib_mmc64_enable
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
BYTE lib_mmc64_st_value
|
||||
FUNC lib_mmc64_status ( out:lib_mmc64_st_value )
|
||||
ASM
|
||||
lda $df12
|
||||
and #%00111001
|
||||
asl
|
||||
asl
|
||||
asl ; flash jumper enabled bit. true if set!
|
||||
bcc lib_mmc64_rstatus_l1 ; if NOT flash jumper is set
|
||||
|
||||
;flash jumper is set!
|
||||
lda #3
|
||||
sta lib_mmc64_st_value
|
||||
rts
|
||||
|
||||
lib_mmc64_rstatus_l1
|
||||
asl
|
||||
asl ; card inserted bit. card NOT inserted if set
|
||||
bcc lib_mmc64_rstatus_l2 ; if card IS inserted
|
||||
|
||||
; no card inserted!
|
||||
lda #2
|
||||
sta lib_mmc64_st_value
|
||||
rts
|
||||
|
||||
lib_mmc64_rstatus_l2
|
||||
and #%00100000 ; the current position of the busy-bit after ASL's above
|
||||
beq lib_mmc64_rstatus_l3 ; after the and-operation we have a 0-value if all is ok, so we store it!
|
||||
|
||||
lda #1 ; card is busy
|
||||
lib_mmc64_rstatus_l3
|
||||
sta lib_mmc64_st_value
|
||||
ENDASM
|
||||
FEND
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_mmc64_set512blocks
|
||||
//
|
||||
// Send CMD16 to MMC/SD to set the blocksize to $200 (512) which is the
|
||||
// only transfer size used in this lib.
|
||||
// This size is the defaut when doing read operations, but must be
|
||||
// exclusivly set when attempting writes to the MMC/SD
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFDEF __LIB_MMC64_WRITESUPPORT
|
||||
|
||||
FUNC lib_mmc64_set512blocks
|
||||
|
||||
ASM
|
||||
ldy #$09
|
||||
lib_mmc64_s5_l1
|
||||
lda lib_mmc64_s5_cmd16-1,y
|
||||
sta $df10
|
||||
dey
|
||||
bne lib_mmc64_s5_l1
|
||||
ENDASM
|
||||
FEND
|
||||
|
||||
ASM
|
||||
lib_mmc64_s5_cmd16
|
||||
!8 $ff,$ff,$ff,$00,$02,$00,$00,$50,$ff ;CMD16
|
||||
ENDASM
|
||||
|
||||
#IFEND
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_mmc64_cardinit
|
||||
//
|
||||
// Purpose: Reset the SD||MMC card and set it up in SPI mode
|
||||
// Params: none.
|
||||
// Preparation: lib_mmc64_enable,
|
||||
// (lib_mmc64_status
|
||||
// to know that there is a working card in the slot)
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
FUNC lib_mmc64_cardinit
|
||||
ASM
|
||||
|
||||
lib_mmc64_reset
|
||||
ldx #$0a ;initialize counter (10*8 pulses)
|
||||
ldy #$ff ;initialize value to be written (bits must be all high)
|
||||
lib_mmc64_reset_l1
|
||||
sty $df10 ;send 8 pulses to the card
|
||||
lib_mmc64_reset_l2
|
||||
lda $df12 ;we catch the status register
|
||||
and #$01 ;all bits shiftet out?
|
||||
bne lib_mmc64_reset_l2 ;nope, so wait
|
||||
dex ;decrement counter
|
||||
bne lib_mmc64_reset_l1 ;until 80 pulses sent
|
||||
lda $df11 ;pull card chip select line down for SPI communication
|
||||
and #%11111101
|
||||
sta $df11
|
||||
|
||||
lib_mmc64_reset_l6
|
||||
ldy #$09 ;we send 8 command bytes to the card
|
||||
lib_mmc64_reset_l3
|
||||
lda lib_mmc64_reset_cmdtxt0-1,y ;grab command byte
|
||||
sta $df10 ;and fire it to the card
|
||||
lib_mmc64_reset_l4
|
||||
lda $df12 ;we check the busy bit
|
||||
and #$01 ;to ensure that the transfer is safe
|
||||
bne lib_mmc64_reset_l4
|
||||
dey ;decrease command counter
|
||||
bne lib_mmc64_reset_l3 ;until the entire command has been sent
|
||||
lda $df10 ;now we check the card response
|
||||
and #$01 ;did it accept the command ?
|
||||
bne lib_mmc64_reset_l5 ;ok, everything is fine !
|
||||
lda $df12 ;is there a card at all ?
|
||||
and #$08
|
||||
beq lib_mmc64_reset_l6 ;yup, so we just resend the command
|
||||
lib_mmc64_reset_l5
|
||||
|
||||
lib_mmc64_reset_l7
|
||||
ldy #$09 ;we send 8 command bytes to the card
|
||||
lib_mmc64_reset_l8
|
||||
lda lib_mmc64_reset_cmdtxt1-1,y ;grab command byte
|
||||
sta $df10 ;and fire it to the card
|
||||
lib_mmc64_reset_l9
|
||||
lda $df12 ;we check the busy bit
|
||||
and #$01 ;to ensure that the transfer is safe
|
||||
bne lib_mmc64_reset_l9
|
||||
dey ;decrease command counter
|
||||
bne lib_mmc64_reset_l8 ;until entire command has been sent
|
||||
lda $df10 ;did the card left its init state?
|
||||
and #$01
|
||||
bne lib_mmc64_reset_l7 ;no, so we resend the command to check it again
|
||||
|
||||
;Enable 8Mhz mode
|
||||
lda $df11
|
||||
ora #%00000100
|
||||
sta $df11
|
||||
|
||||
ENDASM
|
||||
#IFDEF __LIB_MMC64_WRITESUPPORT
|
||||
CALL lib_mmc64_set512blocks
|
||||
#IFEND
|
||||
|
||||
FEND
|
||||
|
||||
ASM
|
||||
|
||||
lib_mmc64_reset_cmdtxt0
|
||||
!8 $ff,$ff,$95,$00,$00,$00,$00,$40,$ff ;CMD0
|
||||
lib_mmc64_reset_cmdtxt1
|
||||
!8 $ff,$ff,$ff,$00,$00,$00,$00,$41,$ff ;CMD1
|
||||
|
||||
ENDASM
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_mmc64_readsector
|
||||
//
|
||||
// Purpose: To read a sector specified by the 24-bit number sent in.
|
||||
// (65CM does not support larger types than 16-bit so we have
|
||||
// to use two.) and put the data where the buffer pointer points.
|
||||
//
|
||||
// lib_mmc64_readsector_part
|
||||
//
|
||||
// Purpose: Like above but optionally be able to choose what part of the
|
||||
// sector caller wants to read. This call was implemented to
|
||||
// allow FAT16 to:
|
||||
// 1. Read files to their real end (not the end of the last sector of a file)
|
||||
// 2. fgetc()
|
||||
//
|
||||
// Params:
|
||||
// lib_mmc64_rs_sectornr_lo = the two lowest bytes of the 24-bit sector#
|
||||
// lib_mmc64_rs_sectornr_hi = the highest byte of the 24-bit sector#
|
||||
// lib_mmc64_buffer_ptr = the address where to put the read data
|
||||
// lib_mmc64_rs_status = after a completed operation the caller can
|
||||
// check if it went OK. 0=OK. !0=fail!
|
||||
//
|
||||
// Params (extended for "lib_mmc64_readsector_part"):
|
||||
// WORD first_pos - first byte in the sector to write to memory
|
||||
// WORD read_count - how many bytes to write to target memory
|
||||
//
|
||||
// Preparation: lib_mmc64_cardinit
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
WORD lib_mmc64_rs_sectornr_lo
|
||||
BYTE lib_mmc64_rs_sectornr_hi
|
||||
BYTE lib_mmc64_rs_status
|
||||
|
||||
FUNC lib_mmc64_readsector ( lib_mmc64_rs_sectornr_lo lib_mmc64_rs_sectornr_hi lib_mmc64_buffer_ptr out:lib_mmc64_rs_status )
|
||||
|
||||
WORD first_pos // in bytes
|
||||
WORD read_count
|
||||
|
||||
LET first_pos = 0
|
||||
LET read_count = 512
|
||||
|
||||
FUNC lib_mmc64_readsector_part ( lib_mmc64_rs_sectornr_lo lib_mmc64_rs_sectornr_hi lib_mmc64_buffer_ptr first_pos read_count out:lib_mmc64_rs_status )
|
||||
|
||||
WORD totalread
|
||||
BYTE readbyte
|
||||
|
||||
LET lib_mmc64_rs_status = 1
|
||||
|
||||
// If what we are reading up is to the internal buffer
|
||||
// We compare the sector# sent in with the last sector#
|
||||
// read there. We don't need to read it up if it's equal.
|
||||
// Note: this code relies on lib_fat16. Not nice, but
|
||||
// It'll do for now.
|
||||
// Note2: this is not neccessary for normal operation
|
||||
// but will certainly speed up continous read-speed when
|
||||
// used on a non-fragmented file, a whole lot.
|
||||
// (without optimization it reads up a sector from the
|
||||
// FAT everytime we change cluster, as it's unaware of
|
||||
// whats in the fat_buffer for the moment)
|
||||
// Therefore it's only included if compiled with speed
|
||||
// optimization.
|
||||
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
||||
ASM
|
||||
lda lib_mmc64_buffer_ptr
|
||||
cmp #<lib_fat16_fatbuffer
|
||||
bne lib_mmc64_rs_buffnotequal_skip
|
||||
lda lib_mmc64_buffer_ptr+1
|
||||
cmp #>lib_fat16_fatbuffer
|
||||
bne lib_mmc64_rs_buffnotequal_skip
|
||||
; here we know that the pointer sent in is indeed the internal FAT buffer.
|
||||
|
||||
lda lib_mmc64_rs_sectornr_lo
|
||||
cmp lib_mmc64_rs_oldsector
|
||||
bne lib_mmc64_rs_storenewbuffsector
|
||||
lda lib_mmc64_rs_sectornr_lo+1
|
||||
cmp lib_mmc64_rs_oldsector+1
|
||||
bne lib_mmc64_rs_storenewbuffsector
|
||||
lda lib_mmc64_rs_sectornr_hi
|
||||
cmp lib_mmc64_rs_oldsector+2
|
||||
bne lib_mmc64_rs_storenewbuffsector
|
||||
|
||||
lda #0
|
||||
sta lib_mmc64_rs_status
|
||||
rts ; if everything matched we just saved the caller the whole readup
|
||||
; of the sector in question.
|
||||
lib_mmc64_rs_storenewbuffsector
|
||||
lda lib_mmc64_rs_sectornr_lo
|
||||
sta lib_mmc64_rs_oldsector
|
||||
lda lib_mmc64_rs_sectornr_lo+1
|
||||
sta lib_mmc64_rs_oldsector+1
|
||||
lda lib_mmc64_rs_sectornr_hi
|
||||
sta lib_mmc64_rs_oldsector+2
|
||||
|
||||
jmp lib_mmc64_rs_buffnotequal_skip
|
||||
lib_mmc64_rs_oldsector
|
||||
!24 $ffffff
|
||||
|
||||
lib_mmc64_rs_buffnotequal_skip
|
||||
ENDASM
|
||||
#IFEND //__LIB_MMC64_OPTIMIZE_SPEED
|
||||
|
||||
ASM
|
||||
|
||||
;first we recalc the sector nr to byte nr (that the card requires)
|
||||
;since a sector of a MMC or SD card is 512 bytes it's "shift left 9"
|
||||
;shift left 8 is done by just shifting the bytes (naturally) which
|
||||
;leaves us 1 shift left to do.
|
||||
|
||||
clc
|
||||
rol lib_mmc64_rs_sectornr_lo
|
||||
rol lib_mmc64_rs_sectornr_lo+1
|
||||
rol lib_mmc64_rs_sectornr_hi
|
||||
|
||||
lda #0
|
||||
sta lib_mmc64_rs_bytenr
|
||||
lda lib_mmc64_rs_sectornr_lo
|
||||
sta lib_mmc64_rs_bytenr+1
|
||||
lda lib_mmc64_rs_sectornr_lo+1
|
||||
sta lib_mmc64_rs_bytenr+2
|
||||
lda lib_mmc64_rs_sectornr_hi
|
||||
sta lib_mmc64_rs_bytenr+3
|
||||
|
||||
ldy #$09
|
||||
lib_mmc64_rs_l1
|
||||
lda lib_mmc64_rs_cmd17-1,y
|
||||
sta $df10
|
||||
dey
|
||||
bne lib_mmc64_rs_l1
|
||||
|
||||
lib_mmc64_rs_l2
|
||||
lda #$ff
|
||||
sta $df10 ;write all high bits
|
||||
lda $df10 ;to give the possibility to respond
|
||||
cmp #$fe ;has it started?
|
||||
beq lib_mmc64_rs_l4 ; start receive
|
||||
cmp #0
|
||||
beq lib_mmc64_rs_l2 ; still waiting for card to answer
|
||||
cmp #$ff
|
||||
beq lib_mmc64_rs_l2 ; still waiting for card to answer
|
||||
|
||||
jmp lib_mmc64_rs_error_exit ; Serious error - sector could not be read.
|
||||
; (normaly this is because we've called the
|
||||
; blockread CMD17 with a wrong param!)
|
||||
|
||||
|
||||
lib_mmc64_rs_l4 ; start receive
|
||||
|
||||
lda $df11 ;set MMC64 into read trigger mode
|
||||
ora #%01000000 ;which means every read triggers a SPI transfer
|
||||
sta $df11
|
||||
|
||||
lda $df10 ;we have to start with one dummy read here
|
||||
|
||||
ENDASM
|
||||
|
||||
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
||||
|
||||
//If we're about to read the whole sector we use this routine!
|
||||
//It's faster than the one below, 'coz it does not check for
|
||||
//anything except the $200 (512) limit.
|
||||
IF first_pos == 0
|
||||
IF read_count == 512
|
||||
ASM
|
||||
ldx #$02 ;set up counters
|
||||
ldy #$00
|
||||
lib_mmc64_rs_l3
|
||||
lda $df10 ;get data byte from card
|
||||
sta (lib_mmc64_buffer_ptr),y ;store it into memory ( memptr has to be initialized)
|
||||
iny ;have we copied 256 bytes ?
|
||||
bne lib_mmc64_rs_l3 ;nope, so go on!
|
||||
inc lib_mmc64_buffer_ptr+1 ;increase memory pointer for next 256 bytes
|
||||
dex ;have we copied 512 bytes ?
|
||||
bne lib_mmc64_rs_l3
|
||||
|
||||
ENDASM
|
||||
GOTO lib_mmc64_rs_skipelse1
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
#IFEND //__LIB_MMC64_OPTIMIZE_SPEED
|
||||
|
||||
//ELSE - we want to read just a part of the sector. so this routine is used instead
|
||||
|
||||
LET totalread = 0
|
||||
WHILE totalread < 512
|
||||
IF first_pos == 0
|
||||
IF read_count == 0
|
||||
GOTO lib_mmc64_rs_dummyread
|
||||
ENDIF
|
||||
PEEK $df10 -> readbyte
|
||||
POKE lib_mmc64_buffer_ptr , readbyte
|
||||
INC lib_mmc64_buffer_ptr
|
||||
DEC read_count
|
||||
ELSE //prepare for first position
|
||||
DEC first_pos
|
||||
LABEL lib_mmc64_rs_dummyread
|
||||
ASM
|
||||
lda $df10 ; dummyread a byte (to move forward for the desired offset)
|
||||
ENDASM
|
||||
ENDIF
|
||||
INC totalread
|
||||
WEND
|
||||
|
||||
|
||||
LABEL lib_mmc64_rs_skipelse1
|
||||
ASM
|
||||
lda $df10 ;we have to end the data transfer with one dummy read
|
||||
|
||||
lda $df11 ;now we put the hardware back into write trigger mode again
|
||||
and #%10111111
|
||||
sta $df11
|
||||
|
||||
ENDASM
|
||||
|
||||
LET lib_mmc64_rs_status = 0 // if we got this far it's a successful read!
|
||||
|
||||
LABEL lib_mmc64_rs_error_exit
|
||||
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
|
||||
ASM
|
||||
;!pet "debugtxt>"
|
||||
|
||||
lib_mmc64_rs_cmd17
|
||||
;Outline of the command (read sector 0)
|
||||
;!8 $ff,$ff,$ff,$00,$00,$00,$00,$51,$ff ;CMD17
|
||||
; ^^^^^^^^^^^^^^^ <- 32 bit byte offset where we want to read
|
||||
; In this lib we always send in byte-offsets corresponding to a sector start.i (i.e. $200*sectornr)
|
||||
;
|
||||
;Start of command
|
||||
!8 $ff,$ff,$ff
|
||||
lib_mmc64_rs_bytenr
|
||||
!32 0
|
||||
!8 $51,$ff ;CMD17
|
||||
|
||||
ENDASM
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// lib_mmc64_writesector
|
||||
//
|
||||
// Purpose: To write a sector specified by the 24-bit number sent in.
|
||||
// (65CM does not support larger types than 16-bit so we have
|
||||
// to use two.) data for the write is taken from where
|
||||
// lib_mmc64_buffer_ptr points and onwards $200(512) bytes.
|
||||
//
|
||||
// lib_mmc64_writesector_part
|
||||
//
|
||||
// Purpose: Like above but optionally be able to choose what part of the
|
||||
// sector caller wants to write. This call was implemented to
|
||||
// allow FAT16 to write just the part of the sector that represents
|
||||
// the actual EOF in the file. (rest will be zero-filled)
|
||||
//
|
||||
// Note: Mem-pointer points to the actual area to be written.
|
||||
// I.e. first_pos equals byte @ lib_mmc64_buffer_ptr
|
||||
//
|
||||
// Params:
|
||||
// lib_mmc64_ws_sectornr_lo = the two lowest bytes of the 24-bit sector#
|
||||
// lib_mmc64_ws_sectornr_hi = the highest byte of the 24-bit sector#
|
||||
// lib_mmc64_buffer_ptr = the address where to read data for writing
|
||||
// lib_mmc64_ws_status = after a completed operation the caller can
|
||||
// check if it went OK. 0=OK. !0=fail!
|
||||
//
|
||||
// Params (extended for "lib_mmc64_readsector_part"):
|
||||
// WORD first_pos - first byte in the sector to write to memory
|
||||
// WORD read_count - how many bytes to write to target memory
|
||||
//
|
||||
// Preparation: lib_mmc64_cardinit
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFDEF __LIB_MMC64_WRITESUPPORT
|
||||
|
||||
//Block write command - set up a 512 byte transfer to the SD Card from $00000100 to $000002ff
|
||||
|
||||
WORD lib_mmc64_ws_sectornr_lo
|
||||
BYTE lib_mmc64_ws_sectornr_hi
|
||||
BYTE lib_mmc64_ws_status
|
||||
|
||||
FUNC lib_mmc64_writesector ( lib_mmc64_ws_sectornr_lo lib_mmc64_ws_sectornr_hi lib_mmc64_buffer_ptr out:lib_mmc64_ws_status )
|
||||
|
||||
WORD first_pos // in bytes
|
||||
WORD read_count
|
||||
|
||||
LET first_pos = 0
|
||||
LET read_count = 512
|
||||
|
||||
FUNC lib_mmc64_writesector_part ( lib_mmc64_ws_sectornr_lo lib_mmc64_ws_sectornr_hi lib_mmc64_buffer_ptr first_pos read_count out:lib_mmc64_ws_status )
|
||||
|
||||
WORD totalwritten
|
||||
BYTE writebyte
|
||||
|
||||
LET lib_mmc64_ws_status = 1
|
||||
|
||||
|
||||
//To make writesector compatible with the internal
|
||||
//buffer-caching done in readsector we must update
|
||||
//the pointers to the "oldsector". A write will
|
||||
//always be issued though
|
||||
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
||||
ASM
|
||||
lda lib_mmc64_buffer_ptr
|
||||
cmp #<lib_fat16_fatbuffer
|
||||
bne lib_mmc64_ws_buffnotequal_skip
|
||||
lda lib_mmc64_buffer_ptr+1
|
||||
cmp #>lib_fat16_fatbuffer
|
||||
bne lib_mmc64_ws_buffnotequal_skip
|
||||
; here we know that the pointer sent in is indeed the internal FAT buffer.
|
||||
|
||||
;here we write down (for eventual future caller request)
|
||||
;what sector the data in the buffer will represent after we write it
|
||||
lda lib_mmc64_ws_sectornr_lo
|
||||
sta lib_mmc64_rs_oldsector
|
||||
lda lib_mmc64_ws_sectornr_lo+1
|
||||
sta lib_mmc64_rs_oldsector+1
|
||||
lda lib_mmc64_ws_sectornr_hi
|
||||
sta lib_mmc64_rs_oldsector+2
|
||||
|
||||
lib_mmc64_ws_buffnotequal_skip
|
||||
ENDASM
|
||||
#IFEND //__LIB_MMC64_OPTIMIZE_SPEED
|
||||
|
||||
ASM
|
||||
|
||||
;first we recalc the sector nr to byte nr (that the card requires)
|
||||
;since a sector of a MMC or SD card is 512 bytes it's "shift left 9"
|
||||
;shift left 8 is done by just shifting the bytes (naturally) which
|
||||
;leaves us 1 shift left to do.
|
||||
|
||||
clc
|
||||
rol lib_mmc64_ws_sectornr_lo
|
||||
rol lib_mmc64_ws_sectornr_lo+1
|
||||
rol lib_mmc64_ws_sectornr_hi
|
||||
|
||||
lda #0
|
||||
sta lib_mmc64_ws_bytenr
|
||||
lda lib_mmc64_ws_sectornr_lo
|
||||
sta lib_mmc64_ws_bytenr+1
|
||||
lda lib_mmc64_ws_sectornr_lo+1
|
||||
sta lib_mmc64_ws_bytenr+2
|
||||
lda lib_mmc64_ws_sectornr_hi
|
||||
sta lib_mmc64_ws_bytenr+3
|
||||
ENDASM
|
||||
|
||||
//Now we send CMD24 (Write single sector command) to MMC/SD
|
||||
ASM
|
||||
ldy #$09
|
||||
lib_mmc64_ws_l1
|
||||
lda lib_mmc64_ws_cmd24-1,y
|
||||
sta $df10
|
||||
dey
|
||||
bne lib_mmc64_ws_l1
|
||||
|
||||
ldx #$ff ;we send the sequence $ff,$ff,$fe to start the transfer
|
||||
stx $df10
|
||||
stx $df10
|
||||
dex
|
||||
stx $df10
|
||||
|
||||
ENDASM
|
||||
|
||||
//If we're about to write the whole sector we use this routine
|
||||
//just like the write routine
|
||||
IF first_pos == 0
|
||||
IF read_count == 512
|
||||
ASM
|
||||
;And now we can write the data to the card:
|
||||
|
||||
ldx #$02 ;set up counters
|
||||
ldy #$00
|
||||
lib_mmc64_ws_l2
|
||||
lda (lib_mmc64_buffer_ptr),y ;get byte from C64 memory
|
||||
sta $df10 ;give it to the card
|
||||
|
||||
iny ;have we copied 256 bytes ?
|
||||
bne lib_mmc64_ws_l2
|
||||
inc lib_mmc64_buffer_ptr+1 ;increase memory pointer for next 256 bytes
|
||||
dex ;have we copied 512 bytes ?
|
||||
bne lib_mmc64_ws_l2
|
||||
ENDASM
|
||||
GOTO lib_mmc64_ws_skipelse1
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
//ELSE - we want to write just a part of the sector. so this routine is used instead
|
||||
LET totalwritten = 0
|
||||
WHILE totalwritten < 512
|
||||
IF first_pos == 0
|
||||
IF read_count == 0
|
||||
GOTO lib_mmc64_ws_dummywrite
|
||||
ENDIF
|
||||
PEEK lib_mmc64_buffer_ptr -> writebyte
|
||||
POKE $df10 , writebyte
|
||||
INC lib_mmc64_buffer_ptr
|
||||
DEC read_count
|
||||
GOTO lib_mmc64_ws_skipelse2
|
||||
ENDIF
|
||||
//ELSE prepare for first position
|
||||
|
||||
DEC first_pos
|
||||
LABEL lib_mmc64_ws_dummywrite
|
||||
ASM
|
||||
lda #0
|
||||
sta $df10 ; dummywrite NULL to rest of the sector.
|
||||
ENDASM
|
||||
|
||||
LABEL lib_mmc64_ws_skipelse2
|
||||
INC totalwritten
|
||||
WEND
|
||||
|
||||
ASM
|
||||
|
||||
lib_mmc64_ws_skipelse1
|
||||
|
||||
lda #$ff ;send 2 sync bytes
|
||||
sta $df10
|
||||
sta $df10
|
||||
lib_mmc64_ws_l3
|
||||
sta $df10 ;wait until card has left busy state
|
||||
ldx $df10
|
||||
cpx #$ff
|
||||
bne lib_mmc64_ws_l3
|
||||
|
||||
ENDASM
|
||||
|
||||
LET lib_mmc64_ws_status = 0
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
ASM
|
||||
lib_mmc64_ws_cmd24
|
||||
!8 $ff,$ff,$ff
|
||||
lib_mmc64_ws_bytenr
|
||||
!32 0 ; byte offset on card to write
|
||||
!8 $58,$ff ;CMD24
|
||||
ENDASM
|
||||
|
||||
#IFEND
|
||||
|
||||
LABEL lib_mmc64_skip
|
||||
|
||||
#IFEND
|
||||
101
lib/koalalib.c65
Normal file
101
lib/koalalib.c65
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
//-------------------------------------------------------
|
||||
//
|
||||
// KOALALIB
|
||||
//
|
||||
// Library that shows koala pictures
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// License: GPL2
|
||||
// Compiler version: c65cm, v.04+
|
||||
// ZP usage: $9e-$9f, $fb-$ff
|
||||
//
|
||||
//-------------------------------------------------------
|
||||
|
||||
#IFNDEF __LIB_KOALA
|
||||
#DEFINE __LIB_KOALA = 1
|
||||
|
||||
#INCLUDE <c64scr.c65>
|
||||
#INCLUDE <c64defs.c65>
|
||||
|
||||
GOTO lib_koala_skip
|
||||
|
||||
WORD lib_koala_skpicptr @ $fc
|
||||
|
||||
//-------------------------------------------------------
|
||||
//
|
||||
//-------------------------------------------------------
|
||||
FUNC lib_koala_show ( io:lib_koala_skpicptr )
|
||||
|
||||
// Koala format description (excluding CBM loading address)
|
||||
// Bitmap: $0000-$1f3f (0-7999)
|
||||
// Videoram: $1f40-$2327 (8000-8999)
|
||||
// Colorram: $2328-$270f (9000-9999)
|
||||
// Background: $2710 (10000)
|
||||
|
||||
WORD lib_koala_skpoke @ $9e
|
||||
BYTE lib_koala_sktemp @ $fb
|
||||
|
||||
GOSUB lib_c64scr_blank
|
||||
|
||||
//-----------------------------------------
|
||||
// Copy picture data to the right locations
|
||||
//-----------------------------------------
|
||||
|
||||
LET lib_koala_skpoke = $e000
|
||||
WHILE lib_koala_skpoke < $e000+8000
|
||||
PEEK lib_koala_skpicptr -> lib_koala_sktemp
|
||||
POKE lib_koala_skpoke , lib_koala_sktemp
|
||||
INC lib_koala_skpicptr
|
||||
INC lib_koala_skpoke
|
||||
WEND
|
||||
|
||||
LET lib_koala_skpoke = $c000
|
||||
WHILE lib_koala_skpoke < $c000+1000
|
||||
PEEK lib_koala_skpicptr -> lib_koala_sktemp
|
||||
POKE lib_koala_skpoke , lib_koala_sktemp
|
||||
INC lib_koala_skpicptr
|
||||
INC lib_koala_skpoke
|
||||
WEND
|
||||
|
||||
LET lib_koala_skpoke = colorram
|
||||
WHILE lib_koala_skpoke < colorram+1000
|
||||
PEEK lib_koala_skpicptr -> lib_koala_sktemp
|
||||
POKE lib_koala_skpoke , lib_koala_sktemp
|
||||
INC lib_koala_skpicptr
|
||||
INC lib_koala_skpoke
|
||||
WEND
|
||||
|
||||
//background color (one of the colors in MCB mode)
|
||||
PEEK lib_koala_skpicptr -> lib_koala_sktemp
|
||||
POKE vic2+$21 , lib_koala_sktemp
|
||||
|
||||
//----------------------------
|
||||
// Setup VIC2 to show picture
|
||||
//----------------------------
|
||||
|
||||
//Setup bank 4 ($c000-$ffff) for VIC-II (bits 0 and 1 negated)
|
||||
PEEK cia2 -> lib_koala_sktemp
|
||||
AND lib_koala_sktemp WITH $fc -> lib_koala_sktemp
|
||||
POKE cia2 , lib_koala_sktemp
|
||||
|
||||
//Setup bitmap @ $e000 and videoram @ $c000
|
||||
PEEK vic2+$18 -> lib_koala_sktemp
|
||||
AND lib_koala_sktemp WITH 7 -> lib_koala_sktemp
|
||||
OR lib_koala_sktemp WITH 8 -> lib_koala_sktemp
|
||||
POKE vic2+$18 , lib_koala_sktemp
|
||||
|
||||
//Setup multicolor graphics
|
||||
PEEK vic2+$11 -> lib_koala_sktemp
|
||||
OR lib_koala_sktemp WITH 32 -> lib_koala_sktemp
|
||||
POKE vic2+$11 , lib_koala_sktemp
|
||||
PEEK vic2+$16 -> lib_koala_sktemp
|
||||
OR lib_koala_sktemp WITH 16 -> lib_koala_sktemp
|
||||
POKE vic2+$16 , lib_koala_sktemp
|
||||
|
||||
GOSUB lib_c64scr_show
|
||||
|
||||
FEND
|
||||
|
||||
LABEL lib_koala_skip
|
||||
|
||||
#IFEND
|
||||
67
lib/libsc.c65
Normal file
67
lib/libsc.c65
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//------------------------------------------------------------------------
|
||||
// Library shortcuts Library
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2005 Mattias Hansson
|
||||
// License: GNU LGPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies: (all libs might be included, selectively)
|
||||
//
|
||||
// Purpose: To shorten lib names to normal usage length
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFNDEF __LIB_SC
|
||||
#DEFINE __LIB_SC = 1
|
||||
|
||||
#IFDEF __LIB_FAT16
|
||||
#DEFINE mount = lib_fat16_mount_partition
|
||||
#DEFINE fopen = lib_fat16_fopen
|
||||
#DEFINE fclose = lib_fat16_fclose
|
||||
#DEFINE fcloses = lib_fat16_fcloses
|
||||
#DEFINE fblockread = lib_fat16_fblockread
|
||||
#DEFINE fblockwrite = lib_fat16_fblockwrite
|
||||
#DEFINE chdir = lib_fat16_chdir
|
||||
#DEFINE dirstart = lib_fat16_dirstart
|
||||
#DEFINE dirnext = lib_fat16_dirnext
|
||||
#IFEND
|
||||
|
||||
#IFDEF __LIB_CBMIO
|
||||
#DEFINE print = lib_cbmio_print
|
||||
#DEFINE printlf = lib_cbmio_printlf
|
||||
#DEFINE hexoutb = lib_cbmio_hexoutb
|
||||
#DEFINE hexoutw = lib_cbmio_hexoutw
|
||||
#DEFINE lf = lib_cbmio_lf
|
||||
#DEFINE home = lib_cbmio_home
|
||||
#DEFINE input = lib_cbmio_input
|
||||
#IFEND
|
||||
|
||||
#IFDEF __LIB_STRING
|
||||
#DEFINE strlen = lib_string_strlen
|
||||
#DEFINE strchr = lib_string_strchr
|
||||
#DEFINE strcpy = lib_string_strcpy
|
||||
#DEFINE stpcpy = lib_string_stpcpy
|
||||
#DEFINE strncpy = lib_string_strncpy
|
||||
#DEFINE strcmp = lib_string_strcmp
|
||||
#DEFINE memset = lib_string_memset
|
||||
#DEFINE strcat = lib_string_strcat
|
||||
#DEFINE strncat = lib_string_strncat
|
||||
#IFEND
|
||||
|
||||
#IFDEF __LIB_STRLIST
|
||||
#DEFINE sl.count = lib_strlist_count
|
||||
#DEFINE sl.get = lib_strlist_get
|
||||
#DEFINE sl.strget = lib_strlist_strget
|
||||
#DEFINE sl.add = lib_strlist_add
|
||||
#DEFINE sl.free = lib_strlist_free
|
||||
#IFEND
|
||||
|
||||
#IFDEF __LIB_STRLIST2
|
||||
#DEFINE str_to_strlist = lib_strlist2_str_to_strlist
|
||||
#IFEND
|
||||
|
||||
#IFDEF __LIB_MEM
|
||||
#DEFINE malloc = lib_mem_malloc
|
||||
#DEFINE free = lib_mem_free
|
||||
#IFEND
|
||||
|
||||
#IFEND
|
||||
304
lib/memlib.c65
Normal file
304
lib/memlib.c65
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
//-----------------------------------------------------------
|
||||
//
|
||||
// Memory library ( Malloc, Free )
|
||||
//
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2000-2005 Mattias Hansson
|
||||
// License: GNU LGPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies:
|
||||
// Target: generic 6502
|
||||
//
|
||||
// Purpose: Provide some functions the help to create, update and access
|
||||
// a linked list of strings.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Internals:
|
||||
//
|
||||
// Makes heap-handling in a defined part of the memory.
|
||||
//
|
||||
// Requested memory is placed "from bottom upwards".
|
||||
// Allocation entries are written from the top downwards.
|
||||
//
|
||||
// layout:
|
||||
//
|
||||
// Bottom ( e.g. $2000-$2fff )
|
||||
// --------------
|
||||
// $2000
|
||||
// .
|
||||
// . area 1 allocated by application
|
||||
// .
|
||||
// $2020
|
||||
// $2021
|
||||
// .
|
||||
// . area 2 allocated by application
|
||||
// .
|
||||
// $2025
|
||||
//
|
||||
// .
|
||||
// .
|
||||
// .
|
||||
//
|
||||
// $2ff8 + $2ff9 = $2025 end of area 2
|
||||
// $2ffa + $2ffb = $2021 start of area 2
|
||||
// $2ffc + $2ffd = $2020 end of area 1
|
||||
// $2ffe + $2fff = $2000 start of area 1
|
||||
|
||||
#IFNDEF __LIB_MEM
|
||||
#DEFINE __LIB_MEM = 1
|
||||
|
||||
#IFNDEF __LIB_MEM_START
|
||||
#DEFINE __LIB_MEM_START = $$5000
|
||||
#IFEND
|
||||
|
||||
#IFNDEF __LIB_MEM_END
|
||||
#DEFINE __LIB_MEM_END = $$9fff
|
||||
#IFEND
|
||||
|
||||
#IFNDEF NULL
|
||||
#DEFINE NULL = 0
|
||||
#IFEND
|
||||
|
||||
GOTO lib_memlib_skip
|
||||
|
||||
WORD CONST lib_memstart = __LIB_MEM_START
|
||||
WORD CONST lib_memend = __LIB_MEM_END
|
||||
|
||||
WORD lib_alloctable_end
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Init: sets upp things for the lib in mem before start
|
||||
//-----------------------------------------------------------
|
||||
FUNC lib_mem_init
|
||||
|
||||
//set allocation table end start value
|
||||
LET lib_alloctable_end GET lib_memend
|
||||
INC lib_alloctable_end
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Malloc: alloc memory of size size_t
|
||||
// Address to allocated space is returned in result
|
||||
//-----------------------------------------------------------
|
||||
|
||||
FUNC lib_mem_malloc ( {WORD size_t} out:{WORD result} )
|
||||
WORD maxsize //max possible size now in heap
|
||||
WORD newspaceb
|
||||
WORD newspacee
|
||||
WORD newtableend
|
||||
|
||||
DEC size_t // 1 = e.g. $2001-$2001 ( $2001 - $2001 = 0 )
|
||||
|
||||
LET newtableend GET lib_alloctable_end
|
||||
SUBT newtableend - 4 -> newtableend
|
||||
|
||||
IF lib_alloctable_end > lib_memend THEN // only when first item!
|
||||
|
||||
SUBT newtableend - lib_memstart -> maxsize
|
||||
IF maxsize < size_t THEN
|
||||
//error handling: return NULL pointer!
|
||||
LET result GET NULL
|
||||
GOTO lib_malloc_exit
|
||||
ENDIF
|
||||
|
||||
LET newspaceb GET lib_memstart
|
||||
ADD newspaceb + size_t -> newspacee
|
||||
|
||||
//insert first record and recalc lib_alloctable_end
|
||||
DEC lib_alloctable_end
|
||||
DEC lib_alloctable_end
|
||||
PUTASWORD@ lib_alloctable_end VALUE newspaceb
|
||||
DEC lib_alloctable_end
|
||||
DEC lib_alloctable_end
|
||||
PUTASWORD@ lib_alloctable_end VALUE newspacee
|
||||
|
||||
LET result GET newspaceb
|
||||
|
||||
GOTO lib_malloc_exit;
|
||||
|
||||
ENDIF
|
||||
//else if this is not the first item then:
|
||||
|
||||
WORD lib_malloc_ptr
|
||||
WORD lib_malloc_spaceend
|
||||
WORD lib_malloc_spacestart
|
||||
|
||||
LET lib_malloc_ptr GET lib_memend
|
||||
SUBT lib_malloc_ptr - 3 -> lib_malloc_ptr
|
||||
|
||||
GETASWORD@ lib_malloc_ptr -> lib_malloc_spaceend
|
||||
|
||||
LET newspaceb GET NULL //if not found afterwards
|
||||
|
||||
WHILE 1
|
||||
|
||||
//if we reached the last record in the alloc-table
|
||||
IF lib_malloc_ptr = lib_alloctable_end THEN
|
||||
//is there sufficient space left @ top of heap?
|
||||
INC lib_malloc_spaceend
|
||||
SUBT newtableend - lib_malloc_spaceend -> maxsize
|
||||
|
||||
IF maxsize > size_t THEN
|
||||
LET newspaceb GET lib_malloc_spaceend
|
||||
ADD size_t + newspaceb -> newspacee
|
||||
ENDIF
|
||||
|
||||
BREAK
|
||||
ENDIF
|
||||
|
||||
DEC lib_malloc_ptr
|
||||
DEC lib_malloc_ptr
|
||||
GETASWORD@ lib_malloc_ptr -> lib_malloc_spacestart
|
||||
SUBT lib_malloc_spacestart - lib_malloc_spaceend -> maxsize
|
||||
DEC maxsize
|
||||
//if we found a space big enough for the allocation
|
||||
IF maxsize > size_t THEN
|
||||
//Save the pointer to the new space end the pointer in the alloctable
|
||||
LET newspaceb GET lib_malloc_spaceend
|
||||
INC newspaceb // must start @ the next byte
|
||||
ADD size_t + newspaceb -> newspacee
|
||||
|
||||
INC lib_malloc_ptr // set it to start of record! ( for move )
|
||||
// INC lib_malloc_ptr
|
||||
|
||||
BREAK
|
||||
ENDIF
|
||||
|
||||
DEC lib_malloc_ptr
|
||||
DEC lib_malloc_ptr
|
||||
GETASWORD@ lib_malloc_ptr -> lib_malloc_spaceend
|
||||
|
||||
WEND
|
||||
|
||||
IF newspaceb <> NULL THEN // allocate @ found space
|
||||
IF lib_malloc_ptr = lib_alloctable_end THEN //allocate @ end of table
|
||||
|
||||
//insert record and recalc lib_alloctable_end
|
||||
DEC lib_alloctable_end
|
||||
DEC lib_alloctable_end
|
||||
PUTASWORD@ lib_alloctable_end VALUE newspaceb
|
||||
DEC lib_alloctable_end
|
||||
DEC lib_alloctable_end
|
||||
PUTASWORD@ lib_alloctable_end VALUE newspacee
|
||||
|
||||
//return new pointer
|
||||
LET result GET newspaceb
|
||||
|
||||
GOTO lib_malloc_exit
|
||||
ENDIF
|
||||
//else = insert into alloctable
|
||||
WORD lib_malloc_from
|
||||
WORD lib_malloc_to
|
||||
BYTE lib_malloc_byte
|
||||
|
||||
// move the rest of the stack
|
||||
LET lib_malloc_from GET lib_alloctable_end
|
||||
LET lib_malloc_to GET newtableend
|
||||
|
||||
WHILE 1
|
||||
PEEK lib_malloc_from -> lib_malloc_byte
|
||||
POKE lib_malloc_to WITH lib_malloc_byte
|
||||
IF lib_malloc_from = lib_malloc_ptr THEN
|
||||
BREAK
|
||||
ENDIF
|
||||
INC lib_malloc_from
|
||||
INC lib_malloc_to
|
||||
WEND
|
||||
|
||||
//insert record and recalc lib_alloctable_end
|
||||
DEC lib_malloc_ptr
|
||||
PUTASWORD@ lib_malloc_ptr VALUE newspaceb
|
||||
DEC lib_malloc_ptr
|
||||
DEC lib_malloc_ptr
|
||||
PUTASWORD@ lib_malloc_ptr VALUE newspacee
|
||||
LET lib_alloctable_end GET newtableend
|
||||
|
||||
//return new pointer
|
||||
LET result GET newspaceb
|
||||
|
||||
ENDIF
|
||||
|
||||
IF newspaceb = NULL THEN // return null pointer
|
||||
LET result GET NULL
|
||||
GOTO lib_malloc_exit
|
||||
ENDIF
|
||||
|
||||
LABEL lib_malloc_exit
|
||||
|
||||
INC size_t
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Free: free alloced memory at m_ptr
|
||||
//-----------------------------------------------------------
|
||||
|
||||
FUNC lib_mem_free ( {WORD m_ptr} )
|
||||
WORD ptr
|
||||
WORD startaddr
|
||||
WORD lastrecfirst
|
||||
WORD from
|
||||
WORD to
|
||||
BYTE tempb
|
||||
|
||||
IF lib_alloctable_end > lib_memend THEN // no entries
|
||||
GOTO lib_free_exit
|
||||
ENDIF
|
||||
|
||||
LET ptr GET lib_memend
|
||||
DEC ptr
|
||||
|
||||
ADD 2 + lib_alloctable_end -> lastrecfirst
|
||||
|
||||
WHILE 1
|
||||
GETASWORD@ ptr -> startaddr
|
||||
|
||||
IF startaddr = m_ptr THEN //found allocation!
|
||||
//remove it!
|
||||
IF ptr = lastrecfirst THEN
|
||||
ADD 4 + lib_alloctable_end -> lib_alloctable_end
|
||||
BREAK
|
||||
ENDIF
|
||||
|
||||
LET to GET ptr
|
||||
INC to
|
||||
SUBT to - 4 -> from
|
||||
|
||||
WHILE 1
|
||||
PEEK from -> tempb
|
||||
POKE to WITH tempb
|
||||
IF from = lib_alloctable_end THEN
|
||||
BREAK
|
||||
ENDIF
|
||||
DEC from
|
||||
DEC to
|
||||
WEND
|
||||
|
||||
ADD 4 + lib_alloctable_end -> lib_alloctable_end
|
||||
|
||||
BREAK
|
||||
ENDIF
|
||||
|
||||
DEC ptr
|
||||
DEC ptr
|
||||
|
||||
IF ptr = lib_alloctable_end THEN
|
||||
BREAK
|
||||
ENDIF
|
||||
|
||||
DEC ptr
|
||||
DEC ptr
|
||||
|
||||
WEND
|
||||
|
||||
LABEL lib_free_exit
|
||||
|
||||
FEND
|
||||
|
||||
LABEL lib_memlib_skip
|
||||
|
||||
#IFEND
|
||||
87
lib/multdivlib.c65
Normal file
87
lib/multdivlib.c65
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
//------------------------------------------------
|
||||
// Mult/Div routines, taken from "The Fridge"
|
||||
// Made with 65CM interfaces
|
||||
//------------------------------------------------
|
||||
|
||||
#IFNDEF __LIB_MULTDIV
|
||||
#DEFINE __LIB_MULTDIV = 1
|
||||
|
||||
GOTO lib_multdiv_skip
|
||||
|
||||
|
||||
WORD lib_multdiv_acc
|
||||
WORD lib_multdiv_aux
|
||||
WORD lib_multdiv_ext
|
||||
|
||||
//------------------------------------------------
|
||||
// * MULTIPLY ROUTINE
|
||||
//* ACC*AUX -> [ACC,EXT] (low,hi) 32 bit result
|
||||
//------------------------------------------------
|
||||
|
||||
FUNC lib_multdiv_mult ( io:lib_multdiv_acc lib_multdiv_aux )
|
||||
FUNC lib_multdiv_mult32 ( io:lib_multdiv_acc lib_multdiv_aux out:lib_multdiv_ext )
|
||||
ASM
|
||||
|
||||
lda #0
|
||||
sta lib_multdiv_ext+1
|
||||
ldy #$11
|
||||
clc
|
||||
lib_multdiv_l1
|
||||
ror lib_multdiv_ext+1
|
||||
ror
|
||||
ror lib_multdiv_acc+1
|
||||
ror lib_multdiv_acc
|
||||
bcc lib_multdiv_mul2
|
||||
clc
|
||||
adc lib_multdiv_aux
|
||||
pha
|
||||
lda lib_multdiv_aux+1
|
||||
adc lib_multdiv_ext+1
|
||||
sta lib_multdiv_ext+1
|
||||
pla
|
||||
lib_multdiv_mul2
|
||||
dey
|
||||
bne lib_multdiv_l1
|
||||
sta lib_multdiv_ext
|
||||
ENDASM
|
||||
|
||||
FEND
|
||||
|
||||
//------------------------------------------------
|
||||
// * DIVIDE ROUTINE
|
||||
//* ACC/AUX -> ACC, remainder in EXT
|
||||
//------------------------------------------------
|
||||
|
||||
FUNC lib_multdiv_div ( io:lib_multdiv_acc lib_multdiv_aux )
|
||||
FUNC lib_multdiv_divmod ( io:lib_multdiv_acc lib_multdiv_aux out:lib_multdiv_ext )
|
||||
ASM
|
||||
lda #0
|
||||
sta lib_multdiv_ext+1
|
||||
ldy #$10
|
||||
lib_multdiv_l2
|
||||
asl lib_multdiv_acc
|
||||
rol lib_multdiv_acc+1
|
||||
rol
|
||||
rol lib_multdiv_ext+1
|
||||
pha
|
||||
cmp lib_multdiv_aux
|
||||
lda lib_multdiv_ext+1
|
||||
sbc lib_multdiv_aux+1
|
||||
bcc lib_multdiv_div2
|
||||
sta lib_multdiv_ext+1
|
||||
pla
|
||||
sbc lib_multdiv_aux
|
||||
pha
|
||||
inc lib_multdiv_acc
|
||||
lib_multdiv_div2
|
||||
pla
|
||||
dey
|
||||
bne lib_multdiv_l2
|
||||
sta lib_multdiv_ext
|
||||
ENDASM
|
||||
|
||||
FEND
|
||||
|
||||
|
||||
LABEL lib_multdiv_skip
|
||||
#IFEND
|
||||
397
lib/string.c65
Normal file
397
lib/string.c65
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
//------------------------------------------------------------------------
|
||||
// String library
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2005 Mattias Hansson
|
||||
// License: GNU GPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies:
|
||||
// ZP usage: $fb-$fe
|
||||
//
|
||||
// External functions:
|
||||
// lib_string_strlen
|
||||
// lib_string_strchr
|
||||
// lib_string_strcpy
|
||||
// lib_string_stpcpy
|
||||
// lib_string_strncpy
|
||||
// lib_string_strcmp
|
||||
// lib_string_memset
|
||||
// lib_string_strcat
|
||||
// lib_string_strncat
|
||||
|
||||
//
|
||||
// Internal function:
|
||||
//
|
||||
//
|
||||
// Note: Several of the lib-functions are combined to save space, where
|
||||
// this can be done at a fairly small speed penalty.
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFNDEF __LIB_STRING
|
||||
#DEFINE __LIB_STRING = 1
|
||||
|
||||
GOTO lib_string_skip
|
||||
|
||||
//Makes it possible for all modules that needs NULL
|
||||
//to define the constant
|
||||
#IFNDEF NULL
|
||||
#DEFINE NULL = 0
|
||||
#IFEND
|
||||
|
||||
WORD lib_string_strptr1 @ $fb
|
||||
WORD lib_string_strptr2 @ $fd
|
||||
WORD lib_string_length
|
||||
|
||||
//just aliases for the mem* functions
|
||||
WORD lib_string_ptr1 @ $fb
|
||||
WORD lib_string_ptr2 @ $fd
|
||||
|
||||
WORD lib_string_temp
|
||||
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_strlen
|
||||
//
|
||||
// Purpose: Returns the string length of a null-terminated
|
||||
// string in memory.
|
||||
//
|
||||
// Params:
|
||||
// lib_string_strptr1 - pointer to string to measure
|
||||
// lib_string_length - returns the length of the string
|
||||
//
|
||||
// lib_string_strchr
|
||||
//
|
||||
// Purpose: Returns pointer to where char lib_string_sl_matchchar
|
||||
// first occurs in string at lib_string_strptr1.
|
||||
// Returns NULL if not found.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
BYTE lib_string_sl_matchchar
|
||||
|
||||
FUNC lib_string_strlen ( lib_string_strptr1 out:lib_string_length )
|
||||
|
||||
LET lib_string_sl_matchchar = 0
|
||||
|
||||
FUNC lib_string_strchr ( io:lib_string_strptr1 lib_string_sl_matchchar )
|
||||
|
||||
BYTE char
|
||||
|
||||
LET lib_string_length = 0
|
||||
|
||||
PEEK lib_string_strptr1 -> char
|
||||
|
||||
WHILE char
|
||||
IF char == lib_string_sl_matchchar
|
||||
SUBEND
|
||||
ENDIF
|
||||
INC lib_string_strptr1
|
||||
INC lib_string_length
|
||||
PEEK lib_string_strptr1 -> char
|
||||
WEND
|
||||
|
||||
LET lib_string_strptr1 = NULL
|
||||
FEND
|
||||
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_strcpy
|
||||
//
|
||||
// Purpose: Copies the null-terminated string at
|
||||
// lib_string_strptr1 to lib_string_strptr2
|
||||
//
|
||||
// lib_string_stpcpy
|
||||
//
|
||||
// Purpose: Same as strcpy but returns a pointer to the
|
||||
// end of the copy in lib_string_strptr2
|
||||
//
|
||||
// lib_string_strncpy
|
||||
//
|
||||
// Purpose: Copies the null-terminated string at
|
||||
// lib_string_strptr1 to lib_string_strptr2, but
|
||||
// stops after lib_string_length chars regardless
|
||||
// of if the full string is copied
|
||||
//
|
||||
// Note: Dont send in 0 (zero) into lib_string_length.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
FUNC lib_string_stpcpy ( lib_string_strptr1 io:lib_string_strptr2 )
|
||||
|
||||
FUNC lib_string_strcpy ( lib_string_strptr1 lib_string_strptr2 )
|
||||
|
||||
LET lib_string_length = 0
|
||||
|
||||
FUNC lib_string_strncpy ( lib_string_strptr1 lib_string_strptr2 lib_string_length )
|
||||
|
||||
BYTE char
|
||||
LET char = $ff
|
||||
|
||||
WHILE char
|
||||
PEEK lib_string_strptr1 -> char
|
||||
POKE lib_string_strptr2 , char
|
||||
INC lib_string_strptr1
|
||||
INC lib_string_strptr2
|
||||
DEC lib_string_length
|
||||
IF lib_string_length == 0
|
||||
BREAK
|
||||
ENDIF
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_memset
|
||||
//
|
||||
// Purpose: Sets lib_string_length bytes starting at
|
||||
// lib_string_ptr1 to the value lib_string_memset_value
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
|
||||
BYTE lib_string_memset_value
|
||||
FUNC lib_string_memset ( lib_string_ptr1 lib_string_memset_value lib_string_length )
|
||||
|
||||
ADD lib_string_ptr1 + lib_string_length -> lib_string_ptr2
|
||||
DEC lib_string_ptr2
|
||||
WHILE lib_string_ptr2 >= lib_string_ptr1
|
||||
POKE lib_string_ptr2 , lib_string_memset_value
|
||||
DEC lib_string_ptr2
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_strcmp
|
||||
//
|
||||
// purpose: Compare two strings.
|
||||
// Returns 2 if str1 is less than str2
|
||||
// 1 if str1 is greater than str2
|
||||
// 0 if they are equal.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
BYTE lib_string_strcmp_result
|
||||
|
||||
FUNC lib_string_strcmp ( lib_string_strptr1 lib_string_strptr2 out:lib_string_strcmp_result )
|
||||
BYTE val1
|
||||
BYTE val2
|
||||
|
||||
LET lib_string_strcmp_result = 0
|
||||
|
||||
PEEK lib_string_strptr1 -> val1
|
||||
PEEK lib_string_strptr2 -> val2
|
||||
|
||||
WHILE val1 == val2
|
||||
INC lib_string_strptr1
|
||||
INC lib_string_strptr2
|
||||
PEEK lib_string_strptr1 -> val1
|
||||
PEEK lib_string_strptr2 -> val2
|
||||
IF val1 == 0
|
||||
BREAK
|
||||
ENDIF
|
||||
IF val2 == 0
|
||||
BREAK
|
||||
ENDIF
|
||||
WEND
|
||||
|
||||
IF val1 < val2
|
||||
LET lib_string_strcmp_result = 2
|
||||
ENDIF
|
||||
|
||||
IF val1 > val2
|
||||
LET lib_string_strcmp_result = 1
|
||||
ENDIF
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_strstr
|
||||
//
|
||||
// purpose:
|
||||
// Locate the position of one string in another.
|
||||
// Returns a pointer to the location of the
|
||||
// substring. (or NULL if not found)
|
||||
//-----------------------------------------------------------
|
||||
|
||||
WORD lib_string_strstr_return
|
||||
|
||||
FUNC lib_string_strstr ( lib_string_strptr1 lib_string_strptr2 out:lib_string_strstr_return )
|
||||
|
||||
LET lib_string_strstr_return = NULL
|
||||
WORD strlen1
|
||||
WORD strlen2
|
||||
WORD substartpos
|
||||
WORD mainlastpos
|
||||
BYTE mainval
|
||||
BYTE subval
|
||||
WORD strptr1firstmatch
|
||||
BYTE innerloop
|
||||
|
||||
//Ugly hack: Since "lib_string_strptr1" is used internally in strlen we remember the value in a temp variable
|
||||
LET lib_string_temp = lib_string_strptr1
|
||||
CALL lib_string_strlen ( lib_string_strptr1 strlen1 )
|
||||
CALL lib_string_strlen ( lib_string_strptr2 strlen2 )
|
||||
//Ugly hack: Since "lib_string_strptr1" is used internally in strlen we restore the value from a temp variable
|
||||
LET lib_string_strptr1 = lib_string_temp
|
||||
|
||||
IF strlen1 == 0
|
||||
SUBEND
|
||||
ENDIF
|
||||
IF strlen2 == 0
|
||||
SUBEND
|
||||
ENDIF
|
||||
|
||||
IF strlen2 > strlen1
|
||||
SUBEND
|
||||
ENDIF
|
||||
|
||||
SUBT strlen1 - strlen2 -> mainlastpos
|
||||
ADD lib_string_strptr1 + mainlastpos -> mainlastpos
|
||||
|
||||
LET substartpos = lib_string_strptr2
|
||||
LET innerloop = 0
|
||||
PEEK lib_string_strptr2 -> subval
|
||||
|
||||
WHILE lib_string_strptr1 <= mainlastpos
|
||||
PEEK lib_string_strptr1 -> mainval
|
||||
IF mainval = subval
|
||||
LET strptr1firstmatch = lib_string_strptr1
|
||||
LET innerloop = 1
|
||||
ENDIF
|
||||
WHILE mainval = subval
|
||||
INC lib_string_strptr1
|
||||
INC lib_string_strptr2
|
||||
PEEK lib_string_strptr1 -> mainval
|
||||
PEEK lib_string_strptr2 -> subval
|
||||
IF subval = 0
|
||||
//This is the match! We found substr!
|
||||
LET lib_string_strstr_return = strptr1firstmatch
|
||||
SUBEND
|
||||
ENDIF
|
||||
WEND
|
||||
IF innerloop != 0
|
||||
LET innerloop = 0
|
||||
LET lib_string_strptr1 = strptr1firstmatch
|
||||
LET lib_string_strptr2 = substartpos
|
||||
PEEK lib_string_strptr2 -> subval
|
||||
ENDIF
|
||||
INC lib_string_strptr1
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_strcat
|
||||
//
|
||||
// purpose:
|
||||
// To concatenate two strings.
|
||||
// Appends lib_string_strptr1 to the
|
||||
// end of lib_string_strptr2 (overwritng
|
||||
// the terminating NULL character).
|
||||
//
|
||||
// lib_string_strncat
|
||||
//
|
||||
// purpose:
|
||||
// very similar to strcat except at most
|
||||
// lib_string_sc_copymaxchars are
|
||||
// copied from the source. result is
|
||||
// always NULL-terminated.
|
||||
// (i.e. result string is at most
|
||||
// length( lib_string_strptr1 ) +
|
||||
// lib_string_sc_copymaxchars + 1
|
||||
//
|
||||
// Note:
|
||||
// Be sure that memory after NULL
|
||||
// in lib_string_strptr2 is avaliable
|
||||
// for writing (so you don't overwrite
|
||||
// something else lying there, or you
|
||||
// may get some very unexpected
|
||||
// results.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
WORD lib_string_sc_copymaxchars
|
||||
|
||||
FUNC lib_string_strcat ( lib_string_strptr1 lib_string_strptr2 )
|
||||
|
||||
LET lib_string_sc_copymaxchars = $ffff
|
||||
|
||||
FUNC lib_string_strncat ( lib_string_strptr1 lib_string_strptr2 lib_string_sc_copymaxchars )
|
||||
|
||||
BYTE char
|
||||
|
||||
//first find end of string2
|
||||
PEEK lib_string_strptr2 -> char
|
||||
WHILE char
|
||||
INC lib_string_strptr2
|
||||
PEEK lib_string_strptr2 -> char
|
||||
WEND
|
||||
|
||||
PEEK lib_string_strptr1 -> char
|
||||
POKE lib_string_strptr2 , char
|
||||
WHILE char
|
||||
PEEK lib_string_strptr1 -> char
|
||||
POKE lib_string_strptr2 , char
|
||||
INC lib_string_strptr1
|
||||
INC lib_string_strptr2
|
||||
DEC lib_string_sc_copymaxchars
|
||||
IF lib_string_sc_copymaxchars == 0
|
||||
POKE lib_string_strptr2 , 0
|
||||
SUBEND
|
||||
ENDIF
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_memcmp
|
||||
//
|
||||
// Purpose:
|
||||
// Compare two memory areas.
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
|
||||
BYTE lib_string_mc_res
|
||||
|
||||
FUNC lib_string_memcmp ( lib_string_ptr1 lib_string_ptr2 lib_string_length out:lib_string_mc_res )
|
||||
|
||||
BYTE b1
|
||||
BYTE b2
|
||||
|
||||
LET lib_string_mc_res = 1
|
||||
WHILE lib_string_length
|
||||
PEEK lib_string_ptr1 -> b1
|
||||
PEEK lib_string_ptr2 -> b2
|
||||
IF b1 != b2
|
||||
SUBEND
|
||||
ENDIF
|
||||
INC lib_string_ptr1
|
||||
INC lib_string_ptr2
|
||||
DEC lib_string_length
|
||||
WEND
|
||||
|
||||
LET lib_string_mc_res = 0
|
||||
FEND
|
||||
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_string_memcpy
|
||||
//
|
||||
// Purpose:
|
||||
// Copy contants of a memory area to another memory area
|
||||
//-----------------------------------------------------------
|
||||
|
||||
FUNC lib_string_memcpy ( lib_string_ptr1 lib_string_ptr2 lib_string_length )
|
||||
|
||||
BYTE btemp
|
||||
|
||||
WHILE lib_string_length
|
||||
PEEK lib_string_ptr1 -> btemp
|
||||
POKE lib_string_ptr2 , btemp
|
||||
INC lib_string_ptr1
|
||||
INC lib_string_ptr2
|
||||
DEC lib_string_length
|
||||
WEND
|
||||
FEND
|
||||
|
||||
|
||||
LABEL lib_string_skip
|
||||
|
||||
#IFEND
|
||||
153
lib/strlist.c65
Normal file
153
lib/strlist.c65
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
//------------------------------------------------------------------------
|
||||
// Library String-List
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2005 Mattias Hansson
|
||||
// License: GNU LGPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies: string.c65 memlib.c65
|
||||
// Target: generic 6502
|
||||
//
|
||||
// Purpose: Provide some functions the help to create, update and access
|
||||
// a linked list of strings.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#IFNDEF __LIB_STRLIST
|
||||
#DEFINE __LIB_STRLIST = 1
|
||||
|
||||
GOTO lib_strlist_skip
|
||||
|
||||
#INCLUDE <string.c65>
|
||||
#INCLUDE <memlib.c65>
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_strlist_get
|
||||
//
|
||||
// purpose:
|
||||
// To get address to an item# (0..count-1)
|
||||
// (send in item# $ffff for last item)
|
||||
//
|
||||
// lib_strlist_strget
|
||||
//
|
||||
// purpose:
|
||||
// To get address of an string inside item#
|
||||
// (send in item# $ffff for last item)
|
||||
//
|
||||
// lib_strlist_count
|
||||
// purpose:
|
||||
// To get the # of items in the list.
|
||||
// NOTE: Returns the value in computer notation. I.e.
|
||||
// 1 string, count == 0; 2 strings, count == 1 etc.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
|
||||
FUNC lib_strlist_count ( {WORD objref} out:{WORD count} )
|
||||
|
||||
WORD itemnr
|
||||
LET itemnr = $ffff
|
||||
|
||||
FUNC lib_strlist_get ( objref itemnr out:{WORD itemptr} )
|
||||
|
||||
FUNC lib_strlist_strget ( objref itemnr out:{WORD s} )
|
||||
|
||||
WORD nextptr
|
||||
|
||||
IF objref == NULL //no list, no action
|
||||
EXIT
|
||||
ENDIF
|
||||
|
||||
//return values reset
|
||||
LET count = 0
|
||||
LET itemptr = objref
|
||||
LET s = NULL
|
||||
|
||||
WHILE 1
|
||||
ADD 2 + itemptr -> s
|
||||
GETASWORD@ itemptr -> nextptr
|
||||
IF nextptr == NULL //are we at last item?
|
||||
EXIT
|
||||
ENDIF
|
||||
IF itemnr == count
|
||||
EXIT //if searching for this item we're done.
|
||||
ENDIF
|
||||
INC count
|
||||
LET itemptr = nextptr
|
||||
//MH TAG 20051218 debug
|
||||
//CALL lib_cbmio_hexoutw ( itemptr )
|
||||
WEND
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_strlist_add
|
||||
//
|
||||
// purpose:
|
||||
// To either create a new linklist (send in NULL as
|
||||
// root-node), or add a new node to an existing linklist.
|
||||
//
|
||||
// Params:
|
||||
// objref - send in root-node-pointer to the
|
||||
// list. If new list is to be created
|
||||
// send in the value NULL.
|
||||
// returns: address to the root node
|
||||
// on successful add, or NULL on error
|
||||
// (normal cause: out of memory)
|
||||
//-----------------------------------------------------------
|
||||
|
||||
FUNC lib_strlist_add ( io:{WORD objref} {WORD s} )
|
||||
WORD link_length
|
||||
WORD link_ptr
|
||||
WORD old_link_ptr
|
||||
|
||||
IF objref != 0 //add new link
|
||||
CALL lib_strlist_get ( objref $ffff old_link_ptr )
|
||||
ENDIF
|
||||
|
||||
CALL lib_string_strlen ( s link_length )
|
||||
//Add space for:
|
||||
// 1. "link to next member" (2)
|
||||
// 2. null terminator (1)
|
||||
ADD 3 + link_length -> link_length
|
||||
CALL lib_mem_malloc ( link_length link_ptr )
|
||||
IF link_ptr == NULL // Alloc failed == out of memory
|
||||
LET objref = NULL
|
||||
EXIT
|
||||
ENDIF
|
||||
IF objref == 0 //create new list
|
||||
LET objref = link_ptr //return the start of the list to the caller
|
||||
ELSE //link up the new link to the end of the old list
|
||||
PUTASWORD@ old_link_ptr , link_ptr
|
||||
ENDIF
|
||||
PUTASWORD@ link_ptr , NULL //Mark as last link
|
||||
//move beyond link-pointer
|
||||
INC link_ptr
|
||||
INC link_ptr
|
||||
//and finally add the string to memory
|
||||
CALL lib_string_strcpy ( s link_ptr )
|
||||
|
||||
FEND
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_strlist_free
|
||||
//
|
||||
// purpose:
|
||||
// To remove a strlist and free all resources allocated by
|
||||
// it.
|
||||
//
|
||||
// Params:
|
||||
// lib_strlist_f_rootptr - Address to root item.
|
||||
//-----------------------------------------------------------
|
||||
|
||||
FUNC lib_strlist_free ( io:{WORD objref} )
|
||||
WORD nextptr
|
||||
|
||||
WHILE objref
|
||||
GETASWORD@ objref -> nextptr
|
||||
CALL lib_mem_free ( objref )
|
||||
LET objref = nextptr
|
||||
WEND
|
||||
LET objref = NULL
|
||||
FEND
|
||||
|
||||
LABEL lib_strlist_skip
|
||||
|
||||
#IFEND
|
||||
101
lib/strlist2.c65
Normal file
101
lib/strlist2.c65
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
//------------------------------------------------------------------------
|
||||
// Library Extended String-List routines
|
||||
//
|
||||
// Author: Mattias Hansson
|
||||
// Copyright (c) : 2005 Mattias Hansson
|
||||
// License: GNU LGPL 2
|
||||
// Language: 65CM v0.4+
|
||||
// Dependencies: string.c65 memlib.c65
|
||||
// Target: generic 6502
|
||||
//
|
||||
// Purpose: Provide more advanced functions for manipulating/maintaining
|
||||
// stringlists. By making a additional library, developers can
|
||||
// choose how much they wsnt compared to the memory size cost
|
||||
// of the libraries.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
#IFNDEF __LIB_STRLIST2
|
||||
#DEFINE __LIB_STRLIST2 = 1
|
||||
|
||||
GOTO lib_strlist2_skip
|
||||
|
||||
#INCLUDE <strlist.c65>
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// lib_str_to_strlist
|
||||
//
|
||||
// purpose:
|
||||
// To splitt a string into 0..several elements into a new
|
||||
// stringlist. The separator character defines the
|
||||
// "splitt indicator".
|
||||
//
|
||||
// Note: If several separator-chars are found together they
|
||||
// are still threated as one.
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
|
||||
FUNC lib_strlist2_str_to_strlist ( {WORD s} {BYTE separator} io:{WORD slref} )
|
||||
|
||||
BYTE b
|
||||
BYTE inword
|
||||
WORD start
|
||||
WORD copylen
|
||||
WORD tmpstr_ptr
|
||||
BYTE eow //end of word
|
||||
|
||||
LET inword = 0
|
||||
LET eow = 0
|
||||
|
||||
WHILE 1
|
||||
PEEK s -> b
|
||||
|
||||
IF inword == 0
|
||||
IF b == 0
|
||||
EXIT
|
||||
ENDIF
|
||||
IF b != separator //start of new "word"
|
||||
LET inword = 1
|
||||
LET start = s
|
||||
ENDIF
|
||||
ELSE //we are inside a "word"
|
||||
IF b == 0
|
||||
LET eow = 1
|
||||
ENDIF
|
||||
IF b == separator //end of this "word"
|
||||
LET eow = 1
|
||||
ENDIF
|
||||
|
||||
IF eow == 1
|
||||
//copy the "word" to a new string
|
||||
|
||||
SUBT s - start -> copylen
|
||||
//hexoutw ( copylen )
|
||||
INC copylen //make room for zero termination
|
||||
lib_mem_malloc ( copylen tmpstr_ptr )
|
||||
IF tmpstr_ptr == NULL
|
||||
EXIT //if errorhandling is to be added in the future, check this :-)
|
||||
ENDIF
|
||||
DEC copylen
|
||||
lib_string_strncpy ( start tmpstr_ptr copylen )
|
||||
//manually zero terminating the copy to add (borrowing start as temp)
|
||||
ADD tmpstr_ptr + copylen -> start
|
||||
POKE start , NULL
|
||||
lib_strlist_add ( slref tmpstr_ptr )
|
||||
lib_mem_free ( tmpstr_ptr )
|
||||
LET inword = 0
|
||||
LET eow = 0
|
||||
ENDIF
|
||||
ENDIF
|
||||
IF b == 0
|
||||
EXIT
|
||||
ENDIF
|
||||
|
||||
INC s
|
||||
WEND
|
||||
|
||||
FEND
|
||||
|
||||
LABEL lib_strlist2_skip
|
||||
|
||||
#IFEND
|
||||
Loading…
Reference in a new issue