A new multicolor engine called BIFROST*

24

Comments

  • edited March 2012
    For gods who are very comfortable with their sexuality, presumably...

    P.S. Its 'les rosbifs', if you're a grenouille and wish to insult the English. And as for The History Channel, I don't trust em'. I thought there were laws about profiting from the Nazis? :lol:
    Joefish
    - IONIAN-GAMES.com -
  • edited March 2012
    joefish wrote: »
    And as for The History Channel, I don't trust em'. I thought there were laws about profiting from the Nazis? :lol:

    Nazis used IBM mainframes, Asgard used ZX-Spectrum computers. Thus I see no relation here! :)

    Seriously, now that we have already met Godwin's law in this thread, let's drop this subject and get back on topic!
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    Fikee wrote: »
    All of this is very interesting but that points me to question:

    Why a multicolor engine to be used by wider adience should touch pixels at all ? Let the engine render either 8x1 or 8x2 attr and then pass all action to programmer.

    Sure, this is exactly the reason I implemented "special mode 255" and documented how to change multicolor attributes directly. I even suggested BIFROST* could be used this way when I answered ewgf's post. :)

    Fikee wrote: »
    Regarding the upper border, let engine wait in a loop and document how much time the loop should take.

    If you set all tiles to "special mode 255", the engine will be waiting in an idle loop until it has something to render, exactly as you described.

    Fikee wrote: »
    If anyone wants to use time wasted in loop he can do it at all.

    Current version already supports doing so. Right after "preserve all registers" you can jump to your own routine, do whatever you want, then jump back to "synchronize with the raster beam". But I agree it's a great idea to document how to do it exactly. I will add a proper explanation in the "technicalities" section, thanks for the suggestion!

    In practice it's a real nightmare to implement complex routines that must execute taking an exact number of T-states every time regardless of the execution path it takes (I bet joefish will agree here), thus I do not recommend anyone attempting to do so. For this reason, BIFROST* was designed to be as useful as possible during this time, thus hopefully the programmer won't feel compelled to even try. Even so this option is already available in BIFROST*, and I agree this idea could be necessary to implement action games like "Exolon" as I mentioned above.

    Besides documenting how to do it in BIFROST*, do you see anything else would be necessary here? Perhaps wait until I update the documentation before answering this question...

    Fikee wrote: »
    If you want provide more modules which allow drawing tiles, acces from basic or whatever then do it. But let other coders opportunity to lift up just core stripped to bone.

    Yes that's exactly the design principle behind the BIFROST* ENGINE. It's supposed to be as easy to use as possible, but still provide complete freedom for programmers to do whatever they want.

    Fikee wrote: »
    And i forgot to say : excellent work :)

    Thanks! :)

    Fikee wrote: »
    P.s.: Also there is on more challenge for multicolor maniacs - and that is using precise timing they already had built-in for some AY miracles - from phaser sound to play short digitised sound. Probably not good deal for 8x1 multicolor but 8x2 could be way ;)

    Too late, ZXodus 2.04 already plays AY music while rendering 8x1 multicolor :)

    BIFROST* will (most certainly) never incorporate any music support, but it should be trivial to add AY music yourself. Just change instruction "jp $38" inside BIFROST* to jump instead to any music player routine of your choice, and it will be called 50 times per second at exactly 69888 T-state intervals every time (even more exact that calling it directly from the interrupt vector, since BIFROST* synchronizes perfectly with the screen raster beam to eliminate all interrupt delays). I will keep in mind to add this information to the documentation also.

    Again this point illustrates the difference between the design principles behind ZXodus and BIFROST*. As I mentioned before, ZXodus is becoming a full development platform that will be managing and controlling everything, so the developer won't need to worry about anything and can concentrate on the game itself. BIFROST* goes the opposite way, trying to be as flexible as possible (although still easy-to-use) and give full control for the programmer to do whatever s/he wants.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    R-Tape wrote: »
    You've done a dangerous thing though, looking at the Bifrost* code there's an outside chance I now understand enough to write my own engine in a game at some point (with appropriate credits of course)!

    You are welcome to do so!

    I believe in freedom of information, thus I always release the source code for all my ZX-Spectrum projects, and always allow people to create derivative work from them (just asking for proper credit). I'm glad you could learn something from it.

    Also I perfectly understand when people is tempted to develop all their own tools. I have this urge myself simply because it's a lot of fun to do so, although I try to resist this idea for my own projects since I'm aware it's not very productive to reinvent the wheel. In particular I would have implemented Vexed using ZXodus if it supported the features I needed, and I just created a new engine because I felt I needed something different, and perhaps I would be able to advance this technique a little further since I was "standing on shoulder of giants".
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    joefish wrote: »
    And now a special message for Einar, who thinks that everyone's telling him what to do and won't leave him alone to get on with it - Har Har! :D

    No problem at all, I'm glad there has been so much interest so I take it as a compliment. I must have done something right. :)
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    How good would Lords of Midnight / Doomdark's Revenge be with multi-coloured graphics like that!!!!

    My dream would be someone one day producing enhanced versions of LoM/DDR with better graphics, but retaining the gameplay... or better still The Eye of the Moon, as a 128k game maybe as a community effort overseen by Chris Wild and Mike Singleton.

    Einar, how feasible would the Bifrost engine integrate with an identikit style graphic engine to produce variable character profiles and landscapes with generated trees / fortresses / citadels that the Computer Gamer article mentioned?

    I live in hope lol.
  • edited March 2012
    In practice it's a real nightmare to implement complex routines that must execute taking an exact number of T-states every time regardless of the execution path it takes (I bet joefish will agree here), thus I do not recommend anyone attempting to do so.
    Yep, that's why, for the most part, I avoid doing any branching whatsoever. You're asking for trouble using the LD method for multi-colour and having optional tile codes. I just make it draw seven sprites regardless. My screen line table is 256 lines long and has a few entries for above and below the 192 screen lines that just point to address 0 (into the ROM). If you position a sprite off-screen it still goes through the steps of drawing it and takes just as long as if it was on-screen. All the optional stuff, deciding what to erase and what to draw next, comes after the colour routine, when precise timing doesn't matter.
    Joefish
    - IONIAN-GAMES.com -
  • edited March 2012
    joefish wrote: »
    Yep, that's why, for the most part, I avoid doing any branching whatsoever. You're asking for trouble using the LD method for multi-colour and having optional tile codes. I just make it draw seven sprites regardless. My screen line table is 256 lines long and has a few entries for above and below the 192 screen lines that just point to address 0 (into the ROM). If you position a sprite off-screen it still goes through the steps of drawing it and takes just as long as if it was on-screen. All the optional stuff, deciding what to erase and what to draw next, comes after the colour routine, when precise timing doesn't matter.

    Thus basically Buzzsaw uses the wait period at the beginning of the interrupt to draw/animate tiles, and let everything else to be done later.

    This is exactly also how BIFROST* works! Except the drawing part is more automated and less specialized, obviously.

    Although using this initial interrupt period for other tasks could be done in theory to implement action games that demand more performance, in practice making it work would be a nightmare. Again I don't recommend trying to do that, but everyone is welcome to try. I'm updating the BIFROST* documentation with the proper information necessary to help make this work.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    My latest engine doesn't work on interrupts at all. It uses a HALT for synchronisation, then calls different functions during the top border segments of several subsequent frames, each followed by a customised pause, then a call to the colour routine, then to another job for the bottom border. It can be a bit of a pain tweaking each pause as it flickers like mad even when just one is off. And if you change the border colour to indicate how long the bottom border function is taking, of course they're all different lengths so they flicker like mad too.

    But it'd be very difficult to present a customisable engine that works like that.
    Joefish
    - IONIAN-GAMES.com -
  • edited March 2012
    Gilby wrote: »
    or better still The Eye of the Moon, as a 128k game maybe as a community effort overseen by Chris Wild and Mike Singleton.


    Yes please!
  • edited March 2012
    Gilby wrote: »
    How good would Lords of Midnight / Doomdark's Revenge be with multi-coloured graphics like that!!!!

    This is another game style that should work quite well!

    Technically landscape drawing could be done as follows:
    • Turn off BIFROST*. This will help speed up drawing a lot;
    • Fill the regular screen attributes (corresponding to multicolor area) with zero, thus hiding the landscape while drawing;
    • Fill all 81 positions of the tile map with 255 to disable automatic tiles. Alternatively you could remove the tile mapping from the engine entirely (see next version of documentation describing how to do so) but you may want to leave it anyway so you can still use animated multicolor tiles in other parts of the game;
    • Erase the bitmaps from the multicolor area to start with a clear screen;
    • Now spend as many frames as needed to draw each element of the landscape, directly changing screen bitmaps and multicolor attributes as documented. Here I doubt colored resizeable scenery elements would look good enough, so each element may require a set of multicolored sprites for each size (thus a Spectrum 128K), but this is more an aesthetical choice than technical. Anyway it will be just a matter of putting the right sprites in the right places;
    • Turn on BIFROST*. The entire colored landscape will appear at once.
    Gilby wrote: »
    Einar, how feasible would the Bifrost engine integrate with an identikit style graphic engine to produce variable character profiles and landscapes with generated trees / fortresses / citadels that the Computer Gamer article mentioned?

    It mostly depends if identikit can be easily adapted to generate colored graphics. I suspect pre-defined colored sprites would be more feasible, reserving certain attribute values to be replaced when drawing (thus some parts of the same sprite could be rendered with different colors).
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    joefish wrote: »
    My latest engine doesn't work on interrupts at all. It uses a HALT for synchronisation, then calls different functions during the top border segments of several subsequent frames, each followed by a customised pause, then a call to the colour routine

    Sure, that's essentially the same thing. If you changed it so these parts were executed inside the interrupt, there would be no practical difference.

    joefish wrote: »
    But it'd be very difficult to present a customisable engine that works like that.

    Agreed. You are using specific routines, and it doesn't seem the kind of stuff that could be reasonably customized.

    I would not mind the extra effort to change my engine so it could do other tasks besides drawing tiles. However it would have to be fully automated tasks useful for most games. Does anybody have a suggestion for such a generic automated task? Perhaps sound, but I don't see much advantage putting this inside the engine, I prefer to leave it outside so the programmer can do whatever s/he wants.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    I just tested BIFROST* ENGINE with Boriel's ZX BASIC Compiler and it seems to work just fine!

    Back to Boriel's ZX BASIC...

    Despite my previous problems to make it work (I'm still convinced it has some issues related to expression evaluation), I actually liked it. So I decide to give it another chance.

    This time I started implementing a proper library interface. Besides making it more efficient and also intuitive to use BIFROST* inside ZX BASIC, there will be another advantage using this library: even if any internal address changes in a future release of BIFROST*, I can just update the library so ZX BASIC programs won't have to worry about anything.

    The interface library file "bifrost.bas" is now available from the following link for anyone interested (just copy it to the folder where you are compiling your ZX BASIC program):

    www.worldofspectrum.org/infoseekid.cgi?id=0027405

    It seems ZX BASIC Compiler and BIFROST* ENGINE could be a good combination, since it's much easier than developing multicolor games directly in Assembly, and ZX BASIC's compilation kinda compensates the performance costs from rendering multicolor.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    And here's the complete BIFROST* ENGINE DEMO adapted to ZX BASIC using the previous library file:
    ' ----------------------------------------------------------------
    ' BIFROST* ENGINE DEMO - converted to Boriel's ZX BASIC Compiler
    '
    ' After compiling it, you can use the following loader to execute:
    '
    ' CLEAR 32767: LOAD ""CODE
    ' LOAD "TILES"CODE
    ' LOAD "BIFROST*"CODE
    ' RANDOMIZE USR 32768
    '
    ' Original version and further information is available at
    ' http://www.worldofspectrum.org/infoseekid.cgi?id=0027405
    ' ----------------------------------------------------------------
    #include "bifrost.bas"
    
      20 INK 5: PAPER 0: BORDER 0: CLS
      30 PRINT INK 6;AT 4,22;"BIFROST*";AT 5,23;"ENGINE";AT 6,24;"DEMO"; INK 4; AT 10,24;"WITH";AT 11,23;"BORIEL";AT 12,22;"ZX-BASIC"
      40 BIFROSTstart()
      50 FOR r=0 TO 8: FOR c=0 TO 8
         BIFROSTsetTile(r, c, BIFROSTSTATIC + r*9+c)
         NEXT c: NEXT r
      60 GO SUB 210
      70 PRINT AT 20,1;"Demonstrating static tiles"
      80 FOR r=0 TO 8: FOR c=0 TO 8
         BIFROSTsetTile(r, c, BIFROSTSTATIC + INT(RND*26)+8)
         NEXT c: NEXT r
      90 GO SUB 210
     100 PRINT AT 20,1;"Animated tiles (4 frames)",
     110 GO SUB 220
     120 PRINT AT 20,17;"2"
     130 BIFROSTresetAnim2Frames()
     140 GO SUB 220
     150 BIFROSTresetAnim4Frames()
     160 PRINT AT 20,1;"Directly modifying areas",
     170 BIFROSTsetTile(4, 4, BIFROSTDISABLED)
         BIFROSTsetTile(4, 5, BIFROSTDISABLED)
     180 PRINT AT 9,9;"BIFR";AT 10,9;"OST*"
     190 FOR c=1 TO 4: LET x=INT (RND*8): FOR b=0 TO 1: FOR f=72+0 TO 72+15: FOR g=9 TO 12
     191 LET y=BIFROSTfindAttr(f, g):
     192 IF b=0 THEN POKE y,x*8
         ELSE POKE y,x
         END IF
     193 IF x=7 THEN LET x=3
         ELSE LET x=x+1
         END IF
     194 NEXT g: NEXT f: NEXT b: NEXT c
     200 GO TO 60
     210 PRINT AT 22,1;INK 7;"PRESS ANY KEY": IF INKEY$="" THEN GO TO 210
         ELSE PRINT AT 22,1,,: RETURN
         END IF
     220 FOR f=0 TO 50
         BIFROSTsetTile(INT (RND*9), INT (RND*9), INT (RND*8))
         NEXT f
     230 PRINT AT 22,1;INK 7;"CHOOSE SPEED 2-4 OR 0 TO EXIT"
     240 LET a$=INKEY$
     250 IF a$="2" THEN BIFROSTresetAnimSlow(): PRINT AT 20,25;" slow)": END IF
     260 IF a$="4" THEN BIFROSTresetAnimFast(): PRINT AT 20,25;" fast)": END IF
     270 IF a$<>"0" THEN GO TO 240: END IF
     280 PRINT AT 22,1,,: RETURN
    
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012

    So please ignore this item. However I still cannot find the reason ZX BASIC cannot compile line 190 properly, I still believe that's a bug.


    Probably related to false being a return of -1 or 255 in a byte usually. I think this will affect the NOT part. But this is something you should be posting on Boriel's forum really - I'm not sure he reads here much.
  • edited March 2012

    Here's the entire library file bifrost.bas for anyone interested (just copy it to sub-directory library in ZX BASIC):

    Or just include it in the same directory as your main code, and use

    #include "bifrost.bas" in the main code instead of <bifrost.bas> -one means "here" the other means <library>.
  • edited March 2012

    ' After compiling it, you can use the following loader to execute:
    '
    ' CLEAR 32767: LOAD ""CODE
    ' LOAD "TILES"CODE
    ' LOAD "BIFROST*"CODE
    ' RANDOMIZE USR 32768
    '

    Why not compile it with the tiles and bifrost code included?

    You can use

    asm
    incbin "bifrost.bin"
    end asm

    To do that. Might need to use org, since it's not relocatable - or put it at the end of the code with a label, and lddr it to the top of memory...

    Though come to think of it, adding source code, and using #include "bifrost.asm" might be easier - make sure key parts are labelled, and the code relocates to the end of the main code regardless. This way it's not going to land on top of the heap and go horribly wrong.
  • edited March 2012
    Gedlion wrote: »
    Or just include it in the same directory as your main code, and use

    #include "bifrost.bas" in the main code instead of <bifrost.bas> -one means "here" the other means <library>.

    Good point. I edited my previous post accordingly.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    Gedlion wrote: »
    Why not compile it with the tiles and bifrost code included?

    You can use

    asm
    incbin "bifrost.bin"
    end asm

    To do that. Might need to use org, since it's not relocatable - or put it at the end of the code with a label, and lddr it to the top of memory...

    Though come to think of it, adding source code, and using #include "bifrost.asm" might be easier - make sure key parts are labelled, and the code relocates to the end of the main code regardless. This way it's not going to land on top of the heap and go horribly wrong.

    Thanks again for the suggestion, but in this case I think it's more convenient to leave it as is, for several reasons.

    If BIFROST* was compiled inside the program and rellocated afterwards, this would require calling an initialization routine that BIFROST* does not need otherwise, thus making it slightly more work for the programmer. Also BIFROST* code takes about 8.5K, thus if it was loaded somewhere else and then reallocated it could take twice as much space! I know these addresses could "overlap" and the source addresses could be used later for something else, but again this would just complicate everything for the programmer.

    If the code was compiled directly to the right place using ORG inside bifrost.asm, then I suppose the program parts after include "bifrost.asm" would be lost. Also it would mean the generated code would always have 32K, since ZX BASIC programs compile to 32768 by default, and the BIFROST* ENGINE must be loaded to the end of memory. Even for the release version, the programmer would probably prefer to load them separately anyway.

    Also including it as ASM could cause conflicts with label names, unless I distributed a different ASM source code version especially for ZX BASIC (using LOCAL declarations) and made all future changes on both, which seems like extra work for no reason.

    I'm still convinced an extra LOAD ""CODE will be much easier for the programmer than the alternatives above. Another advantage is that, if the compiled code was too large so it "invaded" the memory addresses required by BIFROST*, this problem would be obvious looking at the code block sizes on tape, but I guess everything would just crash mysteriously if they were just compiled on top of each other without leaving any clues to the programmer about what happened.

    All these issues refer to the BIFROST* code only. Regarding the tile images, there's no problem if the programmer wanted to include them directly using incbin, instead of loading the tile images from tape separately. For this purpose, I will add a new sub-routine called BIFROSTresetTileImages(addr as UINTEGER) so the programmer can easily configure the chosen tile image address.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    I need to go now, and I haven't played with it yet, but are there any documentation available so that I can make it working with z88dk? :)

    I also prefer the separately loading method as z88dk can't handle multiple ORGs.
  • edited March 2012
    I think my worry is that it might end up in space that the newest versions of zx basic use for heap - I think it uses the top of memory by default...

    Why does it need to be at the end of memory? Surely any space > 32768 is uncontended? I can believe in 256 byte alignments (there's an align compiler directive for that).

    As for labels, I'm a bit paranoid about that. I tend to prepend them with the name of the routine.

    So you get things like:

    HRPrint_Label_Loop_1

    And if someone else crashes on that, I suppose search and replace for the name of the routine works... :)
  • edited March 2012
    And here's the complete BIFROST* ENGINE DEMO adapted to ZX BASIC using the previous library file:
    ' ----------------------------------------------------------------
    ' BIFROST* ENGINE DEMO - converted to Boriel's ZX BASIC Compiler
    '
    ...
     280 PRINT AT 22,1,,: RETURN
    

    This is awesome! :-o
    I would like to convert the library to a set of SUB/Functions (if not already done) and include it in the ZX BASIC official distribution.

    Is the code freely distributable?
    Update: Just seen GPL license code, so yes! I'll include it, linking to the WOS file for crediting it :-)
  • edited March 2012
    Gedlion wrote: »
    I think my worry is that it might end up in space that the newest versions of zx basic use for heap - I think it uses the top of memory by default...

    Is this documented anywhere? I could not find any reference about this information. I only found references to variable ZXBASIC_MEM_HEAP inside ZX BASIC's library code, but this variable doesn't seem to be defined anywhere. I suppose it's directly set by the compiler.

    I believe the best (only?) solution would be a command-line option in the compiler to choose the heap address, just like you can currently choose the heap size. I will post later this suggestion in Boriel's forum.

    Gedlion wrote: »
    Why does it need to be at the end of memory? Surely any space > 32768 is uncontended? I can believe in 256 byte alignments (there's an align compiler directive for that).

    It needs to be at an specific memory address because the interrupt vector is location dependent, thus the code cannot be easily relocated.

    I could perhaps release another version where the entire BIFROST* ENGINE was moved like 4K lower, but even so this would not be the best solution for ZX BASIC, because in this case all ZX BASIC programs would be limited to 4K of heap. Or I could release another version where the entire BIFROST* ENGINE was moved further down, but this would limit the memory space available for the compiled program. And so on...

    Again, I'm convinced the best solution for ZX BASIC programmers is a command-line parameter in ZX BASIC Compiler to specify heap address. This way, BIFROST* can remain at the end of memory, and the programmers would still have the freedom to divide the rest of memory between heap and program anyway s/he wants.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    Timmy wrote: »
    are there any documentation available so that I can make it working with z88dk? :)

    I believe the generic documentation available at http://www.worldofspectrum.org/infoseekid.cgi?id=0027405 (English instructions file "BIFROSTENGINE.txt" under "Additional material") contains all the information you need for using it with z88dk. If you have questions, please ask here or send me an email.

    I'm planning to convert the demo to z88dk and post it here later, so programmers can use it as example when using z88dk... except I have never used z88dk myself so I will need a little time to learn it first :)

    Timmy wrote: »
    I also prefer the separately loading method as z88dk can't handle multiple ORGs.

    OK!
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    Is this documented anywhere? I could not find any reference about this information. I only found references to variable ZXBASIC_MEM_HEAP inside ZX BASIC's library code, but this variable doesn't seem to be defined anywhere. I suppose it's directly set by the compiler.

    I believe the best (only?) solution would be a command-line option in the compiler to choose the heap address, just like you can currently choose the heap size. I will post later this suggestion in Boriel's forum.

    [...]

    Again, I'm convinced the best solution for ZX BASIC programmers is a command-line parameter in ZX BASIC Compiler to specify heap address. This way, BIFROST* can remain at the end of memory, and the programmers would still have the freedom to divide the rest of memory between heap and program anyway s/he wants.

    The label ZXBASIC_MEM_HEAP is defined (declared) just at the end of your code (static variables included).

    At the moment I'm studying how to implement INTERRUPT routines.
    You can set the heap size from the command line, but not the heap start, because of the code unpredicted length.

    On the other hand, using ORG (available in the command line) 32768 + 256, can you place your routine in the 32768 RAM address and then jump from there to a desired location?
  • edited March 2012
    boriel wrote: »
    This is awesome! :-o

    Thank you!

    And since you are visiting this thread, please take a look at my suggestion above for a command-line option in the compiler to specify a different heap address (assuming our assumptions about ZX BASIC heap are correct).

    boriel wrote: »
    I would like to convert the library to a set of SUB/Functions (if not already done)

    Yes, it's already done. I have implemented a library interface for ZX BASIC that is available here:

    http://www.worldofspectrum.org/infoseekid.cgi?id=0027405

    The library interface provides a set of sub/functions that make it easier to access BIFROST* from ZX BASIC programs.

    However notice this library interface is just an interface, i.e. it does not contain BIFROST* itself. Just to make it clear, the idea is to compile a ZX BASIC program using this library interface, save it on tape, copy BIFROST* to the same tape afterwards, and use a loader to load both parts to memory before running the program.

    boriel wrote: »
    and include it in the ZX BASIC official distribution.

    As a matter of fact, I wasn't sure if it would be better to include the library interface into ZX BASIC official distribution or to distribute it directly from the WoS page. I have finally decided to upload it to WoS, but if you prefer to include the library interface inside ZX BASIC itself instead, that's fine!

    boriel wrote: »
    Is the code freely distributable?
    Update: Just seen GPL license code, so yes! I'll include it, linking to the WOS file for crediting it :-)

    Just take note that the library interface (i.e. file "bifrost.bas") is indeed GPL and you are welcome to include it in the ZX BASIC distribution. You are also very welcome to put the demo above in the "examples" folder as part of ZX BASIC distribution (you can save it as "bifrostdemo.bas" for instance).

    However the BIFROST* ENGINE itself is not GPL, please check the documentation file for license conditions!
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    boriel wrote: »
    The label ZXBASIC_MEM_HEAP is defined (declared) just at the end of your code (static variables included).

    Does it mean the heap starts right after the end of the compiled program and grows upwards (instead of starting at top of memory and growing downwards as I implied from Gedlion's post)? If so, this should not cause any interference with BIFROST* at all... unless the program runs out of memory of course, but in this case it would not work any other way either.

    boriel wrote: »
    At the moment I'm studying how to implement INTERRUPT routines.

    Even if ZX BASIC provides its own interrupt mechanism, programs using BIFROST* would better disable it and let BIFROST* control everything. The reason is that multicolor rendering is very sensitive to timing, so any overhead introduced by an external control would probably ruin the results.

    boriel wrote: »
    You can set the heap size from the command line, but not the heap start, because of the code unpredicted length.

    No problem. If ZX BASIC heap occupies the beginning of the memory space after the program (instead of the top of memory) then everything will just work and we don't need to worry about it.

    boriel wrote: »
    On the other hand, using ORG (available in the command line) 32768 + 256, can you place your routine in the 32768 RAM address and then jump from there to a desired location?

    Sorry I don't think I understood this idea...
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited March 2012
    Does it mean the heap starts right after the end of the compiled program and grows upwards (instead of starting at top of memory and growing downwards as I implied from Gedlion's post)? If so, this should not cause any interference with BIFROST* at all... unless the program runs out of memory of course, but in this case it would not work any other way either.
    That's right, the heap grows upwards. Even more, it won't overwrite the memory past a given size (which you can set in the command line). The default is to get all available memory, but for non conversational adventures, 640 bytes should be enough... (oh, wait! :lol:).

    When the heap can't not "malloc" (a la C) a chunk of memory, it returns NULL (e.g. an empty string). Using a debug mem command line parameter (slower, but for debugging purposes) will stop the program with a Sinclair BASIC Out of Memory error (the line number will be your REAL text source code line number).
    Even if ZX BASIC provides its own interrupt mechanism, programs using BIFROST* would better disable it and let BIFROST* control everything. The reason is that multicolor rendering is very sensitive to timing, so any overhead introduced by an external control would probably ruin the results.
    Agree. Infact, ZX Basic does not use IY register (a pity :-() because of that. But I guess i'll have to workaround this problem when records/structs/objects came into place.
    No problem. If ZX BASIC heap occupies the beginning of the memory space after the program (instead of the top of memory) then everything will just work and we don't need to worry about it.
    Great! ;)
    Sorry I don't think I understood this idea...
    I was figuring out you can place your routine at 32768 or near that address and compile your ZX Basic program with a higher ORG address from the command line. ??
  • edited March 2012
    Thank you!

    And since you are visiting this thread, please take a look at my suggestion above for a command-line option in the compiler to specify a different heap address (assuming our assumptions about ZX BASIC heap are correct).
    I'm currently writing an extensive manual (advanced one, even though my knowledge about the Speccy hardware is a bit oxidized ... :-?).

    I will check the BIFROST license, and also, thinking if other people (e.g. you, Britlion, and many others) can commit source code directly into the compiler's tree. I've been thinking of it while porting the compiler to a new branch, to allow it to produce code to other backends, etc.
  • edited March 2012
    Is this documented anywhere?

    I see Boriel Chipped in. Good! He can make it much clearer than me. I think when he said the heap was at the top of memory, I might have misunderstood and thought he meant that literally, as opposed to placed at the top of your code's memory space.


    It needs to be at an specific memory address because the interrupt vector is location dependent, thus the code cannot be easily relocated.

    Ah yes. Though if you make your interrupt vector a tiny bit of code that just jumps to the main one, that's all you need to lock into location - the rest that's jumped to can be moved more or less anywhere. Your overhead is still fixed - the cost of JP NNNN before you get to your routine.

    There is a potential bytes overhead cost, however :) I quite agree - and your solution of "updates need new access subroutines and functions to the fixed code block" is actually quite inventive. I'm just trying to think in terms of updates requiring zero work to plug back in, if you have key labels in key places.

    The more I look at this, the more I see how clever it is. Between ZXODUS and this - it's very fine code. (Literally, since any rough spots throw off the timing! It's like juggling. Very clever stuff.)

    I had a play with this concept a while ago. Have a look at thread:

    http://www.boriel.com/forum/post964.html?hilit=adorable#p964

    Over there. Not sure if it's useful, but it's how I glued in an IM2 routine completely compiled in ZX Basic.

    (And now I look at the date and see it's 2 years old. Yowsers).
Sign In or Register to comment.