说实话,国产FPGA的开发环境真的很简陋,但是应该有的都有吧,毕竟用iverilog和OpenFPGALoader的大神有的是,有简陋IDE已经很了不起了,不是吗?
PicoRV32内核项目地址.
https://github.com/YosysHQ/picorv32
其实整个CPU核心就只有一个文件.
这个处理器核心可以支持AXI-Lite接口或者原生内存接口,也支持中断(软件上稍微做得要多一些),或者作为协处理器(PCPI)存在.我们这次实现最最最简单的移植.即原生接口,没有外设,并对内核做一些定制(比如开启乘法,除法,压缩指令)
首先把picorv32.v塞到工程里,再写一个非常非常简单的顶层文件,注释已经在文件内.
`timescale 1 ns / 1 ps
module system (
input clk, // 输入时钟
input resetn, // 输入复位(Tang Nano 20K按键按下后为高,松开为低,所以实际逻辑会取反!)
output trap, // 陷阱(执行了不被支持的东西,处理器故障!)
output reg [7:0] out_byte, // 数据输出
output reg out_byte_en // 当前out_byte有效
);
// 4096 32bit words = 16kB 内存
parameter MEM_SIZE = 4096;
wire mem_valid;
wire mem_instr;
reg mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
reg [31:0] mem_rdata;
picorv32 #(
.ENABLE_MUL(1), // 乘法指令
.ENABLE_DIV(1), // 除法指令
.COMPRESSED_ISA(1) // 压缩指令
) picorv32_core (
.clk (clk ),
.resetn (!resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata )
);
reg [31:0] memory [0:MEM_SIZE-1];
initial $readmemh("firmware.hex", memory); // 固件,等下编译!
reg [31:0] m_read_data;
reg m_read_en;
// 下面代码会推断出BSRAM
always @(posedge clk) begin
m_read_en <= 0;
mem_ready <= mem_valid && !mem_ready && m_read_en;
m_read_data <= memory[mem_addr >> 2];
mem_rdata <= m_read_data;
out_byte_en <= 0;
(* parallel_case *)
case (1)
mem_valid && !mem_ready && !mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
m_read_en <= 1;
end
mem_valid && !mem_ready && |mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
mem_ready <= 1;
end
mem_valid && !mem_ready && |mem_wstrb && mem_addr == 32'h1000_0000: begin
// 访问地址在0x10000000,则输出到IO上!
out_byte_en <= 1;
out_byte <= mem_wdata;
mem_ready <= 1;
end
endcase
end
endmodule
综合没什么问题,然后开始做软件部分.
因为内核特别精简,默认的编译器是为RV32IG(G=MAFD)构建的,我们根本最多也只能启用M扩展,所以得自己先编译一个编译器.
git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
git submodule update --init --recursive
cd riscv32i
mkdir build; cd build
../configure --with-arch=rv32i
make -j$(nproc)
之后编译程序需要3个文件,这里PicoRV32项目也给出来了.
我们随便进入一个,比如Vivado例子里得,找到这三个文件,他就是我们要的固件.
编译过程
riscv32-unknown-elf-gcc -Os -ffreestanding -nostdlib -o firmware.elf firmware.S firmware.c --std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug -lgcc
riscv32-unknown-elf-objcopy -O binary firmware.elf firmware.bin
python3 makehex.py firmware.bin 4096 > firmware.hex
给Gowin新建一个GAO文件.
当out_byte_en上升沿时,触发.
绑定条件.
设置其他采样信息.
引脚约束.
布局布线下载就不用教了吧,打开GAO准备查看成果.
应该能顺利看到.
the PicoRV32 CPU seems to be working just fine.
至此,最简单的移植,完事,看看资源占用,这么看,官方说9K就适合验证软核,也没错嘛,最乞丐的版本.
关闭所有扩展的资源消耗.
不用仿真器,能用串口刷c编译的bin文件到rom里面运行么? 另外 c编译的bin文件怎么固化到fpga的?
@markman 编译后放到FPGA的Block RAM,通过readmemh可以读取hex,JTAG接口不是CPU必须的.