ModelSim Memory Content import from Intel Hex

May 24, 2007 1 Replies

Hello,



I'm looking for an import utility from Intel Hex to the supported formats of ModelSim, e. g. MTI or Verilog (Hex).


Many thanks in advance Udo



Well, here's a Systemverilog program to read HEX-80 format into a reg[] array. Are there different variations of the HEX format? I wrote this one for Keil's C51 (8051) compiler. You can modify it for your needs:

// // // Author: R***** L*** // // Filename: keil_hex2bin.sv // // Date of Creation: Sun May 20 12:14:48 2007 // // Version: $Revision: 1.1 $ // // Date of Latest Version: $Date: 2007/05/20 12:14:48 $ // // // Description: This is a utility to convert Keil-C51's HEX-80 (*.hex) // output into a $readmemb compatible ASCII-file. // For HEX-80 info, see

formatting link
//

// requires Modelsim 6.1g or later (Systemverilog 3.1a)

/////////////////////////////////////////////////////////////////////////////// // // // This library is free software; you can redistribute it and/or // // modify it under the terms of the GNU Lesser General Public // // License as published by the Free Software Foundation; either // // version 2.1 of the License, or (at your option) any later version. // // // // This library is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // // Lesser General Public License for more details. // // // // Full details of the license can be found in the file LGPL.TXT. // // // // You should have received a copy of the GNU Lesser General Public // // License along with this library; if not, write to the Free Software // // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // // ///////////////////////////////////////////////////////////////////////////////

/* from

formatting link
||||||||||| CC->Checksum |||||||||DD->Data |||||||TT->Record Type |||AAAA->Address |LL->Record Length :->Colon

*/

`ifndef INFILENAME `define INFILENAME "keil.hex" `endif

module keil_hex2bin();

parameter string infilename = `INFILENAME; // default input filename localparam int BUFFER_SIZE = 65536; // # address-locations localparam int LINE_SIZE = 500; // max# bytes per textline

bit [7:0] memory [0:BUFFER_SIZE-1];

typedef struct { bit flag_eof; // end-of-file bit flag_colon; // TRUE==valid record, FALSE==no entry int length; // # bytes in entry bit [15:0] address; bit [7:0] checksum; bit [7:0] record_type; bit [7:0] data [0:LINE_SIZE-1]; // data } t_hex80entry;

int fh_in = 0; int fh_bin_out = 0; int fh_hex_out = 0; // FILE-pointers

///////////////////////////////////////////////////////////////////////////////

function void open_file( input string name ); // make sure we aren't in the middle of processing another file assert ( fh_in == 0 ) else $fatal( 1, "%m(): a file is already open for reading!", name );

fh_in = $fopen( name, "r" ); assert ( fh_in != 0 ) $info( "%m(): initiating read of '%0s'", name ); else $fatal( 1, "%m(): $fopen( \"%0s\", \"r\" ) failed!", name ); endfunction : open_file

///////////////////////////////////////////////////////////////////////////////

function void close_file( int fhandle ); // make sure we aren't in the middle of processing another file assert ( fhandle != 0 ) $info( "%m(): closing file-handle 'h%h", fhandle ); else $error( "%m(): no file was open for reading!" );

$fclose( fhandle ); endfunction : close_file

///////////////////////////////////////////////////////////////////////////////

function t_hex80entry parse_line( input string line ); int error; int data_byte_count; bit [7:0] temp_byte, sum; string phrase; // substring of line[]

int length; // # bytes in entry bit [15:0] address; bit [7:0] record_type; bit [7:0] checksum;

begin parse_line = '{default:'0};

if ( line.len() < 10 ) return parse_line; // too short, can't possibly be a valid entry else if ( line[0] !== ":" ) return parse_line; // no starting colon else if ( line == ":00000001FF\n" ) begin parse_line.flag_eof = 1'b1; // got end of file! return parse_line; end

/* get first few fields :LLAAAATT |||||||TT->Record Type |||AAAA->Address |LL->Record Length */

// if we made it this far, entry appears to be valid! parse_line.flag_colon = 1'b1;

/* error = 0; phrase = line.substr( 1, 2 ); error += $sscanf( phrase, "%02h", parse_line.length );

phrase = line.substr( 3, 6 ); error += $sscanf( phrase, "%04h", parse_line.address );

phrase = line.substr( 7, 8 ); error += $sscanf( phrase, "%02h", parse_line.record_type ); */

// Modelsim 6.1g workaround - $sscanf can't output to struct/union error = $sscanf( line, ":%02h%04h%02h", length, address, record_type ); parse_line.length = length; parse_line.address = address; parse_line.record_type = record_type;

// error = $sscanf( line, ":%02h%04h%02h", parse_line.length, // parse_line.address, parse_line.record_type );

assert ( error == 3 ) else begin $error("%m(): '%0s' (%0d)", line, error ); parse_line.flag_colon = 1'b0; end

// now get checksum (last 2 chars of line[]) phrase = line.substr( line.len()-3, line.len()-2 ); // error = $sscanf( phrase, "%02h", parse_line.checksum ); error = $sscanf( phrase, "%02h", checksum ); parse_line.checksum = checksum; assert ( error == 1 ) else begin $error("%m(): checksum: '%0s' (%0d)", phrase, error ); parse_line.flag_colon = 1'b0; end

// now extract the data-payload

error = 0; for ( int i = 0; i < data_byte_count; ++i ) begin phrase = line.substr( (i*2)+9, (i*2)+10 ); error += $sscanf( phrase, "%02h", parse_line.data[i] ); end assert ( error == data_byte_count ) else begin $error("%m(): DATA: '%0s' (%0d!=%0d)", phrase, error, data_byte_count ); parse_line.flag_colon = 1'b0; end

// finally, validate the checksum sum = 0; error = 0; for ( int i = 1; i < (line.len()-1); i=i+2 ) begin phrase = line.substr( i, i+1 ); error += $sscanf( phrase, "%02h", temp_byte ); sum += temp_byte; end

assert ( sum == 0 ) else $error( "%m(): Checksum (%0d bytes) mismatch (%h!=%h)", error, sum, parse_line.checksum );

end endfunction : parse_line

///////////////////////////////////////////////////////////////////////////////

task create_file( output int fhandle, input string filename ); assert ( fhandle == 0 ) else begin $warning( "%m( '%0s' ): fhandle(0x%h) is already in use, overwriting!", filename, fhandle ); $fclose( fhandle ); end

fhandle = $fopen( filename, "w" ); assert ( fhandle != 0 ) $info( "%m(): creating file '%0s'", filename ); else $fatal( 1, "%m(): could not create file '%0s'!", filename ); endtask : create_file

initial begin : main t_hex80entry h; int n; string line; string outfilename_bin, outfilename_hex; // standalone mode

// assume the last 5-letters of the filename are '.xyz' // (If that's not the case, then we'll accidentally truncate the filename!) outfilename_bin = infilename.substr(0, infilename.len()-5) ; outfilename_hex = infilename.substr(0, infilename.len()-5) ;

outfilename_bin = {outfilename_bin, ".dua"}; // $readmemb-compat output outfilename_hex = {outfilename_bin, ".dhx"}; // $readmemh-compat output

open_file( infilename );

n = $fgets( line, fh_in ); while ( n > 0 ) begin h = parse_line( line ); assert ( n < (LINE_SIZE*2) ) else $fatal( 1, "Line exceeded internal line-buffer size (%0d chars) !", LINE_SIZE*2 ); if ( h.flag_colon && (!h.flag_eof) ) $display( "0x%h: %0d bytes, CHK=%h", h.address, h.length, h.checksum ); n = $fgets( line, fh_in );

// copy entry-data to internal-memory for ( int j = 0; j < h.length; ++j ) memory[ h.address+j ] = h.data[j]; end

close_file( fh_in );

// Create and dump the contents to $readmemb and readmemh files create_file( fh_bin_out, outfilename_bin ); create_file( fh_hex_out, outfilename_hex );

for ( int i = 0; i < BUFFER_SIZE; ++i ) begin $fdisplay( fh_bin_out, "%08b", memory[ i ] ); $fdisplay( fh_hex_out, "%02h", memory[ i ] ); end $fclose( fh_bin_out ); $fclose( fh_hex_out );

$finish; end : main endmodule : keil_hex2bin

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required