众所周知,我有一块旧板子DE2-35,很久很久的那种,大概有十多年历史了,不过好在保养得比较好,现在还完好如初,最近心血来潮,打算在上面运行Freedom E310。
Freedom E310是一个开源SoC,其处理器核心是RISC-V架构的开源处理器E3 Coreplex,由SiFive公司设计发布的。
E310的结构图如下所示,从图中可知,除了处理器E3 Coreplex,还有比较丰富的外设,包括:GPIO控制器、AON、QSPI控制器等。其中GPIO接口是可以复用的,可以有复用为两个UART、两个PWM、两个QSPI。
Freedom E310已经在Xilinx的Digilent Arty开发板上运行成功,并且官网提供了完整的工程文件,没有Digilent Arty的童鞋也不要灰心,下面就是Freedom E310在10年前的DE2上的移植测试过程,旧板子新玩法,没有Digilent Arty,照样可以玩转Freedom E310。开发主机是Ubuntu14.04。
1、clone代码
在Github上clone下列项目的代码:Rocket-chip、Freedom、Freedom-e-sdk。因为Freedom-e-sdk没有clone下来,所以这里的测试程序是使用Rocket-chip中riscv64-unknown-elf-gcc编译的,网速快的童鞋可以直接使用Freedom-e-sdk中的gcc编译器。
2、编译Rocket-chip
具体步骤就不说了,在Readme中都有详细的描述。这次编译的目的是安装GCC编译器。
3、编译Freedom
进入Freedom路径,使用如下语句:
make -f Makefile.e300artydevkit verilog
会在build目录下得到一个sifive.freedom.everywhere.e300artydevkit.E300ArtyDevKitConfig.v
4、建立Quartus工程
新建一个Quartus工程,将上面得到的verilog文件,以及面几个文件添加到该工程中:
freedom\fpga\e300artydevkit\src\system.v
freedom\sifive-blocks\vsrc\SRLatch.v
freedom\rocket-chip\vsrc\AsyncResetReg.v
freedom\rocket-chip\vsrc\DebugTransportModuleJtag.v
5、使用Megawizard Plug-in Manager得到PLL
命名为mmcm,输入频率是27MHz,输出有两个,c0是10.125MHz,c1是27MHz,其中c1是作为处理器的主时钟,另外,还有一个locked信号输出,表示PLL是否稳定。具体步骤如下面图所示:
然后注释掉system.v中的如下代码:
mmcm ip_mmcm
(
.clk_in1(CLK100MHZ),
.clk_out1(clk_out1), // 8.388 MHz = 32.768 kHz * 256
.clk_out2(hfclk), // 65 MHz
.resetn(ck_rst),
.locked(mmcm_locked)
);
改为如下:
mmcm ip_mmcm
(
.areset(ck_rst),
.inclk0(CLK100MHZ), // 27 MHz
.c0(clk_out1), // 10.125Mhz
.c1(hfclk), // 27MHz
.locked(mmcm_locked)
);
6、继续修改system.v
修改clkdivider的例化,改为如下:
clkdivider slowclkgen
(
.clk(clk_out1),
.reset(ck_rst),
.clk_out(slowclk)
);
7、继续修改system.v
注释掉reset_sys的例化部分,使用如下代码代替:
reg reset_periph_t;
always @(posedge clk_out1)
begin
if( ck_rst == 1'b1 || mmcm_locked == 1'b0 || SRST_n == 1'b0) begin
reset_periph_t <= 1'b1;
end else begin
reset_periph_t <= 1'b0;
end
end
assign reset_periph = reset_periph_t;
8、继续修改system.v
使用下面的方法替换所有的IOBUF例化,因为IOBUF是Xilinx的原语。
IOBUF
#(
.DRIVE(12),
.IBUF_LOW_PWR("TRUE"),
.IOSTANDARD("DEFAULT"),
.SLEW("SLOW")
)
IOBUF_gpio_1
(
.O(iobuf_gpio_1_o),
.IO(gpio_1),
.I(dut_io_pads_gpio_1_o_oval),
.T(~dut_io_pads_gpio_1_o_oe)
);
可以使用如下语句代替:
assign gpio_1 = dut_io_pads_gpio_1_o_oe ? dut_io_pads_gpio_1_o_oval : 1'bz;
assign iobuf_gpio_1_o = gpio_1;
9、端口分配
这里只是打算做一个简单的GPIO实验,所以没有没有连接全部的端口,主要如下:
CLK100MHZ——连接板载的27MHz时钟
ck_rst——连接波动开关SW1,作为复位按钮
jd_6——连接拨动开关SW0,要确保使其处于高电位
ck_io[8]——实际就是对应E310的GPIO0,连接绿色LED0
ck_io[9]——实际就是对应E310的GPIO1,连接绿色LED1
ck_io[10]——实际就是对应E310的GPIO2,连接绿色LED2
如下:
set_location_assignment PIN_D13 -to CLK100MHZ
set_location_assignment PIN_AE22 -to ck_io[8]
set_location_assignment PIN_AF22 -to ck_io[9]
set_location_assignment PIN_W19 -to ck_io[10]
set_location_assignment PIN_N26 -to ck_rst
set_location_assignment PIN_N25 -to jd_6
将system.v设置为顶层文件,就可以编译该工程了。但此时下载到DE2上还是观察不到效果的,因为我们还没有编写测试程序。
使用汇编编写,打开rocket-chip\bootrom文件夹下的bootrom.S文件,改为如下内容:
.text
.global _start
_start:
// This boot ROM doesn't know about any boot devices, so it just spins,
// waiting for the debugger to load a program and change the PC.
j 1f // reset vector
nop
nop
.word 0 // reserved
.word 0 // reserved
.word 0 // pointer to config string
.word 0 // default trap vector
.word 0
.word 0
.word 0
1:
li x1, 0x7
li x2,0x10012008 // make GPIO0 GPIO1 GPIO2 out port
sw x1,0(x2)
li x3, 0
li x5,1
2:
// light Green LED2, then wait few seconds
li x1, 0x04
li x2,0x1001200C
sw x1,0(x2)
li x4,0x1dfd240
3:
sub x4,x4,x5
bne x4,x3,3b
// light Green LED1, then wait few seconds
li x1, 0x02
li x2,0x1001200C
sw x1,0(x2)
li x4,0x1dfd240
4:
sub x4,x4,x5
bne x4,x3,4b
// light Green LED0, then wait few seconds
li x1, 0x01
li x2,0x1001200C
sw x1,0(x2)
li x4,0x1dfd240
5:
sub x4,x4,x5
bne x4,x3,5b
j 2b
nop
整个程序很简单,启动后,首先初始化GPIO,设置GPIO0、GPIO1、GPIO2为输出口,然后依次通过这三个端口输出高电平,每输出一个高电平,就等待一段时间,然后再在下一个端口输出高电平,其中用到了E310的地址空间映射,GPIO对应的地址映射如下:
所以0x10012008就是配置输出使能的地址,0x1001200C就是设置输出值的地址,这样一说就容易理解上面的程序了。
还是在rocket-chip\bootrom目录下,使用已有的链接脚本,如下:
SECTIONS
{
. = 0x1000;
.text : { *(.text) }
}
因为E310复位的地址是0x1000,所以上面的测试程序就从0x1000开始执行。然后使用下面的两条语句编译:
riscv64-unknown-elf-gcc -Tlinker.ld bootrom.S -nostdlib -static -o bootrom.elf -m32
riscv64-unknown-elf-objcopy -O binary --change-addresses=-0x1000 --only-section .text bootrom.elf bootrom.img
将上面的bootrom.img,复制到freedom项目路径下的bootrom,重命名为e300artydevkit.img
在freedom路径下,使用如下语句得到新的verilog代码:
make -f Makefile.e300artydevkit clean
make -f Makefile.e300artydevkit verilog
新的文件依然位于将freedom/builds/e300artydevkit/路径下,还是sifive.freedom.everywhere.e300artydevkit.E300ArtyDevKitConfig.v,将该文件复制到Quartus工程中,覆盖之前的文件,然后重新编译Quartus工程,将得到的sof文件下载DE2上,此处就可以观察到实验效果了,三个绿色LED灯依次点亮。