So-net無料ブログ作成
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 ; 2019/08/12 by skyriver 5 ;***************************** 6 7 8 CPU 8086 9 10 SEC_SZ EQU 512 ; sector size 11 WRK_START EQU 01e0H ; work start adr 12 13 FC_EXIT EQU 0 ; EXIT CP/M 14 FC_CONST EQU 1 ; CONST 15 FC_CONIN EQU 2 ; CONIN 16 FC_CONOUT EQU 3 ; CONOUT 17 FC_READ EQU 4 ; READ SD Card 18 FC_WRITE EQU 5 ; WRITE SD Card 19 FC_PUNCH EQU 6 ; PUNCH 20 FC_READER EQU 7 ; READER 21 22 SdBuf EQU WRK_START 23 PicWrk EQU SdBuf + SEC_SZ 24 25 STRUC tPic ; Pic I/F work area 26 00000000 <res 00000001> .FuncNo RESB 1 ; function No 27 00000001 <res 00000001> .RetVal RESB 1 ; return value 28 00000002 <res 00000001> .CoData RESB 1 ; conout data 29 00000003 <res 00000001> .SelDk RESB 1 ; selected disk 30 00000004 <res 00000002> .Track RESB 2 ; track No 31 00000006 <res 00000002> .DmaAdr RESB 2 ; DMA adr 32 00000008 <res 00000001> .Sector RESB 1 ; sector No. 33 ENDSTRUC 34 35 ; *** memory assign *** 36 37 ; ffc00 ffc0:0000 code area 38 ; 39 ; ffde0 ffc0:01e0 SD buf 512byte 40 ; fffe0 ffc0:03e0 work 16byte 41 ; ffff0 ffff:0000 reset jmp 42 43 44 ; SEGMENT CODE ABSOLUTE=0xffc0 45 SEGMENT CODE 46 47 ORG 0 48 49 00000000 8CC8 START: MOV AX,CS 50 00000002 8ED8 MOV DS,AX 51 00000004 8ED0 MOV SS,AX 52 00000006 BCE001 MOV SP,WRK_START 53 00000009 31C0 XOR AX,AX 54 0000000B 8EC0 MOV ES,AX 55 56 0000000D BA0080 MOV DX,8000H 57 58 00000010 BB[2200] MOV BX,MESG 59 00000013 E84100 CALL PUTS 60 00000016 E87300 CALL LOAD 61 00000019 E82800 CALL CONIN ; read CR 62 0000001C E83300 CALL EXIT 63 0000001F E9FDFF JMP $ 64 65 66 00000022 4865784C6F61646572- MESG DB 'HexLoader Start',13,10,0 67 0000002B 2053746172740D0A00 68 00000034 20657272210D0A00 ERRMSG DB ' err!',13,10,0 69 70 ; go pic nterface 71 ; AL <- Function No 72 ; AL -> return value 73 0000003C A2E003 PICSRV: MOV [PicWrk + tPic.FuncNo],AL 74 0000003F EE OUT DX,AL 75 00000040 A0E103 MOV AL,[PicWrk + tPic.RetVal] 76 00000043 C3 RET 77 78 79 ; get console status 80 ; AL -> 0FFH:data exist, 00H:no data 81 ;CONST: MOV AL,FC_CONST 82 ; JMP PICSRV 83 84 ; input from console 85 ; AL -> data 86 87 00000044 B002 CONIN: MOV AL,FC_CONIN 88 00000046 E9F3FF JMP PICSRV 89 90 91 ; output to console 92 ; CL <- data 93 94 00000049 B003 CONOUT: MOV AL,FC_CONOUT 95 0000004B 880EE203 MOV BYTE [PicWrk + tPic.CoData],CL 96 0000004F E9EAFF JMP PICSRV 97 98 99 ; return to PIC world 100 101 00000052 B000 EXIT: MOV AL,FC_EXIT 102 00000054 E9E5FF JMP PICSRV 103 104 105 ; put string 106 ; BX <- string adr 107 108 00000057 8A0F PUTS: MOV CL,[BX] 109 00000059 43 INC BX 110 0000005A 08C9 OR CL,CL 111 0000005C 7406 JZ PUTSE 112 0000005E E8E8FF CALL CONOUT 113 00000061 E9F3FF JMP PUTS 114 00000064 C3 PUTSE: RET 115 116 117 ; read hex nible 118 ; AL -> data 119 00000065 E8DCFF RDNBL: CALL CONIN 120 00000068 2C30 SUB AL,'0' 121 0000006A 3C0A CMP AL,10 122 0000006C 7202 JC RDNBLE 123 0000006E 04F9 ADD AL,10 + '0' - 'A' 124 00000070 C3 RDNBLE: RET 125 126 127 ; read byte data 128 ; AL -> byte data 129 130 00000071 E8F1FF RDBYTE: CALL RDNBL 131 00000074 D0E0 SHL AL,1 132 00000076 D0E0 SHL AL,1 133 00000078 D0E0 SHL AL,1 134 0000007A D0E0 SHL AL,1 135 0000007C 88C7 MOV BH,AL 136 0000007E E8E4FF CALL RDNBL 137 00000081 08F8 OR AL,BH 138 00000083 C3 RET 139 140 141 ; read hex word 142 ; AX -> data 143 00000084 E8EAFF RDWORD: CALL RDBYTE 144 00000087 88C4 MOV AH,AL 145 00000089 E9E5FF JMP RDBYTE 146 147 148 ; load hex file 149 150 0000008C B500 LOAD: MOV CH,0 151 0000008E E8B3FF LOAD01: CALL CONIN 152 00000091 3C3A CMP AL,':' 153 00000093 75F9 JNZ LOAD01 154 155 00000095 E8D9FF CALL RDBYTE ; get byte count 156 00000098 88C3 MOV BL,AL 157 0000009A E8E7FF CALL RDWORD ; get address 158 0000009D 89C7 MOV DI,AX 159 0000009F E8CFFF CALL RDBYTE ; get record type 160 161 000000A2 88C4 MOV AH,AL 162 000000A4 88C1 MOV CL,AL 163 000000A6 2480 AND AL,080H 164 000000A8 B0E0 MOV AL,080H + 'a' - 1 165 000000AA 7502 JNZ LOAD03 166 167 000000AC B030 LOAD02: MOV AL,'0' 168 000000AE 00C1 LOAD03: ADD CL,AL 169 000000B0 E896FF CALL CONOUT 170 000000B3 88E0 MOV AL,AH 171 172 000000B5 3C02 CMP AL,02H ; segment data 173 000000B7 7508 JNZ NXCK1 174 175 000000B9 E8C8FF TYP02: CALL RDWORD ; ** segment 176 000000BC 8EC0 MOV ES,AX 177 000000BE E9CDFF JMP LOAD01 178 179 000000C1 3C85 NXCK1: CMP AL,085H 180 000000C3 73F4 JNC TYP02 181 182 000000C5 08C0 OR AL,AL ; data record 183 000000C7 750E JNZ NXCK2 184 185 000000C9 88D9 TYP00: MOV CL,BL 186 000000CB E8A3FF TYP00A: CALL RDBYTE ; ** DATA 187 000000CE 268805 MOV [ES:DI],AL 188 000000D1 47 INC DI 189 000000D2 E2F7 LOOP TYP00A 190 000000D4 E9B7FF JMP LOAD01 191 192 000000D7 3C81 NXCK2: CMP AL,081H 193 000000D9 73EE JNC TYP00 194 195 000000DB 3C01 CMP AL,01H ; end of data 196 000000DD 7504 JNZ NXCK3 197 198 000000DF E88FFF CALL RDBYTE ; ** EOD 199 000000E2 C3 RET 200 201 000000E3 3C03 NXCK3: CMP AL,03H ; start address 202 000000E5 74A7 JZ LOAD01 ; not implement 203 204 000000E7 BB[3400] MOV BX,ERRMSG 205 000000EA E86AFF CALL PUTS 206 000000ED C3 RET


 テスト用のヘキサファイルは手で作るよりは一般的なツールで作った方がいいので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.02 2019/08/12 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($22);m($00);m($e8);m($41);m($00);m($e8);m($73); 84: m($00);m($e8);m($28);m($00);m($e8);m($33);m($00);m($e9); 85: m($fd);m($ff);m($48);m($65);m($78);m($4c);m($6f);m($61); 86: m($64);m($65);m($72);m($20);m($53);m($74);m($61);m($72); 87: m($74);m($0d);m($0a);m($00);m($20);m($65);m($72);m($72); 88: m($21);m($0d);m($0a);m($00);m($a2);m($e0);m($03);m($ee); 89: m($a0);m($e1);m($03);m($c3);m($b0);m($02);m($e9);m($f3); 90: m($ff);m($b0);m($03);m($88);m($0e);m($e2);m($03);m($e9); 91: m($ea);m($ff);m($b0);m($00);m($e9);m($e5);m($ff);m($8a); 92: m($0f);m($43);m($08);m($c9);m($74);m($06);m($e8);m($e8); 93: m($ff);m($e9);m($f3);m($ff);m($c3);m($e8);m($dc);m($ff); 94: m($2c);m($30);m($3c);m($0a);m($72);m($02);m($04);m($f9); 95: m($c3);m($e8);m($f1);m($ff);m($d0);m($e0);m($d0);m($e0); 96: m($d0);m($e0);m($d0);m($e0);m($88);m($c7);m($e8);m($e4); 97: m($ff);m($08);m($f8);m($c3);m($e8);m($ea);m($ff);m($88); 98: m($c4);m($e9);m($e5);m($ff);m($b5);m($00);m($e8);m($b3); 99: m($ff);m($3c);m($3a);m($75);m($f9);m($e8);m($d9);m($ff); 100: m($88);m($c3);m($e8);m($e7);m($ff);m($89);m($c7);m($e8); 101: m($cf);m($ff);m($88);m($c4);m($88);m($c1);m($24);m($80); 102: m($b0);m($e0);m($75);m($02);m($b0);m($30);m($00);m($c1); 103: m($e8);m($96);m($ff);m($88);m($e0);m($3c);m($02);m($75); 104: m($08);m($e8);m($c8);m($ff);m($8e);m($c0);m($e9);m($cd); 105: m($ff);m($3c);m($85);m($73);m($f4);m($08);m($c0);m($75); 106: m($0e);m($88);m($d9);m($e8);m($a3);m($ff);m($26);m($88); 107: m($05);m($47);m($e2);m($f7);m($e9);m($b7);m($ff);m($3c); 108: m($81);m($73);m($ee);m($3c);m($01);m($75);m($04);m($e8); 109: m($8f);m($ff);m($c3);m($3c);m($03);m($74);m($a7);m($bb); 110: m($34);m($00);m($e8);m($6a);m($ff);m($c3); 111: 112: PmpOff(); 113: 114: LATA[0]=LATA[0]|1; # on reset:a0 115: BusRelease(); 116: Timer_ = 1; 117: while ( Timer_ ); 118: LATA[0]=LATA[0]&$fffe; # off reset:a0 119: 120: while ((LATC[-1]&$40)=0); # wait ready on 121: 122: PicSrv(); 123: 124: BusReq(); 125:} :run HexLoader start 201 :


 ヘキサファイルをダウンロード後のメモリ内容を確認した結果を以下に貼っておきます。
 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) 
共通テーマ:趣味・カルチャー