[ASM-ZX81] How to retrieve a floating-point value from ASM.

Anything Sinclair ZX Basic related; history, development, tips - differences between BASIC on the ZX80 and ZX81
User avatar
XavSnap
Posts: 2062
Joined: Sat May 10, 2008 4:23 pm
Location: 'Zx81 France' Fb group.
Contact:

[ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by XavSnap »

Hi,

Just create a blank command LET with a value.
The machine code will copy the floating-point value to the LET command.
The text value will be ignored by the BASIC monitor.
You can take LET P=1 or P=0="." or other values between 0 to 9...
Only one character to avoid to decay the variable hidden FP value.

Code: Select all

;------- TASM ASM mnemonics. -------
; Compile this file using:
; Set TASMOPTS = -b
; tasm -80 ThisCode.tas MyBinary.BIN
;-----------------------------------
; Zx81 Program name: VB81 XuR [FP.P] :
; REM   line   name: D=16514/16568 : H=4082/40B8

#define ORG  .org       ; TASM cross-assembler definitions
#define equ  .equ

;------------------------------------
;-BASIC sub-routine entry.          -
;+----------------------------------+
; Lb4082  ;  <- USR BASIC Enty.
;+----------------------------------+

;------- Rom and Ram Symbols -------
RAM_CH_ADD equ $4016
RAM_SPARE2 equ $407B
DEC_TO_FP equ $14D9


ORG $4082 ; [@16514/@h4082]
Lb4082:
	HALT 
	HALT 
	LD HL,(RAM_CH_ADD) ; GET CH-ADD
	LD (RAM_SPARE2),HL ; SET UNUSED-16
	LD HL, Lb40A9 
	LD (RAM_CH_ADD),HL ; SET CH-ADD
	RST 18H 
	CALL DEC_TO_FP ; []*BIOS ROM*
	LD BC,$0006 
	LD HL,(RAM_SPARE2) ; GET UNUSED-16
	ADD HL,BC 
	EX DE,HL 
	DEC BC 
	SBC HL,BC 
	LDIR 
	INC BC 
	LD HL,(RAM_SPARE2) ; GET UNUSED-16
	LD (RAM_CH_ADD),HL ; SET CH-ADD
	RET ; ==========================


Lb40A9: ; Your value.
.db 3,'.',1,4,1,6,_,_; ZX-TEXT
.db _,_,_,_,_,_,_,_; ZX-TEXT

.end

Code: Select all

 # VB81 XuR [FP2LEP.bas] 
 # 
 # 1 REM:    92 Bytes@4082-40DD
1 REM [HEX:\
76,76,2A,16,40,22,7B,40,21,A9,40,22,16,40,DF,CD,\
D9,14,01,06,00,2A,7B,40,09,EB,0B,ED,42,ED,B0,03,\
2A,7B,40,22,16,40,C9,1F,1B,1D,20,1D,22,00,00,00,\
00,00,00,00,00,00,00 ]
10 IF USR 16516 THEN LET P=.
20 PRINT P
FP.P
(1014 Bytes) Downloaded 121 times
Xavier ...on the Facebook groupe : "Zx81 France"(fr)
David G
Posts: 428
Joined: Thu Jul 17, 2014 7:58 am
Location: 48 North

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by David G »

The program FP.P works perfectly

I was curious as to how it worked, so I tried typing it in, but it didn't work
Just create a blank command LET with a value.
...
You can take LET P=1 or P=0="." or other values between 0 to 9
This line works:

Code: Select all

10 IF USR 16514 THEN LET P=0
"LET P=." (a la FP2LEP.bas) doesn't work if typed in

I'm surprised enter 10 LET P=. does not result in a syntax error

another thing i've always wondered about: Why is it that a USR routine starting with HALT does not halt the system?
User avatar
XavSnap
Posts: 2062
Joined: Sat May 10, 2008 4:23 pm
Location: 'Zx81 France' Fb group.
Contact:

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by XavSnap »

Hi David,

Yes, it's a weird syntax to set a value to zero...
I seen it from a tread on the forum to save memory space, but in fact, the BASIC monitor add a hidden FP value after the point.

I had to ... run E.O. to check it !!!!
LET P=. (n/l)
PRINT P (n/l)
0
Don't know why you get an error... your "Text2P" seem to lost the FP BASIC argument!
Just edit the line, and type New/line to rebuild the line.

Don't know about the real hardware, but the BASIC seem to jump the numeric characters, and get the hidden FP.
If you enter a LET line, you should be able to poke the characters to hide the value.

1 LET P=.0000000000000000000000000000000000000000 (n/l)
2 LET P=0000000000000000000000000000000000000000.(n/l)
(All zero are displayed on the listing !)

Are Ok, but other characters like "E" (4E4) hang the BASIC ("S" cursor).
Xavier ...on the Facebook groupe : "Zx81 France"(fr)
David G
Posts: 428
Joined: Thu Jul 17, 2014 7:58 am
Location: 48 North

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by David G »

thanks for the explanation. after trying it again, i see it works as you describe


the use of the ROM to print out floating point numbers is very intriguing. I spent most of the afternoon trying to understand how it works. Eventually it began to make sense. The only thing is that negative numbers e.g. "-1" are not handled by DEC-TO-FP ??? With all positive ones it works beautifully, including "3.1415", "3E+3" and "3000000000000000". Logan says that DEC-TO-FP puts the result on the CALC stack, and it seems your code uses DE as a pointer to that value. STKBOT also points to the 5-byte floating-point valve which can then be copied


regarding the HALT instructions at the beginning of a REM machine code, they neaten LIST of wild REM M/C statements. After some experimentation today i found that in FAST mode, it permanently halts (hangs). However, in SLOW mode, the machine does not permanently halt. Perhaps it has something to do with the Interrupt system of the SLOW Display method waking the machine

Here is a method of using HALT (NEWLINE) characters -- but that will still work in FAST mode

Code: Select all

db      $7E     ;hide the next five bytes from LIST
  JR      MCR   ;skip over the HALTs to machine code routine
  NOP           ;so the machine will not HALT permanently in FAST mode
  NOP
  NOP
HALT            ;two 76H/118 NEWLINE will hide the contents of the REM
HALT            ;                    when using LIST

MCR:   ;rest of machine code routine starts here
User avatar
stefano
Posts: 592
Joined: Tue Dec 11, 2012 9:24 am
Contact:

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by stefano »

>Yes, it's a weird syntax to set a value to zero...
>I seen it from a tread on the forum to save memory space, >but in fact, the BASIC monitor add a hidden FP value after the point.

Exactly. Similarly, on a ZX Spectrum, you can use BIN without extra binary 'text', but it will append a mantissa etc. as for a numeric 0.
NOT PI or a variable is still the best choice.
David G
Posts: 428
Joined: Thu Jul 17, 2014 7:58 am
Location: 48 North

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by David G »

So by using a "hidden" LET statement...

Code: Select all

10 LET X=.
It saves bytes compared to a fully-typed in value like:

Code: Select all

10 LET X=32768
which will use 5 bytes or characters '32768', whereas '.' (or '0' or '9') will only use 1 character. In both case there is a hidden 5-byte floating point value of the actual number still in the LET statement

When the program is run, the actual floating point value is used, regardless of what is displayed. So how to get the FP value you want into the LET statement? By doing some extra work of putting it during program creation

I tried typing in the full LET statement, then EDITing it to '.' but as mentioned here it just changes it to zero
machine code will copy the floating-point value to the LET command
I see the vision of using the machine code to copy the FP value to the LET command, then deleting the machine code before SAVE. The resulting program will use fewer bytes

For 0 or 1, using NOT PI (0) or PI/PI (1) saves the most bytes. But for longer values, the hidden method looks good for byte reduction

Xav's method proves the concept of copying a non-trivial FP value into a hidden LET

One could POKE to desired FP value (5-bytes) into every place desired. But what is the value? I was inspired by this thread to write a little program to let us know. It also uses DEC-TO-FP get convert the numeric value of a text string to a FP value, and prints out the 5 bytes
David G
Posts: 428
Joined: Thu Jul 17, 2014 7:58 am
Location: 48 North

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by David G »

i guess i should have attached the program

DEC-TO-FP_CONVERT_2K_rom_independent.p
Requires 2K or more of RAM. Compatible with original ROM and with improved ROM
(1.66 KiB) Downloaded 125 times

This program shows the 5-byte FP value for any (positive) number e.g. "0.25" that you INPUT


But how to get the address of a 'LET=.' FP location? e.g.

Code: Select all

100 LET X=.
If this is the last line of the program it is quite simple: it will always be 6 bytes before DFILE_ADDR

So type in Line 100 into a new program (so it will be the only line)

Code: Select all

NEW
100 LET X=.
Next get the address to POKE. Type

Code: Select all

LET PA=PEEK 16396+(PEEK 16397)*256-6
Then

Code: Select all

POKE PA,[byte 1]
POKE PA+1,[byte 2]
POKE PA+2,[byte 3]
POKE PA+3,[byte 4]
POKE PA+4,[byte 5]
After POKEing the new value into the '.' of Line 100

Code: Select all

RUN
PRINT X
David G
Posts: 428
Joined: Thu Jul 17, 2014 7:58 am
Location: 48 North

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by David G »

Xav, is there a way in VB81 XuR to load a TASM file? I have a few complete programs that TASM.EXE compiles into a P file. I see VB81 has a way to load ASM into a REM, but is there a way to load ASM that includes an entire program including System Variables?


here is the ASM code for line 1 REM of DEC-TO-FP_CONVERT

Code: Select all

        saveFP           .EQU prtbuff+27   ;16444+27 = 16471 ;fixed location in printer buffer
        DEC_TO_FP_NEWROM .EQU $14D9
        DEC_TO_FP_OLDROM .EQU $14D5

             //Start with code-hiding
             db      $7E     ;hide the next five bytes from LIST
               JR      MCR   ;skip over the HALTs to machine code routine
                             ;so the machine will not HALT permanently in FAST mode
	       NOP
               NOP
               NOP
             HALT            ;two 76H/118 NEWLINE will hide the contents of the REM
             HALT            ;                    when using LIST

             //the M/C (machine code) routine
         MCR:LD      HL,(CH_ADD)        ;CH-ADD is the address of the next character in the BASIC program (the character after the USR 16514) which in this case is 'IF '
             LD      (UNUSED2),HL       ;Save CH-ADD
             LD      HL,(VARS)          ;HL now points to first VAR (F for this program)
             INC     HL                 ;skip past 5 bytes of F
             INC     HL
             INC     HL
             INC     HL
             INC     HL                 ;HL now points to second VAR (A$)
             INC     HL                 ;skip past length of string
             INC     HL
             INC     HL                 ;skip past opening QUOTE
             LD      (CH_ADD),HL        ;HL now points to contents of A$
             RST     18H                ;RST 0018 is GET-CH -- loads A with (CH-ADD)
             //DEC-TO-FP in: CH-ADD points to string (text) of the number
             //          in: A is loaded with first character
             //         out: Floating Point version of the number is put on the CALC stack
             CALL    DEC_TO_FP_         ;DEC-TO-FP for either original ROM or improved ROM
             //update VAR F with the FP version of string
             LD      HL,(VARS)
             INC     HL
             EX      DE,HL
             LD      HL,(STKBOT)        ;401A
             LD      BC,5
             LDIR                       ;copy it to F
             //also copy it to a fixed memory location
             ld      hl,(STKBOT) 
             ld      de,saveFP
             ld      bc,5
             LDIR
             //clean up
             LD      HL,(UNUSED2)       ;restore CH-ADD
             LD      (CH_ADD),HL
             RET     

  DEC_TO_FP_:CALL   IS_OLDROM
             JP     NZ,DEC_TO_FP_OLDROM
             JP     DEC_TO_FP_NEWROM
             ;RET WILL BE HANDLED BY THE ROM ROUTINE

  IS_OLDROM: ;returns with NZ set if old (original) ROM 550 is detected
             PUSH   BC       ;register-safe version. begin with saving BC
             LD     C,A      ;save A in C
             LD     A,(5942) ;check contents of ROM location 5942
             CP     $D9      ;compare A with $D9
             LD     A,C      ;restore A
             POP    BC       ;restore BC
             RET        ;return Z if improved ROM 622 or 649
and the BASIC listing

Code: Select all

   5 REM DEMO OF ROM CALL "DEC-TO-FP"
   6 REM THE FP VALUE IS COPIED TO F
   7 REM SO F MUST BE THE FIRST VARIABLE IN THIS PROGRAM
   8 LET F=0
  10 PRINT "TYPE A NUMBER IN TEXT FORMAT"
  11 PRINT "E.G."
  12 PRINT "   ""3.141592654"""
  13 PRINT "   ""3.14159265400000"""
  14 PRINT "OR"
  15 PRINT "   ""  99ASDF"""
  16 PRINT "   ""3E+3"""
  19 PRINT
  20 INPUT A$
  30 RAND USR 16514
  40 PRINT "YOU TYPED:"
  41 PRINT A$
  42 PRINT
  44 PRINT "THE VALUE OF WHICH IS: ";F
  46 PRINT
  50 PRINT "ITS FLOATING POINT FORMAT IS:"
  52 PRINT
  54 PRINT "DECIMAL","HEXADECIMAL"
  60 LET SAVEFP=16471
  61 LET SAVEFP=SAVEFP-1
  70 FOR X=1 TO 5
  80 LET A=PEEK (SAVEFP+X)
  81 PRINT A,CHR$(INT(A/16)+28);CHR$(A-INT(A/16)*16+28)
  90 NEXT X
User avatar
XavSnap
Posts: 2062
Joined: Sat May 10, 2008 4:23 pm
Location: 'Zx81 France' Fb group.
Contact:

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by XavSnap »

Hi David,

No, the VB81's tiny assembler can't be use with the "P" TASM compiled programs as is.

The problem is to reset all BASIC variables and BASIC stats... vars, d_files can be be refresh, the BASIC Stacks will be wrong end may freeze the emulator/Z80!

But, the if the direct assembler can reset the emulator, the generated code can be assembled at another place $4200 with an empty BASIC RAM, and can be save a binary file.

The ORG directive is only used in the assembler $4009 for example, will be a private value used to locate the code in the assembled virtual memory offset.

The destination code location in set to the "USER" value... "User" value must be the same REM value offset. CALL, JP... jumps will refer to the ORG offset not the target "REM" value.

Just assemble your code to the upper empty memory (up to the BASIC program), and save the wole binary block to a "P" file.

I had to test it...
:mrgreen:

note, the latest version don't auto-save "debug_ASM.bin" file in the current directory... this binary should be useful to generate such binary file...



In case of a text file with ASM, the LOAD routine is intercept and apply a background BASIC reset.
Xavier ...on the Facebook groupe : "Zx81 France"(fr)
User avatar
XavSnap
Posts: 2062
Joined: Sat May 10, 2008 4:23 pm
Location: 'Zx81 France' Fb group.
Contact:

Re: [ASM-ZX81] How to retrieve a floating-point value from ASM.

Post by XavSnap »

But how to get the address of a 'LET=.' FP location? e.g.
Yes, and no...

The variable isn't set !
Before the "LET P=." the "P" value isn't set... and can't be viewed in the Vars memory room.
A PRINT P; , will give a 2/0 error report.

But, but the ROM call use a blank variable name ghosted in the Vars the keep it in memory.
In my code, i retrieve the last pointer and in subtract 6 bytes to copy it in the BASIC memory.

The DEST BASIC variable can't be affect but this ROM jump, like a legal LET command because of a partial (latest) use of LET ROM code part .
The ghosted value will be overwitted by the next LET command... LET P=.(new copied FP value).
The BASIC ignore the ASCII value, and only get the FP value to avoid to sent time to convert the decimal value, entered in the primary BASIC line.
Only a line EDIT able to change it!

If you had to reset the value, just edit it and press N/L to refresh the FP value.

The BASIC variables affected:14
E-LINE value, how point to the FP offset at $4014.
STKBOT, $401A
STKEND, $401C

But, all other LET will erase the buffered value "LET P=USR 16516" for example.
In this case, you had to store this value in another location (PRBUFF or in the top of memory).
Xavier ...on the Facebook groupe : "Zx81 France"(fr)
Post Reply