Systems - How to tame IAR C Compiler.

Info Guide #11
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