[Z88dk-users] bifrostldem compilation

Bridge to the z88dk-users mailing list
Post Reply
thricenightly
Member
Posts: 28
Joined: Thu Jun 01, 2017 5:46 pm

[Z88dk-users] bifrostldem compilation

Post by thricenightly »

I'm trying to work out how to compile the bifrostldem demo under Linux. So far I've failed miserably, and I can't work out how to compile a bifrost "hello world" either, so it's time to take it step by step.

First thing I note is that when running the recommended compile line described in the demo's README:

Code: Select all

zcc +zx -vn -SO3 -startup=1 -clib=sdcc_iy --max-allocs-per-node200000 bifrostldem.c ctile.asm -o bifrostldem
it produces 2 binary files:

Code: Select all

bifrostldem_BIFROSTL.bin
bifrostldem_CODE.bin
Why does it do that? What is it about that compile line which makes 2 pieces of code appear?



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

First thing I note is that when running the recommended compile line described in the demo's README:

Code: Select all

zcc +zx -vn -SO3 -startup=1 -clib=sdcc_iy --max-allocs-per-node200000 bifrostldem.c ctile.asm -o bifrostldem
it produces 2 binary files:

Code: Select all

bifrostldem_BIFROSTL.bin
bifrostldem_CODE.bin
Why does it do that? What is it about that compile line which makes 2 pieces of code appear?
It's not in the compile line, it's in the bifrost source code. Bifrost sets up an engine at address 0xe501 which z88dk calls into. This engine is output as a separate binary if it gets used.

You can have a look at the source code to see how it's done:
https://github.com/z88dk/z88dk/blob/mas ... asm.m4#L14

The linker will pull out that block of code, see that section BIFROST_L is not in the memory map so it gets output in its own binary.

You have to arrange to load that binary into the right place in your basic loader. The compile instructions explain what steps need to be taken to create a functioning demo.

The basic loader contained in "loader.tap" looks like this:

Code: Select all

10 CLEAR VAL "32767"
30 LOAD "BIFROSTL"CODE
40 LOAD ""CODE
50 RANDOMIZE USR VAL "32768"
What it does is load the bifrost engine followed by the compiled code and then the compiled code is executed. The instructions are all about building a tap file around this loader.



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
thricenightly
Member
Posts: 28
Joined: Thu Jun 01, 2017 5:46 pm

Post by thricenightly »

This engine is output as a separate binary if it gets used.
OK, but... why?

I'm trying to picture what's happening. I have a bit of code (my C) ORGed at 32768, and another bit of code (BiFrost) ORGed at 58625. Why does the linker not join them together into a single piece of code with a "hole" in the middle?

I can see it might be a design decision. Loading 20KB of zeroes across an area of memory which might have something in it is a wasteful thing to do, so it's more efficient to break the code into chunks. That seems reasonable, if that's the reasoning. I'm just a bit thrown because I can't remember seeing a Spectrum program broken up into separate sections which are loaded individually. Is it possible to have the appmake utility merge them into one piece of loadable code?



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

This engine is output as a separate binary if it gets used.
OK, but... why?
The fixed location is the choice of the original author. Inside the code there are things that have to be located on 256-byte boundaries and then subroutines have been placed to fill holes that such alignment restrictions create. So to rewrite this to allow the linker to place things places more problems on the user by forcing him to plan a memory map where some things are on 256-byte boundaries and then making use of any holes that may appear in the memory map. I thought users wouldn't gain much by doing that.
I'm trying to picture what's happening. I have a bit of code (my C) ORGed at 32768, and another bit of code (BiFrost) ORGed at 58625. Why does the linker not join them together into a single piece of code with a "hole" in the middle? I can see it might be a design decision. Loading 20KB of zeroes across an area of memory which might have something in it is a wasteful thing to do, so it's more efficient to break the code into chunks.
It's a bit of the latter - remember that this is supposed to be a tape so loading a bunch of zeroes is a waste of time and also increases chances of tape loading errors.

But it's also because there's no telling for sure what the user wants to do with the binaries. Sometimes a binary is not meant to be loaded, for example a section can be created to place the heap at a specific place in memory but you don't want to actually load the binary that results for that section because the heap is initialized at runtime. Sometimes the binary is destined for a different memory bank and that may be something the linker doesn't know about. Sometimes a binary is destined for an independent purpose, for example it's a machine code loader for tape or disk.
I'm just a bit thrown because I can't remember seeing a Spectrum program broken up into separate sections which are loaded individually.
At the minimum there's going to be loader, screen$, machine code. For 128 programs it's simplest to load each 16k bank separately.
Is it possible to have the appmake utility merge them into one piece of loadable code?
Yes you can get appmake to make binaries covering each defined memory bank (up to 64k).

For that example,

Code: Select all

zcc +zx -vn -SO3 -startup=1 -clib=sdcc_iy --max-allocs-per-node200000 bifrostldem.c ctile.asm -o bifrostldem -m
appmake +glue -b bifrostldem --clean
appmake +zx -b bifrostldem__.bin --org 32768 --blockname demo -o demo.tap
"appmake +glue" sniffs the map file to figure out what goes where and stitches together binaries for each defined 64k bank, filling in holes as required. Other memory banks must have "BANK_XX" in their section names where XX is a hex number. It also checks alignment of binaries having "align_dd" in their names where dd is a decimal power of 2.

Then "appmake +zx" makes a tap file out glue's output.



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Post Reply