RISC-V MCU中文社区

【分享】 在利用Xilinx开发板烧录E203V2软件程序,无MCU下载器时利用FPGA Jtag 下载器烧录软件程序

发表于 开源蜂鸟E203 2023-05-06 17:16:46
1
2272
3

团队编号:CICC6217
团队名称:会吹风的亚索~
学校:杭州电子科技大学
团队成员:李浩、刘坚、赵博涵
指导老师:申东升

解决问题:在利用Xilinx开发板开发E203V2项目时,会有两个下载器,分别是FPGA Jtag下载器,用于下载硬件代码如(bit、mcs),和MCU下载器,用于下载Nuclei studio 生成的软件代码如(elf\bin),而FPGA开发板的Jtag下载器很常见,MCU下载器需要另行购买,这里提供一种思路仅使用Jtag下载器实现通用。
首先,需要明白软件代码可以下载到ITCM或外部FLASH中,本方法仅支持下载到内部ITCM中,具体方法如下:
1)首先找到ITCM最底层代码如下:

module sirv_sim_ram

(parameter DP = 512, //ram dp=2^13

parameter FORCE_X2ZERO = 0,
parameter DW = 32, //ram dw=64
parameter MW = 4, //ram mw=8
parameter AW = 32 //ram aw=13

)
(
input clk,
input [DW-1 :0] din,
input [AW-1 :0] addr,
input cs,
input we,
input [MW-1:0] wem,
output [DW-1:0] dout
);

reg [DW-1:0] mem_r [0:DP-1];
reg [AW-1:0] addr_r;
wire [MW-1:0] wen;
wire ren;

assign ren = cs & (~we);
assign wen = ({MW{cs & we}} & wem);



genvar i;

always @(posedge clk)
begin
    if (ren) begin
        addr_r <= addr;
    end
end

generate
  for (i = 0; i < MW; i = i+1) begin :mem
    if((8*i+8) > DW ) begin: last
      always @(posedge clk) begin
        if (wen[i]) begin
           mem_r[addr][DW-1:8*i] <= din[DW-1:8*i];
        end
      end
    end
    else begin: non_last
      always @(posedge clk) begin
        if (wen[i]) begin
           mem_r[addr][8*i+7:8*i] <= din[8*i+7:8*i];
        end
      end
    end
  end
endgenerate

wire [DW-1:0] dout_pre;
assign dout_pre = mem_r[addr_r];

generate
if(FORCE_X2ZERO == 1) begin: force_x_to_zero
for (i = 0; i < DW; i = i+1) begin:force_x_gen
ifndef SYNTHESIS//{ assign dout[i] = (dout_pre[i] === 1'bx) ? 1'b0 : dout_pre[i];else//}{
assign dout[i] = dout_pre[i];
`endif//}
end
end
else begin:no_force_x_to_zero
assign dout = dout_pre;
end
endgenerate

endmodule

可以看到将软件程序下载到ITCM的最终方法便是在此模块中给 mem_r寄存器堆赋值,之后从里面读取指令,从而整个系统运转起来。

2)明白了上述下载原理便可开展后续工作
首先,通过外部一个按键或者拨码开关进行选择是否使用此方法,然后在VIVADO中添加VIO IP核具体修改后的代码如下:

module sirv_sim_ram

(parameter DP = 512, //ram dp=2^13

parameter FORCE_X2ZERO = 0,
parameter DW = 32, //ram dw=64
parameter MW = 4, //ram mw=8
parameter AW = 32 //ram aw=13

)
(
input clk,
input [DW-1 :0] din,
input [AW-1 :0] addr,
input cs,
input we,
input [MW-1:0] wem,
output [DW-1:0] dout,

input button

);

reg [DW-1:0] mem_r [0:DP-1];
reg [AW-1:0] addr_r;
wire [MW-1:0] wen;
wire ren;

//VIO控制ITCM总线
wire [DW-1 :0]din_0;
wire [AW-1 :0] addr_0;
wire cs_0;
wire we_0;
wire [MW-1:0] wem_0;

//最终读写ITCM信号
wire [DW-1 :0]din_1;
wire [AW-1 :0] addr_1;
wire cs_1;
wire we_1;
wire [MW-1:0] wem_1;

assign ren = cs_1 & (~we_1);
assign wen = ({MW{cs_1 & we_1}} & wem_1);


assign din_1     =  button     ?    din_0    :        din    ;
assign addr_1   = button     ?  addr_0   :       addr   ;
assign cs_1        = button     ?   cs_0       :       cs        ;
assign  we_1       =button     ?     we_0   :       we      ;
assign  wem_1  =  button     ?  wem_0  :    wem      ;

vio_0 u_vio_0 (
.clk(clk), // input wire clk
.probe_in0(din_0), // input wire [63 : 0] probe_in0
.probe_in1(addr_0), // input wire [12 : 0] probe_in1
.probe_in2(cs_0), // input wire [0 : 0] probe_in2
.probe_in3(we_0), // input wire [0 : 0] probe_in3
.probe_in4(wem_0) // input wire [7 : 0] probe_in4
);

genvar i;

always @(posedge clk)
begin
    if (ren) begin
        addr_r <= addr_1;
    end
end

generate
  for (i = 0; i < MW; i = i+1) begin :mem
    if((8*i+8) > DW ) begin: last
      always @(posedge clk) begin
        if (wen[i]) begin
           mem_r[addr][DW-1:8*i] <= din_1[DW-1:8*i];
        end
      end
    end
    else begin: non_last
      always @(posedge clk) begin
        if (wen[i]) begin
           mem_r[addr_1][8*i+7:8*i] <= din_1[8*i+7:8*i];
        end
      end
    end
  end
endgenerate

wire [DW-1:0] dout_pre;
assign dout_pre = mem_r[addr_r];

generate
if(FORCE_X2ZERO == 1) begin: force_x_to_zero
for (i = 0; i < DW; i = i+1) begin:force_x_gen
ifndef SYNTHESIS//{ assign dout[i] = (dout_pre[i] === 1'bx) ? 1'b0 : dout_pre[i];else//}{
assign dout[i] = dout_pre[i];
`endif//}
end
end
else begin:no_force_x_to_zero
assign dout = dout_pre;
end
endgenerate

endmodule

其原理即利用开关button进行数据选择,din_1等后缀为1的信号为最终控制mem_r寄存器堆的信号,在button为1时由我们控制VIO往mem_r寄存器里面写数据,反之交由原本的cpu核进行写数据。

3)完成上述步骤后生成bit文件用Jtag下载器下载到XILINX开发板中,随后打开VIO界面,将button置1 随后利用TCL脚本将Nuclei stdio 生成的代码(以bin文件为例)写入ITCM中,
这里提供几条TCL语句进行参考
set rom [open “hello.bin”]
set data [read -nonewline $rom ]
上述两条TCL脚本将hello.bin文件中的数据读出到data中,
set_property OUTPUT_VALUE ……
上述TCL脚本用于控制信号的值
4)可按照ITCM的写数据时序用TCL脚本赋值并进行循环写,即写入一个地址数据后更换下一个地址,具体情况均需根据实际情况而定,写入需要一定时间,写完成后记得将button的值置0,此时将ITCM的值交由E203V2内核,并按下复位键,随后便开始执行软件代码,最终得到与通过MCU下载器下载软件代码同样的效果,至此,完美解决了没有MCU下载器的问题。

喜欢3
用户评论 (1)
listen

listen 实名认证

懒的都不写签名

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板