Dies Aliquanti

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PICを作ろう ,インテルHEXを読む(2) ~昼休みにまったり進めるプロジェクト~ (2)

「たっくさん」に指摘されてしまったが、今使っている、Verlogシミュレータ、Veritakには、独自の拡張として、$convert_hex2verというシステムタスク(組み込みタスク)がある。だが、

$convert_hex2ver:ERROR Unknown record type.

というエラーが出てしまい、MPLAB(7.6)のHEXファイルがうまく読めないのだ
(2007/8/8追記:Ver3.38Gで問題なくなりました。FAQ429)MPLABの出力した、HEXファイルをダンプしてみる。
:020000040000FA
:10000000000700003028000000000000
:

どうも、最初の行の「拡張リニアアドレス」(レコードタイプ04)レコードに対応していないようですね。というわけで、だいたい同じものを自分で作りました。ソースコードはこんな感じ。
//
// (c)2007 BakaOyaji
//
`include "ihex2verilog.h"

task ihex2verilog;
input [799:0] infile_name ;
output [799:0] outfile_name ;
output integer error_code ;

integer ifp, ofp ;
integer record_length , offset ,record_type, data, segment ;
integer c_EOF ; // constant
reg [300*8*2-1:0]linebuf ;
reg [7:0] strbuf [300*2-1:0] ;
integer i ;
begin
c_EOF = -1 ; // constant
segment = 0 ;
outfile_name = { infile_name, ".ver" } ;

begin : readandwrite
ifp = $fopen( infile_name, "r" ) ;
if( ifp == 0 ) begin
error_code = `IHEX_ERROR_READOPEN;
disable readandwrite ;
end // if
ofp = $fopen( outfile_name, "w" ) ;
if( ofp == 0 ) begin
error_code = `IHEX_ERROR_WRITEOPEN;
disable readandwrite ;
end
forever begin
// perform a line
if( $fgets( linebuf , ifp) == c_EOF ) begin
error_code = `IHEX_ERROR_UNEXPECTED_EOF ;
disable readandwrite ;
end
// copy string
begin : copy
for( i = 0 ; i < 300*2 ; i = i+1 ) begin
strbuf[i] = linebuf ;
linebuf = linebuf >> 8 ;
if( strbuf[i] == ":" ) begin
disable copy ; // end of copy
end // if
if( strbuf[i] == 8'h00 ) begin
error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ;
disable readandwrite ;
end // if
end // for
// line is too long
error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ;
disable readandwrite ;
end // begin : copy
// get record_length(=2digits), offset(4),record_type(2),
// total 8digit
i = i -8 ;
if( i < 2 ) begin
error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ;
disable readandwrite ;
end // if
record_type = hex2int2( { strbuf[i+1] , strbuf[i]} ) ;
offset = hex2int4(
{ strbuf[i+5] , strbuf[i+4], strbuf[i+3] , strbuf[i+2]} ) ;
record_length = hex2int2( { strbuf[i+7] , strbuf[i+6]} ) ;
if( ( record_length == -1 )
|| (offset == -1 )
|| (record_type == -1 ) ) begin
error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ;
disable readandwrite ;
end // if
case( record_type )
`IHEX_REC_DATA : begin
$fwrite( ofp , "@%4h ", segment + offset ) ;
repeat( record_length ) begin
i=i-2 ;
if( i < 0 ) begin
error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ;
disable readandwrite ;
end // if
data = hex2int2( { strbuf[i+1] , strbuf[i]} ) ;
if( data == -1 ) begin
error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ;
disable readandwrite ;
end // if
$fwrite( ofp , "%2h ", data[7:0] ) ;
end // repeat
$fwrite( ofp, "\n" ) ;
end
`IHEX_REC_END : begin
error_code = `IHEX_NOERROR ;
disable readandwrite ;
end
`IHEX_REC_EXTENDEDADDR : begin
segment = offset << 4 ;
end
`IHEX_REC_STARTADDR : begin
$display("%m Warning, Start Address record, Ignored");
end
`IHEX_REC_EXTENDEDLINERADDR : begin
segment = offset << 16 ;
end
`IHEX_REC_EXTENDEDLINERSTARTADDR : begin
$display("%m Warning, Extended Liner Start Address record, Ignored");
end
default : begin
error_code = `IHEX_ERROR_UNEXPECTED_RECORD ;
disable readandwrite ;
end
// CheckSum calc shuld be add around here, not inplemented yet
endcase
end // forever
end // begin : readandwrite

// errorhandle
if( error_code == `IHEX_ERROR_READOPEN ) begin
end
else if ( error_code == `IHEX_ERROR_WRITEOPEN ) begin
$fclose( ifp ) ;
end
else begin
$fclose( ifp ) ;
$fclose( ofp ) ;
end
end
endtask // ihex2verilog


function integer hex2int ;
input [7:0] c ;

begin
if( "0" <= c && c <= "9" ) begin // '0' <= c <= '9'
hex2int = c - "0" ;
end // if
else if( "A" <= c && c <= "F" ) begin // 'A' <= c <= 'F'
hex2int = c - "A" + 'ha ;
end // else if
else if( "a" <= c && c <= "f" ) begin // 'a' <= c <= 'f'
hex2int = c - "a" + 'ha ;
end // else if
else begin
hex2int = -1 ; // error, out of range
end // else
end
endfunction //hex2int ;



function integer hex2int2 ;
input [8*1+7:0] str ;

integer msnibble, lsnibble ;
begin
msnibble = hex2int( str[8*1+7:8*1] ) ;
lsnibble = hex2int( str[7:0] ) ;
if( (lsnibble == -1) || (msnibble== -1)) begin
hex2int2 = -1 ;
end // if
else begin
hex2int2 = (msnibble << 4 ) + lsnibble ;
end // else
end
endfunction //hex2int2 ;

// 4 digit version
function integer hex2int4 ;
input [8*3+7:0] str ;

integer msb, lsb ;
begin
msb = hex2int2( str[8*3+7:8*2] ) ;
lsb = hex2int2( str[8*2+7:0] ) ;
if( (lsb == -1) || (msb== -1)) begin
hex2int4 = -1 ;
end // if
else begin
hex2int4 = (msb << 8 ) + lsb ;
end // else
end
endfunction //hex2int4 ;

`includeしているファイルは、`IHEX_xxx のマクロ定義をしています。なんか、汚いコードですね(笑)。Verilog-HDLにおける文字列の取り扱いは、ビット列になります。1文字=8bit と、考えれば8*(文字数)の長さのビット列であつかうのですが、いざコードを書いてみるといろいろな問題にぶち当たります。
まず、代入ですが、ビット列で扱っているため、いわゆる右詰めで、余ったところには、'h00がはいることになります。したがって、文字列を前からスキャンするにはちょっと工夫が必要です。
また、Verilogでは、ビット列の部分列を取り出す演算子[:]があるのですが、この中には定数式しかつかえません。このおかげで、一日分の書いたコードをほとんど無駄にしてしまいました(忘れてました、orz...)。仕方ないので、今回は8ビット幅の配列に一回コピーして、作業をしています。
   begin : copy
:
のあたりが、それに相当します。また、部分ビット列の取り出しに定数式以外が使えないので、一番右から処理するので、forループの中で、
    strbuf[i] = linebuf ; linebuf = linebuf >> 8 ;
としています。linebufは4800ビット(600バイト)の長さがありますので、この部分はすんごいオーバーヘッドが多そうです。
さらに、一度キャラクター単位にしたものを、
    {strbuf[i+1] , strbuf[i]}

として、文字列(=ビット列)に戻したりとかやってます(なにやってんだか…)。まあ、このtaskの性格から言って、繰り返し使われるわけではないので、いいことにします。
あとは、少しでも見通しをよくするため、disable文を大域脱出のために、多用しています。大域脱出したい部分を、名前付ブロック(named block)にし、大域脱出するときに、そのブロックをdisableします。
 begin : readandwrite 
     :
   disable readandwrite ;
     :
 end


こんな感じ。c言語と違って、breakやcontinueに相当するしかけがないために、このような書き方をVerilogでは良くします。このほかに、再トリガー付のワンショット(retriggable one-shot)マルチバイブレータをモデリングする際にも使いますが、これは、ウォッチドッグタイマの時にでも再度書くことにします。
 あと、チェックサムの計算はしていません。RS-232でROMライタに送るわけではないので、これもネグります。

さて、これで、プログラムカウンタとインストラクションレジスタ、さらにHEXファイルで初期化可能なコードメモリが準備できたので、次回はプログラムを動かしてみます。
---
本日の御託
林野庁「緑のオーナー制度」で元本割れ・リスク示さず
ひでえニュース。民間企業でこんなことやったら間違いなく出資法違反に問われると思うぞ。もちろん、儲かっていれば誰も文句はいわんだろうが・・・

 



コメント

HEXについて

ご指摘のとおり`IHEX_REC_EXTENDEDLINERADDR 以降は対応していませんでした。お手数をおかけし申し訳ないです。

ところで、[:]は、1995では、確かに定数だけで不便なのですが、Verilog2001では、[変数 +:定数幅]というパートセレクトができます。str[i +:8]とかできます。FPGA合成系もVerilog2001を指定すれば、特に問題ないと思います。

  • 2007/08/04(土) 06:37:53 |
  • URL |
  • たっく #79D/WHSg
  • [ 編集 ]

Re:HEXについて(08/03)

たっくさん
>Verilog2001では、[変数 +:定数幅]というパートセレクトができます。
ご指摘ありがとうございます。早速taskを書き直しました。

  • 2007/08/04(土) 13:39:23 |
  • URL |
  • 莫迦オヤジ #79D/WHSg
  • [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://diesaliquanti.blog.fc2.com/tb.php/353-cd65591a
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

まとめ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。