DEFFNder

Descripción del contenido de la página

Biblioteca de funciones para Sinclair BASIC escritas en Z80.

Etiquetas:

DEFFNder es una pequeña biblioteca de funciones para Sinclair BASIC escritas en Z80. Hasta el momento contiene 20 funciones. Las empecé a escribir para un proyecto escrito en Sinclair BASIC. Cuatro de ellas están basadas en código publicado en Microhobby en 1986 y 1987, principalmente de Ricardo Serrial Wigge (todos los detalles están en las fuentes). Cinco de ellas (y la demostración) fueron escritas y añadidas posteriormente por Derek Bolli.

Algunas de las funciones son genéricas y pueden encontrarse en otras versiones de BASIC más potentes. Otras funciones son específicas, escritas a medida para mi proyecto.

El código fuente está completamente comentado, para que sea útil para entender cómo funciona cada función, cómo modificarla y cómo escribir otras funciones nuevas.

El código de las funciones es reposicionable y está listo para ser usado. Hay más detalles en el fichero README.adoc incluido (en inglés).

Código fuente

; 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

Descarga

También: DEFFNder en GitHub.

Enlaces externos relacionados