DEFFNder
Description of the page content
Library of Sinclair BASIC functions written in Z80.
DEFFNder is a small library of Sinclair BASIC functions written in Z80. So far there are 20 functions in it. I wrote them for a Sinclair BASIC project. Four of them are based on code published on Microhobby in 1986 and 1987, mainly by Ricardo Serrial Wigge (full details in the sources). Five of them (and the demo) were later written and contributed by Derek Bolli.
Some of the functions are generic and can be found in more powerful versions of BASIC. Other functions are very specific, especially written for my project.
The source code is fully documented, in order to help one to understand how every function works, how to modify the functions and how to write new ones.
The code of the functions is relocatable and ready to be used. More details are in the included README.adoc file.
Source code
; fn_band16.z80s
;
; Bitwise AND 16 bit BASIC function for ZX Spectrum
; Version B-00-20151222
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; Portions Copyright (C) 2015 Derek Bolli (dbolli at bigpond dot net dot au)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a bitwise AND 16 bit function to Sinclair
; BASIC, that ANDs a 16-bit value with a second 16-bit value and
; returns the result.
; --------------------------------------------------------------
; Usage
; A function must be defined this way.
; (the actual names are unimportant):
; 10 DEF FN a(a,b)=USR band16
; Where:
; a = word 1 operand
; b = word 2 operand
; band16 = address of the machine code routine
; Example:
; LET n = FN a(43690,65287)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN d(a) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 a(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 b
; +09 14
; +10 0
; +11 [sign byte: 0=positive; 255=negative]
; +12 [16-bit number, LSB first]
; +14 0
; +15 )=
; --------------------------------------------------------------
; History
; 2015-12-22: Written. Version B-00.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_band16,fn_band16_size
fn_band16:
local DEFADD
DEFADD equ 23563 ; system variable
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = word 1
ld e,(ix+12)
ld d,(ix+13)
; de = word 2
ld a,l
and e
ld c,a
; c = LSB of result
ld a,h
and d
ld b,a
; b = MSB of result
ret
fn_band16_size equ $-fn_band16
endp
; vim: textwidth=64
; fn_bor16.z80s
;
; Bitwise OR 16 bit BASIC function for ZX Spectrum
; Version B-00-20151222
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; Portions Copyright (C) 2015 Derek Bolli (dbolli at bigpond dot net dot au)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a bitwise OR 16 bit function to Sinclair BASIC,
; that ORs a 16-bit value with a second 16-bit value and returns
; the result.
; --------------------------------------------------------------
; Usage
; A function must be defined this way.
; (the actual names are unimportant):
; 10 DEF FN r(a,b)=USR bor16
; Where:
; a = word 1 operand
; b = word 2 operand
; bor16 = address of the machine code routine
; Example:
; LET n = FN r(43520,65450)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN d(a) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 r(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 b
; +09 14
; +10 0
; +11 [sign byte: 0=positive; 255=negative]
; +12 [16-bit number, LSB first]
; +14 0
; +15 )=
; --------------------------------------------------------------
; History
; 2015-12-22: Written. Version B-00.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_bor16,fn_bor16_size
fn_bor16:
local DEFADD
DEFADD equ 23563 ; system variable
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = word 1
ld e,(ix+12)
ld d,(ix+13)
; de = word 2
ld a,l
or e
ld c,a
; c = LSB of result
ld a,h
or d
ld b,a
; b = MSB of result
ret
fn_bor16_size equ $-fn_bor16
endp
; vim: textwidth=64
; fn_bxor16.z80s
;
; Bitwise XOR 16 bit BASIC function for ZX Spectrum
; Version B-00-20151222
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; Portions Copyright (C) 2015 Derek Bolli (dbolli at bigpond dot net dot au)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a bitwise XOR 16 bit function to Sinclair BASIC, that XORs a 16-bit
; value with a second 16-bit value and returns the result.
; --------------------------------------------------------------
; Usage
; A function must be defined this way.
; (the actual names are unimportant):
; 10 DEF FN x(a,b)=USR bxor16
; Where:
; a = word 1 operand
; b = word 2 operand
; bxor16 = address of the machine code routine
; Example:
; LET n = FN x(43520,65450)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN d(a) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 x(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 b
; +09 14
; +10 0
; +11 [sign byte: 0=positive; 255=negative]
; +12 [16-bit number, LSB first]
; +14 0
; +15 )=
; --------------------------------------------------------------
; History
; 2015-12-22: Written. Version B-00.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_bxor16,fn_bxor16_size
fn_bxor16:
local DEFADD
DEFADD equ 23563 ; system variable
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = word 1
ld e,(ix+12)
ld d,(ix+13)
; de = word 2
ld a,l
xor e
ld c,a
; c = LSB of result
ld a,h
xor d
ld b,a
; b = MSB of result
ret
fn_bxor16_size equ $-fn_bxor16
endp
; vim: textwidth=64
; fn_dispbin.z80s
;
; Display Binary BASIC function for ZX Spectrum
; Version B-00-20151223
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; Portions Copyright (C) 2015 Derek Bolli (dbolli at bigpond dot net dot au)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a Display Binary function to Sinclair BASIC,
; that prints the 8-bit value passed as an operand as an 8 digit
; binary value.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this way
; (the actual names are unimportant):
; 10 DEF FN b$(b)="" AND USR dispbin
; Where:
; b = 8-bit binary number to display
; dispbin = address of the machine code routine
; Example:
; PRINT FN b$(BIN 01010101)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN s$(s$,n) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 b$(
; +00 n
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 )=
; --------------------------------------------------------------
; History of this file
; 2015-12-23: Written. Version B-00.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_dispbin,fn_dispbin_size
fn_dispbin:
local exit
; ..............................
; System variables
local DEFFADD
DEFADD equ 23563
; ..............................
; ROM routines
local STK_STORE
STK_STORE equ 0x2ab6
; Input:
; A = flag
; DE = string address
; BC = string length
local STK_FETCH
STK_FETCH equ 0x2bf1
; Output:
; A = flag
; DE = string address
; BC = string length
; ..............................
; Start
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = number to display
ld a,l
push af
xor a
ld bc,8
; a = 0 (=new string)
; de = string address, undetermined
; bc = length of the new string
call STK_STORE
rst 0x28 ; calculator
db 0x17 ; concatenate to the empty string in the DEF FN expression
db 0x38 ; end
call STK_FETCH
call STK_STORE
; de = result string address
; bc = result string length
pop af
dispbin:
and a
ld b,8
dispblp1:
rl a
push af
ld a,'0'
jr nc,dispbnc1
ld a,'1'
dispbnc1:
ld (de),a
inc de
pop af
djnz dispblp1
; ..............................
exit:
ld bc,1
ret
fn_dispbin_size equ $-fn_dispbin
endp
; vim: textwidth=64
; fn_disphex.z80s
;
; Display Hex BASIC function for ZX Spectrum
; Version B-00-20151227
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; Portions Copyright (C) 2015 Derek Bolli (dbolli at bigpond dot net dot au)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a Display Hex function to Sinclair BASIC, that
; prints the 8-bit value passed as an operand as a 2 digit hex
; value.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this way
; (the actual names are unimportant):
; 10 DEF FN h$(n)="" AND USR disphex
; Where:
; n = 8-bit binary number to display
; disphex = address of the machine code routine
; Example:
; PRINT FN h$(255)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN s$(s$,n) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 h$(
; +00 n
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 )=
; --------------------------------------------------------------
; History of this file
; 2015-12-27: Written. Version B-00.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_disphex,fn_disphex_size
fn_disphex:
local exit
; ..............................
; System variables
local DEFFADD
DEFADD equ 23563
; ..............................
; ROM routines
local STK_STORE
STK_STORE equ 0x2ab6
; Input:
; A = flag
; DE = string address
; BC = string length
local STK_FETCH
STK_FETCH equ 0x2bf1
; Output:
; A = flag
; DE = string address
; BC = string length
; ..............................
; Start
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = number to display
ld a,l
push af
xor a
ld bc,2
; a = 0 (=new string)
; de = string address, undetermined
; bc = length of the new string
call STK_STORE
rst 0x28 ; calculator
db 0x17 ; concatenate to the empty string in the DEF FN expression
db 0x38 ; end
call STK_FETCH
call STK_STORE
; de = result string address
; bc = result string length
pop af
dumphex:
push af
; Dump two hex digits in A to (DE) and (DE+1)
rrca
rrca
rrca
rrca
and $0f
; %00001111
cp $0a
jr c,dmphnc1
add a,7
dmphnc1:
add a,$30
ld (de),a
; Store hex digit at (DE)
inc de
; Increment destination pointer
pop af
and $0f
; %00001111
cp $0a
jr c,dmphnc2
add a,7
dmphnc2:
add a,$30
ld (de),a
; Store hex digit at (DE)
inc de
; Increment destination pointer
; ret
; DE points to original DE + 2
; ..............................
exit:
ld bc,1
ret
fn_disphex_size equ $-fn_disphex
endp
; vim: textwidth=64
; fn_dpeek.z80s
;
; DPEEK BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a DPEEK function to Sinclair BASIC, that
; returns the 16-bit value from a memory address.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this
; way (the actual names are unimportant):
; 10 DEF FN d(a)=USR dpeek
; Where:
; a = address to peek
; dpeek = address of the machine code routine
; Example:
; PRINT FN d(1887)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN d(a) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 d
; -01 (
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 )
; +08 =
; --------------------------------------------------------------
; History of this file
; 2014-08-07: Written.
;
; 2014-08-10: Removed unnecessary saving and restoring of
; registers. New: 'proc', 'local' and 'public', in order to
; make it possible to combine several modules into a single
; file.
;
; 2015-01-22: Some changes for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_dpeek,fn_dpeek_size
fn_dpeek:
local DEFADD
DEFADD equ 23563 ; system variable
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = parameter address
ld c,(hl)
inc hl
ld b,(hl)
; bc = value, returned by USR
ret
fn_dpeek_size equ $-fn_dpeek
endp
; vim: textwidth=64
; fn_dpoke.z80s
;
; DPOKE BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a DPOKE function to Sinclair BASIC, that pokes
; a 16-bit value into a memory address.
; --------------------------------------------------------------
; Usage
; A function must be defined this way.
; (the actual names are unimportant):
; 10 DEF FN p(a,n)=USR dpoke
; Where:
; a = address to poke into
; n = 16-bit number to poke
; dpoke = address of the machine code routine
; Example:
; RANDOMIZE FN p(22528,1024)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN d(a) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 p(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 n
; +09 14
; +10 0
; +11 [sign byte: 0=positive; 255=negative]
; +12 [16-bit number, LSB first]
; +14 0
; +15 )=
; --------------------------------------------------------------
; History
; 2014-08-10: Written
;
; 2015-01-22: Some changes for publication. Version B-00.
;
; 2015-02-25: Typo in "Internal".
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_dpoke,fn_dpoke_size
fn_dpoke:
local DEFADD
DEFADD equ 23563 ; system variable
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = address
ld e,(ix+12)
ld d,(ix+13)
; de = number
ld (hl),e
inc hl
ld (hl),d
ret
fn_dpoke_size equ $-fn_dpoke
endp
; vim: textwidth=64
; fn_instr1.z80s
;
; Simplified INSTR BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Authors and license
; Copyright (C) 1986 Ricardo Serrial Wigge
; 1986-05, original version.
; Published in:
; Microhobby magazine, issue 77 (1986-05-06), pages 22-24:
; http://microhobby.org/
; http://microhobby.speccy.cz/mhf/077/MH077_22.jpg
; http://microhobby.speccy.cz/mhf/077/MH077_23.jpg
; http://microhobby.speccy.cz/mhf/077/MH077_24.jpg
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; 2014-08, modified version.
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this way
; (the actual names are unimportant):
; 10 DEF FN i(h$,n$)=USR instr1
; Where:
; h$ = the haystack, the searched string
; n$ = the needle, the string to be searched for
; instr1 = address of the machine code routine
; Example:
; PRINT FN i("En vilagxo de La Mancxo kies nomon mi ne...","Mancxo")
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN i(h$,n$) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 i
; -01 (
; +00 h
; +01 $
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string length, LSB first]
; +08 ,
; +09 n
; +10 $
; +11 14
; +12 [string type]
; +13 [string address, LSB first]
; +15 [string length, LSB first]
; +17 )
; +18 =
; --------------------------------------------------------------
; History of this file
; 2014-08-06: This modified version doesn't use the position
; parameter. The search is done always from the start of the
; haystack.
;
; 2014-08-10: Removed unnecessary saving and restoring of
; registers. New: 'proc', 'local' and 'public', in order to
; make it possible to combine several modules into a single
; file.
;
; 2015-01-22: Some typos fixed. Credits improved. Some changes
; for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_instr1,fn_instr1_size
fn_instr1:
local again
local exit
local found
local haystack_exhausted
local match
local needle_exhausted
local not_found
; ..............................
; System variables
local DEFADD
DEFADD equ 23563
; ..............................
; Parameters
ld ix,(DEFADD)
ld a,(ix+6)
or (ix+7) ; empty string?
jr z, not_found
ld e,(ix+4)
ld d,(ix+5)
; de = address of h$
ld l,(ix+6)
ld h,(ix+7)
; hl = length of h$
add hl,de
; hl = address after the end of h$
; Use ix+6 as temporary storage
ld (ix+6),l
ld (ix+7),h
ld l,e
ld h,d
; hl = address of h$
; ..............................
again:
; Start searching h$ for n$ from the current position of h$
ld e,(ix+13)
ld d,(ix+14)
dec de
; de = address of n$ -1
ld c,(ix+15)
ld b,(ix+16)
; bc =length of n$
; ..............................
match:
; Keep on searching h$
inc de
; de = address of current char of n$
; hl = address of current char of h$
ld a,(de)
cpi ; compare a with (hl) and increment hl
ex af,af'
push hl
push de
ld e,(ix+6)
ld d,(ix+7)
; de = address after the end of h$
and a
sbc hl,de
; z = last char of h$?
pop de
pop hl
jr z,haystack_exhausted
ld a,b
or c
; z = last char of n$?
jr z,needle_exhausted
ex af,af'
; z = (hl)=(de)?
jr z,match
jr again
; ..............................
needle_exhausted:
ex af,af'
; z = (hl)=(de)?
jr nz,again
jr found
; ..............................
haystack_exhausted:
ld a,b
or c
; z = bc=0?
jr nz,not_found
ex af,af'
; z = (hl)=(de)?
jr z,found
; ..............................
not_found:
ld bc,0
jr exit
; ..............................
found:
; hl = address of current char of h$
ld e,(ix+4)
ld d,(ix+5)
; de = address of h$
and a
sbc hl,de
; hl = offset to the current char of h$
ld e,(ix+15)
ld d,(ix+16)
; de = length of n$
and a
sbc hl,de
inc hl
; hl = position of n$ in h$
ld b,h
ld c,l
; bc = position of n$ in h$
; ..............................
exit:
; bc = position of n$ in h$ (or zero)
ret
fn_instr1_size equ $-fn_instr1
endp
; vim: textwidth=64
; fn_instr.z80s
;
; INSTR BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Authors and license
; Copyright (C) 1986 Ricardo Serrial Wigge
; The code was published in Microhobby magazine,
; issue 77 (1986-05-06), pages 22-24:
; http://microhobby.org/
; http://microhobby.speccy.cz/mhf/077/MH077_22.jpg
; http://microhobby.speccy.cz/mhf/077/MH077_23.jpg
; http://microhobby.speccy.cz/mhf/077/MH077_24.jpg
; Copyright (C) 2014 Marcos Cruz (programandala.net)
; Typed, commented and improved the code.
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this way
; (the actual names are unimportant):
; 10 DEF FN i(h$,n$,p)=USR instr
; Where:
; h$ = the haystack, the searched string
; n$ = the needle, the string to be searched for
; p = start search position in h$
; instr = address of the machine code routine
; Example:
; PRINT FN i("En vilagxo de La Mancxo kies nomon mi ne...","Mancxo",1)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN i(h$,n$,p) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 i
; -01 (
; +00 h
; +01 $
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string length, LSB first]
; +08 ,
; +09 n
; +10 $
; +11 14
; +12 [string type]
; +13 [string address, LSB first]
; +15 [string length, LSB first]
; +17 ,
; +18 p
; +19 14
; +20 0
; +21 [sign byte: 0=positive; 255=negative]
; +22 [16-bit number, LSB first]
; +24 0
; +25 )
; +26 =
; --------------------------------------------------------------
; History of this file
; 2014-08-06:
;
; Typed from the magazine and compiled with Pasmo. The code had
; useless NOP and DS.
;
; Problem: The FN function always returns 0, and somehow
; corrupts the STOP command, because it is ignored by the
; interpreter. The BREAK key causes the system to frozen.
;
; Fix: I modified the code: I saved the content of the UNUSED
; system variable, and restored it before returning. The strange
; behaviours ceased. It seems that variable is not so "unused"
; by the system, at least by ZX Spectrum 128K, or 48K with the
; gw03 ROM.
;
; Change: An optional method is provided: the parameter zone of
; the function is used as storage instead of UNUSED. Conditional
; compilation is used.
;
; 2014-08-10:
;
; Removed unnecessary saving and restoring of registers.
;
; New: 'proc', 'public' and 'local', in order to make it
; possible to combine several modules into a single file.
;
; 2015-01-22:
;
; Some typos fixed. Some changes for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
; To-do list
; Check if the start position is greater than the length of the
; haystack.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_instr,fn_instr_size
fn_instr:
local again
local exit
local found
local haystack_exhausted
local match
local needle_exhausted
local not_found
; ..............................
; Options
; Use the system variable UNUSED as a temporary store?
; Otherwise, the address of the length of the h$ argument in DEF
; FN will be used.
local USE_UNUSED
USE_UNUSED equ 0
; If USE_UNUSED is true, do save the content of the UNUSED
; system variable? It seems saving it is not required only by
; the original ZX Spectrum 48K without interfaces. Other models
; or certain interfaces may use this system variable.
local SAVE_UNUSED
SAVE_UNUSED equ 1
; ..............................
; System variables
local DEFFADD
DEFADD equ 23563
local UNUSED
UNUSED equ 23728
; ..............................
; Parameters
ld ix,(DEFADD)
ld a,(ix+6)
or (ix+7) ; empty string?
jr z, not_found
if USE_UNUSED && SAVE_UNUSED
; Save the content of the UNUSED system variable
ld hl,(UNUSED)
ld (backup),hl
endif
ld e,(ix+4)
ld d,(ix+5)
; de = address of h$
ld l,(ix+6)
ld h,(ix+7)
; hl = length of h$
add hl,de
; hl = address after the end of h$
if USE_UNUSED
ld (UNUSED),hl
else
ld (ix+6),l
ld (ix+7),h
endif
ld l,(ix+22)
ld h,(ix+23)
; hl = p
dec hl
add hl,de
; hl = start address in h$
; ..............................
again:
; Start searching h$ for n$ from the current position of h$
ld e,(ix+13)
ld d,(ix+14)
dec de
; de = address of n$ -1
ld c,(ix+15)
ld b,(ix+16)
; bc =length of n$
; ..............................
match:
; Keep on searching h$
inc de
; de = address of current char of n$
; hl = address of current char of h$
ld a,(de)
cpi ; compare a with (hl) and increment hl
ex af,af'
push hl
push de
if USE_UNUSED
ld de,(UNUSED)
else
ld e,(ix+6)
ld d,(ix+7)
endif
; de = address after the end of h$
and a
sbc hl,de
; z = last char of h$?
pop de
pop hl
jr z,haystack_exhausted
ld a,b
or c
; z = last char of n$?
jr z,needle_exhausted
ex af,af'
; z = (hl)=(de)?
jr z,match
jr again
; ..............................
needle_exhausted:
ex af,af'
; z = (hl)=(de)?
jr nz,again
jr found
; ..............................
haystack_exhausted:
ld a,b
or c
; z = bc=0?
jr nz,not_found
ex af,af'
; z = (hl)=(de)?
jr z,found
; ..............................
not_found:
ld bc,0
jr exit
; ..............................
found:
; hl = address of current char of h$
ld e,(ix+4)
ld d,(ix+5)
; de = address of h$
and a
sbc hl,de
; hl = offset to the current char of h$
ld e,(ix+15)
ld d,(ix+16)
; de = length of n$
and a
sbc hl,de
inc hl
; hl = position of n$ in h$
ld b,h
ld c,l
; bc = position of n$ in h$
; ..............................
exit:
; bc = position of n$ in h$ (or zero)
if USE_UNUSED && SAVE_UNUSED
backup equ $+1
ld hl,0
ld (UNUSED),hl
endif
ret
fn_instr_size equ $-fn_instr
endp
; vim: textwidth=64
; fn_lookup16.z80s
;
; A database BASIC function for ZX Spectrum
; Version B-00-20150813
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a function to Sinclair BASIC that searchs a
; lookup table of 16-bit values, stored in a string, for a
; 16-bit key value, and returns its associated value.
; --------------------------------------------------------------
; Usage
; A BASIC function must be defined this way:
; (the actual names are unimportant):
; 10 DEF FN f(h$,k)=USR lookup16
; Where:
; h$ = the haystack, the searched string,
; with the following structure:
; every 16-bit key precedes its associated
; 16-bit value; both are stored in two bytes
; (chars of the string), in the usual Z80 format
; (least significant byte first).
; k = the key to be searched for
; lookup16 = address of the machine code routine
; Example for a text adventure, where a$ holds a lookup table of
; actions associated to line numbers:
; GO TO FN f(a$,action)
; WARNING: As explained above, the haystack string must consist
; of groups of exactly 4 bytes: a 16-bit key followed by its
; 16-bit value. When the string is not well formed (for example,
; any single character is missing), the end check will fail and
; strange things will happen.
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN i(h$,n) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 f(
; +00 h$
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string length, LSB first]
; +08 ,
; +09 k
; +10 14
; +11 0
; +12 [sign byte: 0=positive; 255=negative]
; +13 [16-bit number, LSB first]
; +15 0
; +16 )=
; --------------------------------------------------------------
; History of this file
; 2015-02-28: First version (started with the code of
; <fn_termn.z80s>).
;
; 2015-03-01: Fix: Usage.
;
; 2015-08-10: Revision. License.
;
; 2015-08-13: Fixed typo in the usage instructions. Thanks Derek
; (http://www.worldofspectrum.org/forums/discussion/comment/831230/#Comment_831230).
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_lookup16,fn_lookup16_size
fn_lookup16:
local check
local next
local found
; ..............................
; System variables
local DEFADD
DEFADD equ 23563
; ..............................
; Parameters
ld ix,(DEFADD)
ld c,(ix+6)
ld b,(ix+7)
; bc = len of h$
ld a,b
or c ; is h$ empty?
ret z ; if so, back to BASIC (the function returns 0)
ld l,(ix+4)
ld h,(ix+5)
; hl = start of h$
ld e,(ix+13)
ld d,(ix+14)
; de = k
; ..............................
check:
; Check the current key
; hl = address of the current key
; de = key searched for
ld a,(hl)
cp e
inc hl
jr nz,next
ld a,(hl)
cp d
jr z,found
next:
; hl = address of the second byte of the current key
; bc = remaining length
inc hl
inc hl
inc hl ; hl = address of the next key
dec bc
dec bc
dec bc
dec bc ; bc = remaining chars
ld a,b
or c ; end of the haystack?
ret z ; if so, back to BASIC (the function returns 0)
jr check
found:
; The key was found
; hl = address of the second byte of the current key
inc hl
ld c,(hl)
inc hl
ld b,(hl)
; bc = value
ret ; back to BASIC (the function returns the value)
fn_lookup16_size: equ $-fn_lookup16
endp
; vim: textwidth=64
; fn_lookup8.z80s
;
; A database BASIC function for ZX Spectrum
; Version B-00-20150813
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a function to Sinclair BASIC that searchs a
; lookup table of 8-bit values, stored in a string, for a
; 8-bit key value, and returns its associated value.
; --------------------------------------------------------------
; Usage
; A BASIC function must be defined this way:
; (the actual names are unimportant):
; 10 DEF FN f(h$,k)=USR lookup8
; Where:
; h$ = the haystack, the searched string,
; with the following structure:
; every 8-bit key precedes its associated
; 8-bit value.
; k = the key to be searched for
; lookup8 = address of the machine code routine
; Example of a key translation table:
; LET t$=CHR$ 200 + CHR$ 160 + CHR$ 203 + CHR$ 162
; LET key=FN f(t$,key)
; WARNING: As explained above, the haystack string must consist
; of pairs of chars. When the string is not well formed (for
; example, any single character is missing), the end check will
; fail and strange things will happen.
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN i(h$,n) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 f(
; +00 h$
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string length, LSB first]
; +08 ,
; +09 k
; +10 14
; +11 0
; +12 [sign byte: 0=positive; 255=negative]
; +13 [16-bit number, LSB first]
; +15 0
; +16 )=
; --------------------------------------------------------------
; History of this file
; 2015-03-01: First version (started with the code of
; <fn_lookup16.z80s>).
;
; 2015-08-10: Revision. License.
;
; 2015-08-13: Fixed typo in the usage instructions. Thanks Derek
; (http://www.worldofspectrum.org/forums/discussion/comment/831230/#Comment_831230).
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_lookup8,fn_lookup8_size
fn_lookup8:
local check
local next
local found
; ..............................
; System variables
local DEFADD
DEFADD equ 23563
; ..............................
; Parameters
ld ix,(DEFADD)
ld c,(ix+6)
ld b,(ix+7)
; bc = len of h$
ld a,b
or c ; is h$ empty?
ret z ; if so, back to BASIC (the function returns 0)
ld l,(ix+4)
ld h,(ix+5)
; hl = start of h$
ld e,(ix+13)
; e = k
; ..............................
check:
; Check the current key
; hl = address of the current key
; e = key searched for
ld a,(hl)
cp e
inc hl
jr z,found
next:
; hl = address of the current value
; bc = remaining length
inc hl ; hl = address of the next key
dec bc
dec bc ; bc = remaining chars
ld a,b
or c ; end of the haystack?
ret z ; if so, back to BASIC (the function returns 0)
jr check
found:
; The key was found
; hl = address of the current value
ld c,(hl)
ld b,0
; bc = value
ret ; back to BASIC (the function returns the value)
fn_lookup8_size: equ $-fn_lookup8
endp
; vim: textwidth=64
; fn_peekcs.z80s
;
; PEEKC$ BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a PEEKC$ function to Sinclair BASIC. PEEKC$
; gets a counted string from memory. A counted string stores its
; length in its first byte (the length does not include the
; count byte itself). This is the usual format used by the
; Forth language.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this
; way (the actual names are unimportant):
; 10 DEF FN p$(a)="" AND USR peekcs
; Where:
; a = address of the string (whose first byte holds the length)
; peekcs = address of the machine code routine
; Example:
; PRINT FN p$(filename)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN p$(a) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 p$(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +08 )=
; --------------------------------------------------------------
; History of this file
; 2015-01-22: Written.
;
; 2015-02-10: Typo.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_peekcs,fn_peekcs_size
fn_peekcs:
; ..............................
; System variables
local DEFFADD
DEFADD equ 23563
; ..............................
; ROM routines
local STK_STORE
STK_STORE equ 0x2ab6
; Input:
; A = flag
; DE = string address
; BC = string length
; ..............................
; Start
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = counted string address
ld c,(hl)
ld b,0
; bc = string length
inc hl
ex de,hl
; de = string address
xor a
; a = 0 (=new string)
call STK_STORE
rst 0x28 ; calculator
db 0x17 ; concatenate to the empty string in the DEF FN expression
db 0x38 ; end
ret
fn_peekcs_size equ $-fn_peekcs
endp
; vim: textwidth=64
; fn_peeko.z80s
;
; PEEKO BASIC function for ZX Spectrum
; Version B-00-20150225
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a PEEKO function to Sinclair BASIC, that fetchs
; an 8-bit value from a memory address and an offset.
;
; Note: this function was written just to confirm that it's
; slower than its plain BASIC equivalent:
;
; LET n=PEEK (a+o)
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this
; way (the actual names are unimportant):
; 10 DEF FN f(a,o)=USR peeko
; Where:
; a = base address to peek
; o = offset
; peeko = address of the machine code routine
; Example:
; PRINT FN f(1887,12)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN f(a,o) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 f
; -01 (
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 o
; +09 14
; +10 0
; +11 [sign byte: 0=positive; 255=negative]
; +12 [16-bit number, LSB first]
; +14 0
; +15 )=
; --------------------------------------------------------------
; History of this file
; 2015-02-25: Written. Useless: this method is slower than 'LET
; n=PEEK (a+o)'.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_peeko,fn_peeko_size
fn_peeko:
local DEFADD
DEFADD equ 23563 ; system variable
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = base address
ld e,(ix+12)
ld d,(ix+13)
; de = offset
add hl,de
ld c,(hl)
ld b,0
; bc = value, returned by USR
ret
fn_peeko_size equ $-fn_peeko
endp
; vim: textwidth=64
; fn_peeks.z80s
;
; PEEK$ BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a PEEK$ function to Sinclair BASIC. PEEK$ gets
; a string from memory.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this way
; (the actual names are unimportant):
; 10 DEF FN p$(a,l)="" AND USR peeks
; Where:
; a = address of the first char of the string
; l = length of the string
; peeks = address of the machine code routine
; Example:
; PRINT FN p$(filename,10)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN p$(a,l) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 p$(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 l
; +09 14
; +10 0
; +11 [sign byte: 0=positive; 255=negative]
; +12 [16-bit number, LSB first]
; +14 0
; +15 )=
; --------------------------------------------------------------
; History of this file
; 2015-01-22: Written.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_peeks,fn_peeks_size
fn_peeks:
; ..............................
; System variables
local DEFFADD
DEFADD equ 23563
; ..............................
; ROM routines
local STK_STORE
STK_STORE equ 0x2ab6
; Input:
; A = flag
; DE = string address
; BC = string length
; ..............................
; Start
ld ix,(DEFADD)
ld e,(ix+4)
ld d,(ix+5)
; de = string address
ld c,(ix+12)
ld b,(ix+13)
; bc = string length
xor a
; a = 0 (=new string)
call STK_STORE
rst 0x28 ; calculator
db 0x17 ; concatenate to the empty string in the DEF FN expression
db 0x38 ; end
ret
fn_peeks_size equ $-fn_peeks
endp
; vim: textwidth=64
; fn_pokeo.z80s
;
; POKEO BASIC function for ZX Spectrum
; Version B-00-20150122
; --------------------------------------------------------------
; Author
; Copyright (C) 2015 Marcos Cruz (programandala.net)
; --------------------------------------------------------------
; Description
; This code adds a POKEO function to Sinclair BASIC, that stores
; an 8-bit value into a memory address calculated from a base
; address and an offset.
;
; Note: this function was written just to confirm that it's
; slower than its plain BASIC equivalent:
; POKE a+o,n
; --------------------------------------------------------------
; Usage
; A function must be defined this way
; (the actual names are unimportant):
; 10 DEF FN f(a,o,n)=USR pokeo
; Where:
; a = base address to poke into
; o = offset from the base address
; n = 8-bit number to poke
; pokeo = address of the machine code routine
; Example:
; RANDOMIZE FN f(16384,12,15)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN f(a,o,n) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 f(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 o
; +09 14
; +10 0
; +11 [sign byte: 0=positive; 255=negative]
; +12 [16-bit number, LSB first]
; +14 0
; +15 ,
; +16 n
; +17 14
; +18 0
; +19 [sign byte: 0=positive; 255=negative]
; +20 [16-bit number, LSB first]
; +22 0
; +23 )=
; --------------------------------------------------------------
; History
; 2015-02-25: Written. Useless: this method is slower than 'POKE
; a+o,n'.
;
; 2015-02-27: Improved comment.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_pokeo,fn_pokeo_size
fn_pokeo:
local DEFADD
DEFADD equ 23563 ; system variable
ld ix,(DEFADD)
ld l,(ix+4)
ld h,(ix+5)
; hl = base address
ld e,(ix+12)
ld d,(ix+13)
; de = offset
add hl,de
; hl = address
ld a,(ix+20)
ld (hl),a
ret
fn_pokeo_size equ $-fn_pokeo
endp
; vim: textwidth=64
; fn_pokes.z80s
;
; POKE$ BASIC command for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a POKE$ command to Sinclair BASIC. POKE$
; pokes a string into a memory address.
; --------------------------------------------------------------
; Usage
; A BASIC a function must defined this way
; (the actual names are unimportant):
; 10 DEF FN p$(a,s$)=USR pokes
; Where:
; a = address to poke into
; s$ = string to poke
; pokes = address of the machine code routine
; Example:
; RANDOMIZE FN p$(16384,"Saluton!")
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN p$(a,s$) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 p$(
; +00 a
; +01 14
; +02 0
; +03 [sign byte: 0=positive; 255=negative]
; +04 [16-bit number, LSB first]
; +06 0
; +07 ,
; +08 s$
; +10 14
; +11 [string type]
; +12 [string address, LSB first]
; +14 [string length, LSB first]
; +16 )=
; --------------------------------------------------------------
; History of this file
; 2014-08-08: Written.
;
; 2014-08-10: New: 'proc', 'local' and 'public', in order to
; make it possible to combine several modules into a single
; file.
;
; 2015-01-22: Some typos fixed. Renamed from "fn_poke.z80s" to
; "fn_pokes.z80s". Some changes for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_pokes,fn_pokes_size
fn_pokes:
; ..............................
; System variables
local DEFADD
DEFADD equ 23563
; ..............................
ld ix,(DEFADD)
ld c,(ix+14)
ld b,(ix+15)
; bc = string length
ld a,b
or c
; z = empty string?
ret z
ld l,(ix+12)
ld h,(ix+13)
; hl = string address
ld e,(ix+4)
ld d,(ix+5)
; de = destination address
ldir
ret
fn_pokes_size equ $-fn_pokes
endp
; vim: textwidth=64
; fn_string.z80s
;
; STRING$ BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Authors and license
; 1987-12:
; The original code was published in Microhobby Especial, issue 7,
; page 56, by unknown author:
; http://microhobby.org/
; http://microhobby.speccy.cz/mhf/MHEs7/mhes7_56.jpg
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; Typed, translated and commented the code,
; and finally adapted if to the Pasmo assembler.
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a STRING$ function to Sinclair BASIC. STRING$
; produces a specified number of repeats of a string expression.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this
; way (the actual names are unimportant):
; 10 DEF FN s$(s$,n)="" AND USR string
; Where:
; s$ = string expression to be repeated
; n = repetitions
; string = address of the machine code routine
; Example:
; PRINT FN s$("Saluton! ",3)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN s$(s$,n) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 s$(
; +00 s$
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string length, LSB first]
; +08 ,
; +09 n
; +10 14
; +11 0
; +12 [sign byte: 0=positive; 255=negative]
; +13 [16-bit number, LSB first]
; +15 0
; +16 )=
; --------------------------------------------------------------
; History of this file
; 2014-08-07: Written.
;
; 2014-08-10: New: 'proc', 'local' and 'public', in order to
; make it possible to combine several modules into a single
; file.
;
; 2014-12-14: Internal description finished.
;
; 2015-01-22: Some changes for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_string,fn_string_size
fn_string:
local copy
local exit
; ..............................
; System variables
local DEFFADD
DEFADD equ 23563
; ..............................
; ROM routines
local STK_STORE
STK_STORE equ 0x2ab6
; Input:
; A = flag
; DE = string address
; BC = string length
local STK_FETCH
STK_FETCH equ 0x2bf1
; Output:
; A = flag
; DE = string address
; BC = string length
local HLHLDE
HLHLDE equ 0x30a9 ; HL=HL*DE
; ..............................
; Start
ld ix,(DEFADD)
ld e,(ix+6)
ld d,(ix+7)
; de = string length
push de
ld l,(ix+13)
ld h,(ix+14)
; hl = number
push hl
call HLHLDE
ld c,l
ld b,h
xor a
; a = 0 (=new string)
; de = string address, undetermined
; bc = length of the new string
call STK_STORE
rst 0x28 ; calculator
db 0x17 ; concatenate to the empty string in the DEF FN expression
db 0x31 ; duplicate
db 0x38 ; end
call STK_FETCH
; de = result string address
; bc = result string length
ld l,(ix+4)
ld h,(ix+5)
; hl = parameter string address
pop ix ; parameter number
pop bc ; parameter string length
; ..............................
copy:
; de = result string address (updated by ldir after every copy)
; hl = parameter string address
; bc = parameter string length
; ix = counter of copies still to be done
ld a,ixh
or ixl
; z = ixl=0?
jr z,exit
dec ix
push hl
push bc
ldir ; copy the parameter string to the current position of the result string
pop bc
pop hl
jr copy
; ..............................
exit:
ld bc,1
ret
fn_string_size equ $-fn_string
endp
; vim: textwidth=64
; fn_termn.z80s
;
; A database BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a function to Sinclair BASIC that returns the
; n-th term (1 is the first one) in a given list of terms.
; --------------------------------------------------------------
; Usage
; A BASIC function must be defined this way:
; (the actual names are unimportant):
; 10 DEF FN t$(h$,n)="" AND USR termn
; Where:
; h$ = the haystack, the searched string,
; with the following structure:
; every term is prefixed by byte 0, and followed
; by byte 14 and an id byte.
; Example of how a single term could be built:
; let t$=chr$ 0+"term1"+chr$14+chr$ id1
; n = the ordinal number of the term that will be returned
; termn = address of the machine code routine
; Example for a text adventure, where n$ holds a list of noun terms:
; PRINT FN t$(n$,3)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN i(h$,n) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 t$(
; +00 h$
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string length, LSB first]
; +08 ,
; +09 n
; +10 14
; +11 0
; +12 [sign byte: 0=positive; 255=negative]
; +13 [16-bit number, LSB first]
; +15 0
; +16 )=
; --------------------------------------------------------------
; History of this file
; 2014-08-08: Started, with the code of <fn_term.z80s>.
;
; 2014-08-10: New: 'proc', 'public' and 'local', in order to
; make it possible to combine several modules into a single
; file.
;
; 2015-01-22: Some typos fixed. Improved description and usage.
; Some changes for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_termn,fn_termn_size
fn_termn:
local exit
local haystack_char
local needle_char
local needle_end
local needle_found
local next_haystack_char
; ..............................
; System variables
local DEFADD
DEFADD equ 23563
; ..............................
; ROM routines
local STK_STO_$
STK_STO_$ equ 0x2ab2
local STK_STORE
STK_STORE equ 0x2ab6
; Input:
; A = flag
; DE = string address
; BC = string length
; ..............................
; Start
; hl' must be preserved!
; The only mention I've found about this issue is in
; Ian Logan's book "Understanding You Spectrum", 1982, page 43.
exx
push hl
; ..............................
; Parameters
ld ix,(DEFADD)
ld bc,0 ; term counter
ld l,(ix+13)
ld h,(ix+14)
; hl = n
ld a,h
or l
; z = is n zero?
jr z,exit
exx
ld c,(ix+6)
ld b,(ix+7)
; bc = len of h$
ld a,b
or c
; z = is h$ empty?
jr z,exit
ld l,(ix+4)
ld h,(ix+5)
; hl = start of h$
; ..............................
haystack_char:
; Check the current char of h$.
; hl = address of the current char in h$
ld a,(hl)
and a
; z = zero char found?
jr z,needle_found
next_haystack_char:
; hl = address of the current char in h$
; bc = remaining length of h$
inc hl
dec bc
ld a,b
or c
; z = is the haystack exhausted?
jr z,exit
jr haystack_char
; ..............................
needle_found:
; A zero byte has been found in h$;
; it's the marker of a new term.
; But is it the term searched for?
exx
; hl = n
; bc = term count
inc bc
ld d,h
ld e,l
; cy = 0 (because of the 'and a' above)
sbc hl,bc ; is this term the n term?
ld h,d
ld l,e
exx
; z = is this term the n term?
jr nz,next_haystack_char
; ..............................
; The desired n term has been found.
; Now its length has to be calculated.
ld bc,0 ; length of the term
needle_char:
; hl = address of the current char in h$
inc hl
ld a,(hl)
cp 14 ; is it the end of the needle string?
; z = end of string found?
jr z,needle_end
inc bc
jr needle_char
; ..............................
needle_end:
; The end of the n term has been found. In order to return it
; to BASIC, it has to be pushed onto the calculator stack, and
; added to the empty string already there.
; hl = address after the last char of the needle
; bc = length of the n term
sbc hl,bc
ld d,h
ld e,l
xor a
; a = 0 (=new string)
; de = address of the first char of the needle
; bc = length of the needle
call STK_STO_$
rst 0x28 ; calculator
db 0x17 ; concatenate it to the empty string in the DEF FN expression
db 0x38 ; end
ld bc,1 ; to be ANDed with the string
exit:
; bc = 1 (valid string returned) or 0 (empty string returned)
; hl' must be restored
pop hl
push bc
exx
pop bc
ret
fn_termn_size equ $-fn_termn
endp
; vim: textwidth=64
; fn_term.z80s
;
; A database BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
;
; Based on code written by Ricardo Serrial Wigge, published in:
; Microhobby magazine, issue 77 (1986-05-06), pages 22-24:
; http://microhobby.org/
; http://microhobby.speccy.cz/mhf/077/MH077_22.jpg
; http://microhobby.speccy.cz/mhf/077/MH077_23.jpg
; http://microhobby.speccy.cz/mhf/077/MH077_24.jpg
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a function to Sinclair BASIC that
; returns the identifier of a given term in a list of terms.
; --------------------------------------------------------------
; Usage:
;
; A BASIC function must be defined this way
; (the actual names are unimportant):
; 10 DEF FN t(h$,n$)=USR term
; Where:
; h$ = the haystack, the searched string,
; with the following structure:
; every term is prefixed by byte 0, and followed
; by byte 14 and an id byte.
; Example of how a single term could be built:
; let t$=chr$ 0+"term1"+chr$14+chr$ id1
; n$ = the needle, the string to be searched for
; (it must include the starting byte 0 and the
; ending byte 14).
; term = address of the machine code routine
; Example for a text adventure, where v$ holds a list of verb terms:
; PRINT FN t(v$,CHR$ 0+"examine"+CHR$ 14)
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN i(h$,n$) is the following:
; offset content
; ------ -------
; -03 DEF FN
; -02 t(
; +00 h$
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string length, LSB first]
; +08 ,
; +09 n$
; +11 14
; +12 [string type]
; +13 [string address, LSB first]
; +15 [string length, LSB first]
; +17 )=
; --------------------------------------------------------------
; History of this file
; 2014-08-07: Started, with the code of <fn_instr1.z80s>.
;
; 2014-08-10: Removed unnecessary saving and restoring of
; registers. New: 'proc', 'local' and 'public', in order to
; make it possible to combine several modules into a single
; file.
;
; 2014-08-11: A bug was introduced by trying to reduce the
; number of jumps.
;
; 2014-08-12: The bug was fixed by comparing with the previous
; version A-00-201408071702.
;
; 2014-08-13: Simpler 'not_found' exit point, no jump.
;
; 2015-01-22: Some typos fixed. Improved description and usage.
; Some changes for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_term,fn_term_size
fn_term:
local again
local found
local haystack_exhausted
local match
local not_found
local needle_exhausted
; ..............................
; System variables
local DEFADD
DEFADD equ 23563
; ..............................
; Parameters
ld ix,(DEFADD)
ld a,(ix+6)
or (ix+7) ; empty string?
jr z, not_found
ld e,(ix+4)
ld d,(ix+5)
; de = address of h$
ld l,(ix+6)
ld h,(ix+7)
; hl = length of h$
add hl,de
; hl = address after the end of h$
; Use ix+6 as temporary storage
ld (ix+6),l
ld (ix+7),h
ld l,e
ld h,d
; hl = address of h$
; ..............................
again:
; Start searching h$ for n$ from the current position of h$
ld e,(ix+13)
ld d,(ix+14)
dec de
; de = address of n$ -1
ld c,(ix+15)
ld b,(ix+16)
; bc =length of n$
; ..............................
match:
; Keep on searching h$
inc de
; de = address of current char of n$
; hl = address of current char of h$
ld a,(de)
cpi ; compare a with (hl) and increment hl
ex af,af'
push hl
push de
ld e,(ix+6)
ld d,(ix+7)
; de = address after the end of h$
and a
sbc hl,de
; z = last char of h$?
pop de
pop hl
jr z,haystack_exhausted
ld a,b
or c
; z = last char of n$?
jr z,needle_exhausted
ex af,af'
; z = (hl)=(de)?
jr z,match
jr again
; ..............................
needle_exhausted:
ex af,af'
; z = (hl)=(de)?
jr nz,again
jr found
; ..............................
haystack_exhausted:
ld a,b
or c
; z = bc=0?
jr nz,not_found
ex af,af'
; z = (hl)=(de)?
jr z,found
; ..............................
not_found:
ld bc,0
ret
; ..............................
found:
; hl = address after the last char of n$ in h$
ld b,0
ld c,(hl) ; take the term id
ret
fn_term_size equ $-fn_term
endp
; vim: textwidth=64
; fn_trunc.z80s
;
; TRUNC$ BASIC function for ZX Spectrum
; Version B-00-20150122
; This file is part of DEFFNder:
; http://programandala.net/en.program.deffnder.html
; --------------------------------------------------------------
; Author and license
; Copyright (C) 2014,2015 Marcos Cruz (programandala.net)
; You may do whatever you want with this work, so long as you
; retain the copyright notice(s) and this license in all
; redistributed copies and derived works. There is no warranty.
; --------------------------------------------------------------
; Description
; This code adds a TRUNC$ function to Sinclair BASIC, to strip
; the trailing spaces of a string.
; --------------------------------------------------------------
; Usage
; The routine is called from BASIC using a function defined this way:
; (the actual names are unimportant):
; 10 DEF FN t$(s$)="" AND USR trunc
; Where:
; s$ = string to trunc
; trunc = address of the machine code routine
; Example:
; PRINT FN t$("En vilagxo de La Mancxo ")
; --------------------------------------------------------------
; Internal
; During the execution of a FN, the system variable DEFADD holds
; the address of the first parameter of its DEF FN definition
; (the first address after the opening paren). The structure of
; DEF FN t$(s$) is the following:
; offset content
; ------ -------
; -04 DEF FN
; -03 t$(
; +00 s$
; +02 14
; +03 [string type]
; +04 [string address, LSB first]
; +06 [string lenght, LSB first]
; +08 )=
; --------------------------------------------------------------
; History of this file
; 2014-08-06: Start.
;
; 2014-08-07: Finished.
;
; 2014-08-10: Removed unnecessary saving and restoring of
; registers. New: 'proc', 'public' and 'local', in order to
; make it possible to combine several modules into a single
; file.
;
; 2015-01-22: Some changes for publication. Version B-00.
;
; 2015-02-27: Improved comment.
;
; 2015-08-10: Revision. License.
; --------------------------------------------------------------
proc
; The code is relocatable
public fn_trunc,fn_trunc_size
fn_trunc:
local exit
local truncate
local truncated
; ..............................
; System variables
local DEFADD
DEFADD equ 23563
; ..............................
; ROM routines
local STK_STORE
STK_STORE equ 0x2ab6
; Input:
; A = flag
; DE = string address
; BC = string lenght
; ..............................
; Parameters
ld ix,(DEFADD)
ld c,(ix+6)
ld b,(ix+7)
; bc = string lenght
ld a,b
or c
; z = empty string?
jr z, exit
ld l,(ix+4)
ld h,(ix+5)
; hl = string address
add hl,bc
; hl = address after the last char of the string
; ..............................
truncate:
; bc = counter, remaining chars
dec hl
; hl = address of the current char
ld a,(hl)
cp " "
; z=space?
jr nz,truncated
dec bc
ld a,b
or c
; z=end of the string?
jr nz,truncate
; ..............................
truncated:
; bc = string lenght without the trailing spaces
ld e,(ix+4)
ld d,(ix+5)
; de = string address
xor a ; a = 0 (=new string)
call STK_STORE
rst 0x28 ; calculator
db 0x17 ; concatenate to the empty string in the DEF FN expression
db 0x38 ; end
; ..............................
exit:
ld bc,1
ret
fn_trunc_size equ $-fn_trunc
endp
; vim: textwidth=64
Download
Also: DEFFNder in Github.