Tutorials

now browsing by category

 

Z88DK: Creating libraries

Z88DK

About 20 or so years ago a guy called Juergen Buchmeuller joined the VZ200 Yahoo group and was posting updates for MAME (then, MESS) for VZ200 support. He created a few graphics and sound library functions for the VZ200 and created a game “Defense Command” using Z88DK.

I used his base functions and wrote a bunch of my own and created an Arkanoid clone I called “Arkaball“.

The guys at Z88DK used his functions and some of mine and ported them into the main Z88DK repository.

In the years since I have helped add VZ200 support to the Multi-Platform Arcade Game Designer (MPAGD) and Turbo Rascal: ‘;’ expected but “BEGIN”. (TRSE for short!).

I have talked with Prince from the PHAZE101 group and he has “Game Jams” where you get a short amount of time (usually a few weeks) to create a game for a retro platform of your choice, using the theme he decides. The games have to be written in BASIC, Assembly Language or C. While I can write games in Assembler, I prefer something a bit higher level. BASIC is too high and too slow in most cases, but C with Z80 Assembler functions hits the right spot.

I did a lot of research of different ways to do this and finally decided on Z88DK since some of my coding was already done with that and they are really responsive on their forum. The problem is I already wrote a ton of Z80 Assembler code for TRSE Units to code games in Pascal. Now, I need them converted to Z88DK library format.

So, I cloned their github repository and started to work out what to do next. As I had no experience with Z88DK for years it took me a while to grasp things. I also wanted to set up the SublimeText Text Editor to write, build and test my C code.

To start, you will need to BUILD the Z88DK repository code. I will leave you to read this on their website. This was one crucial step I forgot to do! You can set up a SublimeText build system with the following info:

{
    "working_dir": "<YOUR HOME>/Dev/VZ/VZEm-Linux/",
            "cmd": "zcc +vz -zorg=31488 -vn --list -pragma-define:CLIB_CONIO_NATIVE_COLOUR=1 -create-app -lndos -m $file -o $file_path/$file_base_name.vz",
            "shell": true,
    "variants":
    [
        {
            "name": "Run",
            "cmd": "<YOUR HOME>/Dev/VZ/VZEm-Linux/VZEm-SDL -f $file_path/$file_base_name.vz",
            "shell": true
        }
    ]
} 

Remember to change the ‘home’ paths to your own. I am building on Fedora Linux. I recently built Guy’s VZEm Emulator (SDL version) for Linux, which you can download from this site.

You can do something similar if you are on Windows and probably on OSX as well. I called my file BuildVZ200.sublime-build You can add it in the Packages/User folder. Select it in the Tools -> Build System menu.

Now, there are certain conventions when it comes to writing code for Z88DK. If you have a simple function with zero or one parameter, you can get away with just one file. Eg. vz_getrnd.asm

    SECTION code_clib
    PUBLIC  vz_getrnd
    PUBLIC  _vz_getrnd

vz_getrnd:
_vz_getrnd:

    ld bc,$0000
    call $09b4    ; Loads ACC with BCDE
    call $0a9d    ; Set flag to Integer
    call $14c9    ; RND routine. Using ACC, not A
    call $0a7f    ; CINT. Puts ACC into HL
    ret

This is a function I called vz_getrnd(x). It’s used to get a random number. The number returned can be any value from 0 to 65535. This is because it is defined as an Integer. The above built-in VZ ROM functions are built that way. Note the code above does not have code for the value of ‘x’ which is the highest number limit for your random number. The reason for this is when you call one of these functions, Z88DK will by default put the value directly into the HL registers. This is very handy because the VZ ROM rnd() function requires that number to be in HL. You will see it also does not return the number it selects. This is because, again, the VZ ROM routines return the random number in the HL registers by default. How handy is that?? It sure saves a lot of mucking around. Since we only have one parameter for vz_getrnd() and return one, this is all we need. If you put a value in the HL registers this is returned to the calling function. To make it work with your C code using Z88DK you need to do a couple of things.

Add this function to the vz.h header. This is in include/arch/vz.h :

extern int  __LIB__              vz_getrnd(int x);

This let’s you include it at the top of your code. #include <arch/vz.h>

It also defines the return value as an INTeger and the supplied value as INTeger, which is important.

Your Z80 Assembler code goes in z88dk/libsrc/target/vz/ eg. vz_getrnd.asm

You will also need to add the function to the vz200.lst file which is in z88dk/libsrc/target/vz/ eg:

target/vz/vz_getrnd

You also need to add it to vz_clib.lib which is your code compiled and ready to use in a library. To build the library, enter the z88dk/libsrc/ directory. Delete the existing file, make the new library and copy it to z88dk/lib/clibs/ I use this one-liner shortcut from the libsrc directory:

rm vz_clib.lib; make vz_clib.lib; cp vz_clib.lib ../lib/clibs/

Now I can immediately test the C code from SublimeText by using CTRL-B and ENTER to Build the code and CTRL-B, cursor-down to Run to launch the VZ200 VZEm emulator and load and run my code. You can create a SublimeText Build function to build then straight away RUN your new code in the emulator but I like to keep my functions separate.

There is one caveat and that is if your function requires more than one parameter. In which case you need your function.asm file and also a function_callee.asm file.

An example I have is the vz_poke(addr,n) function which just pokes a value into memory somewhere. Handy to use on the graphics MODE(1) screen when you make a game. Since this has two parameters you need the two files. You also need to handle the program stack yourself to make sure things are good to go when Z88DK returns from your function. The return address will be pushed onto the stack, then the second parameter will be pushed onto the stack, then the first parameter will be pushed onto the stack. Eg: vz_poke.asm

; ----- void __FASTCALL__ vz_poke(void *addr, char byte)
    SECTION code_clib
    PUBLIC  vz_poke
    PUBLIC  _vz_poke
    EXTERN  vz_poke_callee
    EXTERN  asm_vz_poke

vz_poke:
_vz_poke:
    pop     af
    pop     bc
    pop     hl
    push    af
    jp      asm_vz_poke

And vz_poke_callee.asm :

; ----- void __CALLEE__ vz_poke_callee(void *addr, char byte)

    SECTION code_clib
    PUBLIC  vz_poke_callee
    PUBLIC  _vz_poke_callee
    EXTERN  asm_vz_poke

vz_poke_callee:
_vz_poke_callee:

    pop     af
    pop     bc
    pop     hl
    push    af

   ;  c = byte
   ; hl = addr

asm_vz_poke:
    ld    a,c
    ld    (hl),a
    ret

You will see above the first thing I do is ‘pop af’. When this function is called the return address is pushed onto the stack. You need to pop this off the stack and store it safely. Next, I use ‘pop bc’. This will get the SECOND parameter. Lastly, ‘pop hl’ will take the FIRST parameter (the address to POKE the second parameter into). Lastly, I use ‘push af’ which puts the return address back onto the stack. Now, when the code hits ‘ret’ to return at the end, it goes back to the correct return address. Note that if you want to return any values, load them into HL before you use ret. You will still need to correctly define your function in vz.h but you will need to have 3 lines to define it. ie:

extern void __LIB__              vz_poke(void *addr, int byte) __smallc;
extern void __LIB__    vz_poke_callee(void *addr, int byte) __smallc __z88dk_callee;
#define vz_poke(a,b)			 vz_poke_callee(a,b)

Now when you build the clib file everything will link up correctly.

The handy thing about parameter values is they will go in the correct sized registers on return. So, an 8-bit (1 byte) or 16-bit (2 byte) value will go into HL and a 32-bit (4 byte) value will go into a combination as DEHL. Your code can ignore the higher byte register if you like, as I have done above where I copy the value in the C register into the Accumulator but ignore the value in the B register. You can read more about this on the Calling Conventions page on the Z88DK website.

Note that when you add your function and your _callee function you will have to add BOTH to vz200.lst :

target/vz/vz_poke
target/vz/vz_poke_callee

Otherwise the clib library will not build with both and you will get errors when you Build (compile).

One handy thing is in the meantime since I first posted on the Z88DK forum 20-odd years ago they’ve added a lot of support for the MC6847 graphics chip which happens to be in the VZ200 so you can use their already existing functions like:

    int mode = 0;
    console_ioctl(IOCTL_GENCON_SET_MODE, &mode); // Set MODE(1) graphics mode
    textcolour(YELLOW); // Set drawing colour to Yellow
    draw(5,5,50,50); // Draw a line from 5,5 to 50,50 in Yellow

You can see a bunch of their functions on the Classic Monochrome Graphics wiki page. Since the Z88DK guys already have a lot of this code it saves me the time, which I appreciate.

Developing for VZ200 – Part 4

I had seen a few people talking about a programming system created for vintage computers. The developer named it Turbo Rascal: Syntax Error (or TRSE for short). It’s free to download and use. Most of the coding is based on Pascal but there are some C-like programming methods in it.

Read More …

Developing for VZ200 – Part 3

I discovered the Multi-Platform Arcade Game Designer by Jon Cauldwell and asked if it could be ported to support VZ200 and VZ300 computers. He said it’d work fine. They already had support for Dragon 32 and Acorn Atom – both which have the same Graphics chip as the VZ200 (Motorola 6847) although the VZ200 and VZ300 only have one hires graphics mode out of all the available modes the 6847 has.

Read More …

Developing for VZ200 – Part 2

I decided to try setting up Visual Studio for my development environment. It’s not as easy to set up as Notepad++ was, but everything is integrated nicely, including GITHUB support so I figured I’d go with it.

You need to set up a custom task in Visual Studio. You can read about that on the “Tasks in Visual Studio Code” page. Below is a screenshot of how I set up the Z88DK compiler to compile my Assembler and C code together.

Visual Studio Task for Z88DK
Read More …

Developing for VZ200 – Part 1

To begin your foray into developing for VZ200 and VZ300 computers, you will first need an IDE. Next, you’ll need to download and set up Z88DK development kit and grab a VZ emulator.

IDE

A good, easy-to-use IDE is Notepad++ as it’s free and simple to use. I use a plugin called NppExec to compile the code with a one-button press. You can also set it to auto-launch an emulator, but at this stage we won’t worry about that.

First, download the latest version of Notepad++ and install it. Next, get NppExec. I watched a neat little video for setting this up. It’s quite easy to do.
Download and install Z88DK. There’s plenty of info there on how to do it and I’m sure you can find a YouTube video or two. I have mine installed at D:\Dev\VZ\z88dk
Make sure you set up your PATH and ENVIRONMENT VARIABLES in Windows as described.

Read More …
© 2026: Blue Bilby | GREEN EYE Theme by: D5 Creation | Powered by: WordPress