Calling functions via RST

ZXNet echo conference «code.zx»

From Alexander Shushkov To All 15 November 2005

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

From acidrain To All 16 November 2005

Hello axor Hmmm, if it’s not a secret, then what are you planning to use it for?

From Alexander Shushkov To All 16 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.

From Kirill Frolov To All 17 November 2005

Hello axor axo> For any ROM firmware, the functions of which can not be used axo> 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.

From Andrey Bogdanovich To All 17 November 2005

Hello axor It’s written optimally, but it’s impossible to make it shorter.

From jtn To All 17 November 2005

Hello Specter Isn’t it wasteful to spend 16k ROM 512b on some kind of table?

From Kirill Frolov To All 17 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.

From Kirill Frolov To All 17 November 2005

Hello fk0 fk0> Available separately fk0> array of addresses - index in the array of this same number. It's already in ROM.

From Kirill Frolov To All 17 November 2005

Hello axor axo> Look at the proposed option below for calling any functions via axo> 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 ───

From Alexandr Sinyakov To All 17 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.

From Alexandr Sinyakov To All 17 November 2005

Hello Sinus Sin> SAM style: you have a knuckle in register A (I didn’t look carefully Sin> 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.

From Alexandr Sinyakov To All 17 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.

From Slavik Tretiak To All 17 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.

From jtn To All 17 November 2005

Hello, SAM style SAM> HL intact. Regarding A - you can border the program with this: yeah. in ROM...

From Aleksey Senilov To Alexandr Sinyakov 18 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 y AS> we have 6 more alternative registers, IX and IY. You can even R AS> to use, but this is already a perversion... You can also PUSH and POP AS> 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.

From Alexandr Sinyakov To All 18 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.

From Kirill Frolov To All 18 November 2005

Hello, SAM style SAM> Hmm... Didn't take it into account. SAM> Then A is sacrificed. An extreme case for passing parameters SAM> we have 6 more alternative registers, IX and IY. You can even R SAM> 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 no SAM> 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.

From Kirill Frolov To All 18 November 2005

Hello Sinus Sin> SAM style: you have a knuckle in register A (I didn’t look carefully Sin> 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 and Sin> is faster, then the option proposed by fk0 is the best. division Sin> functions into two (function / subfunction) is the wrong approach Sin> 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.

From Kirill Frolov To All 18 November 2005

Hello axor axo> Why can’t JP xxxx be made already in ROM, so as not to patch axo> 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).

From Alexander Shushkov To All 18 November 2005

Hello fk0 fk0> Here in the JP instructions xxxx is the number written instead of xxxx. This is when fk0> on disk. And when in memory the number changes to an address. Available separately fk0> 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...

From Vladimir Kladov To All 18 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.

From Semyon Dobrovolsky To All 18 November 2005

Hello axor fk0> ┌─- code ─── fk0> call function fk0> ..... fk0> fk0> function: fk0> JP xxxx ; where xxxx is patched to the required address fk0> ; 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 JP axo> 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 for fk0> 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.

From Slavik Tretiak To All 18 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.

From Gavrilov Vitaly To All 19 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

From acidrain To All 19 November 2005

Hello axor axo> For any ROM firmware, the functions of which can not be used axo> changing the numbers of established functions from version to version. I understand, but what is the firmware? 48basic? =) Or what’s yours?

From Alexander Shushkov To All 19 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.

From Alexander Shushkov To All 19 November 2005

Hello, acidrain aci> I understand this, but what is the firmware? 48basic? =) Or what’s yours? Secret...

From Vladimir Kladov To All 20 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.

From Gavrilov Vitaly To All 20 November 2005

Hello axor axo> Then it turns out that each restart needs its own address table axo> functions, and this, it seems to me, is wasteful. no more wasteful than storing transition tables for each subfunction. but there are fewer hemorrhoids.

From Alexander Shushkov To All 22 November 2005

Hello Vitamin Vit> is no more wasteful than storing transition tables for each Vit> 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.

From Chunin Roman To All 23 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).

From Alexander Shushkov To All 24 November 2005

Hello, SAM style SAM> And here no one thought what would happen if an inquisitive brain like mine SAM> will try to call a subfunction with a number greater than the number of subfunctions SAM> for this function? At best, there will be a call to a completely different program, and SAM> at worst - computer stupor. Or it is necessary to install protection against such insanity SAM> 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.

From Kirill Frolov To All 24 November 2005

Hello, SAM style SAM> ex (sp),hl stack: procedure address, return address, param.HL - in HL SAM> 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.

From Slavik Tretiak To All 24 November 2005

Hello fk0 fk0> As for the arguments, I prefer to follow the accepted conventions fk0> for the HiTech-C compiler. They are quite comfortable. fk0> {{skip}} fk0> The HL and A registers have special meaning. When programming fk0> in OO style in HL contains a pointer to a structure object fk0> 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 ^_~

From Kirill Frolov To All 24 November 2005

Hello Sinus Sin> fk0 Sin> in modern axes on modern petsets there is a modern protected Sin> mode, in which you can redefine the jump addresses of int commands Sin> 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...

From Gavrilov Vitaly To All 24 November 2005

Hello fk0 fk0> When programming fk0> in OO style in HL contains a pointer to a structure object fk0> the first element of which is the address of the array "JP xxx" pointers fk0> 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

From Kirill Frolov To All 25 November 2005

Hello Sinus Sin> this is if you steer objects. Sin> as practice shows, OOP is effective only on sufficiently large ones Sin> tasks. Sin> in the case of Spectrum, the usual procedural approach often turns out to be Sin> 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.

From Kirill Frolov To All 25 November 2005

Hello Vitamin Vit> ...steer objects... Vit> Vit> why not use the index register for these purposes? IMHO Vit> is more rational (after all, a structure). and the second register pair Vit> is used to store the addresses of variables on the stack. it turns out Vit> 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.

From Slavik Tretiak To All 25 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.

From Valery Grigoriev To All 26 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 yours Sin> 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 and Sin> 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 case Sin> 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 this Sin> is a variation of the break operator, only it indicates where this break is needed Sin> 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, like Sin> you need to write programs, namely: use the functions, for, while, and Sin> 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.

From Valery Grigoriev To All 26 November 2005

Hello, Vladimir Kladov Vla> There is such a thing called a macro. Defines a macro Vla> Vla> PrintChar MACRO char Vla> RST 16:DEFB char Vla> ENDM Vla> 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 exist Vla> 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

From Slavik Tretiak To All 27 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.

From Valery Grigoriev To All 28 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???

From Valery Grigoriev To All 28 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.

From Valery Grigoriev To All 28 November 2005

Hello Sinus Sin> this is the first time I hear this argument from you, because it is absolutely clear that GOTO Sin> 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.

From Slavik Tretiak To All 29 November 2005

Hello,GriV Gri> 2Sinus> a very original answer to the question “by whom and for what” - “smart Gri> 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.

From Slavik Tretiak To All 29 November 2005

Hello,GriV Gri> Well, that's what you think - take any of the compilers - get it and Gri> 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.

From Kirill Frolov To All 29 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

From Kirill Frolov To All 29 November 2005

Hello Sinus Sin> in fact, smart guys give only the first argument, because if Sin> the program is large (large, with the volume of source text > 4mb), Sin> then Sin> Then the program where goto is spread over all 4 megabytes of main(), Surely no compiler can digest it...

From Kirill Frolov To All 29 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.

From Gavrilov Vitaly To All 29 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.

From Alexander Shushkov To All 29 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.

From Kirill Frolov To All 29 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).

From Slavik Tretiak To All 30 November 2005

Hello,GriV Gri> I'm actually talking about speck... Gri> But take Blast for example! - compiler for ZX-BASIC and do it Gri> 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?

From Slavik Tretiak To All 30 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. Spruce axo> no one will do this, I will try to do it myself, but, unfortunately axo> 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.

From Slavik Tretiak To All 30 November 2005

Hello fk0 fk0> $ grep -r goto . | wc -l fk0> 12 fk0> 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

From Alexander Shushkov To All 30 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 optimal Sin> 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.

From Kirill Frolov To All 30 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 optimal Sin> 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.

From Alexander Shushkov To All 30 November 2005

Hello fk0 fk0> (as in ALASM list of addresses for fk0> 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.

From Gavrilov Vitaly To All 30 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. Spruce axo> no one will do this, I will try to do it myself, but, unfortunately axo> 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)

From Kirill Frolov To All 1 December 2005

Hello axor axo> This can be done, Alco wrote about this somewhere and there was an example. Or maybe axo> 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.

From Kirill Frolov To All 1 December 2005

Hello Vitamin Vit> Just ask for %) Vit> In the form of my ten cents, I offer direct calls to function addresses Vit> 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 bytes Vit> 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.

From Kirill Frolov To All 1 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).

From Gavrilov Vitaly To All 1 December 2005

Hello fk0 fk0> Everything relocatable is necessarily two-byte. And the question is fk0> how to then distinguish CALL xxx to a library from addresses fk0> changed as a result of a shift in the starting address? Alone fk0> 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 configure fk0> absolutely all programs. Through JP xxxx calls to the "library" fk0> loaded at an absolute address (for example, subroutine calls fk0> 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%)

From Kirill Frolov To All 2 December 2005

Hello Vitamin Vit> not a fact! You can make relocatable one-byte points. once again Vit> I already give a link to my work on this topic. everything works great and Vit> is quite universal. http://zxdocs.fatal.ru/coding/module.zip Vit> 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).

From Gavrilov Vitaly To All 2 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. Saving fk0> 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.

From Valery Grigoriev To All 2 December 2005

Hello fk0 fk0> For ALASM - yes. I don't like. Strongly list of addresses for fk0> the patch turns out to be big. And then in this version it is not implemented fk0> filter function (when its address is slipped into JP xxxx instead fk0> 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?

From Kirill Frolov To All 5 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).

From Valery Grigoriev To All 5 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. this 2fk0> 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). A 2fk0> 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.

From Semyon Dobrovolsky To All 5 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.

From Gavrilov Vitaly To All 5 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 loads cap> for example at an address that is a multiple of 256. cap> cap> 2. Patching not only with immediate values, but also cap> values converted by the formula. Write formulas in cap> 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?

From Valery Grigoriev To All 5 December 2005

Hello, captain cobalt cap> Additional ideas: cap> cap> 1. Add alignment directives to the module so that it loads cap> for example at an address that is a multiple of 256. cap> cap> 2. Patching not only with immediate values, but also cap> values converted by the formula. Write formulas in cap> module object file in reverse Polish notation. It's better to post this in a separate thread.

From Valery Grigoriev To All 5 December 2005

Hello Vitamin People! offtopic gone!

From van Yu Shinn To All 8 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? ;)

From Kirill Frolov To All 8 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.

From van Yu Shinn To All 9 December 2005

Hello axor fk0> And to know what to patch, you need to attach a shortcut to each address fk0> 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.

From Kirill Frolov To All 12 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.

From Kirill Frolov To All 2 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.

From Kirill Frolov To All 2 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 recompile cap> all dependent programs. cap> make world cap> 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).

From van Yu Shinn To All 2 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 relocatable fk0> 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?

From van Yu Shinn To All 2 January 2006

Hello axor fk0> I clearly said - there are several tables and each has its own address fk0> arbitrary. fk0> It is configured before starting. Well okay. Indeed, the dynamic linker can do this. fk0> NOT FIXED. Or rather, not necessarily fixed, if fk0> 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?

From Valery Grigoriev To All 19 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.

From Valery Grigoriev To All 19 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 requires fk0> special support from the assembler, therefore, from my point of view fk0> view, in the general case is not applicable and makes sense in some fk0> specific cases, for example, when it is extremely critical fk0> 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.