DEF FN small self test

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
C.Born
Manic Miner
Posts: 255
Joined: Sat Dec 09, 2017 4:09 pm

DEF FN small self test

Post by C.Born »

Hi

its a side project for creating that zx0 in zx itself. if i want to use DEF FN as a subtitue for an C_file on a command line the coding off the DEF FN has to be copied to the C_file

this is a start:

Code: Select all


; DEF FN small self test

; DEFselftst_030
; pasmo -d --tap --name DEFselftst DEFselftst_030.asm DEFselftst_030.tap DEFselftst_030.symbol
; cat DEFselftst2.tap DEFselftst_030.tap > DEFtest_030.tap

; NO ORG > 100% relocatable IF FINISED and without the 'print'

; 10 DEF FN a(a,b,c,d,e,f,g,h,i,j)= USR selftest
; 20 DEF FN a$(a,b,c,d,e,f,g,h,i,j)=STR$ USR selftest
; 25 REM df needs SOME string instruction on BOTH sides to be accepted by the Basic interpreter
; 30 LET l= FN a(1,2,3,4,5,6,7,8,9,0)
; 40 LET l$= FN a$(1,2,3,4,5,6,7,8,9,0)

; print routine can be removed after prove-of-works
print equ 1

setchan       equ 0x1601   ; ROM openchannel routine for #0 and #2

DEF_ADR       equ 23563    ; sysvar

here equ 25500


              org here

USR           di
              push bc             ; THIS=USR adres to stack
              exx
              pop bc
              push hl
              push bc             ; THIS=USR adres to stack
              jr overdata

amount        defb 0
name          defb 32,32,13,255      ; name$ 2 bytes, 'a ' or 'a$' + /0

overdata      pop de  ; USR adres to DE

             ld hl,9
             add hl,de
             ex de,hl ;  DE should point to 'name'

              ld hl,(DEF_ADR)     ; hl = actual RAM location in BASIC listing at position off the DEF FN
              ld bc,5
              ld a,206            ; = 'DEF FN'
              cpdr                ; lower until DEF FN found

              inc hl              ; 1 step for last result

              inc hl              ; 1 step for chr$
              ld a,(hl)           ; fetch DEF chr$ as NAME
              ld (de),a           ; store chr$ in 'name'
IF print
              rst 16
ENDIF
              inc hl              ;
              ld a,(hl) 
              cp '$'              ; test for string value
              jr nz,count0        ; $+4

              inc de              ; adres for '$' if found
              ld a,(hl)
              ld (de),a           ; store $ aswell
IF print
              rst 16
ENDIF
              dec de              ; step back to 'name'
              inc hl              ; step over '$'

count0        dec de              ; de= 'amount'
              ex de,hl
              ld (hl),1
;              inc (hl)            ; amount+1 > the namestring is 1st variable of argc > arg[0] is filename
              ex de,hl

firstbracket: ld a,(hl)           ; reload DEF data

IF print
              rst 16
              ld a,(hl)
ENDIF

              cp '('
              jr nz,error         ; not a correct DEF FN

testend       inc hl              ; +1
              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp ')'              ; if 1st value is a CLOSE bracket NO VARIABLES are included !!!
                                  ; then DEF FN might have no extra functionality for the USR command
              jr z,closed
 
notyet:       cp 123              ;    'z+1'
              jr nc,error         ;    to big

              cp 56               ;    'A'
              jr c,error          ;     to small
                                  ;  fetch variable chr$name here if needed!!
                                  ;  how? is yr own problem!!

              inc hl              ; +1
              ld a,(hl)
              cp 14               ; only THEN its a 1+5 notation value start marker
              jr nz,error         ; no marker found
 
            ; correct internal DEF FN variable found
              ld bc,6             ; +6
              add hl,bc           ; raise 6 bytes to step over value

              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp ','
              jr nz,error

count1        ex de,hl
              inc (hl)            ; amount+1 > the namestring is 1st variable of argc > arg[0] is filename
              ex de,hl
              jr testend

closed        inc hl
              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp '='
              jr z,done
error         ld bc,65535        ; make here an error message ??
              
done:         ld (errr),bc
              call write
              pop hl
              exx
              ei
              ret










write         
              ld a,(de)
              ld l,a
              call dec_number

              ld a,2
              call setchan
              ld a,13
              rst 16
              ld hl,name
              call ploop
              ld hl,number_str
              call ploop
              ret


ploop:        ld a,(hl)
              cp 0xFF
              ret z
              inc hl        
              rst 16
              jr ploop


;http://zxm.speccy.cz/data/Z80%20Bits.html#5.1
; Input: HL = number to convert, DE = location of ASCII string
;Output: ASCII string at (DE) ,0 fast 99 super long in TSTATE, its a 'rotator'
dec_number      ld h,0   ; cut h for 8bit handeling, yet 5 digits in 0's used
          	ld de,number_str
Num2Dec5        ld bc,-10000
	        call Num1
Num2Dec4        ld bc,-1000
	        call Num1
Num2Dec3        ld bc,-100  ;10t
                call Num1   ;17+
Num2Dec2        ld bc,-10   ;10t  2 digits only
                call Num1   ;17+
                ld c,b      ; 4t  0xffff = -1 in 2complement

Num1	        ld a,"0"-1 ; 7t
Num2	        inc a      ;/ 4t
	        add hl,bc  ;/ 7t  add a negative number, CARRY influenced
	        jr c,Num2  ;/12t-5  /(x*(4+7+12)-5) 0=((23))-5   ,9=(10*(23))-5
	        sbc hl,bc  ;15t 
	        ld (de),a  ; 7t
	        inc de     ; 6t
                ret        ;10t


number_str    defb 32,32,32,32,32,255
errr          defw 0

END here
C.Born
Manic Miner
Posts: 255
Joined: Sat Dec 09, 2017 4:09 pm

Re: DEF FN small self test

Post by C.Born »

cp 56 ; 'A'

must be
cp 65 ; 'A'
User avatar
ParadigmShifter
Dynamite Dan
Posts: 1006
Joined: Sat Sep 09, 2023 4:55 am

Re: DEF FN small self test

Post by ParadigmShifter »

Why not do

cp 'A' ; cp 'A'

:geek:

which works on every assembler I have used (although you still developing on the speccy?)

EDIT: Obvs that will work you're literally using cp '=' and stuff already ;)

EDIT2: All assemblers I have used also support stuff like

cp 'Z'+1

although that may not be supported by speccy assemblers I guess.

EDIT3:

ld a,206 ; = 'DEF FN'

why not

DEF_FN EQU 206

ld a, DEF_FN

as well. Your code will be more readable and comments won't be needed as much.

Final EDIT: So moral of this post is magic numbers are bad... 'A' is much better than 65, DEF_FN is much better than 206, 'z'+1 is much better than 123, etc.

Don't go mad and do ZERO EQU 0 though lol ;)
Dr beep
Manic Miner
Posts: 386
Joined: Mon Oct 01, 2018 8:53 pm

Re: DEF FN small self test

Post by Dr beep »

I don't think you need to test he "(" in DEF FN since the BASIC does the syntaxcheck on entry.
C.Born
Manic Miner
Posts: 255
Joined: Sat Dec 09, 2017 4:09 pm

Re: DEF FN small self test

Post by C.Born »

Thank you doctor, i need a prescription for new glasses actualy.

i mix up notation the long my mind moves, apperently. i should be more conseqent and then probably have less errors my self.
i dont know if eg Tornado handles 'A', i have to start a disk for that. it does not use undocumented code, but i almost never do so myself.

i state the max length of a def fn is 26 but infact its possible to have DEFN with (a,a,a,a,a) its just accepted aslong as its only 1 character or character$
C.Born
Manic Miner
Posts: 255
Joined: Sat Dec 09, 2017 4:09 pm

Re: DEF FN small self test

Post by C.Born »

at the moment this is the result

Code: Select all

;  10 DEF FN a(a,b,c,d,e,f,g,h,i,j)=USR t
;  20 DEF FN a$(a,b,c,d,e,f,g,h,i,j)=STR$ USR t
;  25 DEF FN b$(a$,b,c,d$,e,f,g,h$,i,j)=STR$ USR t
;  30 CLEAR VAL "25499": LET t=VAL "25500": LOAD ""CODE t
;  40 PRINT FN a(1,2,3,4,5,6,7,8,9,0)'
;  50 PRINT FN a$(1,2,3,4,5,6,7,8,9,0)'
;  55 LET x$="hallo"
;  60 PRINT FN b$(x$,2,3,"444",5,6,7,x$,9,0)'


; a(a,b,c,d,e,f,g,h,i,j)
; a
; 00010 5174

; a$(a,b,c,d,e,f,g,h,i,j)
; a$
; 00010 4379

; b$(a
; b$
; 00001 3611
as soon as a string is inside it stops the checking but does NOT give a 65535 error
C.Born
Manic Miner
Posts: 255
Joined: Sat Dec 09, 2017 4:09 pm

Re: DEF FN small self test

Post by C.Born »

I had in mind that the string part for the internal variable was hidden INSIDE the 1+4 mantise but it aint
its a real '$' inside, which make the solution much simpler:

Code: Select all


; DEF FN small self test

; nDEFFNtst_033
; pasmo -d --tap --name nDEFFNtst nDEFFNtst_033.asm nDEFFNtst_033.tap nDEFFNtst_033.symbol
; cat nDEFtest_bas.tap nDEFFNtst_033.tap > nDEFtest_033.tap

; NO ORG > 100% relocatable IF FINISED and without the 'print'


;  10 DEF FN a(a,b,c,d,e,f,g,h,i,j)=USR t
;  20 DEF FN a$(a,b,c,d,e,f,g,h,i,j)=STR$ USR t
;  25 DEF FN b$(a$,b,c,d$,e,f,g,h$,i,j)=STR$ USR t
;  30 CLEAR VAL "25499": LET t=VAL "25500": LOAD ""CODE t
;  40 PRINT FN a(1,2,3,4,5,6,7,8,9,0)'
;  50 PRINT FN a$(1,2,3,4,5,6,7,8,9,0)'
;  55 LET x$="hallo"
;  60 PRINT FN b$(x$,2,3,"444",5,6,7,x$,9,0)'


; a(a,b,c,d,e,f,g,h,i,j)
; a
; 00010 

; a$(a,b,c,d,e,f,g,h,i,j)
; a$
; 00010 

; b$(a
; b$
; 00010 


; print routine can be removed after prove-of-works
print equ 1

setchan       equ 0x1601   ; ROM openchannel routine for #0 and #2

DEF_ADR       equ 23563    ; sysvar

DEFFN         equ 206
CR            equ 13

here equ 25500


              org here

USR           di
              push bc             ; THIS=USR adres to stack
              exx
              pop bc
              push hl
              push bc             ; THIS=USR adres to stack
              jr overdata

amount        defb 0
name          defb 32,32,CR,255      ; name$ 2 bytes, 'a ' or 'a$' + /0

overdata      pop de  ; USR adres to DE

             ld hl,9
             add hl,de
             ex de,hl ;  DE should point to 'name'

              ld hl,(DEF_ADR)     ; hl = actual RAM location in BASIC listing at position off the DEF FN
              ld bc,5
              ld a,DEFFN          ; = 'DEF FN'
              cpdr                ; lower until DEF FN found

              inc hl              ; 1 step for last result

              inc hl              ; 1 step for chr$
              ld a,(hl)           ; fetch DEF chr$ as NAME
              ld (de),a           ; store chr$ in 'name'
IF print
              rst 16
ENDIF
              inc hl              ;
              ld a,(hl) 
              cp '$'              ; test for string value
              jr nz,count0        ; $+4

              inc de              ; adres for '$' if found
              ld a,(hl)
              ld (de),a           ; store $ aswell
IF print
              rst 16
ENDIF
              dec de              ; step back to 'name'
              inc hl              ; step over '$'

count0        dec de              ; de= 'amount'
              ex de,hl
              ld (hl),1
              ex de,hl

firstbracket: ld a,(hl)           ; reload DEF data

IF print
              rst 16
              ld a,(hl)
ENDIF

              cp '('
              jr nz,error         ; not a correct DEF FN

testend       inc hl              ; +1
              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp ')'              ; if 1st value is a CLOSE bracket NO VARIABLES are included !!!
                                  ; then DEF FN might have no extra functionality for the USR command
              jr z,closed
 
notyet:       cp 'A'              ;    'A'
              jr c,error          ;     to small

              cp 'z'+1            ;    'z+1'
              jr nc,error         ;    to big
       
                                  ;  fetch variable chr$name here if needed!!
                                  ;  how? is yr own problem!!

              and 31              ; set capitals 
              cp 'Z'+1            ;    'z+1'
              jr nc,error         ;    to big

; exx
;ld hl,(defnames)
;ld (hl),a
;inc hl
;ld (defnames),hl
; exx

              inc hl              ;
              ld a,(hl) 
              cp '$'              ; test for string value
              jr nz,n14

; exx
;ld hl,(defnames)
;ld (hl),a
;inc hl
;ld (defnames),hl
; exx

IF print
              rst 16
              ld a,(hl)
ENDIF

              inc hl              ; +1 step over internal '$'

n14           ld a,(hl)
              cp 14               ; only THEN its a 1+5 notation value start marker
              jr nz,error         ; no marker found
 
            ; correct internal DEF FN variable found
              ld bc,6             ; +6
              add hl,bc           ; raise 6 bytes to step over value

              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp ','
              jr nz,error

count1        ex de,hl
              inc (hl)            ; amount+1 > the namestring is 1st variable of argc > arg[0] is filename
              ex de,hl
              jr testend

closed        inc hl
              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp '='
              jr z,done
error         ld bc,65535        ; make here an error message ??
              
done:         ld (errr),bc
              call write
              pop hl
              exx
              ei
              ret


write         
              ld a,(de)
              ld l,a
              call dec_number

              ld a,2
              call setchan
              ld a,CR
              rst 16
              ld hl,name
              call ploop
              ld hl,number_str
              call ploop
              ld a," "
              rst 16
              ret


ploop:        ld a,(hl)
              cp 0xFF
              ret z
              inc hl        
              rst 16
              jr ploop


;http://zxm.speccy.cz/data/Z80%20Bits.html#5.1
; Input: HL = number to convert, DE = location of ASCII string
;Output: ASCII string at (DE) ,0 fast 99 super long in TSTATE, its a 'rotator'

dec_number      ld h,0   ; cut h for 8bit handeling, yet 5 digits in 0's used
          	ld de,number_str
Num2Dec5        ld bc,-10000
	        call Num1
Num2Dec4        ld bc,-1000
	        call Num1
Num2Dec3        ld bc,-100  ;10t
                call Num1   ;17+
Num2Dec2        ld bc,-10   ;10t  2 digits only
                call Num1   ;17+
                ld c,b      ; 4t  0xffff = -1 in 2complement

Num1	        ld a,"0"-1 ; 7t
Num2	        inc a      ;/ 4t
	        add hl,bc  ;/ 7t  add a negative number, CARRY influenced
	        jr c,Num2  ;/12t-5  /(x*(4+7+12)-5) 0=((23))-5   ,9=(10*(23))-5
	        sbc hl,bc  ;15t 
	        ld (de),a  ; 7t
	        inc de     ; 6t
                ret        ;10t


number_str    defb 32,32,32,32,32,255
errr          defw 0

defnames      defb 0

END here
the defnames block is a bit to much since the aim off THIS routine is to provide correct info to achieve the corresponding variables.
now i have to get this info in either HL or BC or both
but the info might be 2 or 3 bytes!
then a reference to the correct info migth be a solution OR make a trick in which eg "A" capital is a string and "a" lower case is a integer??
that probably will couse problems later, so i guess it will have to be a reference adres aka pointer to memory where the actual data STARTS
then the NEXT roitine has to deal with the "arg[x]" part
so
d_argc is mostly done now?
any arument and/or suggestion is welcome
cheers
C.Born
Manic Miner
Posts: 255
Joined: Sat Dec 09, 2017 4:09 pm

Re: DEF FN small self test

Post by C.Born »

ready for stripdown and optimisation?
had to wipe the old numbers and made a funny inc de thing, but ldir cost 2+3x3+2=13 bytes at least
the BC register is now correct loaded, i missed that too
hopefully this is now the correct off set for d_arg, so i will link it in z88dk.

https://z88dk.org/forum/viewtopic.php?p=22965#p22965

Code: Select all


; DEF FN small self test

; nDEFFNtst_041
; pasmo -d --tap --name nDEFFNtst nDEFFNtst_041.asm nDEFFNtst_041.tap nDEFFNtst_041.symbol
; cat nDEFFNbas.tap nDEFFNtst_041.tap > nDEFtest_041.tap

; NO ORG > 100% relocatable IF FINISED and without the 'print'


;  10 DEF FN a(a,b,c,d,e,f,g,h,i,j)=USR t
;  20 DEF FN a$(a,b,c,d,e,f,g,h,i,j)=STR$ USR t
;  25 DEF FN b$(a,b,c,d$,e,f,g,h$,i,j)=STR$ USR t
;  30 CLEAR VAL "25499": LET t=VAL "25500": LOAD ""CODE t
;  40 LET l=FN a(1,2,3,4,5,6,7,8,9,0): GO SUB VAL "100"
;  50 LET l=VAL (FN a$(1,2,3,4,5,6,7,8,9,0)): GO SUB VAL "100"
;  55 LET x$="hallo"
;  60 LET l=VAL (FN b$(1,2,3,"444",5,6,7,x$,9,0)): GO SUB VAL "100"
;  70 STOP 
; 100 LET l1=INT VAL "l/256": LET l2=l-l1*VAL "256": PRINT l,l1;"  ";l2: RETURN 


; print routine can be removed after prove-of-works
print equ 0

setchan       equ 0x1601   ; ROM openchannel routine for #0 and #2

DEF_ADR       equ 23563    ; sysvar

DEFFN         equ 206
CR            equ 13


here equ 25500


              org here

USR        di
              push bc             ; THIS=USR adres to stack
              exx
              pop bc
              push hl             ; save sysvar
              push bc             ; THIS=USR adres to stack
              jr overdata

amount        defb 0
name          defb 32,32,0        ; name$ 2 bytes, 'a ' or 'a$' + /0

overdata      pop de              ; USR adres to DE

              ld hl,7
              add hl,de
              ex de,hl            ;  DE should point to 'amount'

              xor a
              ld (de),a           ; wipe old data
              inc de
              ld (de),a
              inc de
              ld (de),a
              inc de
              ld (de),a
              dec de
              dec de
              dec de              ; DE should point to 'name'

              ld hl,(DEF_ADR)     ; hl = actual RAM location in BASIC listing at position off the DEF FN
              ld bc,5
              ld a,DEFFN          ; = 'DEF FN'
              cpdr                ; lower until DEF FN found

              inc hl              ; 1 step for last result

              inc hl              ; 1 step for chr$
              ld a,(hl)           ; fetch DEF chr$ as NAME
              ld (de),a           ; store chr$ in 'name'
IF print
              rst 16
ENDIF
              inc hl              ;
              ld a,(hl) 
              cp '$'              ; test for string value
              jr nz,count0        ; $+4

              inc de              ; adres for '$' if found
              ld (de),a           ; store $ aswell
IF print
              rst 16
ENDIF
              inc hl              ; step over '$'
              dec de              ; step back to 'name'

count0        dec de              ; de= 'amount'
              ex de,hl
              ld (hl),1
              ex de,hl

firstbracket: ld a,(hl)           ; reload DEF data

IF print
              rst 16
              ld a,(hl)
ENDIF

              cp '('
              jr nz,error         ; not a correct DEF FN

testend       inc hl              ; +1
              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp ')'              ; if 1st value is a CLOSE bracket NO VARIABLES are included !!!
                                  ; then DEF FN might have no extra functionality for the USR command
              jr z,closed
 
notyet:       cp 'A'              ;    'A'
              jr c,error          ;     to small

              cp 'Z'+1            ;    'z+1'
              jr c,good           ;

              cp 'a'
              jr c,error          ;     to small

              cp 'z'+1            ;    'z+1'
              jr nc,error           ;
                                  ;  fetch variable chr$name here if needed!!
                                  ;  how? is yr own problem!!

good:

; exx
;ld hl,(defnames)
;ld (hl),a
;inc hl
;ld (defnames),hl
; exx

              inc hl              ;
              ld a,(hl) 
              cp '$'              ; test for string value
              jr nz,n14

; exx
;ld hl,(defnames)
;ld (hl),a
;inc hl
;ld (defnames),hl
; exx

IF print
              rst 16
              ld a,(hl)
ENDIF

              inc hl              ; +1 step over internal '$'

n14           ld a,(hl)
              cp 14               ; only THEN its a 1+5 notation value start marker
              jr nz,error         ; no marker found
 
            ; correct internal DEF FN variable found
              ld bc,6             ; +6
              add hl,bc           ; raise 6 bytes to step over value

              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp ','
              jr z,count1

              cp ')'
              jr z,closed
              jr error

count1        ex de,hl
              inc (hl)            ; amount+1 > the namestring is 1st variable of argc > arg[0] is filename
              ex de,hl
              jr testend

closed        ld a,(de)
              ld b,a
              inc de
              ld a,(de)
              ld c,a

              inc hl
              ld a,(hl)
IF print
              rst 16
              ld a,(hl)
ENDIF
              cp '='
              jr z,done
error         ld bc,65535        ; make here an error message ??
              
done:         ld (errr),bc
IF print
              call write
ENDIF
              pop hl
              exx
              ld bc,(errr)
              ei
              ret

IF print
write         
              ld a,(de)
              ld l,a
              call dec_number

              ld a,2
              call setchan
              ld a,CR
              rst 16
              ld hl,name
              call ploop
              ld hl,number_str
              call ploop
              ld a," "
              rst 16
              ret


ploop:        ld a,(hl)
              and a
              ret z
              inc hl        
              rst 16
              jr ploop
number_str    defb 32,32,32,32,32,0

;http://zxm.speccy.cz/data/Z80%20Bits.html#5.1
; Input: HL = number to convert, DE = location of ASCII string
;Output: ASCII string at (DE) ,0 fast 99 super long in TSTATE, its a 'rotator'

dec_number      ld h,0   ; cut h for 8bit handeling, yet 5 digits in 0's used
          	ld de,number_str
Num2Dec5        ld bc,-10000
	        call Num1
Num2Dec4        ld bc,-1000
	        call Num1
Num2Dec3        ld bc,-100  ;10t
                call Num1   ;17+
Num2Dec2        ld bc,-10   ;10t  2 digits only
                call Num1   ;17+
                ld c,b      ; 4t  0xffff = -1 in 2complement

Num1	        ld a,"0"-1 ; 7t
Num2	        inc a      ;/ 4t
	        add hl,bc  ;/ 7t  add a negative number, CARRY influenced
	        jr c,Num2  ;/12t-5  /(x*(4+7+12)-5) 0=((23))-5   ,9=(10*(23))-5
	        sbc hl,bc  ;15t 
	        ld (de),a  ; 7t
	        inc de     ; 6t
                ret        ;10t
ENDIF


errr            defw 0     ; !!! needed


END here
Post Reply