Hello, All
Dear spektrumists!
Look at the following option for calling any functions via RST without
use of registers.
There are two tasks.
1. How can I reduce the length?
2. How can I do it faster?
Your suggestions, comments.
┌─- CODE ───
;Calling functions via RST, without using registers.
ORG #6000
LD HL,#FFFF ;Parameter
LD BC,#FEFE ;Parameter
LD DE,#0101 ;Parameter
LD A,#11 ;Parameter
CALL EMUL_RST ;Call function
DB 0 ;Function number (0-255)
DB 1 ;Sub-function number (0-127)
... Continues here
program after the function has been executed.
Of course, the function should
will end with the RET command.
EMUL_RST ;clock, byte
LD (BACKBC+1),BC ;20, 4
EX (SP),HL ;19, 1
LD B,(HL) ;FUNCTION NUMBER ;7, 1
INC HL ;6, 1
LD C,(HL) ;SUB-FUNCTION NUMBER ;7, 1
INC HL ;6, 1
EX (SP),HL ;19, 1
PUSH HL ;11, 1
LD L,B ;4, 1
LD H,RST_TAB/256 ;7, 2
LD B,(HL) ;7, 1
INC H ;4, 1
LD H,(HL) ;7, 1
LD L,B ;4, 1LD B,0 ;7, 2
SLA C ;8, 2
ADD HL,BC ;11, 1
LD B,(HL) ;7, 1
INC HL ;6, 1
LD H,(HL) ;7, 1
LD L,B ;4, 1
EX (SP),HL ;19, 1
BACKBC LD BC,0 ;10, 3
RET ;10, 1
;----------------------------
;Total: 217 clock cycles, 32 bytes.
;----------------------------
;Table of transitions to functions.
;Lies only from the same address!
;Takes up 512 bytes for 256 functions.
ORG #7000
RST_TAB DB FUNCTION0 ;low byte of the function address
ORG #7100
DB FUNCTION0 ;high byte of the function address
;The functions themselves...
FUNCTION0
DW F0_1 ;subfunction address
DW F0_2 ;subfunction address
;Subfunction 1
F0_1 RET
;Subfunction 2
F0_2 RET
└── CODE ───
The appendix contains the same example.
File: Function.zip http://zx.pk.ru/attachment.php?attachmentid=1938
Fromacidrain→ToAll16 November 2005
Hello axor
Hmmm, if it’s not a secret, then what are you planning to use it for?
FromAlexander Shushkov→ToAll16 November 2005
Hello, acidrain
aci> Hmmm, if it’s not a secret, then what do you plan to use this for?
For any ROM firmware, the functions of which can be used without changing
numbers of established functions from version to version.
FromKirill Frolov→ToAll17 November 2005
Hello axor
axo> For any ROM firmware, the functions of which can not be usedaxo> changing the numbers of established functions from version to version.
Here in the instructions JP xxxx number is written instead of xxxx. This is when
on disk. And when in memory the number changes to an address. Separately available
array of addresses - index in the array this same number.
FromAndrey Bogdanovich→ToAll17 November 2005
Hello axor
It’s written optimally, but it’s impossible to make it shorter.
Fromjtn→ToAll17 November 2005
Hello Specter
Isn’t it wasteful to spend 16k ROM 512b on some kind of table?
FromKirill Frolov→ToAll17 November 2005
Hello jtn
jtn> Isn't it wasteful to spend 16k ROM 512b on some kind of table?
No. Each function from that table will take more.
FromKirill Frolov→ToAll17 November 2005
Hello fk0
fk0> Available separatelyfk0> array of addresses - index in the array of this same number.
It's already in ROM.
FromKirill Frolov→ToAll17 November 2005
Hello axor
axo> Look at the proposed option below for calling any functions viaaxo> RST without using registers.axo> There are two tasks.axo> 1. How can you reduce the length?axo> 2. How can you do it faster?axo>
┌─- code ───
ld de, args
ld bc, args
call function
.....
function:
JP xxxx ; where xxxx is patched to the required address
; when loading a program into memory.
└── code ───
FromAlexandr Sinyakov→ToAll17 November 2005
Hello Specter
Spe> It’s written optimally, but it’s impossible to make it shorter.
Really?
┌─- CODE ───
ex(sp),hl
ld a,(hl)
inc hl
ex af,af'
ld a,(hl)
inc hl
ex af,af'
ex(sp),hl
push hl
ld l,a
ld h,RST_TAB_hi_addr
ld a,(hl)
inc h
ld h,(hl)
ld l,a
ex af,af'
add a,a
add a,l
ld l,a
ld a,h
adc a,0
ld h,a
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ex(sp),hl
ret
└── CODE ───
Now I don’t remember exactly, but something like 180-190 bars.
FromAlexandr Sinyakov→ToAll17 November 2005
Hello Sinus
Sin> SAM style: you have a knuckle in register A (I didn’t look carefullySin> but along the way HL too) ^_~
HL intact. Regarding A - you can border the program with this:
┌─- code ───
LD (a_reg+1),a
...
a_reg LD a,0
RET
└── code ───
+17 clock cycles and 5 bytes (still faster). Only A' will be killed
You really need to get rid of subfunctions - 256 functions alone is not so
It’s not enough, and it’s unlikely that imagination will be enough to score them all.
FromAlexandr Sinyakov→ToAll17 November 2005
Hello jtn
jtn> yeah. in ROM..
Hmm... Didn't take it into account.
Then A is sacrificed. As an extreme case for passing parameters, we have
6 more alternative registers, IX and IY. You can even use R, but this is already
pervert...
You can also cram in PUSHes and POPs, but there will either be no winnings, or there will be some
miserable.
FromSlavik Tretiak→ToAll17 November 2005
Hello, SAM style
SAM style: your register A is starting to get hot (I didn’t look carefully, but according to
HL too) ^_~
axor: if you are not only theoretically interested in how to make it shorter and faster,
then the option proposed by fk0 is the best. splitting a function into two (function
/ subfunction) is a wrong approach brought over from the days of DOS on the PC.
Fromjtn→ToAll17 November 2005
Hello, SAM style
SAM> HL intact. Regarding A - you can border the program with this:
yeah. in ROM...
FromAleksey Senilov→ToAlexandr Sinyakov18 November 2005
Hello, _/Alexandr/_!
November 17, 2005 22:58, Alexandr Sinyakov wrote to All:
AS> Then we sacrifice A. An extreme case for passing parameters yAS> we have 6 more alternative registers, IX and IY. You can even RAS> to use, but this is already a perversion... You can also PUSH and POPAS> cram in, but there will either be no winnings, or it will be meager.
If A is sacrificed, then in my opinion it is much better to pass the function number in it!
There is a loss in the size of the client code, but a significant gain in speed.
;Variant with a number after the call command and with damage A
ex (sp), hl ;19
ld a, (hl) ;7
inc hl ;6
ex (sp), hl ;19
push hl ;11
ld h,rsttab/256;7
ld l, a ;4
ld a, (hl) ;7
inc h ;4
ld h, (hl) ;7
ld l, a ;4
ex (sp), hl ;19
ret ;10
total 124 bars
;Option with number transfer to A
push hl ;11
ld h,rsttab/256;7
ld l, a ;4
ld a, (hl) ;7
inc h ;4
ld h, (hl) ;7
ld l, a ;4
ex (sp), hl ;19
ret ;10
;Total 73 cyclesMoreover, you can use both options on the same code! Second
option, it’s just a different entry point from the first option. :)
And it is more logical to do the analysis of the subfunction directly in those functions where it is needed. But not
put into the general calling mechanism.
If we compare the function call by number and by the JP table, each option
there are both advantages and disadvantages.
See you again! Best regards, Thann.
FromAlexandr Sinyakov→ToAll18 November 2005
Hello fk0
fk0> I'm also experiencing it. HL and A
ex (sp),hl on the stack - param.HL, in HL - the address next to the call
ex (sp),hl on the stack - return address (+2), param.HL - to HL
push hl stack: param.HL, return address
ex (sp),hl stack: procedure address, return address, param.HL - to HL
ret goes to the address of the procedure.
Where is the damage to HL? Kill me, I don't see it.
FromKirill Frolov→ToAll18 November 2005
Hello, SAM style
SAM> Hmm... Didn't take it into account.SAM> Then A is sacrificed. An extreme case for passing parametersSAM> we have 6 more alternative registers, IX and IY. You can even RSAM> to use, but this is already a perversion...SAM> You can also cram in PUSHs and POPs, but there will either be no winnings, or noSAM> will be minuscule.
I can say that. If you don't have enough arguments to pass
functions of the main set of registers then, with rare exceptions,
passing argument data through the stack (if the function allows nested calls)
or through a statically allocated memory area
(nested calls are not allowed) is a completely acceptable option.
You can just kill more by juggling clock registers.
FromKirill Frolov→ToAll18 November 2005
Hello Sinus
Sin> SAM style: you have a knuckle in register A (I didn’t look carefullySin> but along the way HL too) ^_~Sin>
It's happening to me too. HL and A. Just need to have an agreement,
that nothing is passed through these registers when calling non-local
functions. Via HL only the address of the object and/or table can be used
virtual functions are transferred. Through A is the function number.
Sin> axor: if you are not only theoretically interested in how to make it shorter andSin> is faster, then the option proposed by fk0 is the best. divisionSin> functions into two (function / subfunction) is the wrong approachSin> brought from the days of DOS to PC.
As far as I know, this is an approach introduced (including into DOS)
more from CP/M. (ld c, function; call #0005). Why is clear.
The loaded program code can, without any tricks,
be launched immediately.
This is also true in modern operating systems. Built-in OS features (eg
linux or bsd - it’s difficult to understand what it’s like in Windows NT, but it seems to be the same
so) are called in a similar way. For example, the open or read functions (in C language
Wrapper functions are included that distribute arguments across different registers
processor and causing a software interrupt).There are very few built-in OS functions. The same Linux has order
200-300 pieces. Another thing is library functions. There are many of them. They may be
loaded or may not be loaded. Modern operating systems use the approach
close to what I indicated. Any function is available at its address. But before that
like what function could it be
used requires downloading the library and configuring the program and library
for sharing.
FromKirill Frolov→ToAll18 November 2005
Hello axor
axo> Why can’t JP xxxx be made already in ROM, so as not to patchaxo> program?axo>
That's the point: this code must be in the program. Exactly for
in order to patch. Precisely based on the fact that initially the program does not know
addresses of the functions that are going to be called.
> After all, if you make them in the program itself that calls these> functions, then for this you will need to again create and store> tables of these JP xxxx,>
The tables of these JPs are created very simply and once in a text editor.
Each "external" function is assigned a number. The author also makes this “external”
libraries, programs or ROM firmware.
For use by other people, he releases a special file for inclusion
to assembler:
┌─- code ───
function_name_1:
jp function_number_1
function_name_2:
jp function_number_2
...
function_name_N:
jp function_number_N
└── code ───
Thus, at the source text level, the programmer using the library
(firmware) works with function names.
At the machine code level - with a wrapper containing a valid address and
created during program download. And at the interface level - this is the most
important - with function numbers.What is important: if the actual addresses of the functions change in the library
(firmware) - this does not affect anything, since
The function number does not change. Now it can no longer be changed.
> and then patch it. And if you immediately place JP xxxx in ROM, then for this> will need one more byte than usual. >
It makes sense to place JP xxx in ROM. At a fixed address,
of course. Then we also deal with numbers and at the same time
with function addresses. This method is suitable for ROM. For RAM, where
library every time, depending on the availability of free memory,
can be downloaded to different addresses - no, this method does not work.
It must be said that placing the JP xxxx array in RAM has another advantage.
Ability to enable filter functions at the input and output of system
(library) functions (by replacing xxxx with your own wrapper function) For
debugging, etc. may be useful. For example, you can record calls
all system functions.
> And as they said above, there will most likely not be 256 functions.> But still, space for them needs to be taken initially. This is so that you don’t later> it was painful...
And one more thing. If the JP xxxx array is placed in RAM this gives
the advantage is that the size of the array is determined onlythe number of functions called, not the number
functions in total:
┌─- code ───
ifused function
function:
jp function_number
endif
...
└── code ───
On the other hand, the ROM should in any case
addresses of all functions are located. That is, in the variant
array of function addresses (2*N) plus JP xxx array in RAM (3*m)
vs JP xxxx array in ROM (3*N) placement wins
JP xxxx array in ROM (3*N) with m>N/3, where N is the total number of functions, and m is
number of functions called (used
loaded program).
FromAlexander Shushkov→ToAll18 November 2005
Hello fk0
fk0> Here in the JP instructions xxxx is the number written instead of xxxx. This is whenfk0> on disk. And when in memory the number changes to an address. Available separatelyfk0> array of addresses - index in the array of this same number.
Why can’t JP xxxx be made already in ROM, so as not to patch the program? After all
if you make them in the program itself that calls these functions, then for this
You will need to again create and store tables of these JP xxxx, and then patch it.
And if you immediately place JP xxxx in ROM, then this will require a byte more,
than usual.
Although who knows what kind of memory you need to immediately save ROM or RAM...
And as they said above, most likely there will not be 256 functions. But still
space for them must be taken initially. This is so that it won't be painful later...
FromVladimir Kladov→ToAll18 November 2005
Hello fk0
A very simple method has already been discussed, just with numbers. Time is only wasted
during the first call to the patch, on subsequent calls the call occurs.
Additional benefit: call cond can be used. JP use
You can’t, the code in the ROM will patch the wrong thing.
For example, in the ROM at addresses 100H...1FFH there is an adapter of the following type.
ORG 100H
DEFB (E8H)18H,(18H)0
(alternatively, maybe 255 times RST n to the desired address, only then it is necessary from
stack to push one extra return address in the patch code).
After that, approximately the following code is written from address 200H into the ROM:
ORG 200H
EX (SP),IX:PUSH HL,DE,AF
LD E,(IX-2):LD D,0:LD HL,TableJumps:ADD HL,DE:ADD HL,DE
LD (IX-2),L:LD (IX-1),H
;here you can prepare the code for Jumper:
LD A,C3h:LD (Jumper),A ; but you don’t have to cook it if it’s cooked once and eaten
confidence that no one will spoil it
;and this part of Jumper must now be set to the transition address:
LD (Jumper+1),HL
POP AF:POP DE:POP HL
EX (SP),IX:JP Jumper
Space for Jumper must be allocated somewhere in RAM, 3 bytes, for example:
ORG FFF0h
Jumper: JP 0
Yes, the numbers here should be in the range 100H..1FFH so that the 0th addresses do not
borrow, just for RST and other things.
In assembler it is written
Fun0 EQU 100H
Fun1 EQU 101H
Nothing depends on the ROM firmware version; the program always gets to where it needs to be.
Only the first call is long, the others are always direct calls.Another (better!) option, the most common for microcomputers, is
select a transition table in ROM, 3 bytes each, from a given address,
for example, again with 100H:
ORG 100H
Fun0: JP Fun0_implement
Fun1: JP Fun1_implement
In ASMA, use the EQU table:
Fun0 EQU 100H
Fun1 EQU 103H
No perversions, instead of numbers 0..FF, addresses 100H..3FDH are used in increments
3. Everything is fast, you can use JP. Costs in ROM are even less than in case 1
above. I would choose option 2.
FromSemyon Dobrovolsky→ToAll18 November 2005
Hello axor
fk0> ┌─- code ───fk0> call functionfk0> .....fk0> fk0> function:fk0> JP xxxx ; where xxxx is patched to the required addressfk0> ; when loading a program into memory.fk0> └── code ───fk0>
It is suggested to patch the address in the CALL command.
Then the call will be made directly, and JP is not needed.
axo> for this you will again need to create and store tables of these JPaxo> xxxx, and then patch.
Once patching is complete, the tables are no longer needed. Memory is possible
use for other purposes.
fk0> That's the point, that this code must be in the program. Exactly forfk0> in order to patch.
Nothing prevents you from making it part of the ROM. Then he will exist in
a single copy and patch all other programs.
fk0> the function number does not change. Now you can’t change it.
It is also proposed to use meaningful symbolic numbers rather than function numbers
names.
FromSlavik Tretiak→ToAll18 November 2005
Hello fk0
In short, let's go. I answer everyone.
axor
I understand that you are going to make a new ROM, and such that everything would be cool
regardless of the firmware version.
The most compromise option is to create a transition table in the ROM of the form
func1 jp real-func-1
func2 jp real-func-2
in fact, we need to think about what is more important, memory (when we use code like
RST #10
DB func_number
) or performance (transition table). I, like Vladimir Kladov
I think the jp sign is better.
fk0
in modern axes on modern petsets there is a modern protected mode, in
which you can redefine the jump addresses of commands int 0x00 ... int 0xFF.
In order for the program code to be executed, it is not necessary to pass parameters via
stack, patch the program or use constructions like RST XX: DB YY
you just need to come to some agreement about passing parameters and
function calls. let's say
from address #0000 there is 256 jp XXXX. these are system calls. parameters
transmitted in registers. if you need to transfer an address, then it is always in HL, if
you need to transfer one byte, it is always in A.
well, etc.
Then everything works great.
FromGavrilov Vitaly→ToAll19 November 2005
Hello, captain cobalt
Why complicate things?
There are 8 restarts, of which you can use 5-6 for your needs - divided by
functionality. And 256 functions for each restart. Total code:
ldhl,...
ld de,...
ld bc,...
ld a,...
rst N
db func
N: ex (sp),hl ;(sp) - param, hl- retaddr-1
exa
ld a,(hl)
inc hl
ex (sp),hl ;(sp) - retaddr hl- param
push hl
ld l,a
ld h,'table
ld a,(hl)
inc h
ld h,(hl)
ld l,a
exa
ex (sp),hl ;(sp)- jump hl- param
ret
PS: combination
add a,l
ld l,a
ld a,h
adc a,0
ld h,a
can be replaced by
add a,l
ld l,a
adc a,h
subl
ld h,a
Fromacidrain→ToAll19 November 2005
Hello axor
axo> For any ROM firmware, the functions of which can not be usedaxo> changing the numbers of established functions from version to version.
I understand, but what is the firmware? 48basic? =) Or what’s yours?
FromAlexander Shushkov→ToAll19 November 2005
Hello Vitamin
Vit> There are 8 restarts, of which you can use 5-6 for your needs -Vit> division by functionality. And 256 functions for each restart.
Then it turns out that each restart needs its own table of function addresses,
and this, it seems to me, is wasteful.
FromAlexander Shushkov→ToAll19 November 2005
Hello, acidrain
aci> I understand this, but what is the firmware? 48basic? =) Or what’s yours?
Secret...
FromVladimir Kladov→ToAll20 November 2005
Hello,GriV
There is such a thing called a macro. Defining a macro
PrintChar MACRO char
RST 16:DEFB char
ENDM
And further in the code it is written
PrintChar 'a'
There is no need to crawl through the tables with your eyes. That's why compilers exist.
FromGavrilov Vitaly→ToAll20 November 2005
Hello axor
axo> Then it turns out that each restart needs its own address tableaxo> functions, and this, it seems to me, is wasteful.
no more wasteful than storing transition tables for each subfunction.
but there are fewer hemorrhoids.
FromAlexander Shushkov→ToAll22 November 2005
Hello Vitamin
Vit> is no more wasteful than storing transition tables for eachVit> subfunctions. but there are fewer hemorrhoids.
The length of subfunction tables is limited by the number of these same subfunctions.
The number of functions should be as large as possible. This is my opinion
understanding. But, as usual, everyone has their own.
FromChunin Roman→ToAll23 November 2005
Hello, SAM style
RSTs were used as functions in the Sprinter 2000 in its Estex AXIS. You can say
quite convenient from a programming point of view. Although no one is stopping you from doing it
kernal as in CP/M (call table).
FromAlexander Shushkov→ToAll24 November 2005
Hello, SAM style
SAM> And here no one thought what would happen if an inquisitive brain like mineSAM> will try to call a subfunction with a number greater than the number of subfunctionsSAM> for this function? At best, there will be a call to a completely different program, andSAM> at worst - computer stupor. Or it is necessary to install protection against such insanitySAM> or get rid of subfunctions.
The very first function that the program should call is checking the number
kernel versions. If the version number is larger than needed (newer means that's all
old functions are available), then we continue working, otherwise we close the program.
FromKirill Frolov→ToAll24 November 2005
Hello, SAM style
SAM> ex (sp),hl stack: procedure address, return address, param.HL - in HLSAM> ret jump to the procedure address.SAM> SAM> Where is the damage to HL? Kill me, I don’t see.
Without these ex (sp), hl is much faster.
FromSlavik Tretiak→ToAll24 November 2005
Hello fk0
fk0> As for the arguments, I prefer to follow the accepted conventionsfk0> for the HiTech-C compiler. They are quite comfortable.fk0> {{skip}}fk0> The HL and A registers have special meaning. When programmingfk0> in OO style in HL contains a pointer to a structure objectfk0>
This is if you steer objects.
As practice shows, OOP is effective only on fairly large tasks.
in the case of Spectrum, the usual procedural approach is often more effective.
> Multiple inheritance is not provided, because it is difficult> turns out.
it is needed in the same way as goto (i.e. it is almost never unnecessary)
> Yes. If only there was a SINGLE STANDARD for this...
oh! yes...
but he's not there ^_~
FromKirill Frolov→ToAll24 November 2005
Hello Sinus
Sin> fk0Sin> in modern axes on modern petsets there is a modern protectedSin> mode, in which you can redefine the jump addresses of int commandsSin> 0x00 ... int 0xFF.Sin>
And it’s also possible on “non-modern petsets”. That's not the point.
The point is that int numbers are strictly assigned to functions.
Because without some minimum set there is no way at all.
> it is not necessary to transfer the program code> parameters via the stack, patch the program or use constructions like> RST XX: DB YY> you just need to come to some agreement on the transfer> parameters and function calls. let's say>
Yes. But this agreement must exist. That's exactly the point.
> from address #0000 there is 256 jp XXXX. these are system calls. parameters> are passed in registers. if you need to transfer an address, then it is always in HL,> if you need to transfer one byte, then it is always in A.>
This is actually my option. Simply the transition table is placed in ROM and
there is no need to patch it, becauseThe ROM already knows where its functions are located.
Regarding arguments I prefer to follow conventions
adopted for the HiTech-C compiler. They are quite comfortable.
Arguments are passed to DE, BC and further on the stack. Result
returns to HL. Sometimes I deviate from such agreements
when transmission via HL or A is more efficient. But such
functions are usually "internal" to the program, not external
are exported, therefore in relation to them everything is permissible
whatever.
The HL and A register have special meaning. When programming
in OO style in HL there is a pointer to a structure object,
the first element of which is the address of the array "JP xxx" of virtual pointers
functions. When calling a virtual function
register A is used for its number (up to 85 functions). Scheme
something like this:
┌─- code ───
; In the program code:
...
ld hl, object_or_inherited_object
call virtual_function
...
call non_virtual_function
...
; In the code of the included "*.h" file
virtual_function:
ld a, function_number
jp call_virtual
...
; function table - patched after loading:
; function numbers are replaced by their extracted addresses
; from the library function table (located in the library file)
non_virtual_function:
jp function_number
non_virtual_function2:
jp function_number2
...
; In the virtual function support file code:
call_virtual:; here A is added to (HL) and the address is extracted
; from the table of virtual functions
; present in the library file
....
ex (sp), hl
ret ; ~120 clock cycles
;-----------------------------------------------------------------------
; In the library file code
; IMPORTANT: compiled INDEPENDENTLY on the main program file
; and dynamically loaded on the fly
virtual_function:
.... ; regular code
ret
non_virtual_function:
.... ; regular code
ret
└── code ───
Multiple inheritance is not provided, because it is difficult
it turns out.
> then everything works great.
Yes. If only there was a SINGLE STANDARD for this...
FromGavrilov Vitaly→ToAll24 November 2005
Hello fk0
fk0> When programmingfk0> in OO style in HL contains a pointer to a structure objectfk0> the first element of which is the address of the array "JP xxx" pointersfk0> virtual functions.
why not use an index register for these purposes? IMHO it's more
rationally (after all, structure). and use the second register pair for
storing the addresses of variables on the stack. it turns out pretty good
FromKirill Frolov→ToAll25 November 2005
Hello Sinus
Sin> this is if you steer objects.Sin> as practice shows, OOP is effective only on sufficiently large onesSin> tasks.Sin> in the case of Spectrum, the usual procedural approach often turns out to beSin> is more efficient.Sin>
Practice shows, firstly, that you can make a big task out of a mountain.
Secondly, effective and ineffective
OOP and anything else simply don't happen. Quite specific
the task (program) can be viewed both from an OOP point of view,
as well as a system of finite state machines, as well as God knows what else -
it doesn't change. There's just no need to get into anything
one.
> it is needed in the same way as goto (i.e. it is almost never unnecessary)>
The absence of goto means moving the block into a separate function.
A separate function is a separate unrelated space
names and binding variables through arguments by reference.
Or, as an alternative, a lot of logical conditions for ending the loop.
In general, it turns out to be quite confusing to understand and ineffective from the point of view
coding view.
And if you go further
this way, then any branch and loop operators also
not needed. Because they are really, almost, not needed. Program
can be simply transformed into an equivalent one,using exclusively functions and the '?' operator (in C language).
Nonsense about the uselessness of goto - this is a typical “I heard a ringing,
but I have absolutely no idea what it’s all about.” If he's like that
unnecessary, why is it not only in the latest versions of the standards
remained, and is still acquiring different extensions? That is
Yes, it is not needed, exactly to the same extent as while and for are unnecessary.
FromKirill Frolov→ToAll25 November 2005
Hello Vitamin
Vit> ...steer objects...Vit> Vit> why not use the index register for these purposes? IMHOVit> is more rational (after all, a structure). and the second register pairVit> is used to store the addresses of variables on the stack. it turns outVit> pretty good
It would be possible. There is one thing: if the size of the indirectly addressable
structure is small if access to it is mostly sequential,
if address arithmetic is often used - in such cases
via HL faster. Because for every byte accessible through the index
the register takes an extra 8 clock cycles and an extra 2 bytes. If you have
large structure with random access - yes, index register
better. But it won’t take long to shift HL and IY.
FromSlavik Tretiak→ToAll25 November 2005
Hello fk0
> And if you go further> this way, then any branch and loop operators too> are not needed. Because they are really, almost, not needed. Program> can be easily converted into an equivalent one> using exclusively functions and the '?' operator (in C language).
'?' - this is a variant of the branch operator.
> Nonsense about the uselessness of goto - this is a typical “I heard a ringing> but I have absolutely no idea what this is all about.” If he is like this> unnecessary, why is it not only in the latest versions of the standards> remains, and is it still acquiring different extensions? That is> yes, it is not needed, exactly to the same extent as while and for are unnecessary.
How many times have you used goto in your programs in the last 5 years?
Personally, I am 0 (zero).
there is a break, there is a continue.
Of course, there are times when using goto shortens the code and makes it
clearer. but such cases rarely occur.
in all other cases, goto is harmful and should not be used.
why is goto needed? then, in some exceptional case, to jump over
after a few blocks.
Well, in this case there are Exceptions.and in general, the most competent way to do it was in java - it has goto, but it’s a variation
of the break operator, it only indicates where this break should be done.
-+------
As you know, any program can be written without goto.
the same as with goto, but without while, for.
you don't have to use the functions.
you can get by with just goto and ternary operators.
it all depends on the degree of insanity of the person who wrote this program.
however, there are certain generally accepted standards, verified over the years, as they should be
write programs, namely: use functions, for, while, and reduce
Use goto to a minimum.
FromValery Grigoriev→ToAll26 November 2005
Hello Sinus
Sin> '?' - this is a variant of the branch operator.Sin> Sin> how many times over the last 5 years have you used goto in yoursSin> programs?Sin> personally, I am 0 (zero).Sin> there is a break, there is a continue.Sin> Sin> of course, there are cases when using goto shortens the code andSin> makes it clearer. but such cases rarely occur.Sin> in all other cases goto is harmful and should not be used.Sin> Sin> goto is needed why? then, so that in some exceptional caseSin> jump over several blocks.Sin> well, in this case there are Exceptions.Sin> Sin> and in general, the most competent thing to do was in java - there is goto, but thisSin> is a variation of the break operator, only it indicates where this break is neededSin> do.Sin> Sin> --------Sin> Sin> as you know, any program can be written without goto.Sin> Sin> the same as with goto, but without while, for.Sin> functions may not be used.Sin> you can get by with just goto and ternary operators.Sin> Sin> it all depends on the degree of insanity of the person who wrote this program.Sin> Sin> however, there are some generally accepted standards, verified over the years, likeSin> you need to write programs, namely: use the functions, for, while, andSin> reduce the use of goto to a minimum.
Accepted by whom and why?
I wrote all the programs in ZX-BASIC only with goto and try rewriting them without
this operator, then you will get confused in it.
ZX-BASIC does not have repeat intil() or while() at all, only for next, but how
do loops with an indefinite number of iterations?
These are just mastodons of the first editions of the specialty "programmer" such
had a habit and implemented it everywhere.
Arguments:
1) with GOTO programs are difficult to read - just like without GOTO, let's label
GOTO meaningful names or each GOTO transition with a comment.
2) GOTO works slowly - another misconception, everything is slow on translators
works, but in compilers everything depends on the adaptability of the latter3) with GOTO the program is unstable - this is precisely the problem of compilers, if from
loop say FOR NEXT was carried out by GOTO then the stupid compiler saved on
did not remove the loop data from the stack, did a GOTO and the result was fatal
programs - the issue is resolved by changing the compiler.
FromValery Grigoriev→ToAll26 November 2005
Hello, Vladimir Kladov
Vla> There is such a thing called a macro. Defines a macro Vla> Vla> PrintChar MACRO charVla> RST 16:DEFB charVla> ENDMVla> Vla> And then in the code it is written Vla> Vla> PrintChar 'a'Vla> Vla> There is no need to crawl through the tables with your eyes. That's why they existVla> compilers.
This will not make the parsing problem go away; it will remain as it was.
However, not all Z80s have 3.5 MHz apparently :D some have it at 2GHz :D
FromSlavik Tretiak→ToAll27 November 2005
Hello,GriV
Gri> Accepted by whom, accepted for what?
smart guys.
> I wrote all the programs in ZX-BASIC only with goto and try them> rewrite without this operator, then you will get confused in it.
Damn, no matter how many times I repeat, anything can be driven to the point of insanity.
Naturally, there is no way on ZX-BASIC without GOTO, because there is nothing else there.
> ZX-BASIC does not have repeat intil() or while() at all, only for> next, and how to make loops with an indefinite number> iterations?
don't use ZX-BASIC
> 1) with GOTO programs are difficult to read - the same as without GOTO, let's> GOTO labels have meaningful names or accompany each GOTO transition> with a comment.
Why give comments or meaningful names to tags if it’s much more convenient
don't use GOTO?
> 2) GOTO works slowly - another misconception, everything is on translators> works slowly, and in compilers everything depends on adaptability> latest
This is the first time I hear this argument from you, because it is absolutely clear that GOTO
It compiles into a simple JP, which is fast.> 3) with GOTO the program is unstable - these are just problems with compilers> if a GOTO was carried out from a loop, say FOR NEXT, then the compiler is stupid> I did not remove the cycle data stored on the stack, I did GOTO and in> the result is a fatal outcome of the program - the issue is resolved by changing> compiler.
another argument you came up with.
no compiler creates any data on the stack during the loop, and even
even if I created it, there is an excellent break operator (in normal languages),
which does not jump to God knows where, but clearly exits the current cycle.
in fact, smart guys give only the first argument, because if the program
large (large, this is with the volume of source texts > 4mb), then GOTO is absolutely
doesn't drive. both comments and tags will not help you understand in a month
endless and confusing GOTOs.
FromValery Grigoriev→ToAll28 November 2005
Hello,GriV
2Sinus> a very original answer to the question “by whom and for what” - “smart 2Sinus> guys."
Don't use ZX-BASIC - is this offtopic???? And I was also accused of pissing
:(
And in general, regarding GoTo, you contradict yourself - then you say that GoTo
is translated to just Jp , then you are saying that it is better to use loops
repeat until and do while, etc., which compile into such terrible
designs that are simply terrifying. And then (if Goto is faster) why bother?
Are loop operators needed???
FromValery Grigoriev→ToAll28 November 2005
Hello,GriV
2AcidRian> the question is not that you can assign macros, but that you have to 2AcidRian> do the calculation of transition points while the program is running, and not before it 2AcidRian> works as I propose (? Is this really such an incomprehensible thought), that 2AcidRian> will speed up the execution of the program.
FromValery Grigoriev→ToAll28 November 2005
Hello Sinus
Sin> this is the first time I hear this argument from you, because it is absolutely clear that GOTOSin> is compiled into a simple JP, which is fast.
Well, that’s what you think - take any of the compilers - take it out and look at it
that GoTo is compiled there - I think you will be very surprised :D
Moreover, even a naked goto (a program with a single statement in which there is no
other lines in general) will be compiled into a very tricky construction. Very
a good compiler might compile like this (in jp) and even then it’s under
great doubt. Likewise about the stack and the variables on it, not only in it
- registers, etc.
FromSlavik Tretiak→ToAll29 November 2005
Hello,GriV
Gri> 2Sinus> a very original answer to the question “by whom and for what” - “smartGri> guys."
the answer is correct ;)
> Do not use ZX-BASIC - is this offtopic???? And I'm still in> accused of pissing :(
??? and that there is nothing on the ZX except BASIC? :confused: that's it, I'll go drown myself.
where did the C go (there are already two of them, and you can also write on one),
Pascal (well, just kidding), MegaBasic (there in wlile, and repeat and until),
BetaBasic (ie) and a crowd of assemblers???
> And in general, regarding GoTo, you contradict yourself - that's what you say> that GoTo is translated to just Jp , then you say which is better> use repeat until and do while loops, etc., which> are compiled into such terrible constructions that you are simply horrified. A> then (if Goto is faster) why are loop operators needed at all???
I don't contradict myself.
yes, in terms of performance it is more profitable to use Goto and write in
assembler. and in terms of speed of development, I’d rather use pearl barley in 5 minutes
I’ll write what I’ll be using on Asma for a week. and I don’t care that it’s a pearl barley version
generally interpreted, wildly suboptimal and even slow - but I’m the restI’ll be using it for weeks and not hacking my brain with it.
FromSlavik Tretiak→ToAll29 November 2005
Hello,GriV
Gri> Well, that's what you think - take any of the compilers - get it andGri> look at what GoTo is compiled into - I think you will be very surprised :D
ok, let's take any compiler (MS Visual C 7).
void main(void) {test: goto test;}
-->
test: jmp test
and why be surprised? what goto compiled into one jmp?
> Moreover, even a naked goto (a program with a single statement, in> which has no other lines at all) will be a very tricky construction> compiles. A very good compiler might compile like this> (in jp) and even then this is highly doubtful.
Well, I don’t know what kind of compilers you use, but even those compilers that
I’m writing (sometimes I have to at work) they don’t do such nonsense, and they compile
everything is obvious.
> Similarly about the stack and variables on it and not only in it -> registers, etc.
in general, as they say, learn the hardware ;)
disassemble once what was generated by a not quite ancient compiler, and I think there
there is something to see.
FromKirill Frolov→ToAll29 November 2005
Hello Sinus
Sin> '?' - this is a variant of the branch operator.Sin>
This is the wrong operator. This is rather a function that calculates
one or another expression (I emphasize - only
expression, nothing more) depending on the meaning
log. conditions. This is not a statement like if.
Another thing is that this operator can also be replaced
other logical expressions || And &&.
> how many times have you used goto in yours over the last 5 years> programs?>
$ grep -r goto . | wc -l
12
About a year and a half later.
> personally, I am 0 (zero).> there is a break, there is a continue.>
1. veiled goto is worse than the real one.
2.while() {
while() {
for (;;) {
switch() {
...
break ?
}}}}
3. How to treat pearl barley next
FromKirill Frolov→ToAll29 November 2005
Hello Sinus
Sin> in fact, smart guys give only the first argument, because ifSin> the program is large (large, with the volume of source text > 4mb),Sin> thenSin>
Then the program where goto is spread over all 4 megabytes of main(),
Surely no compiler can digest it...
FromKirill Frolov→ToAll29 November 2005
Hello Sinus
Sin> the answer is correct ;)Sin>
"Smart Guy" is undoubtedly a very authoritative source.
I repeat: in the original source of the question about goto it was stated at all
not something they like to repeat so much. The other day I literally came across it again.
It’s just that some citizens read diagonally
and are able to perceive everything exclusively straightforwardly and
literally.
I don't argue that students studying Pascal tend to use
goto to create spaghetti code. But this only means that
that means. This does not mean that goto is good or bad, because
it follows only that goto is a tool with which
can be used incorrectly. And nothing more.
I can put forward another criterion for the "readability" of the code:
if a function does not fit on one screen, it is bad and
unusable function. With a number of special exceptions, when
You can somehow justify why this is so. Where is the place?
goto - think for yourself. It's there.
FromGavrilov Vitaly→ToAll29 November 2005
Hello fk0
This is what we were told about goto
1) unconditional transition to x86 (from there everything went...) is ineffective due to the loss
time to reload the conveyor. It used to be like it is now - I don’t know
2) programs with goto are more difficult to understand. It's better to use tabs instead
arrange nesting of loops and other things. it looks much nicer
3) in C++ there is an implicit analogue of goto: throw...catch. essentially the same ear
only in profile. if the editor has syntax highlighting, then figure it out
The program is much easier in this situation.
FromAlexander Shushkov→ToAll29 November 2005
Hello fk0
Guys, can we draw a line on the topic?
Let me remind you that it sounded like “Calling functions via RST”.
It is advisable to “sort out” all the proposed options. Nobody ate this
won’t do it, I’ll try to do it myself, but, unfortunately, not soon.
FromKirill Frolov→ToAll29 November 2005
Hello, captain cobalt
cap> It is proposed to patch the address in the CALL command.cap> Then the call will be made directly, and JP is not needed.cap>
Then you will need to patch N times more, where N is the number of calls
functions. And the length of the list of addresses subject to correction will become
astronomical...
> It is also proposed to use meaningful numbers rather than function numbers> symbolic names.
Name, number - what the hell difference does it make? Unique, within
of this module, identifier. The number is shorter and simpler, and there is
where to write (instead of the address).
FromSlavik Tretiak→ToAll30 November 2005
Hello,GriV
Gri> I'm actually talking about speck...Gri> But take Blast for example! - compiler for ZX-BASIC and do itGri> in it, you will see that it will be exactly like this.
I don't know what Blast is! nor what is Tobos.
I know what Alasm is and that's enough for me ^_~
> And once again write, in addition to pure GoTo, a set of loop commands - you will see that> your stack will be used and your memory will be wasted.
i.e. you say that if Blast! does not digest cyclones normally, then they are nowhere to be found
shouldn't be used?
FromSlavik Tretiak→ToAll30 November 2005
Hello axor
axo> Guys, can we draw a line on the topic?axo> Let me remind you that it sounded like “Calling functions via RST.”axo> It is advisable to “sort out” all the proposed options. Spruceaxo> no one will do this, I will try to do it myself, but, unfortunatelyaxo> not soon.
Apparently you will have to do this.
And I repeat - the JP plate at the beginning of the ROM is the most optimal option, both
memory size and speed.
FromSlavik Tretiak→ToAll30 November 2005
Hello fk0
fk0> $ grep -r goto . | wc -lfk0> 12fk0> About a year and a half.
yes. You can't argue against such an argument ;)
> 3. How to treat pearl barley next
the same as for Java's break
FromAlexander Shushkov→ToAll30 November 2005
Hello Sinus
Sin> Apparently you will have to do this.Sin> And I repeat - the JP plate at the beginning of the ROM is the most optimalSin> option both in memory size and speed.
Apparently this will be the case if no one gets ahead or if each of those who proposed does not
will formulate his thoughts clearly and distinctly.
FromKirill Frolov→ToAll30 November 2005
Hello Sinus
Sin> Apparently you will have to do this.Sin> And I repeat - the JP plate at the beginning of the ROM is the most optimalSin> option both in memory size and speed.
For ROM - yes, I agree. But I think it makes sense to navigate
on ROM as something more than a system test and initial
bootloader -- NO. Because the space is small and unmodifiable. If
What you need is solid-state memory: bootloader in ROM, the rest
on compact flash. But here there may be other methods. But I
again, I think CALL through the JP xxx array is the most optimal
in memory and speed. Direct CALL wins only 10
clock cycles but terribly inconvenient both for loading and creating
boot file in general (as in ALASM, a list of addresses for
compose a patch?) We are talking about downloading to an absolute address
incl. Via RST there is no point at all except for brakes.
That is, there may be meaning, but only where it is needed
EXACTLY MACHINE CODE, in no case an interpreter,
and you need terrible memory savings. There are no such cases right away
I'll name it. Where you need to save memory it will be more useful
from an interpreted language (even BASIC), from FORTH maybe
be.
FromAlexander Shushkov→ToAll30 November 2005
Hello fk0
fk0> (as in ALASM list of addresses forfk0> compose a patch?)
This can be done, Alco wrote about this somewhere and there was an example. Or maybe not Alco
it was not at all. The topic was about relocation.
FromGavrilov Vitaly→ToAll30 November 2005
Hello axor
axo> Guys, can we draw a line on the topic?axo> Let me remind you that it sounded like “Calling functions via RST.”axo> It is advisable to “sort out” all the proposed options. Spruceaxo> no one will do this, I will try to do it myself, but, unfortunatelyaxo> not soon.
It's time to demand %)
In the form of my ten cents, I offer direct calls to the addresses of the system functions,
patchable (in a word!) when loading the program.
Differences from the kernel method (set of jp at fixed addresses)
- 2 bytes per entry point address (which vary from version to version) versus 3
bytes
- 2 bytes for each call in a custom program. for later setup.
In the future, this memory can be used for your own needs (you don’t have to count it)
- several hundred(?) bytes per tuner (loss)
We win 10 clock cycles for each call and lose a few
hundreds(?) cycles per tuner (once during the entire program operation)
FromKirill Frolov→ToAll1 December 2005
Hello axor
axo> This can be done, Alco wrote about this somewhere and there was an example. Or maybeaxo> it wasn't Alco at all. The topic was about relocatability.
Compilation into two addresses and comparison. Here the rake is planted:
┌─- code ───
typical code:
LD E, char
LD D, FONT / 256
...
└── code ───
Everything relocated is necessarily two-byte. Yes, and the question is
how to then distinguish CALL xxx to a library from addresses,
changed as a result of a shift in the starting address? Alone
questions.
But the point is that there are programs with an absolute address
downloads without any relocation. To them it's all just unnecessary
complication. No relocation when calling via JP xxxx
there is no need to invent at all. It’s simply taken and assembled “head-on”.
After downloading, the addresses of the JP xxxx list were initially known,
All that remains is to replace the function numbers with actual addresses. Location
valid addresses are also known, in case
ROM they (addresses) themselves are located according to predetermined
absolute addresses. The result is trivial code.
FromKirill Frolov→ToAll1 December 2005
Hello Vitamin
Vit> Just ask for %)Vit> In the form of my ten cents, I offer direct calls to function addressesVit> systems that are patched (in a word!) when loading the program.Vit> Differences from the kernel method (set of jp at fixed addresses)Vit> - 2 bytes per entry point address (which vary from version to version)Vit> vs 3 bytesVit>
For the "library" - yes.
> - 2 bytes for each call in a custom program. for the next one> settings. in the future, this memory can be used for your own> needs (can be ignored)> - several hundred(?) bytes per tuner (loss)>
If in a ROM disk (small...)? And then you need to configure
absolutely all programs. Via JP xxxx "library" calls
loaded at an absolute address (for example, subroutine calls
ROM) does not need to be configured.
In addition, there is one more nuance. Let's say the "library" implements
some kind of “driver” for the device. For example, HDD. Downloaded, patched -
work. Fine. WHAT TO DO WHEN YOU NEED A COMPUTER
DOWNLOAD SEVERAL OF THESE "DRIVERS"? This is where all the technology breaks down. INoption with JP xxxx there are two ways to do this:
1) to switch between different "libraries" simply
the entire JP xxxx array is copied over the current one
used. Slow switching, fast calling.
2) call using the method of calling virtual functions, I once wrote.
Calling is slow (100 clock cycles), time switching is not
takes away.
> We win 10 clock cycles for each call and lose> several hundred(?) cycles per tuner (once during the entire operation> programs)
As a compromise I would suggest as a base
option is still JP xxx. Saving a byte from two to tens
"library" functions will not take much away. And who really needs
can quickly implement a variant with direct
challenge. It could also be the other way around, but it’s more difficult.
and more RAM is needed.
FromKirill Frolov→ToAll1 December 2005
Hello Vitamin
Vit> macros for address-sensitive commands and that's it...
For ALASM - yes. I don't like. Strong list of addresses for
The patch turns out to be big. And then in this version it is not implemented
filter function (when its address is inserted into JP xxxx instead of
valid).
FromGavrilov Vitaly→ToAll1 December 2005
Hello fk0
fk0> Everything relocatable is necessarily two-byte. And the question isfk0> how to then distinguish CALL xxx to a library from addressesfk0> changed as a result of a shift in the starting address? Alonefk0> questions.
not a fact! You can make relocatable one-byte points. once again I give
link to your work on this topic. everything works fine and enough
universal. http://zxdocs.fatal.ru/coding/module.zip
fk0> For "library" - yes.
not only. By and large, the program is no different from the library.
fk0> If in a ROM disk (small...)? And then you need to configurefk0> absolutely all programs. Through JP xxxx calls to the "library"fk0> loaded at an absolute address (for example, subroutine callsfk0> ROM) does not need to be configured.
There are not so many calls to ROM functions (in the sense of code). much more often these calls
happen. and no one has canceled compression yet...
In short, it all comes down to priority - speed or size. depending on
This is the option you need to choose. proposed with self-patching according to the jp table
combines all the worst features of both methods%)
FromKirill Frolov→ToAll2 December 2005
Hello Vitamin
Vit> not a fact! You can make relocatable one-byte points. once againVit> I already give a link to my work on this topic. everything works great andVit> is quite universal. http://zxdocs.fatal.ru/coding/module.zipVit>
Again, understand the assembler... Briefly, on macros?
> there are not so many calls to ROM functions (in the sense of code). much more often> these calls occur.>
That's what I'm talking about.
> in short, it all comes down to priority - speed or size.> Depending on this, you need to choose an option. proposed with> self-patching the jp table combines all the worst features of both methods> %)
RST vs CALL? Funny. Saving a byte per call. And loss
hundreds of bars. As well as CALL direct vs via JP. Savings
10 clock cycles in a subroutine that eats up hundreds or thousands is no less ridiculous. But hemorrhoids
with the compilation through the roof. Not everything is in
they write to alasme. And it’s practically impossible to adapt ready-made programs (well, it’s
Of course he will come back to the option with JP xxxx).
I think JP xxxx is a good method. And, of course,
when it's in RAM. Of course, it works in ROM too, but the possibilitiesno longer the same. For libraries loaded into RAM, the JP xxxx array is all
it carries around with the program, so no one bothers you to carry it around
for the ROM version. And completely, all the functions. What
this gives: tuning to ROM via LDIR from ROM to this
the same array in RAM. And then the most interesting thing: the ability to create
filter functions for library functions (tracing
calls, for example, and other hacking).
FromGavrilov Vitaly→ToAll2 December 2005
Hello fk0
fk0> Again, understand the assembler... Briefly, can you use macros?
everything was done there for their loved ones...
fk0> As well as CALL direct vs via JP. Savingfk0> 10 clock cycles in a subroutine that eats up hundreds or thousands is no less funny.fk0> But the hassle with the compilation is through the roof.
saving 10 cycles per call! and spending hundreds-thousands of cycles once per
launch. It is from these considerations that you should choose between speed and size.
RST is out of the question - too slow and too few advantages.
fk0> I think JP xxxx is a good method. And, of course,fk0> when it is in RAM.
in this case, it’s easier to pull out the table of wildcard points as in the method
patching. It will take up less space, and the patcher can already be in the ROM.
FromValery Grigoriev→ToAll2 December 2005
Hello fk0
fk0> For ALASM - yes. I don't like. Strongly list of addresses forfk0> the patch turns out to be big. And then in this version it is not implementedfk0> filter function (when its address is slipped into JP xxxx insteadfk0> real).
Not that big - it is in memory after broadcasting the program according to the given
addresses will take up 0 (zero) bytes of memory - it’s simply not needed
after the broadcast.
The structure that the vitamin is lobbying for has, in addition to the fact that there are no problems with
challenges and a bunch of other advantages.
In addition, the specified table for converting function calls from Call 0 to
Call has significantly higher speed and noise immunity -
because in ROM Call followed by JP will always be
work, but what if suddenly the ROM version is wrong? Function type tracking issue
their numbers, tracking changes from version to version will terrify
the author of the thread himself and he will actually get hooked on the slow RST :D
But if there is a module like a vitamin, then the program simply will not
will start - the ROM will display the error “invalid function number” and, for example, offer
interrupt work.
And now here’s a quick question: which program writer hasn’t done something like this?
p/p
_LDIR_ LDIR
RET
?And after this, someone will say that this is ineffective?
It is precisely these fragments of code that are generally already in the ROM that will not be needed
insert into your program - they will also be called CALL <> but for this
You will need to make the appropriate settings, but this is done only once!!!
How many times does this run in the program? More than a dozen, I know for sure!
clearing the screen, flipping the screen, flipping other areas, etc. etc. - this
everything IS in ROM, but few people use it because it becomes addictive
depending on the ROM version - in the 82nd ROM there are some points, in the 90th - others, but you never know the program
will run into some thread version of the ROM curve. That is why ROM versions are STILL
mails have not changed - at least such parts have changed that would be minimal
changed the structure of the ROM code - TR-DOS, as it was crooked, is probably the same
will remain as crooked BASIC 48 and will remain so.
With the system of patches “on the fly” of the code, everything is simple - we change the ROM system - we change it in it
same broadcast points (i.e. what should this or that Call or Jp be replaced with) - and
we sausage the ROM version at least somehow - at least we put part of it with the shadow ROM at least
we pack it and during Reset we unpack it into memory - when we “patch” the program it
will still call what is needed from where it is needed and will in no way lead to a reset or
what other irrational behavior?
FromKirill Frolov→ToAll5 December 2005
Hello Vitamin
Vit> has everything. and functionality and problems.Vit>
I already wrote: it is impossible to dynamically create a filter function, which kills
rooting the idea of tracing
calls. STS does not show labels. Nothing at all
You can't change it on the fly. Load another library (driver) --
it is impossible. If you dig deeper, you won't find anything out there.
Yes, as a replacement for CALL, it is good. But we're not talking about CALL, we're talking
about the mechanism for calling library functions. And about
what properties does this mechanism (not) have?
> heh. and the fact that the compiler generates code for a hard-wired address is zero> gut? or is there also a relocatable structure?>
There are compilers that cannot generate position-independent
(relocatable, load-configurable) code. There are compilers that can't
generate such code.
There are assemblers that do not support the ability to create the necessary information
to reconfigure the code to the address. Finally, there are simply programs that imply
absolute download address
(99.9% on Spectrum).
> then what's the problem? this is just one of the implementations demonstrating> application of the idea, the format is quite crude, but it works.>
No one doubts that it can theoretically work.No one even says that this is bad for some reason related to
practical implementation. Nobody even says that
This is a bad replacement for CALL - maybe a good one. I say this
bad interface. Because it's just customizable
CALL. It is inconvenient to work with him in dynamics. It's inconvenient to debug. Him,
Finally, you can't run directly from ROM - simply because
the entire code will require customization, not just a small one
interface part, which can be placed in RAM in a small volume
(we are not talking about the practical use of certain solutions yet).
> if it weren’t for him, everyone would say “stop chatting, give me some code> working! you give the code, the front interface becomes distorted %)))>
Alas, this is true. This requires a lot of serious “theoretical” work. Code
writing is a simple matter, a monkey's job in essence.
There are enough other things to do in life. And write code in the trash bin
Moreover, few people will want to.
> with existing in the sense in the source code or in the binary? in the first> in case the problem is solved by contextual search and replacement by text or> by writing a special version of the compiler (at least). and the second case -> clinic... even the jp xx table won't help there...> (we're talking about integrating existing code into the system)
I'm not sure about search and replace. I even think it’s absolutely impossible
Adapt any code to your macros. "Relocator"
It probably doesn't support all assembly language expressions. Otherwise
In this case we will end up with compilation before execution.
I of course meant binary code. JP xxxx is all that remains,
if you wrap it in this interface.
> when compiling... for example, we use the old version of the system, and the program> compile using new header files. option with jp> produces a colorful glitch on the entire screen, and >
And we’ll take it and hang ourselves with the cord from the modem. And we will die from this. Therefore modems
- absolute evil. Same level of argumentation.
For the inattentive: THE INTERFACE DOES NOT CHANGE, IT IS ONLY INHERITED. Or how
option, there is a mandatory basic
interface that allows you to get information about the interface you are using on the go and,
as an option, switch different
interface versions. In general, one thing is true: always available
basic interface. Through which you can identify the used
interface and possible incompatibility. This is possible at the stage
"Settings" of the program.
> the customizer just swears dirty about non-existent functions and nothing> does not run>
The option with JP xxxx also, oddly enough, requires configuration.
Once again: the JP xxxx array is dragged separately IN EACH
DOWNLOADABLE PROGRAM. When loading is updated from the array
JP xxxx available at the library. Why so: because the addresses
in specific commands CALL and JP address exactly their “local”
an array, because its address is known at compilation time,
and the library download address is unknown. As an optimization,
when placing the library at a fixed address in the ROM, a direct
addressing the JP xxxx array located at
to a known address in ROM. But this method of addressing is
NOT DESIRED because it limits the possibilities of using the interface in
parts of filtering, tracing, etc.
And in this case, since the setting becomes "unnecessary" there really is
opportunity to run into a problem. But against this, as in reality
configuration, just by calling the corresponding function of the BASIC INTERFACE,
GUARANTEED TO BE AVAILABLE IN THE INTERFACE, you can find out how available
the library is compatible with the required one.
> mixed system. symbolic names are used for compilation and> static linking. there should be no symbolic names in the final module> in general (although GriV advocates for them, it’s worth it.... but I remember> it’s a pity for such an outrage %)))>
I would feel sorry too. Because there is no practical sense
has. It is better to solve the problem of identifying interfaces. And besides,
assembler level symbolic names - how to make them available at the code level?
Again, serious technical limitations. ALASM can and does, but GENS
again no. Or let’s say ZASM doesn’t know how.
> this is simply not the best example IMHO, of course no one should do that> will be. This means generally procedures from ROM. there are quite a lot> different fragments can be used.>
We are talking about a library of functions with a CLEARLY DEFINED INTERFACE, or about
disjointed set of code fragments?
> refers to the overhead of calling the procedure. multiplied by> number of actual calls...>
There is a function to wait for a button to be pressed. What's the point if you're on it?
Will you save 10 cycles? If it's really for you
speed is critical: import text (assembly) of functions and
give up library stuff. Because 27 clock cycles for CALL and RET in addition -
not a little either. Saving 10 clock cycles in order to immediately give 27 (per iteration) - here
I don't understand this. And I don't want to understand. This is nonsense.In addition, iterative functions should be rewritten so that the loop
transfer to the library. The condition for ending the loop can be determined by the function,
a pointer to which is passed as an argument when calling a library function --
that's where the savings are.
> Truly!!! Know three options painted (GriV did this quite well> qualified). Everyone can choose what is beneficial to them. if points> there are not many inputs, then table jp xxx will do, and if there> spreading cranberries for 1000 with horseradish calls, then you can spend it> a hundred bytes per customizer, saving a kilobyte on the table
If there is a cranberry for 1000 calls, 50 bytes per call will take
all the memory and nothing will remain... Cranberries need their own, specific
solutions.
We're talking about something more general. Where a call takes hundreds-thousands, less often tens
thousands of clock cycles and tens, less often hundreds of bytes. Where is the total number of calls per module --
on the order of a few to tens. Example?
Modem "driver", CMOS, HDD, CDROM... Arithmetic module with
floating point (where are there hundreds of calls? So many functions
will not be enough). Library of string functions. Library
stream (byte-byte) I/O for TR-DOS. Packaging
HRUST. Text console, mouse driver with arrow, primitive (maximumZXASM level) "GUI" interface. Perhaps in the latter case it is possible to exceed
limit of 100 calls. In this case, the interface can be divided into 2-3 parts
(limit is 85 virtual functions per object).
FromValery Grigoriev→ToAll5 December 2005
Hello fk0
2fk0> I agree with many of your arguments, but you agree with mine (and Vitaminov’s)2fk0> you don’t want to agree with the arguments in principle, you don’t even want to 2fk0> consider options for calls of a different type (?). I already wrote in 2fk0> comparative table, what are the advantages and disadvantages of this or that 2fk0> method - so everyone has the right to choose what they want. I THINK (i.e. this2fk0> IMHO) that all other methods have the right to life, but only insofar as 2fk0> because there must be an alternative - I prefer not to use them 2fk0> (I have already described my choice), and therefore I think that I have almost revealed the topic of the thread 2fk0> (missing maybe some very rare method of calling). A2fk0> so I just won’t continue creating flames ;))))) :v2_wink:
P.S. 100% offtopic, but very correct advice in life. Our teacher
philosophy has always taught us to act as follows: “Before criticizing
point of view, feel on your own skin all its advantages and disadvantages, you will not
You like to do this because your worldview is very limited." In this sense I
I shared your (fk0) point of view, I MYSELF tried to write this way andI suffered through all the pros and cons of the system, because I think I have enough
objective point of view.
FromSemyon Dobrovolsky→ToAll5 December 2005
Hello axor
Additional ideas:
1. Add alignment directives to the module so that it is loaded, for example, by
address divisible by 256.
2. Patching not only with direct meanings, but also with meanings
converted according to the formula. Write formulas to the module object file in
reverse Polish notation.
FromGavrilov Vitaly→ToAll5 December 2005
Hello, captain cobalt
2fk0. I won’t bother with quotes and answers, I’m sorry. GriV can be said to express
thoughts hovering in my cauldron.
ishsho one thought arose. It means we have such a global goal - to slap
modular structure, each module inside has a table that
replaces/pins to the main table of entry points.
Number Adyn's question: is the module relocatable? if not, then the idea is not worth breaking
eggs or pennies (as you like)) if relocated, then see.
above.
Question number two: where exactly will we pin/replace the table?
virtual functions of this particular module?
Maybe I misunderstood something, but...
cap> Additional ideas:cap> cap> 1. Add alignment directives to the module so that it loadscap> for example at an address that is a multiple of 256.cap> cap> 2. Patching not only with immediate values, but alsocap> values converted by the formula. Write formulas incap> module object file in reverse Polish notation.
uh huh. p1. IMHO can be solved by sacrificing a few bits in the configuration
byte (absolutely no problem). about p2. the idea is worthwhile, but it's a little difficult IMHOrests on the difficulty of creating a Polish recording. if I'm not mistaken, in modules for
is-dos this was the practice. Can anyone enlighten me on how successful it is?
FromValery Grigoriev→ToAll5 December 2005
Hello, captain cobalt
cap> Additional ideas:cap> cap> 1. Add alignment directives to the module so that it loadscap> for example at an address that is a multiple of 256.cap> cap> 2. Patching not only with immediate values, but alsocap> values converted by the formula. Write formulas incap> module object file in reverse Polish notation.
It's better to post this in a separate thread.
FromValery Grigoriev→ToAll5 December 2005
Hello Vitamin
People! offtopic gone!
Fromvan Yu Shinn→ToAll8 December 2005
Hello axor
The JP table works quite well when it comes to ROM flashing.
Now let's say we want to use JP tables and again
developed modules designed to work in RAM. Then each module
you will need a JP table for its procedures. We cannot each module for it
JP tables assign an address that will not change for the rest of your life.
This means that JP tables must be movable. And if they should be
moving, then you will need to patch all CALLs into these tables. What if
If you need to patch CALLs, then why are these tables needed? ;)
FromKirill Frolov→ToAll8 December 2005
Hello, captain cobalt
cap> The JP table works quite well when it comes to ROM firmware.cap>
It's exactly the opposite. The ROM is just bad for a number of others
reasons...
> Now let's assume that we want to use JP tables for again> developed modules designed to work in RAM. Then> each module will need a JP table for its procedures. We can't> assign each module for its JP table an address that will not> change for the rest of your life. So the JP tables should be> movable. And if they must be movable, then it will be required> patch all CALLs into these tables. And if necessary> patch CALLs, then why are these tables needed? ;)
Horror. It is not CALL that is patched, but JP in the table itself. The point is that
the program itself is statically linked with this table,
at the compilation stage. Her address is known exactly as the address
locally defined functions for a given program.
And it’s easier to patch one table than all CALLs, especially
that this is done with one LDIR instruction - by copying
exactly the same as another table, but statically linkedwith another library program. You only need to do it once before
by starting, know the address where the table is in the library and copy it
on top of your table. Well, of course, variations are possible here when
for example, the local table is smaller than the library table (included
only used functions) and only the addresses of the necessary ones are copied
functions.
Fromvan Yu Shinn→ToAll9 December 2005
Hello axor
fk0> And to know what to patch, you need to attach a shortcut to each addressfk0> indicating the module to which it belongs.
All that remains is to overcome this difficulty for complete happiness.
fk0> Currently, no assembler supports this.
This is a really serious problem.
Not everyone will like the solution for only one assembler.
The problem should probably be solved by developing an assembler that can
replace all other assemblers.
FromKirill Frolov→ToAll12 December 2005
Hello, captain cobalt
cap> All that remains is to overcome this difficulty for complete happiness.cap>
Here's how to overcome it, for example, for ZXASM 3.00?
> Not everyone will like the solution for only one assembler.> > Probably, the problem should be solved by developing an assembler that> will be able to replace all other assemblers.
This is a strong word. "SOLUTION FOR ONLY ONE ASSEMBLY..." --
hence the development of ONE ASSEMBLY
It won't do anything, that's obvious.
I look from the other side. For the basic method, you can take the option with JP xxx.
Because information is easily extracted from this structure
required for the functioning of any other method. Who desperately needs how
direct call - let him patch his calls as he pleases using any method, and addresses from
JP xxx can remove signs immediately.
Who needs RST #10 - similarly. Write your code, addresses
take it from the same tablet. Patching all programs using the direct method
call is impossible. Use RST absolutely everywhere - too
impossible. Due to purely software restrictions.
FromKirill Frolov→ToAll2 January 2006
Hello, captain cobalt
cap> That's it. The table address must be fixed.cap>
"Regarding me or you?" (C)
It is perfectly fixed relative to each program
with which a COPY of this table is linked. You see,
COPY. There are a lot of them. These tables. Each program has its own. And one more thing
one per library, YOUR OWN COPY. Therefore her address is known,
how the address of any procedure in its program is known.
> This is not a big problem if there is only one table.> But what if there are two or more tables?> Who chooses addresses for tables?>
Assembler. When compiling.
> What if independent developers choose overlapping addresses?>
Then two programs cannot be loaded at the same time. Or two
libraries. Therefore, write relocatable code. And the table
the relocation itself will work out. A COPY of the table, that is,
local. And then, when everything is loaded, the information
from the MAIN TABLE, which is associated with the function program
which are called through this table must be copied
in SECONDARY TABLES, which are used by third parties
programs to call functions from a library or program
with which the MAIN TABLE is associated. What's unclear here?> This method is actually used in offtopics. Table together with> is molded into one whole by the code. But there CALL commands are relative,> therefore always shown in the table no matter what> module was loaded to address. But on the Z80 there are no relative CALLs, only> short JR.
I just described how the "relative CALL" substitute works. This is exactly what
he allows it. Call to a known address
relative to its own software module.
FromKirill Frolov→ToAll2 January 2006
Hello, captain cobalt
cap> This completely sucks and mustdie.cap> For this reason alone, this method is a “firebox.”cap> And when recompiling the library, you will need to recompilecap> all dependent programs.cap> make worldcap> Ugh.cap>
You don't read the text diagonally, right? I said clearly -
There are several tables and each has its own, arbitrary address.
It is configured before launch.
> This does not apply to ROM only. ROM is always at the same address. And a table for him> can be done at a fixed address.>
It's possible. The question is: your own table of ROM programs - yes. table,
used by downloadable programs is also possible, but then there is a problem
the problem you describe, that’s why it’s not advisable to do this, and it’s possible
do not do it, but use your table located in RAM. Which is essentially
case is a complete copy of the ROM with the only difference being
that its address (the one in RAM) is known. BUT HE IS NOT FIXED. Rather,
not necessarily fixed,
if the program is relocatable. What's unclear here?
> Of course.> Every time, before making a CALL, you need to calculate the address at which> do this CALL.>
Nonsense. For programs with an absolute load address, simply
LDIR is made or the table is otherwise copied from ROM.
The address of which (ROM) may also not be fixed.
For relocating programs, when they are configured to the launch address,
the address of your own table is configured AUTOMAGICALLY!
And the addresses in this table are again copied from ROM.
> What is the overhead for the execution time of these calculations and> memory to store their code?>
Time - 10 cycles. Memory 3*N, where Ni is the number of “external” ones in relation to
loaded function program.
> Do they exceed the costs of one-time patching?
Over an infinite period of time - exceed (oo*10 == oo).
Fromvan Yu Shinn→ToAll2 January 2006
Hello axor
fk0> Then two programs cannot be loaded at the same time. Or two libraries.
This completely sucks and mustdie.
For this reason alone, this method is a “firebox”.
Also, when recompiling the library, you will need to recompile everything
dependent programs.
make world
Ugh.
This does not apply to ROM alone. ROM is always at the same address. And he can have a table
do it at a fixed address.
fk0> Therefore, write relocatable code. And the table itself is relocatablefk0> will work.
Well, of course.
Every time, before making a CALL, you need to calculate the address at which to make
this CALL.
What is the overhead in execution time for these calculations and in memory for
storing their code?
Do they not exceed the costs of one-time patching?
Fromvan Yu Shinn→ToAll2 January 2006
Hello axor
fk0> I clearly said - there are several tables and each has its own addressfk0> arbitrary.fk0> It is configured before starting.
Well okay.
Indeed, the dynamic linker can do this.
fk0> NOT FIXED. Or rather, not necessarily fixed, iffk0> relocatable program. What's unclear here?
The concept of “relocable program” implies patching addresses in CALL to
local moved table?
fk0> Time -- 10 clock cycles. Memory 3*N
And during loading except LDIR?
FromValery Grigoriev→ToAll19 January 2006
Hello,GriV
2fk0> generally speaking, this method of calling a p/n from other p/n strongly overlaps with 2fk0> other elements - well, I think it’s clear with which ones specifically - and is 2fk0> is a kind of optimal for the OS on the ZX.
Any data transfer interface can be used inside the p/n - even Hitech-C
even if it was developed by an unknown black man from Bobruisk - I think that the question is not
principled.
FromValery Grigoriev→ToAll19 January 2006
Hello fk0
2fk0> in fact there are several pitfalls here.
I agree, any acceleration (including the use of current funds
development as an acceleration of the process) carries a return on other resources -
a kind of “payment” for speed.
And now more specifically:
1. External memory - there is almost (!) as much of it as you want
Example: floppy disk, hard disk, compact disk
1.a. Using modular structures in the method, the system uses this memory
1.b. Using the core method does not imply any kind of transfer
"load" on this part of the computer
2. Internal memory
Example: RAM
The specificity is the impossibility of directly addressing an arbitrary point, only
through the page access mechanism. Page size - 16kb.
2.a. Modular structure - the program takes exactly as much as there is, and on
line more
2.b. Each call to RAM is supplemented by a jump line to a long address.
3. Relocability
This means transferring a program already compiled to any arbitrary address
Example: inside the program, go to the inner part:
Call Internal_label1
Internal_label1 ld a,1
Modifying a label within a program
ld a,5
ld(mem_label1+1)
mem_label ld h,0
3.a. The modular system - any way and anywhere - is its main bonus
3.b. Kernal system - I don’t understand how relocations are configured (if at all)there is such a possibility), more precisely, I realized that this is not easy to do
4. Calling external software and modules
Organization is understood in such a way that a loaded substation can
interact with other subsystems already available in ROM and RAM.
There is fundamentally no difference between 4.a. and 4.b. so don't paint them
I will.
And now the most important thing (kind of a snack):
Those who wrote OSs for Speck faced the problem of lack of RAM - a program
written and compiled did not want to take up less than 1 page - i.e.
how many memory pages there are - that's the maximum (or almost that much) you can
was download applications.
This is because it is difficult to predict where one program should end
(its code + service data) and, accordingly, another one will start from there. Because
As a rule, we managed to compile to address #C000.
Those. if there is already a loaded program from address #c000 and length say #1AF0
then you need the next loaded software to have the compilation address #DAF0 - but nothing
no less, although more address is possible. And if next time the program is
have the same starting address but the length is already #2AF0 - what to do?
This is one of the reasons for the emergence of the so-called. dynamic compilation -
it is not known in advance where the program should be loaded (base address).
Regarding program recording systems.
Modular system - now you can download as many programs as you needthere are memories, being attached to the page principle only PARTIALLY. I think from
The above example will make it clear why.
The kernel principle - exactly where they were there and remained - i.e. per process
It will take 1 page of memory.
Now regarding saving memory - there are direct and indirect benefits. Straight me
described in paragraph 1., and here they are indirect ones - you can now stuff them into memory
exceptional number of processes.
The AXIS itself can even be optimized (read - trimmed) to suit the 48K machine and
At the very least, applications in a modular structure will run on it.
Regarding the kernel system, we won’t be able to download more than 1 application.
(more precisely, we will download but not launch, there is no relocation).
fk0> Method N2 is extremely difficult to implement and requiresfk0> special support from the assembler, therefore, from my point of viewfk0> view, in the general case is not applicable and makes sense in somefk0> specific cases, for example, when it is extremely criticalfk0> function call time.
I agree with everything you said, but looking at the bonuses given by the modular
system, these shortcomings do not look so decisive.