团队编号: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 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 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下载器的问题。