解析Intel Hex(16bit)文件并自动读入到MCU软核ROM中的Verilog程序

时间:2024-02-25 14:30:53

根据网上程序,进行了一些改善。

 1 // verilog只支持readmemh,这个程序可以解析单片机的16bit Intel—HEX格式的文件
2 // 并将数据直接写入ROM中,实现软件自动烧写MCU软核内部ram和rom。
3 // modelsim版本要大于5.5
4
5 module Hex2Rom;
6
7 parameter filename="test.hex";
8
9 reg[ 7:0] Row_1st_char;
10 reg[15:0] row_data_basic_addr;
11 reg[ 7:0] row_data_len;
12 reg[ 7:0] row_data;
13 reg[ 7:0] row_check_sum;
14
15 reg[500*8:1] noused;
16 reg[ 640:1] errstr;
17 //
18 reg[7:0] ram[0:2047];
19
20 integer i,fd,code;
21
22 initial begin
23 fd=$fopen(filename,"r");
24 if(fd==0)
25 begin
26 $display("ERROR: File Cann\'t Be Opened!");
27 $fclose(fd);
28 $stop; // stop when no such file
29 end
30 forever begin : continue
31
32 if($ferror(fd,errstr))
33 begin
34 $display("%s",errstr);
35 $stop;
36 end
37
38 Row_1st_char=$fgetc(fd);
39 if(Row_1st_char=="\n") //遇到换行符,读取下一行首字符
40 Row_1st_char=$fgetc(fd);
41 if(Row_1st_char!=":") // every line begin with ":" int the IntelHex form
42 begin
43 code=$fgets(noused,fd);
44 $display("ERROR: Row 1st char isn\'t [:]");
45 disable continue; //若第1个字符不为":",Hex文件结束
46 end
47
48 code=$fscanf(fd,"%2x",row_data_len); // 第2,3个hex数代表数据长度
49 if(row_data_len==0)
50 begin
51 $display("Current Row Data Length ==0, Rom initial finish!");
52 $stop; // stop when no data
53 end
54
55 row_check_sum=row_data_len;
56
57 code=$fscanf(fd,"%4x",row_data_basic_addr); // 第4,5,6,7个hex数代表数据的存放首地址
58
59 row_check_sum=row_check_sum+row_data_basic_addr;
60 row_check_sum=row_check_sum+(row_data_basic_addr>>8); // unsigned row_check_sum
61
62 code=$fscanf(fd,"%2x",row_data); // data type // 第8,9个hex数代表数据类型
63
64 row_check_sum=row_check_sum+row_data;
65
66 for(i=0;i<row_data_len;i=i+1)
67 begin
68 code=$fscanf(fd,"%2x",row_data);
69 row_check_sum=row_check_sum+row_data;
70 ram[row_data_basic_addr]=row_data; // ram read data from file
71 row_data_basic_addr=row_data_basic_addr+1;
72 end
73
74 code=$fscanf(fd,"%2x\n",row_data); // check data // 由于MODELSIM版本问题,程序在6.1版时有些问题,改动如下,可兼容:code=$fscanf(fd,"%2x\n",row_data);
75 row_check_sum=row_check_sum+row_data;
76 if(row_check_sum!=0)
77 begin
78 $display("error:checksum is not zero!");
79 $stop;
80 end
81 end
82 end
83
84 initial
85 begin
86 $monitor($time,"ram[%d] = %h",row_data_basic_addr,row_data);
87 end
88
89 endmodule


下面是带Debug信息的

  1 // verilog只支持readmemh,在设计mcu时,这个程序可以将编译后Intel HEX格式的*.hex文件直接读入ROM中,
2 // modelsim版本要大于5.5
3
4
5 module Hex2Rom;
6
7 parameter filename="test.hex";
8
9 reg[ 7:0] char_1st;
10 reg[15:0] address; // Rom绝对地址
11 reg[ 7:0] len; // 数据长度
12 reg[ 7:0] dat;
13 reg[ 7:0] sum; // intel hex file 检校和
14
15 reg[500*8:1] noused;
16 reg[ 640:1] errstr;
17 //
18 reg[7:0] ram[0:2047];
19
20 integer i,fp,code;
21
22 initial
23 begin
24 char_1st=0;
25 address =0;
26 len =0;
27 dat =0;
28 sum =0;
29
30 fp=$fopen(filename,"r");
31
32 if(fp==0)
33 begin
34 $display($time,"ERROR: Hex File %s cann\'t be open!",filename);
35 $stop; // stop when no such file
36 end
37 else
38 begin
39 $display($time,"Message: Hex File %s open succese!",filename);
40 end
41
42 forever
43 begin : Hex_Rom
44 //------------- 测试文件好坏 ------------------
45 if($ferror(fp,errstr))
46 begin
47 $display("%s",errstr);
48 $display($time,"ERROR: Hex File %s error",filename);
49 $stop;
50 end
51 //------------- 检测每行第1个字符:起始位 -------------------
52 char_1st=$fgetc(fp);
53 if(char_1st=="\n") //若当前字符是行尾换行符
54 char_1st=$fgetc(fp); //读取下一个字符
55 else
56 if(char_1st!=":") // every line begin with ":" int the IntelHex form
57 begin //起始位不为“:”,停止循环
58 code=$fgets(noused,fp);
59 $display($time,"A-ERROR: The 1st char isn\'t [:]Hex File convert end! ");
60 $display($time,"A-Noting: Jump out of [Reading Hex/Initial Rom]");
61 $stop;
62 disable Hex_Rom;
63 end
64 else
65 begin
66 //-------------检测第2,3个字符:数据长度 -------------------
67 code=$fscanf(fp,"%2x",len);
68 if(len==0) //长度为0,停止
69 begin
70 $display($time,"B-Message: The data length is Zero(0)!");
71 $display($time,"B-Noting: Initial Rom Finish^_^!");
72 $stop; // stop when no data
73 //disable Hex_Rom;
74
75 end
76 else
77 begin
78 //-------------------检校和计算-------------------------------
79 sum=len;
80 //-------------检测第4,5,6,7个数据:起始基址 -------------------
81 code=$fscanf(fp,"%4x",address);
82 //-------------------检校和计算-------------------------------
83 sum=sum+address;
84 sum=sum+(address>>8); // unsigned sum
85 //---------------- 检测数据(16bit) -------------------------
86 code=$fscanf(fp,"%2x",dat); // data type
87 sum=sum+dat;
88 for(i=0;i<len;i=i+1)
89 begin
90 code=$fscanf(fp,"%2x",dat);
91 sum=sum+dat;
92 ram[address]=dat; // ram read data from file
93 $display($time,"Noting Ram[%d]=%h",address,dat);
94 address=address+1;
95 end
96 //---------------- 检测检校和 -----------------------------
97 code=$fscanf(fp,"%2x\n",dat); // check data // 若每行数据行尾有换行符,则必须如下更改 由于MODELSIM版本问题,程序在6.1版时有些问题,改动如下,可兼容:code=$fscanf(fp,"%2x\n",dat);
98 sum=sum+dat;
99
100 if(sum!=0)
101 begin
102 $display("error:checksum is not zero!");
103 $stop;
104 end
105
106 end
107 end
108 end
109
110
111 end
112
113
114 endmodule