SSブログ
English Version

レトロマイコン86ボードの構想(その5)HEXファイルローダーの製作 [8086]

 前回の記事で書いたように8088互換のV20とPICとのインターフェース部の動作確認が出来たので、今回はインテルヘキサファイルのローダーの製作について書いてみます。

 インテルヘキサファイルのフォーマットに関してはネット上に色々あります(例えばIntel HEX)ので情報は豊富です。
 レコードタイプは
  • 00 : data record(CP/M-86独自の81H~84Hも含む)
  • 01 : end of file
  • 02 : segment(CP/M-86独自の85H~88Hも含む)
  • 03 : start address

に対応しました。メモリへのダウンロードが目的なのでタイプ3については空読みするようにしています。

★2019/08/12 追記
 CP/M-86のASM86独自のレコードタイプ(81H~88H)に下記のソースも含めて対応しました。

 HexLoader自体はアセンブリ言語で書き、nasmを使ってアセンブルしています。
 アセンブルは下のようなバッチファイルで行い、アセンブルで生成されたたbinファイルを自作のbin2state(バイナリからpicleのステートメントへ変換するツール)で変換し、picleのソースに埋め込んでいます。

nasm -l %1.lst -o %1.bin %1.asm
bin2state <%1.bin >%1.txt


 ソースは以下のとおりです。

HexLoaderのアセンブリソース
1 ;***************************** 2 ; Pic24V20 HexLoader 3 ; Ver0.02 supports ASM86 HexFile 4 ; Ver0.03 make compact a little 5 ; 2020/10/26 by skyriver 6 ;***************************** 7 8 9 CPU 8086 10 11 %define JMPS JMP SHORT 12 13 SEC_SZ EQU 512 ; sector size 14 WRK_START EQU 01e0H ; work start adr 15 16 FC_EXIT EQU 0 ; EXIT CP/M 17 FC_CONST EQU 1 ; CONST 18 FC_CONIN EQU 2 ; CONIN 19 FC_CONOUT EQU 3 ; CONOUT 20 FC_READ EQU 4 ; READ SD Card 21 FC_WRITE EQU 5 ; WRITE SD Card 22 FC_PUNCH EQU 6 ; PUNCH 23 FC_READER EQU 7 ; READER 24 25 SdBuf EQU WRK_START 26 PicWrk EQU SdBuf + SEC_SZ 27 28 STRUC tPic ; Pic I/F work area 29 00000000 .FuncNo RESB 1 ; function No 30 00000001 .RetVal RESB 1 ; return value 31 00000002 .CoData RESB 1 ; conout data 32 00000003 .SelDk RESB 1 ; selected disk 33 00000004 .Track RESB 2 ; track No 34 00000006 .DmaAdr RESB 2 ; DMA adr 35 00000008 .Sector RESB 1 ; sector No. 36 ENDSTRUC 37 38 ; *** memory assign *** 39 40 ; ffc00 ffc0:0000 code area 41 ; 42 ; ffde0 ffc0:01e0 SD buf 512byte 43 ; fffe0 ffc0:03e0 work 16byte 44 ; ffff0 ffff:0000 reset jmp 45 46 47 ; SEGMENT CODE ABSOLUTE=0xffc0 48 SEGMENT CODE 49 50 ORG 0 51 52 00000000 8CC8 START: MOV AX,CS 53 00000002 8ED8 MOV DS,AX 54 00000004 8ED0 MOV SS,AX 55 00000006 BCE001 MOV SP,WRK_START 56 00000009 31C0 XOR AX,AX 57 0000000B 8EC0 MOV ES,AX 58 59 0000000D BA0080 MOV DX,8000H 60 61 00000010 BB[2100] MOV BX,MESG 62 00000013 E83D00 CALL PUTS 63 00000016 E86D00 CALL LOAD 64 00000019 E82700 CALL CONIN ; read CR 65 0000001C E83000 CALL EXIT 66 0000001F EBFE JMPS $ 67 68 69 00000021 4865784C6F61646572- MESG: DB 'HexLoader Start',13,10,0 70 0000002A 2053746172740D0A00 71 00000033 20657272210D0A00 ERRMSG: DB ' err!',13,10,0 72 73 ; go pic nterface 74 ; AL <- Function No 75 ; AL -> return value 76 0000003B A2E003 PICSRV: MOV [PicWrk + tPic.FuncNo],AL 77 0000003E EE OUT DX,AL 78 0000003F A0E103 MOV AL,[PicWrk + tPic.RetVal] 79 00000042 C3 RET 80 81 82 ; get console status 83 ; AL -> 0FFH:data exist, 00H:no data 84 ;CONST: MOV AL,FC_CONST 85 ; JMPS PICSRV 86 87 ; input from console 88 ; AL -> data 89 90 00000043 B002 CONIN: MOV AL,FC_CONIN 91 00000045 EBF4 JMPS PICSRV 92 93 94 ; output to console 95 ; CL <- data 96 97 00000047 B003 CONOUT: MOV AL,FC_CONOUT 98 00000049 880EE203 MOV BYTE [PicWrk + tPic.CoData],CL 99 0000004D EBEC JMPS PICSRV 100 101 102 ; return to PIC world 103 104 0000004F B000 EXIT: MOV AL,FC_EXIT 105 00000051 EBE8 JMPS PICSRV 106 107 108 ; put string 109 ; BX <- string adr 110 111 00000053 8A0F PUTS: MOV CL,[BX] 112 00000055 43 INC BX 113 00000056 08C9 OR CL,CL 114 00000058 7405 JZ PUTSE 115 0000005A E8EAFF CALL CONOUT 116 0000005D EBF4 JMPS PUTS 117 0000005F C3 PUTSE: RET 118 119 120 ; read hex nible 121 ; AL -> data 122 00000060 E8E0FF RDNBL: CALL CONIN 123 00000063 2C30 SUB AL,'0' 124 00000065 3C0A CMP AL,10 125 00000067 7202 JC RDNBLE 126 00000069 04F9 ADD AL,10 + '0' - 'A' 127 0000006B C3 RDNBLE: RET 128 129 130 ; read byte data 131 ; AL -> byte data 132 133 0000006C E8F1FF RDBYTE: CALL RDNBL 134 0000006F D0E0 SHL AL,1 135 00000071 D0E0 SHL AL,1 136 00000073 D0E0 SHL AL,1 137 00000075 D0E0 SHL AL,1 138 00000077 88C7 MOV BH,AL 139 00000079 E8E4FF CALL RDNBL 140 0000007C 08F8 OR AL,BH 141 0000007E C3 RET 142 143 144 ; read hex word 145 ; AX -> data 146 0000007F E8EAFF RDWORD: CALL RDBYTE 147 00000082 88C4 MOV AH,AL 148 00000084 EBE6 JMPS RDBYTE 149 150 151 ; load hex file 152 153 00000086 E8BAFF LOAD: CALL CONIN 154 00000089 3C3A CMP AL,':' 155 0000008B 75F9 JNZ LOAD 156 157 0000008D E8DCFF CALL RDBYTE ; get byte count 158 00000090 88C3 MOV BL,AL 159 00000092 E8EAFF CALL RDWORD ; get address 160 00000095 89C7 MOV DI,AX 161 00000097 E8D2FF CALL RDBYTE ; get record type 162 163 0000009A 88C4 MOV AH,AL 164 0000009C 88C1 MOV CL,AL 165 0000009E 2480 AND AL,080H 166 000000A0 B0E0 MOV AL,080H + 'a' - 1 167 000000A2 7502 JNZ LOAD03 168 169 000000A4 B030 LOAD02: MOV AL,'0' 170 000000A6 00C1 LOAD03: ADD CL,AL 171 000000A8 E89CFF CALL CONOUT 172 000000AB 88E0 MOV AL,AH 173 174 000000AD 3C02 CMP AL,02H ; segment data 175 000000AF 7507 JNZ NXCK1 176 177 000000B1 E8CBFF TYP02: CALL RDWORD ; ** segment 178 000000B4 8EC0 MOV ES,AX 179 000000B6 EBCE JMPS LOAD 180 181 000000B8 3C85 NXCK1: CMP AL,085H 182 000000BA 73F5 JNC TYP02 183 184 000000BC 08C0 OR AL,AL ; data record 185 000000BE 750D JNZ NXCK2 186 187 000000C0 88D9 TYP00: MOV CL,BL 188 000000C2 E8A7FF TYP00A: CALL RDBYTE ; ** DATA 189 000000C5 268805 MOV [ES:DI],AL 190 000000C8 47 INC DI 191 000000C9 E2F7 LOOP TYP00A 192 000000CB EBB9 JMPS LOAD 193 194 000000CD 3C81 NXCK2: CMP AL,081H 195 000000CF 73EF JNC TYP00 196 197 000000D1 3C01 CMP AL,01H ; end of data 198 000000D3 7504 JNZ NXCK3 199 200 000000D5 E894FF CALL RDBYTE ; ** EOD 201 000000D8 C3 RET 202 203 000000D9 3C03 NXCK3: CMP AL,03H ; start address 204 000000DB 74A9 JZ LOAD ; not implement 205 206 000000DD BB[3300] MOV BX,ERRMSG 207 000000E0 E870FF CALL PUTS 208 000000E3 C3 RET
★2020/10/26 最新版に変更

 テスト用のヘキサファイルは手で作るよりは一般的なツールで作った方がいいのでLASMを使いました。LASMはソースが100行以下であれば無料で使えます。

テスト用データ作成のためのLASM用ソース
;++++++++++++++++++++++++++++++++ ; Test data for HexLoader ; for lasm assembler ; ; asm & link command ; lasm32 testdata.asm ; lil32 -hex -sdseg=0030 testdata.obj ; ; 2019/08/10 by skyriver ;++++++++++++++++++++++++++++++++ dseg segment byte data: db '0123456789ABCDEF' dseg ends end


 上のソース内にアセンブルとリンクの方法をコメントで書いていますが、dsegの値を0030Hにしてリンクして生成されたヘキサファイルの内容はこんな感じです。

:020000020030CC
:10000000303132333435363738394142434445464E
:00000001FF


 下記がHexLoaderのpicleのリスト表示後、実行し、上のヘキサファイルをTeraTermにコピペした際のログです。
 スタートメッセージを表示後、「201」と表示されていますが、これはV20側の処理で受信したヘキサファイルのレコードタイプを出力しているものです(81H~88Hは'a'~'h'で表示)。

HexLoader実行時のログサンプル
:l 1:# Pic24V20 HexLoader v0.03 2020/09/02 2:# by skyriver 3: 4:use LibCpm; 5:use LibSpi; 6: 7:var ProgWrk,_WrkVal,_PicDma,WrkTrk; 8: 9: 10:proc m( data ) { 11: MemWr( data ); 12:} 13: 14: 15:proc PicSrv() { 16: var i,fno,rval; 17: 18: while (1) { 19: while (LATC[-1]&$40) {} # wait ready off 20: CMCON[0] = CMCON[0]&$feff; # CMP1 off 21: PmpOn(); 22: PmpSetAdr(ProgWrk); 23: fno = MemRd(); # dummy 24: for (i=0;i<3;i=i+1) { 25: _WrkVal[i] = MemRd(); 26: } 27: fno = _WrkVal[0]; # function No 28: 29: if (fno=1) { # CONST 30: if (InpChk_()) { 31: rval = $ff; 32: } else { 33: rval = 0; 34: } 35: } 36: else if (fno=2) { # CONIN 37: rval = InpChar_(); 38: } 39: else if (fno=3) { # CONOUT 40: PrnChar_( _WrkVal[2] ); 41: } 42: else if (fno=0) { 43: break; 44: } else { 45: PrnStr_("\nFunc err"); 46: } 47: PmpSetAdr(ProgWrk+1); 48: MemWr(rval); 49: 50: PmpOff(); 51: BusRelease(); 52: CMCON[0] = CMCON[0]|$0100; # CMP1 on 53: } 54:} 55: 56: 57:proc main() { 58: var adr; 59: init(); 60: initPmp(); 61:# initSpi(); 62:# initSd(); 63: 64: ProgWrk = $ffe0; # work addr(fffe0) 65: _PicDma = $fde0; 66: _WrkVal = Alloc( 5 ); 67: WrkTrk = Alloc( 2 ); 68: 69: LATA[0]=LATA[0]|1; # on reset:a0 70: BusReq(); 71: LATA[0]=LATA[0]&$fffe; # off reset:a0 72: 73: PmpOn(); 74: 75: PmpSetAdr($07f0); 76: m($ea);m($00);m($00);m($c0);m($ff); 77: 78: adr = $400; # adr:ffc00 79: PmpSetAdr(adr); 80: 81: m($8c);m($c8);m($8e);m($d8);m($8e);m($d0);m($bc);m($e0); 82: m($01);m($31);m($c0);m($8e);m($c0);m($ba);m($00);m($80); 83: m($bb);m($21);m($00);m($e8);m($3d);m($00);m($e8);m($6d); 84: m($00);m($e8);m($27);m($00);m($e8);m($30);m($00);m($eb); 85: m($fe);m($48);m($65);m($78);m($4c);m($6f);m($61);m($64); 86: m($65);m($72);m($20);m($53);m($74);m($61);m($72);m($74); 87: m($0d);m($0a);m($00);m($20);m($65);m($72);m($72);m($21); 88: m($0d);m($0a);m($00);m($a2);m($e0);m($03);m($ee);m($a0); 89: m($e1);m($03);m($c3);m($b0);m($02);m($eb);m($f4);m($b0); 90: m($03);m($88);m($0e);m($e2);m($03);m($eb);m($ec);m($b0); 91: m($00);m($eb);m($e8);m($8a);m($0f);m($43);m($08);m($c9); 92: m($74);m($05);m($e8);m($ea);m($ff);m($eb);m($f4);m($c3); 93: m($e8);m($e0);m($ff);m($2c);m($30);m($3c);m($0a);m($72); 94: m($02);m($04);m($f9);m($c3);m($e8);m($f1);m($ff);m($d0); 95: m($e0);m($d0);m($e0);m($d0);m($e0);m($d0);m($e0);m($88); 96: m($c7);m($e8);m($e4);m($ff);m($08);m($f8);m($c3);m($e8); 97: m($ea);m($ff);m($88);m($c4);m($eb);m($e6);m($b5);m($00); 98: m($e8);m($b8);m($ff);m($3c);m($3a);m($75);m($f9);m($e8); 99: m($da);m($ff);m($88);m($c3);m($e8);m($e8);m($ff);m($89); 100: m($c7);m($e8);m($d0);m($ff);m($88);m($c4);m($88);m($c1); 101: m($24);m($80);m($b0);m($e0);m($75);m($02);m($b0);m($30); 102: m($00);m($c1);m($e8);m($9a);m($ff);m($88);m($e0);m($3c); 103: m($02);m($75);m($07);m($e8);m($c9);m($ff);m($8e);m($c0); 104: m($eb);m($ce);m($3c);m($85);m($73);m($f5);m($08);m($c0); 105: m($75);m($0d);m($88);m($d9);m($e8);m($a5);m($ff);m($26); 106: m($88);m($05);m($47);m($e2);m($f7);m($eb);m($b9);m($3c); 107: m($81);m($73);m($ef);m($3c);m($01);m($75);m($04);m($e8); 108: m($92);m($ff);m($c3);m($3c);m($03);m($74);m($a9);m($bb); 109: m($33);m($00);m($e8);m($6e);m($ff);m($c3); 110: 111: PmpOff(); 112: 113: LATA[0]=LATA[0]|1; # on reset:a0 114: BusRelease(); 115: Timer_ = 1; 116: while ( Timer_ ); 117: LATA[0]=LATA[0]&$fffe; # off reset:a0 118: 119: while ((LATC[-1]&$40)=0); # wait ready on 120: 121: PicSrv(); 122: 123: BusReq(); 124:} :run HexLoader start 201 :
★2020/09/02 最新版に変更

 ヘキサファイルをダウンロード後のメモリ内容を確認した結果を以下に貼っておきます。
 0x0300からのデータがヘキサファイル内容のように「0123・・・DEF」になっていることから正常にダウンロードできたものと判断できます。

ヘキサファイルロード結果の確認
:l 1:# Pic24V20 dump 2:# by skyriver 3: 4:use LibCpm; 5:use LibSpi; 6: 7: 8:proc main() { 9: var adr; 10: init(); 11: initPmp(); 12:# initSpi(); 13:# initSd(); 14: 15: LATA[0]=LATA[0]|1; # on reset:a0 16: BusReq(); 17: LATA[0]=LATA[0]&$fffe; # off reset:a0 18: 19: PmpOn(); 20: dump($300); 21:} :run 0300 : 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 0310 : 0E 8D DC 81 31 D7 85 3B DD 97 58 AD 02 F5 12 6E 0320 : 59 D3 97 8C 40 B4 20 B9 B1 FD A9 5C 00 59 40 66 0330 : A7 AD 93 DD A1 D7 46 FF 19 E8 23 F9 11 5D 04 FF 0340 : B8 8D 89 29 40 7F 00 6F 6C FC 08 7E C5 7A 11 F5 0350 : D4 97 06 F8 89 AF 2A C4 60 E5 B1 FB 00 75 08 76 0360 : 59 8F A8 1C 02 8B 02 3B 24 FA 60 AB 10 39 20 E6 0370 : 51 9C 06 F7 9B 2E 0A FB 69 DE A1 57 10 6E 02 EE :


★2019/08/12 追記
 CP/M-86のasm86が出力するhexファイルの中にタイプが81H等のインテルヘキサファイルフォーマットに反するレコードがありました。
 調べてみたところ、CP/M-86システムガイドの中にasm86だけが使う拡張タイプについて書いてありましたので貼っておきます。

asm86での拡張ヘキサファイルフォーマット



[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(1) 
共通テーマ:趣味・カルチャー