Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Save bug (*solved*)
#16
Code:
MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars

This is the same as MEMBOT or 23698 with a length of 30 bytes.
Reply
#17
Darkstar Wrote:
Code:
MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars

This is the same as MEMBOT or 23698 with a length of 30 bytes.
Yes, the print routine (both in the ROM and ZX Basic one) uses MEMBOT to store the char bytes as a temporary buffer (e.g. graphic chars, inverse, Italic, bold effects, etc). This is much faster than heap, as it its done per char and membot is already there.

Load routine already uses the heap for loading (one side). Save uses MEMBOT, and I see there is a bug in it (still debugging it).
Why you find hard to refactor it? :? It is easy to use the heap, anyway. I will look for it.
Reply
#18
boriel Wrote:
Darkstar Wrote:
Code:
MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars

This is the same as MEMBOT or 23698 with a length of 30 bytes.
Yes, the print routine (both in the ROM and ZX Basic one) uses MEMBOT to store the char bytes as a temporary buffer (e.g. graphic chars, inverse, Italic, bold effects, etc). This is much faster than heap, as it its done per char and membot is already there.

Load routine already uses the heap for loading (one side). Save uses MEMBOT, and I see there is a bug in it (still debugging it).
Why you find hard to refactor it? :? It is easy to use the heap, anyway. I will look for it.

Function, formats, flexlibillty or the three Fs.

The membot buffer has a fixed format of 30 bytes and the SAVE routine needs it and it's custom routines to use it and this limites flexibillty if we
would need a file name of 255 chars to be saved not to mention when the supposedly gerneric part of the routines are to be moved unto SNES as
file names are needed there as well. Speed is not critical in those routines. This also puts a limit (flexibillty) on generic refoctoring as function
follows form and unrelated bits in the routines gets thrown together according and tied to formats as one routine does too much work.
Code:
LD_TYPE:
    cp 4                    ; check if type in acceptable range 0 - 3.
    jr nc, LD_LOOK_H        ; back to LD-LOOK-H with 4 and over.
                            ; else A indicates type 0-3.
    call PRINT_TAPE_MESSAGES; Print tape msg
    ld hl, HEAD1 + 1
....
LD_CH_PR:
    call __PRINTCHAR        ; PRINT-A prints character
    djnz LD_NAME            ; loop back to LD-NAME for ten characters.

    bit 7, c                ; test if all matched
    jr nz, LD_LOOK_H        ; back to LD-LOOK-H if not

;   else print a terminal carriage return.

    ld a, 0Dh               ; prepare carriage return.
    call __PRINTCHAR        ; PRINT-A outputs it.

    ld a, (HEAD1)
    cp 03                   ; Only "bytes:" header is used un ZX BASIC
    jr nz, LD_LOOK_H

    ; Ok, ready to check for bytes start and end

VR_CONTROL:
    ld e, (ix + 11)         ; fetch length of new data
    ld d, (ix + 12)         ; to DE.

Here the output from the LOAD routine is sent directly to the screen. But what if I do not want it there and instead I want it sent to the printer, to
a NUL device or to a LCD eletronics board? Or maybe over a modem? Then it would be hard to change the code. This functionality is NOT directly
related to the LOAD routine. Sure you can call the PRINT_TAPE_MESSAGES routine but I would call it OUTPUT_TAPE_MESSAGES and it would output
it to the heap and then later on it would get printed from there/whatever or grapped by the appropriate routine. If this seems convoulted then there is a
simpler way. Put the output on the heap but print it right away, sort of like the routine above. If the ouput has been flagged down/surrpressed or
redirected then the PRINT routines in the LOAD routine will not kick in and the printing it self is done from one place after the string has been built
in three places instead of three now or buliding the string directly on the screen. An alternitive of using the heap is to use a temporary buffer for
strings like this that is not hardware specific and can be placed anywere or failing that, a specially allocated zone within the heap itself for temporary
storage that is fixed during the execution of the program. Then we have another problem, how to figure out the size of this zone? Through format
descriptors. SAVE has a maximum length of 17 bytes and output codes in the range of 0-3, 3 meaning bytes. So on the ZX there are 10 bytes starting
at at byte 1 I think that stands for name, on another machine it could start at byte 7 and allow for 16 chars in a name, but it does not matter. What
matters is that you have the length of all the fields for a given situation and can do or not do anything you want with it. So, you load the header
info somewhere, perhaps straight into the temporary zone in the heap and print it from there through format descriptors and load appropite START/LENGTH
information for the main data block into the registers and load as normal. And here is the good part, the format descriptors are bulit into the
compiler itself and are not in the asm files for a given platform. So LD (IX+11) comes LD (IX+20) if needed as the asm files are modified on the fly. The
format descriptors can even hold info like the max length for a given zone like: SAVE: ZONE 17 SUB ZONE NAME START 2 LEN 10. And if the length
of the subzones is greater than 17 then an error gets thrown or if the fields overlap. I do not think that even Microsof is aware of this idea with it's
constant buffer overruns. So the load routine just "prints" directly from the buffer if needed into the print heap or temporary buffer for the
print command or the generic heap and/or temporary zone for strings were it can be grapped by any routine. Or if you are really pressed
for space just point a pointer to it and save it to be used right after the LOAD routine has loaded the header, put "Bytes: " into it along with
another pointer to the SAVENAME that just got loaded. Then the internal format would be, LEN OF_BLOCK_DESCRIPTION BLOCK_DESCRIPTION
POINTER_TO_BLOCKNAME as a sub and above it would be: POINTER_TO_LOADSTRING. But then the file name would have to be rahter long for
space savings as this must be done in code internally. Or a string stored in two places.

But the best approach would be simply to build the string as it is done now inside of the LOAD routine and get a pointer to a generic buffer
were it resides, the same zone the print routine uses for data sharing purposes and all other routines, heap or no heap; then print it all in one
go. In other routines than the LOAD routine the printing is then done OUTSIDE of that routine as the LOAD routine is a poor example. LOAD does
LOAD and not PRINT even though it does have an output in the form of Chars or a string, but here the output must happen in the routine it
self as it's loads the header first. Or we could break it down further and do "LOAD_HEADER" routine and then "LOAD_MAIN_BLOCK routine. That
is refactoring with the print factored to a simple internal text output to be used by a controlling routine that determines what to do with the
output. The main structure for LOAD would be: LOAD and that calls LOAD_HEADER OUTPUT_STRING_ON_SCREEN LOAD_MAIN_BLOCK and in the
meantime for example the length of the block could be pushed on the the stack in the LOAD_HEADER section only to be poped out again
in the LOAD_MAIN_BLOCK section so the computer will not have to cycle through the loaded header again. Much cleaner. And the format descriptors
can be used to modify the asm files for simple common things like the maximum length of file names.

Different format templates for different machines that are based on commonality as all files have a name and a length and that is tied to functions and
an easier way to factorize programs and what goes with what and what does not, that is the essence of it. It keeps the harware speciffic things to
the minmum.

Imagine the human brain with all of it's millions of brain cells, to us it's just an electical storm but the cells are highly factorised compontents with
CLEARLY definded input and output working on a small piece of a problem individually but yet in tandem with one another and that can not be
done unless the control of input and output is very well definded along specific pathways or templates that get built as the human brain learns.
Unlike cats that have mostly a fixed program or templates. The trick is not so much in the programming but in the templates. There are even
templates for pathways based on probabillity (quantum computing) based on the properties of six or seven and that ties to the atom itself, not
just for the formats. The templates of what works in factorized flexibillty. Not to mention the never ending problem of line ending differences
between Windows and Linux, it's such a simple problem but it never goes away does it? Template......

I see you are having problems of maintaning dual versions of routines, that will only get worse as you move onto other (cat like) machines like the
SNES.

Just throwing some ideas around Smile
Reply
#19
Don't forget the three S:

Speed, size and security.

You sort of have to pick one for most small system routines.

You can have it fast.
You can have it small.
Or you can have it error checked...

If you want flexibility, you're generally choosing to forgo speed and size anyway.
Reply
#20
I think it's finally fixed. Please download Version 1.3.0s997.

This version does still uses MEMBOT. Using the heap while preserving registers and so on will increase the code more than 17 bytes (which would be equivalent to define a DW 0, 0, 0, ... <8 times + 1 extra byte> in static memory for the header). The other solution is, yes, you can write your own save routine in asm, like:
Code:
Sub SaveCode(name as string, start as Uinteger, len as Uinteger)
    asm
    ...
    end asm
End Sub
which will do exactly what you want.

I tried to implement SAVE/LOAD just for backward compatibility only (I would like them to work with ZX Divide; I own one :mrgreen: )

Anyway, can you check PRINT now works after SAVE, please? :roll:
BTW, the problem with this PRINT bug was due to the "Start Tape, then press any key" ROM msg, which was tampering ECHO_E System variable (used by PRINT routines).
Reply
#21
Thank you Boriel, it works now the print and all. Sorry but I meant to get back to you sooner but life got in the way and I wanted you to take your
time with this.

"23682-23863 ECHO E 33 column number and 24 line number (in lower half) of end of input buffer. "

That would be logical, the printing of messages from the ROM creating a conflict with your PRINT routines but not directly related to MEMBOT itself.
LOAD uses the heap and then it would make sense that SAVE would also do so, expecially when thinking of porting it to other systems while the
execution pathway/template would remain the same for theese "insect" systems or the ASM files as they are. Pathway wise.

Maybe ECHO E could be POKEd to surpress output to the screen during LOAD.

Maybe you can use some of my ideas I wrote about previously to implement the ZX Divide SAVE/LOAD.

I have another idea, a relocatble SYSTEM variables area. Now it is comptible with the ZX but it should be remappable to the static memory or to
anyplace you like by changing the location of the DATA areas, then for e.x. ECHO E=23682,2 [Address,Length] as a format template is maybe a
possibillty.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)