目次

MiniCを復活

 Z80関係の開発ツール一式の中に、SYSTEM LOAD社の
 「MiniC」の評価版が含まれていたので、これを
 利用して、Z80のファームウエア開発を短縮する
 ことにします。
 (現在ネット検索で出てくるSYSTEM LOAD社ではありません。)

 MiniCは、Cのソースコードをコンパイルし
 Z80ニモニックのアセンブリ言語コードを
 生成するだけなので、アセンブラ、リンカ
 が別途必要になります。

 開発ツールの中には、SYSTEM LOAD社のアセンブラ
 リンカであるXA80があったので、この2つでHEX
 ファイルを生成し、ROMライターでファームウエア
 を作成します。

 コンパイル、アセンブル、リンクと続く処理を
 ひとつのバッチファイルmmc.batにまとめました。

mc %1.c
xa80 %1 %1 %1 %1

 Windowsが動作しているPersonalComputerでは、DOS窓
 を利用して、バッチ処理で、HEXファイルまで生成でき
 ます。

 MiniCの仕様を読むと、スタートアップルーチンは
 ヘッダファイルに記述することと、I/O関係は自作
 して対応すると分かりました。

 I/O関係は、入力関数をinportb、出力関数をoutportb
 とし、TurboCの仕様に合わせて、定義します。

void outportb(int port,int data)
{
#asm
  push  af
  push  bc
  push  hl
    ld    hl,8
    add   hl,sp
    ld    a,(hl)
    ld    hl,10
    add   hl,sp
    ld    c,(hl)
    out   (c),a
  pop   hl
  pop   bc
  pop  af
#endasm
}

int inportb(int port)
{
#asm
  push  af
  push  bc
    ld    hl,6
    add   hl,sp
    ld    c,(hl)
    in    a,(c)
    ld    l,a
    ld    h,0
  pop   bc
  pop  af
#endasm
}

 Cは、スタックを利用し関数と関数の
 間で値を渡します。

 スタックに値を入れる方式は、パラメータ
 を左から順に、データサイズ分だけ、積み
 上げていきます。レジスタペアHL、スタック
 ポインタSPの演算で、データの在りかを求め
 転送します。

 関数からの戻り値は、HLレジスタペアに入れる
 ので、in命令でデータを入力したなら、2つの
 レジスタH、Lに転送しておきます。

 ヘッダファイルdos.hに、この内容をいれるため
 次のように記述します。

/* dos.h */

void outportb(int address,int data)
{
#asm
  push  af
  push  bc
  push  hl
  ;
  ld    hl,8
  add   hl,sp
  ld    a,(hl)
  ;
  ld    hl,10
  add   hl,sp
  ;
  ld    c,(hl)
  out   (c),a
  ;
  pop   hl
  pop   bc
  pop   af
#endasm
}

int inportb(int address)
{
#asm
  push  af
  push  bc
  ;
  ld    hl,6
  add   hl,sp
  ;
  ld    c,(hl)
  in    a,(c)
  ;
  ld    l,a
  ld    h,0
  ;
  pop   bc
  pop   af
#endasm
}

 PIOAを入力、PIOBを出力にし、スイッチとLEDを
 接続して、入力の状態を出力に反映する処理を
 記述してみます。

#include "dos.h"
#include "aki80c.h"

#define OFF 0
#define ON  OFF+1

#define MASKFF 0x00ff

/* function prototype */
void init();

void main()
{
  int tmp ;
  /* initialize */
  init();
  /* endless loop */
  while ( ON ) {
    /* get data */
    tmp = inportb(PAD);
    /* invert */
    tmp ^= MASKFF ;
    /* impress */
    outportb(PBD,tmp);
  }
}

void init()
{
  /* PIOA (mode 1) input no interrupt */
  outportb(PAC,0x4f);
  outportb(PAC,0x03);
  /* PIOB all zero */
  outportb(PBD,0x00);
  /* PIOB (mode 0) output no interrupt */
  outportb(PBC,0x0f);
  outportb(PBC,0x03);
}

 利用しているヘッダファイルのうち、aki80c.hは
 CTC、PIO、SIOのI/Oアドレスを定義しています。

/* counter / timer */
#define CTC0    0x10
#define CTC1    CTC0+1
#define CTC2    CTC0+2
#define CTC3    CTC0+3

/* serial I/O */
#define CHAB    0x18
#define CHACS   CHAB+1
#define CHBB    0x1A
#define CHBCS   CHBB+1

/* parallel I/O */
#define PAD     0x1C
#define PAC     PAD+1
#define PBD     PAD+2
#define PBC     PAD+3

 コンパイルし、アセンブリ言語生成させると
 以下のようになっていました。

;System Load Compiler [mini-'C' V1.0] for Z80/KC80 1995.3
;By System Load CO.,LTD. & K.Kino Copyright (C) All rights reserved
;
 include	"startup.h"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       [SLC] liblary file -- [ OLIBZ.LIB ]          ;
;        File make time: Tue Feb 14 1995             ;
;                            ... by System Load.,ltd ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BDOS              EQU	00005h
;
	JP    __CPM                   ;
	JP    MC_GCHAR                 ;
	JP    MC_SXT                   ;
	JP    MC_CDR                   ;
	JP    MC_GINT                  ;
	JP    MC_PINT                  ;
	JP    MC_OR                    ;
	JP    MC_OROR                  ;
	JP    MC_XOR                   ;
	JP    MC_AND                   ;
	JP    MC_ANDAND                ;
	JP    MC_EQ                    ;
	JP    MC_NE                    ;
	JP    MC_GT                    ;
	JP    MC_LE                    ;
	JP    MC_GE                    ;
	JP    MC_LT                    ;
	JP    MC_CMP                   ;
	JP    MC_LNEG                  ;
	JP    MC_UGE                   ;
	JP    MC_ULT                   ;
	JP    MC_UGT                   ;
	JP    MC_ULE                   ;
	JP    MC_UCMP                  ;
	JP    CUCMP1                  ;
	JP    MC_ASR                   ;
	JP    MC_ASL                   ;
	JP    MC_ASL4                  ;
	JP    MC_SUB                   ;
	JP    MC_NEG                   ;
	JP    MC_COM                   ;
	JP    MC_MULT                  ;
	JP    MC_MLT1                  ;
	JP    CMLT2                   ;
	JP    MC_DIV                   ;
	JP    MC_DIV1                  ;
	JP    MC_DIV2                  ;
	JP    MC_DIV3                  ;
	JP    MC_DENEG                 ;
	JP    MC_BCNEG                 ;
	JP    MC_RDEL                  ;
	JP    MC_PBCDE                 ;
	JP    DEBUGSP                 ;
__CPM:
	POP   HL                      ;
	POP   DE                      ;
	POP   BC                      ;
	PUSH  BC                      ;
	PUSH  DE                      ;
	PUSH  HL                      ;
	CALL  BDOS                    ;
	JR    MC_SXT                   ;
MC_GCHAR:
	LD    A,(HL)                  ;
MC_SXT:
	LD    L,A                     ;
	RLCA                          ;
	SBC   A,A                     ;
	LD    H,A                     ;
	RET                           ;
MC_CDR:
	INC   HL                      ;
	INC   HL                      ;
MC_GINT:
	LD    A,(HL)                  ;
	INC   HL                      ;
	LD    H,(HL)                  ;
	LD    L,A                     ;
	RET                           ;
MC_PINT:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    A,L                     ;
	LD    (DE),A                  ;
	INC   DE                      ;
	LD    A,H                     ;
	LD    (DE),A                  ;
	RET                           ;

MC_OROR:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    A,L                     ;
	OR    H                       ;
	JP    NZ,__OR2R               ;
	LD    A,E                     ;
	OR    D                       ;
	JP    NZ,__OR2R               ;
	LD    HL,0                    ;
	RET                           ;
__OR2R:                               ;
	LD    HL,1                    ;
        RET
MC_OR:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    A,L                     ;
	OR    E                       ;
	LD    L,A                     ;
	LD    A,H                     ;
	OR    D                       ;
	LD    H,A                     ;
	RET                           ;
MC_XOR:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    A,L                     ;
	XOR   E                       ;
	LD    L,A                     ;
	LD    A,H                     ;
	XOR   D                       ;
	LD    H,A                     ;
	RET                           ;
MC_ANDAND:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    A,L                     ;
	OR    H                       ;
	JP    Z,__AND2R               ;
	LD    A,E                     ;
	OR    D                       ;
	JP    Z,__AND2R               ;
	LD    HL,1                    ;
	RET
__AND2R:                              ;
	LD    HL,0                    ;
	RET	                      ;
MC_AND:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    A,L                     ;
	AND   E                       ;
	LD    L,A                     ;
	LD    A,H                     ;
	AND   D                       ;
	LD    H,A                     ;
	RET                           ;
MC_EQ:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_CMP                   ;
	RET   Z                       ;
	DEC   HL                      ;
	RET                           ;
MC_NE:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_CMP                   ;
	RET   NZ                      ;
	DEC   HL                      ;
	RET                           ;
MC_GT:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	EX    DE,HL                   ;
	CALL  MC_CMP                   ;
	RET   C                       ;
	DEC   HL                      ;
	RET                           ;
MC_LE:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_CMP                   ;
	RET   Z                       ;
	RET   C                       ;
	DEC   HL                      ;
	RET                           ;
MC_GE:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_CMP                   ;
	RET   NC                      ;
	DEC   HL                      ;
	RET                           ;
MC_LT:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_CMP                   ;
	RET   C                       ;
	DEC   HL                      ;
	RET                           ;
MC_CMP:
	LD    A,E                     ;
	SUB   L                       ;
	LD    E,A                     ;
	LD    A,D                     ;
	SBC   A,H                     ;
	LD    HL,00001H               ;
	JP    M,MC_CMP1                ;
	OR    E                       ;
	RET                           ;
MC_CMP1:
	OR    E                       ;
	SCF                           ;
	RET                           ;
MC_LNEG:
	LD  A,H
	OR  L
	LD  HL,0
	JR  Z,MC_LNEG1
	RET
MC_LNEG1:
	INC L
	RET
MC_UGE:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_UCMP                  ;
	RET   NC                      ;
	DEC   HL                      ;
	RET                           ;
MC_ULT:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_UCMP                  ;
	RET   C                       ;
	DEC   HL                      ;
	RET                           ;
MC_UGT:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	EX    DE,HL                   ;
	CALL  MC_UCMP                  ;
	RET   C                       ;
	DEC   HL                      ;
	RET                           ;
MC_ULE:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	CALL  MC_UCMP                  ;
	RET   Z                       ;
	RET   C                       ;
	DEC   HL                      ;
	RET                           ;
MC_UCMP:
	LD    A,D                     ;
	CP    H                       ;
	JR    NZ,CUCMP1               ;
	LD    A,E                     ;
	CP    L                       ;
CUCMP1:
	LD    HL,00001H               ;
	RET                           ;
MC_ASR:
	EX    DE,HL                   ;
	DEC   E                       ;
	RET   M                       ;
	LD    A,H                     ;
	RLA                           ;
	LD    A,H                     ;
	RRA                           ;
	LD    H,A                     ;
	LD    A,L                     ;
	RRA                           ;
	LD    L,A                     ;
	JR    MC_ASR+1                 ;
MC_ASL:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	EX    DE,HL                   ;
MC_ASL4:
	DEC   E                       ;
	RET   M                       ;
	ADD   HL,HL                   ;
	JR    MC_ASL4                  ;
MC_SUB:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    A,E                     ;
	SUB   L                       ;
	LD    L,A                     ;
	LD    A,D                     ;
	SBC   A,H                     ;
	LD    H,A                     ;
	RET                           ;
MC_NEG:
	CALL  MC_COM                   ;
	INC   HL                      ;
	RET                           ;
MC_COM:
	LD    A,H                     ;
	CPL                           ;
	LD    H,A                     ;
	LD    A,L                     ;
	CPL                           ;
	LD    L,A                     ;
	RET                           ;
MC_MULT:
	POP   BC                      ;
	POP   DE                      ;
	PUSH  BC                      ;
	LD    B,H                     ;
	LD    C,L                     ;
	LD    HL,00000H               ;
MC_MLT1:
	LD    A,C                     ;
	RRCA                          ;
	JR    NC,CMLT2                ;
	ADD   HL,DE                   ;
CMLT2:
	XOR   A                       ;
	LD    A,B                     ;
	RRA                           ;
	LD    B,A                     ;
	LD    A,C                     ;
	RRA                           ;
	LD    C,A                     ;
	OR    B                       ;
	RET   Z                       ;
	XOR   A                       ;
	LD    A,E                     ;
	RLA                           ;
	LD    E,A                     ;
	LD    A,D                     ;
	RLA                           ;
	LD    D,A                     ;
	OR    E                       ;
	RET   Z                       ;
	JR    MC_MLT1                  ;
MC_DIV:
	LD    B,H                     ;
	LD    C,L                     ;
	LD    A,D                     ;
	XOR   B                       ;
	PUSH  AF                      ;
	LD    A,D                     ;
	OR    A                       ;
	CALL  M,MC_DENEG               ;
	LD    A,B                     ;
	OR    A                       ;
	CALL  M,MC_BCNEG               ;
	LD    A,010H                  ;
	PUSH  AF                      ;
	EX    DE,HL                   ;
	LD    DE,00000H               ;
MC_DIV1:
	ADD   HL,HL                   ;
	CALL  MC_RDEL                  ;
	JR    Z,MC_DIV2                ;
	CALL  MC_PBCDE                 ;
	JP    M,MC_DIV2                ;
	LD    A,L                     ;
	OR    001H                    ;
	LD    L,A                     ;
	LD    A,E                     ;
	SUB   C                       ;
	LD    E,A                     ;
	LD    A,D                     ;
	SBC   A,B                     ;
	LD    D,A                     ;
MC_DIV2:
	POP   AF                      ;
	DEC   A                       ;
	JR    Z,MC_DIV3                ;
	PUSH  AF                      ;
	JR    MC_DIV1                  ;
MC_DIV3:
	POP   AF                      ;
	RET   P                       ;
	CALL  MC_DENEG                 ;
	EX    DE,HL                   ;
	CALL  MC_DENEG                 ;
	EX    DE,HL                   ;
	RET                           ;
MC_DENEG:
	LD    A,D                     ;
	CPL                           ;
	LD    D,A                     ;
	LD    A,E                     ;
	CPL                           ;
	LD    E,A                     ;
	INC   DE                      ;
	RET                           ;
MC_BCNEG:
	LD    A,B                     ;
	CPL                           ;
	LD    B,A                     ;
	LD    A,C                     ;
	CPL                           ;
	LD    C,A                     ;
	INC   BC                      ;
	RET                           ;
MC_RDEL:
	LD    A,E                     ;
	RLA                           ;
	LD    E,A                     ;
	LD    A,D                     ;
	RLA                           ;
	LD    D,A                     ;
	OR    E                       ;
	RET                           ;
MC_PBCDE:
	LD    A,E                     ;
	SUB   C                       ;
	LD    A,D                     ;
	SBC   A,B                     ;
	RET                           ;
MC_SWITCH:
	EX	DE,HL
	POP	HL
SWLOOP:
	LD	C,(HL)
	INC	HL
	LD	B,(HL)
	INC	HL
	LD	A,B
	OR	C
	JR	Z,SWEND
	LD	A,(HL)
	INC	HL
	CP	E
	LD	A,(HL)
	INC	HL
	JR	NZ,SWLOOP
	CP	D
	JR	NZ,SWLOOP
	LD	H,B
	LD	L,C
SWEND:
	JP	(HL)
DEBUGSP:
	LD	HL,2
DEBUGSP2:
	ADD	HL,SP
	PUSH	HL
	POP	IY
	RET
;;;;;;;;; END IOLIBZ.LIB ;;;;;;;;;;;;;;
__outportb:
;#asm

	push	af
	push	bc
	push	hl
	;
	ld	hl,8
	add	hl,sp
	ld	a,(hl)
	;
	ld	hl,10
	add	hl,sp
	;
	ld	c,(hl)
	out	(c),a
	;
	pop	hl
	pop	bc
	pop	af

;#endasm
	RET
__inportb:
;#asm

	push	af
	push	bc
	;
	ld	hl,6
	add	hl,sp
	;
	ld	c,(hl)
	in	a,(c)
	;
	ld	l,a
	ld	h,0
	;
	pop	bc
	pop	af

;#endasm
	RET
__main:
	PUSH BC
	CALL __init
mc_4:
	LD HL,00H
	PUSH HL
	LD HL,01H
	POP DE
	ADD HL,DE
	LD A,H
	OR L
	JP Z,mc_5
	LD HL,00H
	ADD HL,SP
	PUSH HL
	LD HL,1CH
	PUSH HL
	CALL __inportb
	POP BC
	CALL mc_pint
	LD HL,00H
	ADD HL,SP
	PUSH HL
	CALL mc_gint
	PUSH HL
	LD HL,0FFH
	CALL mc_xor
	CALL mc_pint
	LD HL,1CH
	PUSH HL
	LD HL,02H
	POP DE
	ADD HL,DE
	PUSH HL
	LD HL,02H
	ADD HL,SP
	CALL mc_gint
	PUSH HL
	CALL __outportb
	POP BC
	POP BC
	JP mc_4
mc_5:
	POP BC
	RET
__init:
	LD HL,1CH
	PUSH HL
	LD HL,01H
	POP DE
	ADD HL,DE
	PUSH HL
	LD HL,4FH
	PUSH HL
	CALL __outportb
	POP BC
	POP BC
	LD HL,1CH
	PUSH HL
	LD HL,01H
	POP DE
	ADD HL,DE
	PUSH HL
	LD HL,03H
	PUSH HL
	CALL __outportb
	POP BC
	POP BC
	LD HL,1CH
	PUSH HL
	LD HL,02H
	POP DE
	ADD HL,DE
	PUSH HL
	LD HL,00H
	PUSH HL
	CALL __outportb
	POP BC
	POP BC
	LD HL,1CH
	PUSH HL
	LD HL,03H
	POP DE
	ADD HL,DE
	PUSH HL
	LD HL,0FH
	PUSH HL
	CALL __outportb
	POP BC
	POP BC
	LD HL,1CH
	PUSH HL
	LD HL,03H
	POP DE
	ADD HL,DE
	PUSH HL
	LD HL,03H
	PUSH HL
	CALL __outportb
	POP BC
	POP BC
	RET

	END
;; --- End of Compilation ---

 ざっと眺めて、評価版のMiniCコンパイラでは
 どういうことをやっているのか理解します。

 ヘッダファイルstartup.hを利用し、ROM、RAMの
 割当てアドレスを確認しています。

 ヘッダファイルstartup.hは、次のように定義
 されています。

CPM	EQU	0

	if (CPM EQ 0)
;RAM_TOP	EQU	0fe00h
RAM_TOP	EQU	8000h
;
	ORG	0h
	DI
	LD	SP,0
	CALL	__main
__st_loop__:
	DI
	nop
	JR	__st_loop__
	endif

	if ( CPM EQ 1)

RAM_TOP	EQU	8000H
;
	ORG	100h
	jp	start
start:	
	DI
	LD	SP,7000h
	CALL	__main
__st_loop__:
	jp	0
	ENDIF

 8080やZ80用のOSとして、CP/M80の存在を忘れることが
 できないので、MiniCでもCP/M80が動いている環境で
 走るプログラムか、それ以外かを判断しています。

 CP/M80では、プログラムは必ず100hから始まるので
 00h〜FFhをスキップするかどうかを指定できます。

 他に、RAMとスタックの存在エリアを利用できる
 ようにしてあります。

 MiniCでは、内部ラベルの前と後にアンダースコアを
 2つ付加するのが、お約束のようです。

 Cのソースをアセンブリ言語に展開するために、必要な
 各種サブルーチンは、MC_で始まるラベルを使います。

 機能拡張をする場合、ヘッダファイルを定義し、その中に
 必要な関数を記述するスタイルを採用しています。

 生成されたアセンブリ言語から、理解できることを
 挙げてみます。

 Cはパラメータを値渡しし、参照渡しではないので
 スタック上に関数の引数を、どういう方式で渡す
 のか、そのカラクリがわかるアセンブリ言語ソース
 コードを生成しています。

 MiniCを使い、ハードウエアを扱うファーム
 ウエアを作成してみます。


目次

inserted by FC2 system