Using Z88DK - RC2014Z80/RC2014 GitHub Wiki
Z88DK is a complete development toolkit for the 8080, 8085, gbz80, z80, z180 (ez80), z80n and Rabbit processors.
The Z88DK wiki is the source for information relating to how to install and use the Z88DK generally. This wiki entry is specific to the RC2014.
The Z88DK contains two C compilers, an assembler / linker / librarian, data compression tools and a utility for processing the raw binaries into forms needed by specific targets (z88dk-appmake).
It comes with an extensive library of functions written in assembly language that implements the C standard and many extensions supporting specific target hardware. It holds the largest repository of z80 code on the Internet.
Development in assembly language or C is completely integrated; projects can be 100% assembler, 100% C or any mixture of the two. The toolset treats both as first-class languages and is designed to make it very easy to mix them at will with C and asm functions being able to call each other or make use of the hand-optimized library functions.
The Z88DK Installation page has full instructions on how to install the compilers and environment. Follow that first as it is more likely to be up to date and acccurate.
Development pace within Z88DK is fairly rapid, and as such it is best to use a git clone of the z88DK repository and build your own installation where possible.
Where you prefer (for MacOS or Windows platforms), the latest nightly build should be installed using the normal MacOS or Windows binary installation instructions. The nightly build contains a ready made z88dk-zsdcc
for these platforms, so there is no need to build it following below instructions.
To clone the current Z88DK Github package:
git clone https://github.com/z88dk/z88dk.git
sudo apt-get install expect texinfo libxml2-dev flex bison gputils libboost-dev
This will create a populated z88dk directory in the current working directory.
To succeed in building the z80svg
graphics tool you need the libxml2
library to be previously installed, although its absence will not prevent the rest of the kit from building.
Check the installation page for a complete set of dependencies required to be installed before building.
Then to build the z88dk (with z88dk-zsdcc
), just type:
cd z88dk
git submodule update --init --recursive
export BUILD_SDCC=1
chmod 777 build.sh
./build.sh
You can run z88dk keeping it in the current location, all you need to do is to set the following environment variables.
Supposing you have bash (most likely it is your system default shell) and you want to keep z88dk in your home directory, you can configure it permanently in this way:
vi ~/.profile
Modify the configuration by adding these lines (with the appropriate paths).
export PATH=${PATH}:${HOME}/z88dk/bin
export ZCCCFG=${HOME}/z88dk/lib/config
A system install is not supported in this release of Z88DK.
To install the sdcc
compiled specifically for the Z88DK, also called z88dk-zsdcc
, these are the instructions. If you exported the export BUILD_SDCC=1
in the previous step, then z88dk-zsdcc
will have already been built for you and you do not need to do this step.
Check out the current development version of sdcc
. If you already have the sdcc/sdcc-code
tree available from a previous checkout you can instead perform an update.
svn checkout svn://svn.code.sf.net/p/sdcc/code/trunk@14648 sdcc-code
# or if you're doing this to refresh your sdcc installation...
cd sdcc-code
svn update -r 14648
You will have to apply the patch found in src/zsdcc
and build sdcc from source. Copy sdcc-z88dk.patch
into the sdcc-code
directory.
The supplied configuration options below disables all ports other than the Z80 family ports, and turns off compilation of many unnecessary libraries and tools. This will also prevent potential errors from completing the build process, and results in a smaller compiler binary.
cd sdcc-code/sdcc
patch -p0 < ../sdcc-z88dk.patch
./configure --disable-ds390-port --disable-ds400-port --disable-hc08-port --disable-s08-port --disable-mcs51-port --disable-pic-port --disable-pic14-port --disable-pic16-port --disable-tlcs90-port --disable-xa51-port --disable-stm8-port --disable-pdk13-port --disable-pdk14-port --disable-pdk15-port --disable-pdk16-port --disable-mos6502-port --disable-mos65c02-port --disable-r2k-port --disable-non-free --disable-device-lib --disable-ucsim --disable-packihx --disable-sdcpp --disable-sdcdb --disable-sdbinutil
make all
Copy the patched sdcc
executable built in the src
directory to {z88dk}/bin
and rename it z88dk-zsdcc
.
cp src/sdcc ~/z88dk/bin/z88dk-zsdcc
Undo the patch.
patch -Rp0 < ../sdcc-z88dk.patch
You can stop here and verify the install was successful below. Keeping the sdcc source tree in an unpatched state can allow you to update the zsdcc binary by repeating the steps above as sdcc itself is updated. Both z88dk and sdcc are active projects that see frequent updates.
To verify that sdcc is usable from z88dk, try compiling sudoku.c
for the rc2014 target using sdcc:
zcc +rc2014 -subtype=sio -v -m -SO3 --max-allocs-per-node200000 --c-code-in-asm --list sudoku.c -o sudoku -create-app
Assuming we have a source code called test.c
.
int main(void)
{
return(0);
}
We can compile it and produce binary CODE
and DATA
sections. The CODE
and DATA
sections need to be concatenated, and then assembled into an Intel HEX file by z88dk-appmake
.
zcc +rc2014 -v -m -SO3 --max-allocs-per-node200000 --c-code-in-asm --list test.c -o test -create-app
The binary code can be checked by installing and then using a disassembler z80dasm
sudo apt install z80dasm
z80dasm --address --labels --origin=0x9000 test.bin
Or the z88dk disassembler z88dk-dis
can be used.
There are two C compilers available. One C compiler is z88dk-sccz80
which is derived from small-C but z88dk's version has seen continuous development over the past 30 years so it's had most of the limitations of small-C removed. For example, floating point is supported, ANSI C declarations are supported, 8/16/32-bit integers are supported and so on.
The other C compiler is a patch of sdcc
, another open source compiler that attempts to implement subsets of C89, C99 and C11. sdcc
is an optimizing compiler and z88dk's patch improves on sdcc's output by supplying a few Z80 bugfixes not yet incorporated into sdcc itself, providing a large number of optimised intrinsic compiler functions, and by supplying a very large set of peephole rules to further improve output.
You can choose which C compiler you use by selecting the appropriate switch on the command line. In your command line you are using z88dk-sccz80
if you use -clib=new
. To use z88dk-zsdcc
, -clib=sdcc_ix
or -clib=sdcc_iy
would appear in the compile command line.
A command line for compiling a C file or .lst
file containing a simple list of mixed C and asm files can look complicated, but really it is pretty straight forward.
zcc +rc2014 -subtype=basic -clib=sdcc_iy -SO3 -v -m --list --c-code-in-asm --fverbose-asm --max-allocs-per-node100000 --math32 -llib/hbios/time -llib/hbios/diskio_hbios -llib/hbios/ff @mytest.lst -o mytest -create-app
-
zcc
is the preprocessor, and is always used. Calls to the individual compilers, assembler, linker, and packager are not typical. -
+rc2014
is the target. Unless you're preferring the CP/M+cpm
or RomWBW HBIOS+hbios
targets, you should always use this+rc2014
target. -
-subtype=basic
is the subtype, as described below. If it is missing, a default subtype will be selected. -
-clib=sdcc_iy
is the compiler and library choice (sdcc_iy
is the default and can be ommited). If you prefer to usez88dk-sccz80
compiler then use-clib=new
. -
-SO3
is the optimisation. Unless you're debugging the compiler, always use this maximum optimisation setting. -
-v
is verbose.-vn
is silent compilation. -
-m
produces a map file. This is very useful to see where each label and section is located in memory. -
-w
produces a warning ifCODE
,DATA
, orBSS
sections overlap (default). -
--list
produces an assembly listing of the C files and the crt. -
--c-code-in-asm
includes C comments in the assembly listing. This is useful to track specifically what assembly is being generated from your C. Often simple adjustments to your C can substantially improve the generated assembly. Don't use this for your final build, as some peephole optimisations will be affected by comments interspersed within the assembly files. -
--fverbose-asm
produces verbose assembly listings when--list
is added. Don't use this for your final build, as some peephole optimisations will be affected by comments interspersed within the assembly files. -
--max-allocs-per-node100000
defines how aggressively thez88dk-zsdcc
compiler should attempt to optimise the code. Typical values range from 3000 to 400000. Increasing the value produces better code, but the compilation time can become excessive. -
--math32
use the IEEEmath32
library. The traditionalmath48
library is linked by-lm
. The APU Module library is--am9511
. -
-llib/target/library
links a specific 3rd party library. -
@mytest.lst
is a file containing a simple list of C and assembly programs to be compiled and linked into one outcome. If you have only one C filemyfile.c
is then the form used instead. -
-o test
specifies the root of the output files.test_CODE
,test_DATA
, andtest_UNASSIGNED
should be generated.test_UNASSIGNED
should have 0 bytes content; there should be nothing unassigned. -
-create-app
calls uponz88dk-appmake
to produce the final binary and Intel HEX files required to upload to the RC2014.
The classic C library is the C library that has always shipped with z88dk. It has many crts
available for it that allows compiling for a lot of target machines out of the box. The level of library support varies by target with the best supported having sprite libraries, sound, graphics, etc. supplementing the standard C library. It is mostly written in machine code and has a small stdio implementation. However, at this time it cannot be used to generate ROM-able code as it mixes variables with code in the output binary.
The new C library is a rewrite from scratch with the intention of meeting a subset of C11 compliance. It is 100% machine code, is written to be compatible with any C compiler, and can generate ROM-able code with separation of ROM and RAM data. The stdio model is object oriented and allows device drivers to be written using code inheritance from the library. Although it's not finished and is an ongoing development (it is missing disk I/O and non-blocking I/O), it is in an advanced state.
The RC2014 is supported by the new C library for all of its subtypes. The classic C library and the +cpm
target, can be used with the RC2014 when it is running any implementation of CP/M. The classic C library does not support the RC2014 directly.
The choice of C library is made on the compile line. -clib=new
, -clib=sdcc_ix
and -clib=sdcc_iy
all use the new C library. Anything else uses the classic C library. In order to generate ROM-able code, you must be using the new C library.
The sdcc_ix
and sdcc_iy
libraries are chosen when z88dk-zsdcc
is the compiler and are selected between by either -clib=sdcc_ix
or -clib=sdcc_iy
on the compile line. The difference between the two is which index register the C library uses. sdcc_ix
corresponds to the library using ix
and sdcc_iy
corresponds to the library using iy
, leaving ix
to the compiler to use for the stack frame pointer.
It's always preferable to use the sdcc_iy
version of the library because this gives zsdcc sole use of ix
for its frame pointer while the library uses iy
. If sdcc_ix
is selected, zsdcc and the library must share ix
which means the library must insert extra code to preserve the ix
register when it is used. This means the sdcc_iy
compile will be smaller and faster.
z88dk's C libraries are different from other development environments and compilers in that they are written in z80 (8080, 8085, z180, z80n) assembly language, so they are faster and more compact than other C libraries which are written in C.
The standard I/O library #include <stdio.h>
provides console output for either one or two serial interfaces, depending on the hardware configuration. For the ACIA and BASIC subtypes stdin
, stdout
, and stderr
are provided. For SIO and HBIOS subtypes ttyin
, ttyout
, and ttyerr
are added on the second serial terminal. The CP/M subtype provides stdrdr
, stdpun
, stdlst
to reference the CP/M reader, punch and list devices respectively.
Terminal attributes can be controlled by modifying the rc2014_rules.inc
file, according to the instructions here.
For stdin
, ttyin
, stdrdr
:
bits 15..10 reserved (includes some state for driver base class)
bit 9 = 1 to enable printed cursor
bit 8 = 1 to enable crlf conversion (will be filtered to generate lf only)
bit 7 = 1 to echo typed input characters
bit 6 = 1 to enable password mode (input printed as *)
bit 5 = 1 to enable line mode (input is edited before being delivered)
bit 4 = 1 to enable cook mode (input characters are interpretted in some way)
bit 3 = 1 for caps lock
bits 2..0 reserved (device state)
For stdout
, ttyout
, stdpun
, stdlst
:
bit 13 = (page mode) 1 = clear on full screen, 0 = wrap on full screen
bit 9 = enable signal bell
bit 8 = enable bell
bit 7 = page mode (1) or scroll mode (0)
bit 6 = enable pause on full screen
bit 5 = cook output chars
bit 4 = enable crlf conversion (C side \n -> \r\n)
bits 3..0 reserved (device state)
z88dk has the standard inp()
and outp()
functions for compliance, but there's a much faster method described in the SDCC Manual in section 3.5.2, which we use almost exclusively. The compiler recognises the special function register __sfr
ports and generates in a,(*)
and out (*),a
(or the relevant register where the info is to be accessed) directly. This takes 18 cycles to output a byte, typically.
These special function register ports defined for the RC2014 are generated from configuration file here.
An example of writing 0x01
to the RC2014 ROM toggle port, and then reading the ACIA status register, and using the compiler to do this:
#include <arch.h> // brings in the predefined RC2014 standard ports from the target build.
#include <arch/rc2014.h> // defines __sfr for these ports (special function registers)
uint8_t status;
io_rom_toggle = 1; // writes 0x01 to the port
status = io_acia_status; // reads the ACIA status port
Generates assembly like this:
ld a,$01 ; 7
out (__IO_ROM_TOGGLE),a ; 11
in a,(__IO_ACIA_STATUS_REGISTER)
ld (ix+*),a
You can also do this via the standard C inp()
and outp()
functions, but it is much much slower.
It typically takes more than 145 cycles to achieve the same outcome.
If we take an example of using the outp()
callee function:
#include <z80.h>
z80_outp(__IO_ROM_TOGGLE,$01);
The resulting assembly looks like this:
; in the C program
ld h,$01 ;7
push hl ;11
inc sp ; 6
ld hl,__IO_ROM_TOGGLE ; 10
push hl ; 11
call _z80_outp_callee ; 17
_z80_outp_callee:
pop af ;10
pop bc ;10
dec sp ;6
pop hl ;10
push af ;11
ld l,h ;4
jp asm_z80_outp ;10
asm_z80_outp:
; enter : bc = port
; l = data
; uses : none
out (c),l ;12
ret ;10
For the RC2014, the z88dk new library offers two main floating point libraries. The math48
library is the default (linked using -lm
), and has been proven correct over many years. It is usually faster than the default classic library floating point library, genmath
.
The computational accuracy provided by math48
with a 40-bit mantissa is unused by z88dk-zsdcc
which only supports IEEE-754 single precision floating point with a 24-bit mantissa. The additional accuracy of math48
is only useful with z88dk-sccz80
which supports many 4 byte and 6 byte floating point formats.
The math32
library is written to take advantage of z180 (ez80) and z80n (SpectrumNext) hardware multiply instructions and provides optimised software multiply options for the z80 (linked using --math32
). It works well with the z88dk-zsdcc
compiler which supports only IEEE-754 32-bit floating point format. math32
is mostly IEEE-754 32-bit floating point compliant, but doesn't handle some exceptions according to the standard.
The z88dk classic library provides some performance benchmarking of the many floating point math libraries available for z80, including 40-bit BBC BASIC, and 32-bit and 64-bit MS BASIC found in the ROM of classic machines.
In addition to the two main floating point libraries, there is an adjunct IEEE-754 half precision floating point library math16
. The math16
library is approximately 4 times faster than math32
, but results are limited in accuracy by the format.
The specialised nature of 16-bit floating point implies that math16
is an adjunct or special purpose maths library. It can be used to accelerate the calculation of floating point, where the results are only needed to 3.5 significant decimal digits. Applications can include video games, or neural networks, for example. Either the math48
(-lm
) or the math32
(--math32
) libraries must be used in conjunction with math16
(--math16
) to provide stdio input and output (printf()
) capabilities.
With the additional APU Module, it is possible to use the Am9511A Floating Point library
, (linked with --am9511
), which is IEEE 32-bit compliant. The library masks the difference between the Am9511A floating point hardware and IEEE 32-bit floating point, and the API interfaces are identical to the math32
library.
External libraries are installed using the z88dk-lib
tool. The z88dk-lib
function is used to install a library for the desired target. e.g. for the ff library on the rc2014 machine.
z88dk-lib +rc2014 ff
Some further examples of z88dk-lib
usage.
- libraries list help
z88dk-lib
- list 3rd party libraries already installed for the rc2014 target
z88dk-lib +rc2014
- remove the
libname1
libname2
... libraries from the rc2014 target,-f
for no nagging about deleting files.
z88dk-lib +rc2014 -r -f libname1 libname2 ...
Once installed, the libraries can be linked against on the compile line by adding -llib/target/library
and the include file can be found with #include <lib/target/library.h>
.
A collection of libraries relevant to the RC2014 can be found here. Specifically the ff
, diskio_hbios
, and time
libraries are worth attention.
The support for the RC2014 within Z88DK is extensive. To differentiate build characteristics across different hardware and software environments Z88DK uses the concept of subtypes. Depending on your interest and hardware, different subtypes can be invoked to best support your needs.
Whilst the default configurations of each subtype are provided here, it is easy to use #pragma
defines from within your program or from the command line to change any configuration as needed.
The ACIA and SIO subtypes are useful to build ROM-able code, that includes configuration and driver code for either the ACIA or SIO/2 serial hardware. There is no dependency on a monitor or other code pre-existing on your RC2014. Both require the RC2014 Classic, Mini, Micro, as a minimum starting point, but can be configured to support all the RAM or ROM available on a RC2014 Plus or Pro as required.
The BASIC subtype is useful if you have a RC2014 Classic, Mini, or Micro with a BASIC ROM. As this is the minimum starting point for the RC2014 world, it is expected that quite a few people will be able to use this option, together with the (now obsolete) hexload program, to get started in writing their own C or assembly programs. Recent RC2014 BASIC ROMs now incorporate an integrated hload
function which uploads Index Hex code and adjusts the BASIC Memory top
correctly.
The BASIC subtype is also for the Small Computer Monitor SCM
. As the SCM uses RAM slightly differently than BASIC, programs need to provide #pragma
to define the correct origins. More on this below.
The CPM subtype is a useful adjunct to the Z88DK classic CPM target. It can be used to get direct access to hardware, drivers, and libraries available for the RC2014, that don't exist in the classic target. For example, the IDE drivers and FAT32 support available to the RC2014 new library are not found in the classic library CPM target.
The RomWBW HBIOS subtype is similarly an adjunct to the Z88DK HBIOS target, and can be used to provide access to RC2014 specific hardware. However as HBIOS supports most hardware available to the RC2014 there is little to distinguish these two alternatives.
Additionally, subtypes for the 8085 CPU Module have been developed. These are basic85
for MS Basic for 8085, and for the ACIA Serial Module acia85
.
The zcc +rc2014 -subtype=acia
subtype is designed for the RC2014 Classic, Mini, or Micro platforms where RAM is located from 0x8000
and between 8kB and 32kB of ROM is located at 0x0000
, and the MC68B50 (ACIA) module is installed.
The ACIA subtype is intended for programs to be burnt to ROM, and provides the full configuration and drivers required to run on bare metal. Use the map file to ensure that your code does not extend beyond the end of available ROM. A warning has been added when your CODE
section passes beyond 0x8000
or 32kBytes.
The Z88DK default configuration table is located here.
The zcc +rc2014 -subtype=acia85
subtype is designed for the RC2014 Classic, Mini, or Micro platforms equipped with a 8085 CPU Module, where RAM is located from 0x8000
and between 8kB and 32kB of ROM is located at 0x0000
, and the MC68B50 (ACIA) module is installed.
It is otherwise similar to the ACIA subtype.
The zcc +rc2014 -subtype=sio
subtype is designed for the RC2014 Classic, Mini, or Micro platforms where RAM is located from 0x8000
and between 8kB and 32kB of ROM is located at 0x0000
, and the SIO/2 module is installed.
The SIO subtype is intended for programs to be burnt to ROM, and provides the full configuration and drivers required to run on bare metal. Use the map file to ensure that your code does not extend beyond the end of available ROM. A warning has been added when your CODE
section passes beyond 0x8000
or 32kBytes.
The Z88DK default configuration table is located here.
The zcc +rc2014 -subtype=basic
subtype is designed for the RC2014 Classic, Mini, or Micro platforms and the BASIC ROM is installed. The BASIC subtype is intended to be loaded to RAM.
By default programs are loaded at 0x9000
to allow space between 0x8000
where RAM originates and the data origin for BASIC and to initially load a (now unnecessary) hexload program to support uploading Intel Hex code.
The functionality of uploading Intel Hex has been integrated into several BASIC implementations so a space reservation for the BASIC hexload program is no longer necessary. Therefore it is possible to load Intel Hex at 0x8400
, beyond the end of the BASIC system, and the integrated hload
function will configure the BASIC Memory Top to suit. To make this change to the default configuration for the BASIC subtype the following lines can be added to your C programs.
#pragma output CRT_ORG_CODE = 0x8400
To provide the maximum space for CODE
, DATA
, BSS
, and heap space, CODE
is loaded by default from 0x9000
, DATA
, BSS
, and heap follow contiguously using RAM through to 0xFFFF
. The stack is configured to start at 0xFFFF
and grow downwards.
The Z88DK default configuration table is located here.
For example for sudoku.c
:
zcc +rc2014 -subtype=basic -SO3 --max-allocs-per-node200000 sudoku.c -o sudoku -create-app
Or for umchess.c
:
zcc +rc2014 -subtype=basic -SO3 --max-allocs-per-node200000 --math32 umchess.c -o umchess --fsigned-char -create-app
This will create an IHEX file with the origin at 0x9000
, which can be loaded into the RAM of the RC2014 using the 'hexload' BASIC program with the standard RC2014 BASIC ROM.
The memory model for this implementation has the C data and bss sections will follow immediately after the C code loaded at 0x9000
, and the C stack will be located at 0xFFFF
and grow down.
To ensure there is no conflict with BASIC hexload program, the initial Memory top?
question should be answered with 35071
(0x88FF
) or lower.
Further information on preparing C programs can be found on the hexload page.
If using the NASCOM BASIC Version here, the Z80 RST vectors are directed to a jump table starting at 0x8000
. This allows the user to redirect the RST instructions to a routine of choice.
For example if the user wants to use RST20
for their own program, then the following C can be used.
#include <cpu.h>
#define Z80_VECTOR_BASE $8000
// whole RST table for reference
#define RST_00_ADDR Z80_VECTOR_BASE+$01
#define RST_08_ADDR Z80_VECTOR_BASE+$05
#define RST_10_ADDR Z80_VECTOR_BASE+$09
#define RST_18_ADDR Z80_VECTOR_BASE+$0D
#define RST_20_ADDR Z80_VECTOR_BASE+$11
#define RST_28_ADDR Z80_VECTOR_BASE+$15
#define RST_30_ADDR Z80_VECTOR_BASE+$19
#define RST_38_ADDR Z80_VECTOR_BASE+$1D
#define INT_INT0_ADDR Z80_VECTOR_BASE+$1D
#define INT_NMI_ADDR Z80_VECTOR_BASE+$21
void my_rst_20_function(void);
int main(void)
{
uint16_t volatile * const interrupt_vector = (uint16_t *) RST_20_ADDR;
* interrupt_vector = (uint16_t) my_rst_20_function;
return 0;
}
void my_rst_20_function(void)
{
return;
}
To use SCM with the BASIC subtype, the code origin and the stack origin need to be relocated. SCM stores its configuration data from 0xFC00
to 0xFFFF
, so our stack origin must be moved down to 0xFC00
to avoid a clash. However SCM does not use RAM at 0x8000
, so our code origin can also be moved down to 0x8000
without any issue.
To make these changes to the default configuration for the BASIC subtype the following lines can be added to your C programs.
#pragma output CRT_ORG_CODE = 0x8000
#pragma output REGISTER_SP = 0xFC00
Pragmas can also be done from the command line, but it is usually more convenient to do it once in the program file.
The command line then includes...
zcc +rc2014 -subtype=basic -clib=sdcc_iy ... mycode.c -o mycode -create-app
The resulting Intel Hex (mycode.ihx
) can be uploaded to the SCM monitor using instructions found in the SCM User Guide, and the program initiated using the g 8000
command.
The zcc +rc2014 -subtype=basic85
subtype is designed for the RC2014 Classic, Mini, or Micro platforms equipped with a 8085 CPU Module, and the BASIC ROM is installed. The BASIC subtype is intended to be loaded to RAM.
It is otherwise similar to the BASIC subtype.
The zcc +rc2014 -subtype=cpm
subtype is designed for any RC2014 running CP/M.
The CP/M subtype is intended to be run from RAM, and resulting binaries mycode.bin
or mycode.com
can be transferred to the RC2014 using XMODEM
(for example) and stored to disk as MYCODE.COM
and then run from the CP/M command line. Alternatively mycode.ihx
files can be transferred using PIP
, and then converted to .COM
on the RC2014 using LOAD
, or MLOAD
.
As is traditional, programs are loaded at 0x0100
and rely on BDOS calls for all access to hardware. This subtype doesn't have direct access to a file system as the new library doesn't currently support file I/O. To use file I/O in a CP/M application it is necessary to either: use the +cpm target and classic library, or use the ChaN FatFS library and the RC2014 IDE module for direct access to FAT32 formatted CF or IDE drives.
The Z88DK default configuration table is located here.
To use this subtype for RC2014, this is the relevant command line for the program Test.c
.
zcc +rc2014 -subtype=cpm -clib=sdcc_iy -SO3 -v -m --list --max-allocs-per-node100000 --math32 -llib/rc2014/ff Test.c -o Test -create-app
The ChaN FATFS library ff
must be installed for the RC2014 target, and then used as shown.
As noted above, to access the CP/M file system it is necessary to use the the z88dk standard CP/M target. It is accessed by zcc +cpm -subtype=default
.
The zcc +rc2014 -subtype=hbios
subtype is designed for any RC2014 running RomWBW. The HBIOS subtype is intended to be loaded to RAM using the dbgmon provided by RomWBW.
When RomWBW boots enter M
to initialise the dbgmon. Within dbgmon use L
to load Intel Hex (mycode.ihx
) to RAM, and then use R100
to run the program loaded at 0x0100
.
As is traditional, programs are loaded at 0x0100
and rely on HBIOS calls for all access to hardware. The HBIOS API is defined in the RomWBW Architecture Document.
The Z88DK default configuration table is located here. A warning has been added when your DATA section passes beyond 0x8000
and would collide with the BSS section. This is because BSS section is configured to start at 0x8000
, so that HBIOS buffering restrictions are respected. The BSS section can then be moved using a #pragma
to remove the overlap (see below).
To use this subtype for RC2014, this is the relevant command line for the program Test.c
.
zcc +rc2014 -subtype=hbios -clib=sdcc_iy -SO3 -v -m --list --max-allocs-per-node100000 -llib/hbios/time -llib/hbios/diskio_hbios -llib/hbios/ff Test.c -o Test -create-app
The time
, diskio_hbios
, and ff
libraries must be installed for the HBIOS target, and then used as shown.
Many example programs are located in the EXAMPLES
directory of Z88DK, and further are located here and further external examples here.
This is one example which demonstrates a file copy, which will work under either ACIA, SIO or CPM subtypes with the RC2014 IDE module or HBIOS subtype for any disk interface.
zcc +rc2014 -subtype=cpm -clib=sdcc_iy -SO3 -v -m --list --max-allocs-per-node100000 -llib/rc2014/ff fileCopyTest.c -o fileCopyTest -create-app
zcc +rc2014 -subtype=hbios -clib=sdcc_iy -SO3 -v -m --list --max-allocs-per-node100000 -llib/hbios/time -llib/hbios/diskio_hbios -llib/hbios/ff fileCopyTest.c -o fileCopyTest -create-app
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#if __RC2014
#include <lib/rc2014/time.h> /* Declaration of system time */
#warning No timer calculation possible.
#else
#error Do you have time?
#endif
//#if __RC2014 /* CPM subtype */
//#include <lib/rc2014/ff.h> /* Declarations of FatFs API */
//#include <arch/rc2014/diskio.h> /* Declarations of diskio & IDE functions */
#if __RC2014 /* HBIOS subtype */
#include <lib/hbios/ff.h> /* Declarations of FatFs API */
#include <lib/hbios/diskio_hbios.h> /* Declarations of diskio functions */
#include <arch/hbios.h> /* Declarations of HBIOS functions */
#else
#warning - no FatFs library available
#endif
// #pragma output CRT_ORG_BSS = 0x9000 // for hbios move bss origin to address 0x9000 (check map to confirm there is no overlap between data and bss sections)
#pragma printf = "%s %c %u %li %lu" // enables %s, %c, %u, %li, %lu only
static FIL FileIn, FileOut; /* File object needed for each open file */
#define BUFFER_SIZE 4096 /* size of working buffer (on heap) */
static BYTE * buffer; /* working buffer */
/* must be in bss (which is above 0x8000) for romwbw hbios buffer */
static FATFS * FatFs; /* FatFs work area needed for each volume */
/* Pointer to the filesystem object (on heap) */
int main (void)
{
UINT bw;
UINT br;
DWORD bwt = 0;
FRESULT res;
struct timespec startTime, endTime, resTime;
buffer = (BYTE *)malloc(sizeof(BYTE)*BUFFER_SIZE); /* Get working buffer space */
FatFs = (FATFS *)malloc(sizeof(FATFS)); /* Get work area for the volume */
startTime.tv_sec = 1577836800 - UNIX_OFFSET;
clock_settime(CLOCK_REALTIME, &startTime); /* Set the time of day, y2k epoch */
if ((res = f_mount(FatFs, "0:", 1)) == FR_OK) { /* Give a work area to the default drive */
printf("\r\n\nFatFs->fs_type %u\nFatFs->fsize %lu\n", FatFs->fs_type, FatFs->fsize);
printf("\r\nOpening 0:random1.txt");
if ((res = f_open(&FileIn, "0:random1.txt", FA_READ)) == FR_OK) {
printf(" - Opened");
if ((res = f_lseek(&FileIn, 0)) == FR_OK) {
printf("\r\nCreating 0:random2.txt");
if ((res = f_open(&FileOut, "0:random2.txt", FA_CREATE_ALWAYS | FA_WRITE)) == FR_OK) {
printf(" - Created\r\n\nCopying...");
clock_gettime(CLOCK_REALTIME,&startTime);
for (;;) {
res = f_read(&FileIn, buffer, sizeof(BYTE)*BUFFER_SIZE, &br); // put_rc(res);
if (res != FR_OK || br == 0) break; // eof or error
res = f_write(&FileOut, buffer, br, &bw); // put_rc(res);
bwt += bw;
if (res != FR_OK || bw != br) break; // error or disk full
}
clock_gettime(CLOCK_REALTIME,&endTime);
f_close(&FileOut);
if ((res = f_unlink("0:random2.txt")) != FR_OK) {
printf("\r\nCouldn't delete 0:random2.txt - f_unlink error #%u\r\n", res);
}
} else {
printf("\r\nCouldn't open 0:random2.txt - f_open error #%u\r\n", res);
}
} else {
printf("\r\nCouldn't seek 0:random1.txt - f_lseek error #%u\r\n", res);
}
f_close(&FileIn);
} else {
printf("\r\nCouldn't open 0:random1.txt - f_open error #%u\r\n", res);
}
timersub(&endTime, &startTime, &resTime);
printf("\r\nCopied %lu bytes", bwt );
printf(", the time taken was %li.%.4lu seconds\n", resTime.tv_sec, resTime.tv_nsec/100000 );
f_mount(0, "0:", 0); /* Free work area */
} else {
printf("\r\nCouldn't mount drive - f_mount error #%u\r\n", res);
}
// Perform any shutdown/cleanup.
free(FatFs);
free(buffer);
return 0;
}