I think it's because there is very little code reuse going on in the Spectrum community. The people who are producing have their own stuff and reuse their own stuff. They don't share much or use other's work much.
1. Actually writing some code by yourself may be easier than understanding somebody else code ;)
2. Somebody's else code usually doesn't fit to the exact thing that you want to do. It may be easier to write something yourself from scratch than do a dirty hack of something existing.
3. Using somebody's code takes away a lot of fun of creating from us. Hey, the ultimate goal with hobby programming isn't to produce software quickly, the goal is just to have fun.
4. As others say reusing the code, leads to repetitive, boring stuff like Churrera (not always but quite often)
5. You learn more by making something yourself than including a "library" and calling it
1. Actually writing some code by yourself may be easier than understanding somebody else code ;)
2. Somebody's else code usually doesn't fit to the exact thing that you want to do. It may be easier to write something yourself from scratch than do a dirty hack of something existing.
3. Using somebody's code takes away a lot of fun of creating from us. Hey, the ultimate goal with hobby programming isn't to produce software quickly, the goal is just to have fun.
5. You learn more by making something yourself than including a "library" and calling it
No one is speaking against learning things and having fun.
What I was responding to was a claim that tools without linking ability are claimed completely adequate for the programmers that have used them.
I was saying they're found completely adequate because the programmers aren't sharing source code. That's all :)
4. As others say reusing the code, leads to repetitive, boring stuff like Churrera (not always but quite often)
Sprite engines do not limit the kind of games you can make any more than openGL or directX controls the kinds of games you can make on a PC.
OTOH, because the spectrum is such a resource constrained platform, it is not possible to make one sprite engine that does everything. Instead you can make sprite engines that are good at certain things, meaning there is room for many different sprite engines on the spectrum that are good at different kinds of games. It is not as restrictive as it sounds. The sp1 engine, for example, is probably capable of duplicating 70% of the spectrum (arcade) games archive.
Churrerra is a platform-game framework that sits on top of the splib sprite engine. What you're seeing are the first attempts by many different people at making a game using the framework and what you'll see is most of them simply following the tutorial with their first efforts, arriving at similar results. The author's games (the latest Ninjajar being an example) tend to showcase what can be done better.
So this "linker" would certainly fail to find all "unused" code and it would be more a problem, rather than a benefit. .... Indeed, there would be no warnings in assembler, but the program would just fail to work :) .... So for me such linker would bring more problem for real asm programmer, if he do not use only "CALL" and "JP" all the time, and indeed, if you check code for modern games, written directly in assembler, I am sure you will find, that 90% of them use non-direct execution of calls (actually most of games from the past use that too).
I am not sure why you think a linker does not work in assembler. This is an assembler-level feature -- it has nothing to do with high level languages. All assemblers since the 1960s, skipping the small machines of the '80s, work this way. All subroutines, referenced data, etc, will be properly linked no matter how you do it in assembler. The only requirement is referenced code or data be given a name. eg, "ld ix,print; jp (ix)" is enough for the linker to attach "print".
I may have misled you a bit in describing the linker as a source code analyzer -- that's not how it works. Source code is stored in a partially assembled state with external references left unresolved by the assembler (the "object file"). All the linker (which can also be the assembler) does is resolve those references when the binary is built. In effect, it splits the assembly process in two to allow late binding of unresolved references. That's why it will always resolve references perfectly, indirect calls notwithstanding.
You just thinking like a z88dk user, that's the problem :) C is not assembler, and obv yes, in C your asm routine had to be kept mostly same. I guess you never coded big game project in assembler?
And I probably never will -- it's just too convenient to do the boiler plate code in C :) C is close to assembler but let's leave that one alone as it's not relevant.
In z88dk, the C library is an example of a large shared code base written in assembly language. The fact that the API is specified in the C standard document doesn't mean it's not an example of what happens when you have a large z80 library with subroutines meant to be shared.
If we put all the code for the Spectrum into one program, it would add up to a program ~150k in size. We need the linker to pull out only those portions used by the program to even have something that will fit into 48k ram.
What I am saying is the same thing will happen with any significant z80 library meant to be shared. The examples I gave were a floating point math package and a real sprite engine for the spectrum but you can always go further into file systems, graphics routines, music routines, sound effects (z88dk has about 75 of them and most programs will not use more than a handful), device drivers, and so on. All of these will provide a large set of functions from which only a few might be used by any program. The linker is going to make sure the program is as small as possible without the person using those libraries having to go into unfamiliar code by hand and pick stuff out that is needed. The going in by hand part is really something that should be done by the machine and not the programmer.
You can give me example of library, written by others in assembler, used by others in assembler?
All the available sprite libraries are written in assembler. I'm not sure why you think it's relevant whether the rest of the game is written in assembler? That's a choice made by the person writing the game.
Here's a list of the openly available sprite engines for the spectrum that I am aware of:
sp1/splib: This one is part of z88dk, is written in assembler and can be used from either C or assembler. About 30 games have been written using it but I *think* only one had the game logic written in assembler. Cherrarra is a platform game framework that sits on splib.
Nirvana/BiFrost: These are multicolour sprite engines written in assembler that can be used from assembler, C or Boriel's basic. I believe three games have been released using these engines so far, all written in assembler.
FASE: This is a 50fps sprite engine written in assembler that can be used from assembler, C or Boriel's basic. No games yet, just a demo and still being worked on.
AGD, SEUD: The game creators written by Jonathan. These are game frameworks running on the spectrum but the idea is the same -- a sprite engine is being provided, written in asm, (+ a framework) but running on the Spectrum. It would do better as a PC tool but I think it was something Jonathan had in mind implementing in the 80s and now here it is :)
Probably about a dozen games now.
I think more engines will arrive to serve other purposes. One missing now is a scrolling engine.
So much better would be not creating libraries, but make a site with tons of snippets, to be included in the code, by me...
I think that's only comfortable for small code snippets. I'm more talking about medium to large libraries that would take months or years to duplicate in someone's spare time.
I told you examples, in which linker is useless, as it would not be able to find out references.
Libraries I meant should be examples of big library, containing the things like "acos, asin" etc., which you tell need to be used "untouched".
AGD, SEUD, FASE, sp1 - these are not libraries, as I cannot just take what I want from AGD and throw away everything else, means execute from my own code the part I want, without use of the rest of the framework.
So (as here we are speaking about assembler only), I actually want to see example of real LIBRARY, which is used to write custom-coded game in assembler, without uses of all that AGD, Churrera, FASE and other similar "design your game" frameworks.
By me only Nirvana could be consided as such library.
I think that's only comfortable for small code snippets. I'm more talking about medium to large libraries that would take months or years to duplicate in someone's spare time.
What I am trying to tell you is that person, who program in Z80 ASSEMBLER ONLY do not need libraries in the way you suggest, as if the game is not similar to someone's else project library - it would mean that not much could be reused as is - as all logic had to be written from scratch, map - most likely too, what else remain? Sprite/screen output and keymapping? They would need to be changed too, not much, but still would have to be changed, so not "as is".
So I really have an opinion, that there is no benefits in having a super-library with tons of routines, which would be thrown away by a linker, while you usually need max 5-6 or less routines without their code change. That's why really better just to copypaste that 5-6 routines from somewhere, rather than struggle later with a linker, which fail to see the method you execute your routine...
By me only Nirvana could be consided as such library.
Also ZX7 and RCS. In z88dk and Boriel's ZX BASIC there's a single file containing multiple implementations, their linkers will discard whatever is not used. In Assembly each implementation is in a separate file, and programmers must manually choose the files they need.
This is what I am telling all the way along - that if programmer need - he just take source code for needed parts and use it, but making assembler libs with assembler linker for assembler - it just would not work on ZX.
I told you examples, in which linker is useless, as it would not be able to find out references.
It is not possible to confound the linker. The linker is the second half of the assemble process so confounding the linker means your program cannot be assembled.
AGD, SEUD, FASE, sp1 - these are not libraries, as I cannot just take what I want from AGD and throw away everything else, means execute from my own code the part I want, without use of the rest of the framework.
Only AGD and SEUD are not libraries. You are stuck with the fullsize runtime because Jonathan made them as a tool running on the Spectrum.
The others -- sp1, FASE, Churerra, Nirvanna, BiFrost -- are available as libraries where the linker can pick out what is required.
FASE, Nirvanna and BiFrost are in fact quite small so they can be used easily in the way you are talking about by just copying the asm code into your own project.
However, sp1/splib (and therefore Churerra) is not small. I wrote sp1/splib so I can speak fairly authoritatively about it :) It is not just a code snippet for writing masked sprites to screen that is fifty lines long and is something you might find posted in the forum someplace. Its design features the following:
* It will never flicker because it never draws intermediate results on screen. To accomplish this it must know about all backgrounds and sprites on screen.
* It is a differential updater. It will only draw portions of the screen that change, at character size resolution. The engine maintains a data structure that tracks what portions of the screen will be redrawn at update time. There are two consequences of this: 1- an attempt is made to speed things up by only drawing changing areas of the screen (this also means static sprites acting as foreground elements do not contribute to draw time unless they are in an area that is changing) 2- screen areas are only drawn once. If you have two sprites that move over the same area, some people's sprite routines will draw that same area twice. This one will only draw each character square exactly once no matter what happens.
* Sprites can be clipped to character-resolution rectangles. The sprite data structures are therefore character-oriented which makes them more complicated than how most people's sprite routines work.
* Sprites can be any size and any draw type. This means the engine provides unrolled code to draw sprites as MASK (two-byte definitions), OR (1/2 byte def), XOR (1/2 byte def), LOAD (1/2 byte def), ATTRIBUTE. That actually works out to 24 different unrolled draw loops for the built in draw functions. You do not want to have 24 unrolled loops in your final program.
* Functions are provided to move sprites by character or pixel amounts, animate backgrounds, create simple windows, and draw backgrounds from compressed strings.
FASE and nirvanna/bifrost are small and are mainly providing knowledge from the authors to the users. Programs using them will use all or most of the source code of those engines.
sp1 is different -- it is something that is large and is trying to do quite a lot -- and including all its code would come at a penalty of several K in program size. A linker is very desirable for such a library to prune out unused portions. This is the sort of practical library that I have in mind when espousing the benefits of linkers.
So (as here we are speaking about assembler only), I actually want to see example of real LIBRARY, which is used to write custom-coded game in assembler,.....By me only Nirvana could be consided as such library.
sp1 is the best example as it has many optional features and functions that you would not want included in your program. It is written in 100% assembler and can be called from assembler if that's what you want. The fact that almost all programs that use it are written in C was a choice of the programmers using it and nothing else. Currently, people who are using the C compilers are already comfortable with code reuse, which cannot be said of many others (you yourself being an example :) ), so it's no surprise that people who are familiar with C would be the first to use shared libraries.
Once a library, such as sp1, achieves a certain level of complexity, it is not easy for someone else to make sense of the code nor is it easy to cut and paste what you want to use. If you think you can use it easily without the assistance of the linker, I invite you to go into the source and try. Every program that uses sp1 will need to call the function "sp1_UpdateNow" located here and most likely one of the move sprite functions, eg sp1_MoveSprPix. You can begin by looking for all the code needed by those two functions and adding it to your hypothetical project.
So I really have an opinion, that there is no benefits in having a super-library with tons of routines, which would be thrown away by a linker, while you usually need max 5-6 or less routines without their code change. That's why really better just to copypaste that 5-6 routines from somewhere, rather than struggle later with a linker, which fail to see the method you execute your routine...
What I am suggesting is people are not sharing significant libraries of code so the need is not obvious. In z88dk, the need is clear because we have hundreds of thousands of lines of code in libraries. In spectrum development in general, large bodies of code are not available outside projects like z88dk, spectranet, etc, but that is not the same as saying there isn't a use for such libraries and I do think we will see more in the future.
Visit my ZX-Modules homepage with lot of free programs!
Or visit my music-related website if you're interested in synthesizer music or computer animations and movies I've created
The spectranet firmware was originally all written for sjasmplus but winston ported it all over to binutils in 2010 because the linking in sjasmplus is so primitive that files had to be assembled in a specific order which made the build scripts really cumbersome.
Being an early adopter and recipient of a pre-production board I remember finding windows builds of all the tools and setting up a windows version of the early build environment. I became infuriated with sjasmplus because different versions had vastly different command line arguments so I had to try about three different versions before I found one that would work with winston's build scrips :lol:
It is not possible to confound the linker. The linker is the second half of the assemble process so confounding the linker means your program cannot be assembled.
you're wrong. For ex (very rough example), I have a list of things like:
TableRoutines
db 10
db 40
db 90
RoutStart
Routine1 blablabla ; len 10bytes
ret
Routine2 blabla ; len 40 bytes
ret
Routine3 blabla ; len 90 bytes
Which I execute sort of as
Cycle ld a,(ix)
or a
ret z
ld b,a
call CallR
inc ix
jr Cycle
CallR ld hl,TableRoutines-1
inc hl
djnz $-1
ld c,(hl)
ld b,0
ld hl,RoutStart
add hl,bc
push hl
ret
Linker would recognize this and throw away all the non-used routines? Oh, I doubt this.
So, well, what I am trying to tell (in 3rd time) that this approach would not work for all the cases.
I would like to speak with a person, who ever designed a real game in real assembler in full using sp1/churrera/similar. As you are not a person, who did anything like that, as I understand. As from my experience (which of course could be different from others) this would be useless (at least for me).
So, assembler coders, anyone? As C/Java programmers take over the thread :)
The spectranet firmware was originally all written for sjasmplus but winston ported it all over to binutils in 2010 because the linking in sjasmplus is so primitive that files had to be assembled in a specific order which made the build scripts really cumbersome.
I believe this is not sjasmplus issue, this is issue of nature of Spectrum assembler itself :) Anyway you should give examples for claus with the description of that issue, what was the problem, etc., so if he would start his assembler, he would avoid that.
Being an early adopter and recipient of a pre-production board I remember finding windows builds of all the tools and setting up a windows version of the early build environment. I became infuriated with sjasmplus because different versions had vastly different command line arguments so I had to try about three different versions before I found one that would work with winston's build scrips :lol:
Issue is that sjasmplus was dropper by its original maintainer (I believe it was Aprisobal) and even original maintainer did not had exact plan how to proceed, so after that everyone started doing their own builds... Even myself...
Anyway, this hardly could be assembler problem that you were unable to find appropriate version, used by winston, correct?
I believe this is not sjasmplus issue, this is issue of nature of Spectrum assembler itself :) Anyway you should give examples for claus with the description of that issue, what was the problem, etc., so if he would start his assembler, he would avoid that.
Issue is that sjasmplus was dropper by its original maintainer (I believe it was Aprisobal) and even original maintainer did not had exact plan how to proceed, so after that everyone started doing their own builds... Even myself...
Anyway, this hardly could be assembler problem that you were unable to find appropriate version, used by winston, correct?
I agree to you that linkers are not always necessary, especially for small projects and not projects in a dimension of a big game. Even if not for this at all...
Besides, a linker could be a problem, when code and data segments are mixed, e.g. like I saw in the VU3D tool. Code is generated by code in data areas and then executed.
On the other hand, a linker is useful for big projects that repeatedly use code fragments, as that was discussed above.
For this topic, the facts are clear: Unless ZX-Assembler will later not be used for so-called 'hardcore coders', who in fact have good enough tools for their purposes, I will not (yet) implement a linker.
About starting ZX-Assembler: It's just far from being at a beginning stage. Just now, it does many things quite good, it reached the abilities of SjASM pretty good, but some important things are missing for a fully functional beta release (and I'm just making a small 'excurse' to ZX-Blockeditor and ZX-Paintbrush anyway).
There are no problems, only solutions (K. Flynn)
Visit my ZX-Modules homepage with lot of free programs!
Or visit my music-related website if you're interested in synthesizer music or computer animations and movies I've created
So, well, what I am trying to tell (in 3rd time) that this approach would not work for all the cases.
Clearly an Assembly linker won't be useful in many cases, but it should be useful in many others. IMHO that's a good enough reason to implement it in assemblers, although using it should be optional (obviously).
However it would work much better if this feature was defined as a small set of standard assembler directives, that could be implemented by different assemblers, instead of something specific to ZX-Assembler. That's not the kind of problem that requires an IDE to solve (although IDEs should support it also).
I believe this is not sjasmplus issue, this is issue of nature of Spectrum assembler itself :) Anyway you should give examples for claus with the description of that issue, what was the problem, etc., so if he would start his assembler, he would avoid that.
I'm not sure of the specifics as I was just learning z80 at the time and besides building the firmware from source with very minor changes I didn't do anything else with it until much later on post-porting.
The problem was roughly something to do with having multiple bits of paged code all assembled to the same address. Everything had to be built separately and done in a specific order because of interdependencies.
A proper linker takes care of everything like that automagically.
Anyway, this hardly could be assembler problem that you were unable to find appropriate version, used by winston, correct?
I found one in the end yes. The problem was that winston develops on Unix so I had to cross compile or find windows binaries for all the tools used. He didn't specify what version/whose version of sjasmplus he was using in the readme and it took a little while to get to the bottom of the problem (to realise there were different programs all called sjasmplus but with different arguments)
TableRoutines
db 10
db 40
db 90
RoutStart
Routine1 blablabla ; len 10bytes
ret
Routine2 blabla ; len 40 bytes
ret
Routine3 blabla ; len 90 bytes
....
Which I execute sort of as
....
Cycle ld a,(ix)
or a
ret z
ld b,a
call CallR
inc ix
jr Cycle
CallR ld hl,TableRoutines-1
inc hl
djnz $-1
ld c,(hl)
ld b,0
ld hl,RoutStart
add hl,bc
push hl
ret
Linker would recognize this and throw away all the non-used routines? Oh, I doubt this.
No, because your code is written such that it requires every single subroutine to be present (as you intended). If you really wanted some subroutines to be optionally present, you would not write code that way.
Here is another possibility that does let you optionally omit subroutines. Just eliminate the "defw Routine" lines you don't want or if you want to keep the same indices for all subroutines you can replace the unwanted "defw Routine" with a single "defw DefaultError" so that an error routine is jumped to instead.
There are, of course, many ways to do a jump table. I chose the one above as example because changing the set of subroutines is simply a matter of eliminating a "defw Routine" line. The linker will only pull in the subroutines found in "TableRoutines".
If you really wanted to have a table of offsets instead (not a good idea IMO as it only saves an appreciable amount of bytes when the table size is large and when the table size is large your jump code is also very slow), you would need to lay out the subroutines in their own section to guarantee they appear one after another:
I created an independent SECTION for the optional "RoutineN". This means all "RoutineN" will be placed in the same memory block. In addition, the short "PackedRoutinesRoot" label will appear as the first item in the SECTION by construction (I would place it there in my "main" file). The order that the routines appear in the section will be the same as they appear in "TableRoutines". This solution also allows the RoutineN to appear in any order in the table --- your previous snippet requires the RoutineN to appear in a certain order in the source file. Presumably with a slow lookup as in your example CodeR, you would want the most commonly used subroutines to appear first and if that changes, would require you to reorder the routines in the source file as well as the table.
Now you can run the same code as your example and you can eliminate individual items from TableRoutines and the linker will properly attach only the ones in TableRoutines to the binary.
However, for such a thing that requires routines to appear contiguously one after the other, I might implement with a 'lower tech' solution that does not involve the linker:
defc WANTEDROUTINES = $ff ; one set bit per wanted routine
TableRoutines:
IF WANTED_ROUTINES & $01
defb Routine1Len
ENDIF
...
IF WANTED_ROUTINES & $08
defb Routine4Len
ENDIF
...
IF WANTED_ROUTINES & $01
Routine1:
...
ret
defc Routine1Len = $ - Routine1
ENDIF
....
Although the linker solution would require no work by the programmer, this last solution I might find more appropriate in some circumstances because the linker may not place the subroutines into the section in the same order if some other part of the program makes reference to routines referenced in TableRoutines first. If the table is the only place the routines are referenced this is not an issue.
This last solution is also easier to understand and portable to any assembler. But if I were bundling together a library, the linker solution would allow the library to be used without the programmer having to set the "WANTED_ROUTINES" constant.
So, well, what I am trying to tell (in 3rd time) that this approach would not work for all the cases.
I can't think of any cases but I won't say there aren't any. A legitimate example will surely be something the author wants very much to be one single glob rather than something that can be pruned. Keep in mind you do not have to make use of linking features -- linking assemblers are just like other assemblers, only more :)
I would like to speak with a person, who ever designed a real game in real assembler in full using sp1/churrera/similar. As you are not a person, who did anything like that, as I understand. As from my experience (which of course could be different from others) this would be useless (at least for me).
If you never have a need or desire to use code written by someone else, the merits of a linker are not clear.
If your personal library of routines is small, again the need for a linker for personal use is not clear.
The above summarizes much of Spectrum development. But once you start to see people writing programs that communicate over the internet, read and write to disk, and so on, writing code yourself to do the same thing might take you years to do and then you may find the need to share :)
So, assembler coders, anyone? As C/Java programmers take over the thread :)
It has nothing to with programming in a high level language -- it's all about code reuse and sharing and whether you want to do that.
How shy are you about using the TRDOS ROM to read/write from disk? Why haven't you written your own FDC control software to do that?
Imagine if TRDOS had to sit in RAM and could not be in its own paged out ROM. In order to use TRDOS disk you would have to place an 8k blob into your program. That 8k blob would contain code to read, write basic, code, strings, erase files, rename files, etc. Wouldn't it be nice if you could just pick out the one routine you really needed -- most likely a load binary? With a linker, it would do that for you, by hand you would have to extract from that 8k binary what was needed.
No, because your code is written such that it requires every single subroutine to be present (as you intended). If you really wanted some subroutines to be optionally present, you would not write code that way.
It is example of subroutines from a game. I would code another game, where some of them would be not needed. And I need linker to recognize which are not needed and throw them again (to get any benefit from it), but this would not work. This is what I mean. Anyway, seems everyone here now understand the pros and cons from linker you suggest. I (for 2nd time) hope you would take sjasmplus and implement it, so everyone could check how it would work on real projects...
If I develop CODE together with someone (never happened, actually, and I doubt this would ever happen - never heard of anyone, who coded together with someone via internet) I would use github, also I doubt someone would be dumb enough to include whole libraries. We're speaking about max 42k of code, it is so small, that could be revised easily without linker.
Why speaking about things, which do not exist? These are hypothetical things, which I personally would never do.
Comments
1. Actually writing some code by yourself may be easier than understanding somebody else code ;)
2. Somebody's else code usually doesn't fit to the exact thing that you want to do. It may be easier to write something yourself from scratch than do a dirty hack of something existing.
3. Using somebody's code takes away a lot of fun of creating from us. Hey, the ultimate goal with hobby programming isn't to produce software quickly, the goal is just to have fun.
4. As others say reusing the code, leads to repetitive, boring stuff like Churrera (not always but quite often)
5. You learn more by making something yourself than including a "library" and calling it
No one is speaking against learning things and having fun.
What I was responding to was a claim that tools without linking ability are claimed completely adequate for the programmers that have used them.
I was saying they're found completely adequate because the programmers aren't sharing source code. That's all :)
Sprite engines do not limit the kind of games you can make any more than openGL or directX controls the kinds of games you can make on a PC.
OTOH, because the spectrum is such a resource constrained platform, it is not possible to make one sprite engine that does everything. Instead you can make sprite engines that are good at certain things, meaning there is room for many different sprite engines on the spectrum that are good at different kinds of games. It is not as restrictive as it sounds. The sp1 engine, for example, is probably capable of duplicating 70% of the spectrum (arcade) games archive.
Churrerra is a platform-game framework that sits on top of the splib sprite engine. What you're seeing are the first attempts by many different people at making a game using the framework and what you'll see is most of them simply following the tutorial with their first efforts, arriving at similar results. The author's games (the latest Ninjajar being an example) tend to showcase what can be done better.
Write games in C using Z88DK and SP1
I am not sure why you think a linker does not work in assembler. This is an assembler-level feature -- it has nothing to do with high level languages. All assemblers since the 1960s, skipping the small machines of the '80s, work this way. All subroutines, referenced data, etc, will be properly linked no matter how you do it in assembler. The only requirement is referenced code or data be given a name. eg, "ld ix,print; jp (ix)" is enough for the linker to attach "print".
I may have misled you a bit in describing the linker as a source code analyzer -- that's not how it works. Source code is stored in a partially assembled state with external references left unresolved by the assembler (the "object file"). All the linker (which can also be the assembler) does is resolve those references when the binary is built. In effect, it splits the assembly process in two to allow late binding of unresolved references. That's why it will always resolve references perfectly, indirect calls notwithstanding.
And I probably never will -- it's just too convenient to do the boiler plate code in C :) C is close to assembler but let's leave that one alone as it's not relevant.
In z88dk, the C library is an example of a large shared code base written in assembly language. The fact that the API is specified in the C standard document doesn't mean it's not an example of what happens when you have a large z80 library with subroutines meant to be shared.
If we put all the code for the Spectrum into one program, it would add up to a program ~150k in size. We need the linker to pull out only those portions used by the program to even have something that will fit into 48k ram.
What I am saying is the same thing will happen with any significant z80 library meant to be shared. The examples I gave were a floating point math package and a real sprite engine for the spectrum but you can always go further into file systems, graphics routines, music routines, sound effects (z88dk has about 75 of them and most programs will not use more than a handful), device drivers, and so on. All of these will provide a large set of functions from which only a few might be used by any program. The linker is going to make sure the program is as small as possible without the person using those libraries having to go into unfamiliar code by hand and pick stuff out that is needed. The going in by hand part is really something that should be done by the machine and not the programmer.
Write games in C using Z88DK and SP1
All the available sprite libraries are written in assembler. I'm not sure why you think it's relevant whether the rest of the game is written in assembler? That's a choice made by the person writing the game.
Here's a list of the openly available sprite engines for the spectrum that I am aware of:
sp1/splib: This one is part of z88dk, is written in assembler and can be used from either C or assembler. About 30 games have been written using it but I *think* only one had the game logic written in assembler. Cherrarra is a platform game framework that sits on splib.
Ninjajar, Sgt Hemlet Zero, Forest Raider Cherry
Nirvana/BiFrost: These are multicolour sprite engines written in assembler that can be used from assembler, C or Boriel's basic. I believe three games have been released using these engines so far, all written in assembler.
DreamWalker (Alter Ego 2), El Stompo
FASE: This is a 50fps sprite engine written in assembler that can be used from assembler, C or Boriel's basic. No games yet, just a demo and still being worked on.
AGD, SEUD: The game creators written by Jonathan. These are game frameworks running on the spectrum but the idea is the same -- a sprite engine is being provided, written in asm, (+ a framework) but running on the Spectrum. It would do better as a PC tool but I think it was something Jonathan had in mind implementing in the 80s and now here it is :)
Probably about a dozen games now.
I think more engines will arrive to serve other purposes. One missing now is a scrolling engine.
I think that's only comfortable for small code snippets. I'm more talking about medium to large libraries that would take months or years to duplicate in someone's spare time.
Write games in C using Z88DK and SP1
Libraries I meant should be examples of big library, containing the things like "acos, asin" etc., which you tell need to be used "untouched".
AGD, SEUD, FASE, sp1 - these are not libraries, as I cannot just take what I want from AGD and throw away everything else, means execute from my own code the part I want, without use of the rest of the framework.
So (as here we are speaking about assembler only), I actually want to see example of real LIBRARY, which is used to write custom-coded game in assembler, without uses of all that AGD, Churrera, FASE and other similar "design your game" frameworks.
By me only Nirvana could be consided as such library.
What I am trying to tell you is that person, who program in Z80 ASSEMBLER ONLY do not need libraries in the way you suggest, as if the game is not similar to someone's else project library - it would mean that not much could be reused as is - as all logic had to be written from scratch, map - most likely too, what else remain? Sprite/screen output and keymapping? They would need to be changed too, not much, but still would have to be changed, so not "as is".
So I really have an opinion, that there is no benefits in having a super-library with tons of routines, which would be thrown away by a linker, while you usually need max 5-6 or less routines without their code change. That's why really better just to copypaste that 5-6 routines from somewhere, rather than struggle later with a linker, which fail to see the method you execute your routine...
Also ZX7 and RCS. In z88dk and Boriel's ZX BASIC there's a single file containing multiple implementations, their linkers will discard whatever is not used. In Assembly each implementation is in a separate file, and programmers must manually choose the files they need.
It is not possible to confound the linker. The linker is the second half of the assemble process so confounding the linker means your program cannot be assembled.
Only AGD and SEUD are not libraries. You are stuck with the fullsize runtime because Jonathan made them as a tool running on the Spectrum.
The others -- sp1, FASE, Churerra, Nirvanna, BiFrost -- are available as libraries where the linker can pick out what is required.
FASE, Nirvanna and BiFrost are in fact quite small so they can be used easily in the way you are talking about by just copying the asm code into your own project.
However, sp1/splib (and therefore Churerra) is not small. I wrote sp1/splib so I can speak fairly authoritatively about it :) It is not just a code snippet for writing masked sprites to screen that is fifty lines long and is something you might find posted in the forum someplace. Its design features the following:
* It will never flicker because it never draws intermediate results on screen. To accomplish this it must know about all backgrounds and sprites on screen.
* It is a differential updater. It will only draw portions of the screen that change, at character size resolution. The engine maintains a data structure that tracks what portions of the screen will be redrawn at update time. There are two consequences of this: 1- an attempt is made to speed things up by only drawing changing areas of the screen (this also means static sprites acting as foreground elements do not contribute to draw time unless they are in an area that is changing) 2- screen areas are only drawn once. If you have two sprites that move over the same area, some people's sprite routines will draw that same area twice. This one will only draw each character square exactly once no matter what happens.
* Sprites can be clipped to character-resolution rectangles. The sprite data structures are therefore character-oriented which makes them more complicated than how most people's sprite routines work.
* Sprites can be any size and any draw type. This means the engine provides unrolled code to draw sprites as MASK (two-byte definitions), OR (1/2 byte def), XOR (1/2 byte def), LOAD (1/2 byte def), ATTRIBUTE. That actually works out to 24 different unrolled draw loops for the built in draw functions. You do not want to have 24 unrolled loops in your final program.
* Functions are provided to move sprites by character or pixel amounts, animate backgrounds, create simple windows, and draw backgrounds from compressed strings.
FASE and nirvanna/bifrost are small and are mainly providing knowledge from the authors to the users. Programs using them will use all or most of the source code of those engines.
sp1 is different -- it is something that is large and is trying to do quite a lot -- and including all its code would come at a penalty of several K in program size. A linker is very desirable for such a library to prune out unused portions. This is the sort of practical library that I have in mind when espousing the benefits of linkers.
sp1 is the best example as it has many optional features and functions that you would not want included in your program. It is written in 100% assembler and can be called from assembler if that's what you want. The fact that almost all programs that use it are written in C was a choice of the programmers using it and nothing else. Currently, people who are using the C compilers are already comfortable with code reuse, which cannot be said of many others (you yourself being an example :) ), so it's no surprise that people who are familiar with C would be the first to use shared libraries.
Once a library, such as sp1, achieves a certain level of complexity, it is not easy for someone else to make sense of the code nor is it easy to cut and paste what you want to use. If you think you can use it easily without the assistance of the linker, I invite you to go into the source and try. Every program that uses sp1 will need to call the function "sp1_UpdateNow" located here and most likely one of the move sprite functions, eg sp1_MoveSprPix. You can begin by looking for all the code needed by those two functions and adding it to your hypothetical project.
What I am suggesting is people are not sharing significant libraries of code so the need is not obvious. In z88dk, the need is clear because we have hundreds of thousands of lines of code in libraries. In spectrum development in general, large bodies of code are not available outside projects like z88dk, spectranet, etc, but that is not the same as saying there isn't a use for such libraries and I do think we will see more in the future.
Write games in C using Z88DK and SP1
There are no problems, only solutions (K. Flynn)
Visit my ZX-Modules homepage with lot of free programs!
Or visit my music-related website if you're interested in synthesizer music or computer animations and movies I've created
Being an early adopter and recipient of a pre-production board I remember finding windows builds of all the tools and setting up a windows version of the early build environment. I became infuriated with sjasmplus because different versions had vastly different command line arguments so I had to try about three different versions before I found one that would work with winston's build scrips :lol:
TableRoutines db 10 db 40 db 90 RoutStart Routine1 blablabla ; len 10bytes ret Routine2 blabla ; len 40 bytes ret Routine3 blabla ; len 90 bytesWhich I execute sort of as
Cycle ld a,(ix) or a ret z ld b,a call CallR inc ix jr Cycle CallR ld hl,TableRoutines-1 inc hl djnz $-1 ld c,(hl) ld b,0 ld hl,RoutStart add hl,bc push hl retLinker would recognize this and throw away all the non-used routines? Oh, I doubt this.
So, well, what I am trying to tell (in 3rd time) that this approach would not work for all the cases.
I would like to speak with a person, who ever designed a real game in real assembler in full using sp1/churrera/similar. As you are not a person, who did anything like that, as I understand. As from my experience (which of course could be different from others) this would be useless (at least for me).
So, assembler coders, anyone? As C/Java programmers take over the thread :)
Issue is that sjasmplus was dropper by its original maintainer (I believe it was Aprisobal) and even original maintainer did not had exact plan how to proceed, so after that everyone started doing their own builds... Even myself...
Anyway, this hardly could be assembler problem that you were unable to find appropriate version, used by winston, correct?
I agree to you that linkers are not always necessary, especially for small projects and not projects in a dimension of a big game. Even if not for this at all...
Besides, a linker could be a problem, when code and data segments are mixed, e.g. like I saw in the VU3D tool. Code is generated by code in data areas and then executed.
On the other hand, a linker is useful for big projects that repeatedly use code fragments, as that was discussed above.
For this topic, the facts are clear: Unless ZX-Assembler will later not be used for so-called 'hardcore coders', who in fact have good enough tools for their purposes, I will not (yet) implement a linker.
About starting ZX-Assembler: It's just far from being at a beginning stage. Just now, it does many things quite good, it reached the abilities of SjASM pretty good, but some important things are missing for a fully functional beta release (and I'm just making a small 'excurse' to ZX-Blockeditor and ZX-Paintbrush anyway).
There are no problems, only solutions (K. Flynn)
Visit my ZX-Modules homepage with lot of free programs!
Or visit my music-related website if you're interested in synthesizer music or computer animations and movies I've created
Clearly an Assembly linker won't be useful in many cases, but it should be useful in many others. IMHO that's a good enough reason to implement it in assemblers, although using it should be optional (obviously).
However it would work much better if this feature was defined as a small set of standard assembler directives, that could be implemented by different assemblers, instead of something specific to ZX-Assembler. That's not the kind of problem that requires an IDE to solve (although IDEs should support it also).
The problem was roughly something to do with having multiple bits of paged code all assembled to the same address. Everything had to be built separately and done in a specific order because of interdependencies.
A proper linker takes care of everything like that automagically.
I found one in the end yes. The problem was that winston develops on Unix so I had to cross compile or find windows binaries for all the tools used. He didn't specify what version/whose version of sjasmplus he was using in the readme and it took a little while to get to the bottom of the problem (to realise there were different programs all called sjasmplus but with different arguments)
No, because your code is written such that it requires every single subroutine to be present (as you intended). If you really wanted some subroutines to be optionally present, you would not write code that way.
Here is another possibility that does let you optionally omit subroutines. Just eliminate the "defw Routine" lines you don't want or if you want to keep the same indices for all subroutines you can replace the unwanted "defw Routine" with a single "defw DefaultError" so that an error routine is jumped to instead.
There are, of course, many ways to do a jump table. I chose the one above as example because changing the set of subroutines is simply a matter of eliminating a "defw Routine" line. The linker will only pull in the subroutines found in "TableRoutines".
If you really wanted to have a table of offsets instead (not a good idea IMO as it only saves an appreciable amount of bytes when the table size is large and when the table size is large your jump code is also very slow), you would need to lay out the subroutines in their own section to guarantee they appear one after another:
I created an independent SECTION for the optional "RoutineN". This means all "RoutineN" will be placed in the same memory block. In addition, the short "PackedRoutinesRoot" label will appear as the first item in the SECTION by construction (I would place it there in my "main" file). The order that the routines appear in the section will be the same as they appear in "TableRoutines". This solution also allows the RoutineN to appear in any order in the table --- your previous snippet requires the RoutineN to appear in a certain order in the source file. Presumably with a slow lookup as in your example CodeR, you would want the most commonly used subroutines to appear first and if that changes, would require you to reorder the routines in the source file as well as the table.
Now you can run the same code as your example and you can eliminate individual items from TableRoutines and the linker will properly attach only the ones in TableRoutines to the binary.
However, for such a thing that requires routines to appear contiguously one after the other, I might implement with a 'lower tech' solution that does not involve the linker:
defc WANTEDROUTINES = $ff ; one set bit per wanted routine TableRoutines: IF WANTED_ROUTINES & $01 defb Routine1Len ENDIF ... IF WANTED_ROUTINES & $08 defb Routine4Len ENDIF ... IF WANTED_ROUTINES & $01 Routine1: ... ret defc Routine1Len = $ - Routine1 ENDIF ....Although the linker solution would require no work by the programmer, this last solution I might find more appropriate in some circumstances because the linker may not place the subroutines into the section in the same order if some other part of the program makes reference to routines referenced in TableRoutines first. If the table is the only place the routines are referenced this is not an issue.
This last solution is also easier to understand and portable to any assembler. But if I were bundling together a library, the linker solution would allow the library to be used without the programmer having to set the "WANTED_ROUTINES" constant.
I can't think of any cases but I won't say there aren't any. A legitimate example will surely be something the author wants very much to be one single glob rather than something that can be pruned. Keep in mind you do not have to make use of linking features -- linking assemblers are just like other assemblers, only more :)
If you never have a need or desire to use code written by someone else, the merits of a linker are not clear.
If your personal library of routines is small, again the need for a linker for personal use is not clear.
The above summarizes much of Spectrum development. But once you start to see people writing programs that communicate over the internet, read and write to disk, and so on, writing code yourself to do the same thing might take you years to do and then you may find the need to share :)
It has nothing to with programming in a high level language -- it's all about code reuse and sharing and whether you want to do that.
How shy are you about using the TRDOS ROM to read/write from disk? Why haven't you written your own FDC control software to do that?
Imagine if TRDOS had to sit in RAM and could not be in its own paged out ROM. In order to use TRDOS disk you would have to place an 8k blob into your program. That 8k blob would contain code to read, write basic, code, strings, erase files, rename files, etc. Wouldn't it be nice if you could just pick out the one routine you really needed -- most likely a load binary? With a linker, it would do that for you, by hand you would have to extract from that 8k binary what was needed.
Write games in C using Z88DK and SP1
If I develop CODE together with someone (never happened, actually, and I doubt this would ever happen - never heard of anyone, who coded together with someone via internet) I would use github, also I doubt someone would be dumb enough to include whole libraries. We're speaking about max 42k of code, it is so small, that could be revised easily without linker.
Why speaking about things, which do not exist? These are hypothetical things, which I personally would never do.