某所の資料
テクニカルハンドブック
に書かれているUTILS機能を持つアセンブラをマクロを用いて書いてみる。このマクロとアセンブラだけで
DOSコマンド上で動くコマンドを作成できる。Cのライブラリを作成するときにも便利。Cとの違いに注意。
util.asm
;マクロを用いたutilsアセンブラルーチン群。
;
.area _ASMCODE
;DOSファンクションコールを用いて一文字出力する
;引数:chcode
.macro putchar chcode
push af
push bc
push de
push hl
ld e,chcode ;char code
ld c,#0x02 ;function #02
call 0x0005 ;function call
pop hl
pop de
pop bc
pop af
.endm
;数値を2桁16進に変換してDOS画面表示する
;引数:num
.macro puthex num,?puthx1,?puthx2
ld a,num
push af ;一桁目をプッシュ
rr a
rr a
rr a
rr a
push af ;二桁目をプッシュ
and #0x0f ;一桁目の処理
cp #10
jr c,puthx1
add a,#'A-10-'0
puthx1:
add a,#'0
putchar a
pop af ;二桁目の処理
pop af
;push af
and #0xf ;数値を16進範囲でマスク
cp #10 ;10で比較
jr c,puthx2 ;もし10以下ならばputhx2にジャンプ
add a,#'A-10-'0 ;16進英字のコード処理
puthx2:
add a,#'0 ;数値文字コードの処理
putchar a
;pop af
.endm
;2桁の16進文字列から整数へ変換
;引数:address
;HL=戻り値
.macro hex2int address
ld hl,#0
ld de,#address
push af
push de
call sub
pop de
pop af
sub:
ld a,(de) ;文字列ポインタから値を読み
inc de ;ポインタ加算
;sub #48
sub #'0 ;文字を数値に変換
ret c ;文字列終端検出時に戻る
cp #10
jr c,jump1 ;HEX数字範囲検出
;sub #17
sub #'A-'0
ret c
cp #6 ;HEX文字数字範囲検出
ret nc
add A,#10 ;hex2intの整数加算処理
jump1:
add hl,hl ;上位桁へのシフト
add hl,hl
add hl,hl
add hl,hl
or l
ld l,a
jr sub
.endm
;DOSコマンド上の引数要素(ARGS)を文字列バッファへ取り出す
;引数:index=argsの要素番号, buffer=コピー先文字列のアドレス
;DE=文字列バッファのアドレス
.macro getarg index,buffer,?skiparg,?skip1,?skip2,?copyarg,?copy1,?noarg,?exit,?termchk
push af
push bc
push hl
ld c,index ;ARGSのパラメータ要素指定
ld hl,#0x0080 ;ゼロページ領域のポインタ指定cpmのargsは0x0080から始まるが先頭の1byteに文字数の長さ
ld b,(hl) ;2byte目には空白を示す0x20が入っているため実質的に文字列は0x0082から始まる
inc hl
inc b ;ARG文字数=Bレジスタ
skiparg: ;コマンド引数なしの時の判定処理
dec b
jr z,noarg ;
skip1:
ld a,(hl) ;ARGの先頭の一つの文字列の検出
inc hl
call termchk ;文字列の終端確認
jr nz,skip1
skip2:
ld a,(hl) ;ARGの後続文字列の検出
inc hl
call termchk
jr z,skip2 ;文字列の終端確認
dec hl
dec c ;ARGS要素の指定要素値に達したか判定
jr nz,skiparg
copyarg:
ld de,buffer ;文字列コピー先バッファアドレスの指定
copy1:
ld a,(hl) ;ARGSから文字列をバッファへ複写処理
ld (de),a
inc hl
inc de
call termchk ;文字列終端検出
jr nz,copy1
dec de ;文字列最後にCPMの終端記号を追加
ld a,#'$
ld (de),a
ld de,buffer ;バッファアドレスを返して戻る
jr exit ;終了
termchk:
cp #0x09 ;文字列終端チェックサブルーチン
ret z
cp #0x0d
ret z
cp #0x20 ;' '
ret z
cp #0x3b ;';'
ret z
ret
noarg:
ld de,buffer ;引数なしの場合は終端記号のみで戻る
ld a,#'$
ld (de),a
exit:
pop hl
pop bc
pop af
;ret ;元のコードはサブルーチンなのでマクロではコメントアウト
.endm
;指定アドレスのメモリ内容を16進データとしてDOS画面に一行ダンプする
;引数:address
.macro dump8b address,?dumpln,?dump1,?dump2,?dump3,?dump4
dumpln:
ld hl,address
push hl ;アドレスを保存
ld b,#16 ;桁表示用のカウンタ設定(オリジナルは8桁)
dump1:
ld a,(hl) ;16進ダンプ開始
inc hl
;call puthex
puthex a ;マクロ内部からマクロを呼ぶ
ld a,#0x20 ;' '
;call putchar
putchar a
djnz dump1 ;Bカウンタ以内で繰り返し
pop hl ;再度アドレスを取り出す
ld b,#16 ;桁カウンタ設定(オリジナルは8桁)
dump2:
ld a,(hl) ;以下ASCII文字表示
inc hl
cp #0x20
jr c,dump3 ;制御コードの場合ジャンプ
cp #0x7f
jr nz,dump4 ;ASCII,カナ文字の場合ジャンプ
dump3:
ld a,#0x2e ;'.'
dump4:
;call putchar
putchar a
djnz dump2 ;Bカウンタ以内で8文字処理の繰り返し
ld a,#0 ;空白と改行
;call putchar
putchar a
ld a,#0x0a
;call putchar
putchar a
;ret
.endm
sdasアセンブラのutilマクロを利用したサンプル例。マクロアセンブラはこのようにして使う。マクロの引数は
レジスタや即値なので高級言語やCと引数のとりかたが若干違う。
マクロはincludeしているが短い場合はソース中の先頭に貼ってもよい。
.area _ASMCDOE
.include /util.asm/
main:
putchar a ;レジスタAの文字コード表示
putchar #'B ;即値で文字Bを表示
putchar #'\n ;改行
puthex c ;レジスタCの内容を2桁16進画面表示
hex2int str1 ;str1の文字列の2桁16進を整数にしてHLへ
getarg #1,buff ;ARGSの1番目の文字列をbuffへコピー
dump8b addr ;addrのメモリ内容をダンプ表示
ret ;DOSなので最後に必ずRET
アセンブル例
>sdasz80 -o util.rel util.asm
>sdld -b _ASMCODE=0x100 -i util.ihx util.rel
>makebin -s 8192 util.ihx > util.bin
>cscript bin2com.vbs util.bin (先頭255バイト削除コマンド)
最終更新:2017年05月05日 01:54