RISC-V技术论坛
直播中

陈光琦

8年用户 1053经验值
私信 关注
[经验]

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

解决问题:在利用Xilinx开发板开发E203V2项目时,会有两个下载器,分别是FPGA Jtag下载器,用于下载硬件代码如(bit、mcs),和MCU下载器,用于下载Nuclei studio 生成的软件代码如(elfbin),而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;    endendgenerate  for (i = 0; i < MW; i = i+1) begin :mem    if((8*i+8) > DW ) begin: last      always @(posedge clk) begin        if (wen) 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) begin           mem_r[addr][8*i+7:8*i] <= din[8*i+7:8*i];        end      end    end  endendgenerate  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 = (dout_pre === 1'bx) ? 1'b0 : dout_pre;else//}{
         assign dout = dout_pre;
          `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;    endendgenerate  for (i = 0; i < MW; i = i+1) begin :mem    if((8*i+8) > DW ) begin: last      always @(posedge clk) begin        if (wen) 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) begin           mem_r[addr_1][8*i+7:8*i] <= din_1[8*i+7:8*i];        end      end    end  endendgenerate  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 = (dout_pre === 1'bx) ? 1'b0 : dout_pre;else//}{
         assign dout = dout_pre;
          `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下载器的问题。
                                                                                

更多回帖

×
20
完善资料,
赚取积分