How to tame IAR C Compiler
DimkaM
IAR'out of the box' is completely unsuitable
for Specky and spektrumist. There is no bible in it─
swelling for the Spectrum, it costs a lot of money,
they will not be able to compile the binary with one
line incmd,and it does not know how to generate
trd/tap/scletc.
But still, let's try to master it.
* * *
Where to start? Let's create a directory"IAR"
(or whatever you want) and copy the folder into it
"z80" from the archive with IAR. Download the latest
xlink.exe, from the official IAR website, in
directory "z8Obin" . Now let's create
in the directory "IAR" folder with the project
"lesson1", and in it a directory"list" for
all sorts of useful garbage.
Let's copy the default cstartup.s01 from
IAR(z8Oiccz80) to the directory with your
project. We are interested in two points in it:
the first is the beginning of the binary, also known as the start
programs:
ASEG
ORG 0
Accordingly, we change it to our address,
let's sayORG 0x6000:
ASEG
ORG 0x6000
The second point is to disable interrupts
immediately after the labelinit_C:
init_C
DI
LD SP,.SFE.(CSTACK-1);from high
;to low address
This completes the changes.
Now we need to create a fileLnk.xcl,
empty, we will write the lines in it:
-cZ80 //processor for which we assemble
-Z(CODE)RCODE,CODE,CDATAO,CONST,CSTR,
CCSTR=6000-BFFE//memory segments with
//constants and code
-Z(DATA)INTVEC=BFFF-COO0 //segment with
//table for im2 interrupts
-Z(DATA)DATAO,IDATAO,UDATAO,ECSTR,
ALIGN8|8,CSTACK+200=C001-FFFF//segments
//stack, variables, etc.
-e_medium_write=_formatted_write
//printf/sprintf configuration
-e_medium_read=_formatted_read
//scanf/sscanf configuration
cstartup //link our startup
-C ../z80/lib/clz80 //connect
//library, the '-C' option will allow us
//link your cstartup
-Fraw-binary //collect a clean binary
-l list/cout.html
-o code.cou //binary name
-xehinms //include everything for completeness
Save and close. If something is not right─
It’s clear, you can always look at the document─
tation, everything is described in detail there.
Let's create a filemain.c:
//everything is banal here
void main(void)
{
}
Let's create a batch file"make_c.bat", again
don't be lazy to read the description of the options in
documentation:
..z8Obiniccz80 -v0 -ml -uua -q -e -K
-gA -s9 -t4 -T -Llist -Alist
-I"../z80/inc/" main.c
..z8Obinaz80 Cstartup.s01
..z8Obinxlink main -f Lnk.xcl
del *.r01
And let's launch it. We have compiled
"naked" binarycode.cou (if you haven't forgotten
download the latestxlink ), which you can for─
load and run from address0x6000. Also
infolderlist there was a file main.s01 with number─
tym asm and filecout.html with the address map─
owls, these files may be useful for debugging─
ki.
When using the operator'?' (ter─
narry conditional operation) with complex you─
I highly recommend optimization
above 7 (-s7 or -z7 ), as noted
bugs.
We will use the current project as
template. To create a floppy image, you can
use the utilitytrdtool, adding to
end of the batch file:
..z8Obintrdtool # test.scl
..z8Obintrdtool + test.scl boot.b
..z8Obintrdtool + test.scl code.cou
Well, watching a clean screen is very interesting─
resno. There are two options: write everything in C,
or create a library on ASMA.
* * *
Let's consider the first option.
Let's copy the template project.
We need screen initialization, printing
character and a static variable with the current
acquaintance address:
#include
#include<intrz80.h>
#include <stdio.h>
static union {char * w;char b[2];}scrxy;
void scr_init(char a){
*((char *)0x5800)=a;
output8(Oxfe,a>>3);
memcpy((void *)0x5801,
(void *)0x5800, 32*24-1);
scrxy.w=(void *)0x4000;
*((char *)0x4000)=0;
memcpy((void *)0x4001,
(void *)0x4000,
(unsigned int)256*192/8-1);
}
int putchar(int ch){
switch(ch){
case 'n':
scrxy.b[0]+=32;
case 'r':
scrxy.b[0]&=OxeO;
break;
default:{
char* s=(char*)
((ch<<3)+OxЗcOO);
unsigned char i=8;
while(i--){
*scrxy.w=*(s++);
scrxy.b[1]++;
}
}
scrxy.w-=0x07ff;
break;
}
if(!scrxy.b[0]){
if((scrxy.b[1]+=8)==0x58)
scrxy.b[1]=0x40;
}
return 1;
}
void main(void){
scr_init(0x07<<3);
puts("Hello World!");
while(1) printf(
"Keyboard scan: 0x%02Xr",
input(OxOOfe));
}
Комментировать код нет смысла, т.к. это
типичная печаталка символов. Нашputchar
подменит собой библиотечный, который испо─
льзуютputs, printf и т.п.
Чтобы каждый раз это не компилировать,
нужно скомпилировать исходник как библио─
теку.
Удалите функцию main() иrename
source in "mylib.c". We will also rename
project directory in"mylib". Remove from
project all files except"mylib.c". Created─
dim the file "make_c.bat" and write it into it
the following line:
..z8Obiniccz80 -v0 -ml -uua -b -q -x -K
-gA -z9 -t4 -T -Llist -Alist
-I"../z80/inc/" mylib.c
And let’s run it, it’s compiled for us
library"mylib.r01".
Create a header file"mylib.h" with
line:
void scr_init(char a);
Now let's open the file"Lnk.xcl" from our
template project and before the line
"-C ../z80/lib/clz80" add the line
"../mylib/mylib". It should look like this:
...
cstartup //link ourstartup
../mylib/mylib //link our own
//library
-C ../z80/lib/clz80 //connect
//IAR library, the '-C' option will allow
//we should link your cstartup.s01
...
You can test our library by creating
new project and compiling the lines:
#include
#include
#include "../mylib/mylib.h"
void main(void){
scr_init(0x07<<3);
puts("Hello World!");
while(1) printf(
"Keyboard scan: 0x%02Xr",input(OxOOfe));
}
* * *
IO functions are usually written in ASMA, Poe─
So we will write the following function in
him. It is advisable to wrap each function
into modules, so that when linkingclung then─
Only modules used:
MODULE mymod1
...
ENDMOD
MODULE mymod2
...
ENDMOD
MODULE mymodЗ
...
END ;last module in the file
;ends this way, not ENDMOD
Let's create the graf.s01 file in the projectmylib,
with code:
MODULE fast_set_pix
PUBLIC fast_set_pix,
fast_set_pix_table
RSEG CODE
fast_set_pix
;http://zxdn.narod.ru/coding/zg1etud2.txt
push bc
push de ld l,c
LD H,HIGH(fast_set_pix_table)
LD D,HIGH(fast_set_pix_table)+2
LD A,(DE)
INC D
OR (HL)
INC H
LD H,(HL)
LD L,A
LD A,(DE)
OR (HL)
LD (HL),A
pop de
pop bc
ret
RSEG ALIGN8
fast_set_pix_table
DEFS 1024
ENDMOD
MODULE fast_set_pix_init
PUBLIC fast_set_pix_init
EXTERN fast_set_pix_table
RSEG CODE
fast_set_pix_init
push bc
push de
LD HL,fast_set_pix_table+256
LD DE,0x4000
GENO
LD (HL),D
DEC H
LD (HL),E
INC H
INC D
LD A,D
AND 7
JR NZ,LABEL
LD A,E
SUB OxEO
LD E,A
SBC A,A
AND -8
ADD A,D
LD D,A
LABEL
LD A,D
SUB 88
JR NZ,$+3
LD D,A
INC L
JR NZ,GENO
INC H
LD A,128
GEN1
LD (HL),E
INC H
LD (HL),A
DEC H
RRCA
JR NC,$+3
INC E
INC L
JR NZ,GEN1
pop de
pop bc
ret
ENDMOD
MODULE little_set_pix
PUBLIC little_set_pix
RSEG CODE
little_set_pix
ld a,c
and 0x07
or 0x40
ld h,a
ld a,c
rrca
rrca
rrca
ld l,a
and %00011000
or h
ld h,a
ld a,l
ld l,e
rrca
rr l
rra
rr l
rra
rr l
rra
rrca
rrca
and %00111000
xor %11111110
ld (l2+1),a;конечно, так нельзя
;делать в либах
l2 set 0,(hl)
ret
END
Here we have two typical drawing tools─
ki, one is faster, the second is shorter. Specify
about parameters when calling functions
in the documentation, section "Assembly language
interface".
* * *
In order not to proliferate libraries, we will co─
take them into one.
In a new file namedmylib.xlib write─
shem lines:
fetch-modules graf.r01 mylib.r01
list-modules mylib.r01
quit
After the line"quit" must
be an empty string, becausexlib swears at
missing EOF.
This is a script for the library builder, it
will combine two libs into one.
Let's add a compile line to"make_c.bat"─
tionsgraf.s01 and collect the lib into one file.
The body file will look like:
..z8Obiniccz80 -v0 -ml -uua -b -q -x -K
-gA -z9 -t4 -T -Llist -Alist
-I"../z80/inc/" mylib.c
..z8Obinaz80 -uu -b -v0 graf.s01
..z8Obinxlib mylib.xlib
Соответственно в заголовочный файл
mylib.h добавьте:
void fast_set_pix_init(void);
void fast_set_pix(unsigned char x,
unsigned char y);
void little_set_pix(unsigned char x,
unsigned char y);
#ifdef FASTPIXEL
#define set_pix fast_set_pix
#define set_pix_init fast_set_pix_init
#else
#define set_pix_init()
#define set_pix little_set_pix
#endif
Теперь запустим батник и проверим биб─
лиотеку:
#include
//#define FASTPIXEL
#include "../mylib/mylib.h"
void main(void){
unsigned char x=0;
scr_init(0x07<<3);
set_pix_init();
do{
set_pix(x,
(sin((double)x/20)*20+95));
}while(++x);
}
На фоне вычислений даблов и синусов
быстрый и маленький пиксели практически
неотличимы по скорости, только по размеру
занимаемой памяти.
* * *
Ну и напоследок освоим прерывания (дан─
ный код не будет работать на машинах,у ко─
торых мусор на шине данных):
#include
unsigned int int_count=0;
interrupt[0] void myint(void){
int_count++;
output8(Oxfe,
((unsigned char)int_count&0x70)>>4);
}
C_task void main(void){
load_I_register(Oxbf);
interrupt_mode_2();
enable_interrupt();
}
For "junk" tires a beautiful solution I
I don't know.
As an option, allocate a memory segment for
interrupt table(INTTABLE) and segment with
"mirror" (Oxbfbf,0x8181, etc.) address─
somJP:
-Z(CODE)RCODE,CODE,CDATAO,CONST,CSTR,
CCSTR=6000-BEBD//memory segments with
//constants and code
-Z(DATA)INTJP=BEBE-BECO //segment with JP for
//interrupts im2
-Z(DATA)DATAO,IDATAO,UDATAO,ECSTR,
ALIGN8|8,INTTABLE|8,CSTACK+200=BEC1-FFFF
//segments of stack, variables, etc.
Let's add myim2.s01 to the projectmylib, to which─
let's placeJP on the interrupt handler─
tions, vector table and initialization:
MODULE my_im2
PUBLIC my_im2_init
RSEG INTJP
DEFS 3
RSEG INTTABLE
DEFS 257
RSEG CODE
my_im2_init
di
ld a,OxcЗ
ld (SFB(INTJP)),a
ld (SFB(INTJP)+1),de
lda,HIGH(SFB(INTTABLE))
ld i,a
inc a
ld hl,SFB(INTTABLE)-1
tloop
inc hl
ld (hl),HIGH(SFB(INTJP))
cp h
jr nz,tloop
im 2
ret
END
Строка компиляции в батнике:
...
..z8Obinaz80 -uu -b -v0 myim2.s01
...
Строка вmylib.xlib:
...
fetch-modules myim2.r01 mylib.r01
...
Соответственно вmylib.hдобавим:
extern void my_im2_init(void *);
И собственно пример использования:
#include
#include "../mylib/mylib.h"
unsigned int int_count=0;
interrupt void myint(void){
int_count++;
output8(Oxfe,
((unsigned char)int_count&0x70)>>4);
}
C_task void main(void){
my_im2_init(myint);
enable_interrupt();
}
* * *
Все примеры вы можете найти в прило─
жении к журналу. Для сборки используется
утилита trdtoolby Shiru с исправлениями
from Trefiand DimkaM, references are attached to it
bottoms.
Share your thoughts about the article