(原创)基于or1200最小sopc系统搭建(一)--搭建及仿真(DE2,DE2-70)
做一个or1200的最小系统,or1200+wishbone+ram+gpio,在DE2平台上实现读取SW的值然后再LEDR上显示出来的简单程序。我将记录一些主要的步骤。
在opencores上下载源码or1200-rel1.tar.bz2,wb_conmax_latest.tar.gz, gpio_latest.tar.gz解压出源码到 or1200 , wb_conmax , gpio 目录下。
除此之外,还需要一个onchip-memory和为系统提供时钟的PLL,用altera的MegaWizard Plug-In Manager工具生成。
Ram的生成参考(原创)Altera 1-port ram 的wishbone slave接口写法和wishbone master BFM验证一文,在本文中,用ram0.mif文件初始化(以下会介绍生成方法)。
Pll的配置如下
Inclk0 50M
Clk c0: output clock frequency: 25MHz, Clock phase shift 0.00 ns, Clock duty cycle %:50
为or1200提供时钟
Clk c1: output clock frequency: 10MHz, Clock phase shift 0.00 ns, Clock duty cycle %:50
生成的目录结构
/or1200_sopc
/or1200
/wb_conmax
/gpio
/ram
/pll
建一个sopc的顶层文件,把上述源码连接起来,相当一SOPC Builder的所作的工作,现在靠自己动手做了。编写or1200_sys.v文件
module or1200_sys(
input clk_i,
input rst_n,
// buttons
input [15:0] SW,
// segments
output [31:0] LEDR
);
wire rst = ~rst_n;
// **************************************************
// Wires from OR1200 Inst Master to Conmax m0
// **************************************************
wire wire_iwb_ack_i;
wire wire_iwb_cyc_o;
wire wire_iwb_stb_o;
wire [31:0] wire_iwb_data_i;
wire [31:0] wire_iwb_data_o;
wire [31:0] wire_iwb_addr_o;
wire [3:0] wire_iwb_sel_o;
wire wire_iwb_we_o;
wire wire_iwb_err_i;
wire wire_iwb_rty_i;
// **************************************************
// Wires from OR1200 Data Master to Conmax m1
// **************************************************
wire wire_dwb_ack_i;
wire wire_dwb_cyc_o;
wire wire_dwb_stb_o;
wire [31:0] wire_dwb_data_i;
wire [31:0] wire_dwb_data_o;
wire [31:0] wire_dwb_addr_o;
wire [3:0] wire_dwb_sel_o;
wire wire_dwb_we_o;
wire wire_dwb_err_i;
wire wire_dwb_rty_i;
// **************************************************
// Wires from Conmax s0 to onchip_ram0
// **************************************************
wire wire_ram0_ack_o;
wire wire_ram0_cyc_i;
wire wire_ram0_stb_i;
wire [31:0] wire_ram0_data_i;
wire [31:0] wire_ram0_data_o;
wire [31:0] wire_ram0_addr_i;
wire [3:0] wire_ram0_sel_i;
wire wire_ram0_we_i;
// **************************************************
// Wires from Conmax s15 to GPIO
// **************************************************
wire wire_gpio_ack_o;
wire wire_gpio_cyc_i;
wire wire_gpio_stb_i;
wire [31:0] wire_gpio_data_i;
wire [31:0] wire_gpio_data_o;
wire [31:0] wire_gpio_addr_i;
wire [3:0] wire_gpio_sel_i;
wire wire_gpio_we_i;
wire wire_gpio_err_o;
wire wire_gpio_interrupt;
or1200_top u_or1200(
// System
.clk_i(clk_i),
.rst_i(rst),
.pic_ints_i({18'b0,wire_gpio_interrupt,wire_uart_interrupt}),
.clmode_i(2'b00),
// Instruction WISHBONE INTERFACE
.iwb_clk_i(clk_i),
.iwb_rst_i(rst),
.iwb_ack_i(wire_iwb_ack_i),
.iwb_err_i(wire_iwb_err_i),
.iwb_rty_i(wire_iwb_rty_i),
.iwb_dat_i(wire_iwb_data_i),
.iwb_cyc_o(wire_iwb_cyc_o),
.iwb_adr_o(wire_iwb_addr_o),
.iwb_stb_o(wire_iwb_stb_o),
.iwb_we_o(wire_iwb_we_o),
.iwb_sel_o(wire_iwb_sel_o),
.iwb_dat_o(wire_iwb_data_o),
`ifdef OR1200_WB_CAB
.iwb_cab_o(),
`endif
//`ifdef OR1200_WB_B3
// iwb_cti_o(),
// iwb_bte_o(),
//`endif
// Data WISHBONE INTERFACE
.dwb_clk_i(clk_i),
.dwb_rst_i(rst),
.dwb_ack_i(wire_dwb_ack_i),
.dwb_err_i(wire_dwb_err_i),
.dwb_rty_i(wire_dwb_rty_i),
.dwb_dat_i(wire_dwb_data_i),
.dwb_cyc_o(wire_dwb_cyc_o),
.dwb_adr_o(wire_dwb_addr_o),
.dwb_stb_o(wire_dwb_stb_o),
.dwb_we_o(wire_dwb_we_o),
.dwb_sel_o(wire_dwb_sel_o),
.dwb_dat_o(wire_dwb_data_o),
`ifdef OR1200_WB_CAB
.dwb_cab_o(),
`endif
//`ifdef OR1200_WB_B3
// dwb_cti_o(),
// dwb_bte_o(),
//`endif
// External Debug Interface
.dbg_stall_i(1'b0),
.dbg_ewt_i(1'b0),
.dbg_lss_o(),
.dbg_is_o(),
.dbg_wp_o(),
.dbg_bp_o(),
.dbg_stb_i(1'b0),
.dbg_we_i(1'b0),
.dbg_adr_i(0),
.dbg_dat_i(0),
.dbg_dat_o(),
.dbg_ack_o(),
//`ifdef OR1200_BIST
// // RAM BIST
// mbist_si_i(),
// mbist_so_o(),
// mbist_ctrl_i(),
//`endif
// Power Management
.pm_cpustall_i(0),
.pm_clksd_o(),
.pm_dc_gate_o(),
.pm_ic_gate_o(),
.pm_dmmu_gate_o(),
.pm_immu_gate_o(),
.pm_tt_gate_o(),
.pm_cpu_gate_o(),
.pm_wakeup_o(),
.pm_lvolt_o()
);
wb_conmax_top u_wb(
.clk_i(clk_i),
.rst_i(rst),
// Master 0 Interface
.m0_data_i(wire_iwb_data_o),
.m0_data_o(wire_iwb_data_i),
.m0_addr_i(wire_iwb_addr_o),
.m0_sel_i(wire_iwb_sel_o),
.m0_we_i(wire_iwb_we_o),
.m0_cyc_i(wire_iwb_cyc_o),
.m0_stb_i(wire_iwb_stb_o),
.m0_ack_o(wire_iwb_ack_i),
.m0_err_o(wire_iwb_err_i),
.m0_rty_o(wire_iwb_rty_i),
// .m0_cab_i(),
// Master 1 Interface
.m1_data_i(wire_dwb_data_o),
.m1_data_o(wire_dwb_data_i),
.m1_addr_i(wire_dwb_addr_o),
.m1_sel_i(wire_dwb_sel_o),
.m1_we_i(wire_dwb_we_o),
.m1_cyc_i(wire_dwb_cyc_o),
.m1_stb_i(wire_dwb_stb_o),
.m1_ack_o(wire_dwb_ack_i),
.m1_err_o(wire_dwb_err_i),
.m1_rty_o(wire_dwb_rty_i),
// .m0_cab_i(),
// Slave 0 Interface
.s0_data_i(wire_ram0_data_o),
.s0_data_o(wire_ram0_data_i),
.s0_addr_o(wire_ram0_addr_i),
.s0_sel_o(wire_ram0_sel_i),
.s0_we_o(wire_ram0_we_i),
.s0_cyc_o(wire_ram0_cyc_i),
.s0_stb_o(wire_ram0_stb_i),
.s0_ack_i(wire_ram0_ack_o),
.s0_err_i(0),
.s0_rty_i(0),
//.s0_cab_o(),
// Slave 2 Interface
.s1_data_i(wire_gpio_data_o),
.s1_data_o(wire_gpio_data_i),
.s1_addr_o(wire_gpio_addr_i),
.s1_sel_o(wire_gpio_sel_i),
.s1_we_o(wire_gpio_we_i),
.s1_cyc_o(wire_gpio_cyc_i),
.s1_stb_o(wire_gpio_stb_i),
.s1_ack_i(wire_gpio_ack_o),
.s1_err_i(wire_gpio_err_o),
.s1_rty_i(0)//,
//.s1_cab_o(),
);
ram0_top u_ram0(
.clk_i(clk_i),
.rst_i(rst),
.wb_stb_i(wire_ram0_stb_i),
.wb_cyc_i(wire_ram0_cyc_i),
.wb_ack_o(wire_ram0_ack_o),
.wb_addr_i(wire_ram0_addr_i),
.wb_sel_i(wire_ram0_sel_i),
.wb_we_i(wire_ram0_we_i),
.wb_data_i(wire_ram0_data_i),
.wb_data_o(wire_ram0_data_o)
);
gpio_top u_gpio(
// WISHBONE Interface
.wb_clk_i(clk_i),
.wb_rst_i(rst),
.wb_cyc_i(wire_gpio_cyc_i),
.wb_adr_i(wire_gpio_addr_i),
.wb_dat_i(wire_gpio_data_i),
.wb_sel_i(wire_gpio_sel_i),
.wb_we_i(wire_gpio_we_i),
.wb_stb_i(wire_gpio_stb_i),
.wb_dat_o(wire_gpio_data_o),
.wb_ack_o(wire_gpio_ack_o),
.wb_err_o(wire_gpio_err_o),
.wb_inta_o(wire_gpio_interrupt),
//`ifdef GPIO_AUX_IMPLEMENT
// // Auxiliary inputs interface
// .aux_i(),
//`endif // GPIO_AUX_IMPLEMENT
// External GPIO Interface
.ext_pad_i({16'b0,SW}),
.ext_pad_o(LEDR),
.ext_padoe_o()//,
//`ifdef GPIO_CLKPAD
// .clk_pad_i()
//`endif
);
endmodule
构建顶层模块or1200_sopc.v
//small sopc with openrisc
//`include "or1200_defines.v"
module or1200_sopc
(
//////////////////// Clock Input ////////////////////
CLOCK_27, // On Board 27 MHz
CLOCK_50, // On Board 50 MHz
//////////////////// Push Button ////////////////////
KEY, // Pushbutton[3:0]
//////////////////// DPDT Switch ////////////////////
SW, // Toggle Switch[17:0]
//////////////////////// LED ////////////////////////
LEDR//, // LED Red[17:0]
);
//////////////////////// Clock Input ////////////////////////
input CLOCK_27; // On Board 27 MHz
input CLOCK_50; // On Board 50 MHz
//////////////////////// Push Button ////////////////////////
input [3:0] KEY; // Pushbutton[3:0]
//////////////////////// DPDT Switch ////////////////////////
input [17:0] SW; // Toggle Switch[17:0]
//////////////////////////// LED ////////////////////////////
output [17:0] LEDR; // LED Red[17:0]
wire CPU_RESET;
wire clk_25,clk_10;
Reset_Delay delay1 (.iRST(KEY[0]),.iCLK(CLOCK_50),.oRESET(CPU_RESET));
cpu_pll pll0 (.inclk0(CLOCK_50),.c0(clk_25),.c1(clk_10));
or1200_sys or1200(
.clk_i(clk_25),
.rst_n(CPU_RESET),
// buttons
.SW(SW[15:0]),
// segments
.LEDR(LEDR[17:0])
);
endmodule
其中的Reset_Delay模块如下,产生复位信号。
module Reset_Delay(iRST,iCLK,oRESET);
input iCLK;
input iRST;
output reg oRESET;
reg [23:0] Cont;
always@(posedge iCLK or negedge iRST)
begin
if(!iRST)
begin
oRESET <= 1'b0;
Cont <= 24'h0000000;
end
else
begin
if(Cont!=24'hFFFFFF)
begin
Cont <= Cont+1;
oRESET <= 1'b0;
end
else
oRESET <= 1'b1;
end
end
endmodule
关于or1200_define的配置,参考工程orpXL所写。
or1200_defines.v:
Line 263: Comment out "`define OR1200_ASIC"
Line 326: Enable comment "`define OR1200_ALTERA_LPM"
Line 577: Comment out "`define OR1200_CLKDIV_2_SUPPORTED"
or1200_spram_2048x32.v
Line 591: Comment out "lpm_ram_dq_component.lpm_outdata = "UNREGISTERED","
Other files from opencores.org are remained without change.
下面在modelsim中先做仿真。
从C:\altera\90\quartus\eda\sim_lib目录(参考)下拷贝altera_mf.v和220model.v文件到顶层or1200_sopc目录下
编写or1200_sopc_tb.v测试文件
`timescale 1ns/100ps
module or1200_sopc_tb();
reg CLOCK_50;
reg CLOCK_27;
reg [3:0] KEY;
reg [17:0] SW;
wire [17:0] LEDR;
initial begin
CLOCK_50 = 1'b0;
forever #10 CLOCK_50 = ~CLOCK_50;
end
initial begin
KEY[0] = 1'b0;
#50 KEY[0]= 1'b1;
end
initial begin
SW = 18'h1234;
end
or1200_sopc or1200_sopc_inst
(
//////////////////// Clock Input ////////////////////
.CLOCK_27(CLOCK_27), // On Board 27 MHz
.CLOCK_50(CLOCK_50), // On Board 50 MHz
//////////////////// Push Button ////////////////////
.KEY(KEY), // Pushbutton[3:0]
//////////////////// DPDT Switch ////////////////////
.SW(SW), // Toggle Switch[17:0]
//////////////////////// LED ////////////////////////
.LEDR(LEDR)//, // LED Red[17:0]
);
endmodule
最终的目录结构
/or1200_sopc
/or1200
/wb_conmax
/gpio
/ram
/pll
or1200_sopc.v
or1200_sys.v
or1200_sopc_tb.v
Reset_Delay.v
altera_mf.v
220model.v
编写vlog参数文件vlog.args文件
+libext+.v
-vlog01compat
+acc
-y ./pll
-y ./ram
-y ./or1200
-y ./gpio
-y ./wb_conmax
-v altera_mf.v
-v 220model.v
-work ./work
//
// Test bench files
//
or1200_sopc_tb.v
//
// RTL files (gpio)
//
+incdir+./gpio
./gpio/gpio_top.v
./gpio/gpio_defines.v
//
// RTL files (top)
//
+incdir+../rtl
./or1200_sys.v
./or1200_sopc.v
./pll/cpu_pll.v
./Reset_Delay.v
//
// wb_conmax
//
+incdir+./wb_conmax
./wb_conmax/wb_conmax_arb.v
./wb_conmax/wb_conmax_defines.v
./wb_conmax/wb_conmax_master_if.v
./wb_conmax/wb_conmax_msel.v
./wb_conmax/wb_conmax_pri_dec.v
./wb_conmax/wb_conmax_pri_enc.v
./wb_conmax/wb_conmax_rf.v
./wb_conmax/wb_conmax_slave_if.v
./wb_conmax/wb_conmax_top.v
//
// RTL files (or1200)
//
+incdir+./or1200
./or1200/or1200_defines.v
./or1200/or1200_iwb_biu.v
./or1200/or1200_wb_biu.v
./or1200/or1200_ctrl.v
./or1200/or1200_cpu.v
./or1200/or1200_rf.v
./or1200/or1200_rfram_generic.v
./or1200/or1200_alu.v
./or1200/or1200_lsu.v
./or1200/or1200_operandmuxes.v
./or1200/or1200_wbmux.v
./or1200/or1200_genpc.v
./or1200/or1200_if.v
./or1200/or1200_freeze.v
./or1200/or1200_sprs.v
./or1200/or1200_top.v
./or1200/or1200_pic.v
./or1200/or1200_pm.v
./or1200/or1200_tt.v
./or1200/or1200_except.v
./or1200/or1200_dc_top.v
./or1200/or1200_dc_fsm.v
./or1200/or1200_reg2mem.v
./or1200/or1200_mem2reg.v
./or1200/or1200_dc_tag.v
./or1200/or1200_dc_ram.v
./or1200/or1200_ic_top.v
./or1200/or1200_ic_fsm.v
./or1200/or1200_ic_tag.v
./or1200/or1200_ic_ram.v
./or1200/or1200_immu_top.v
./or1200/or1200_immu_tlb.v
./or1200/or1200_dmmu_top.v
./or1200/or1200_dmmu_tlb.v
./or1200/or1200_amultp2_32x32.v
./or1200/or1200_gmultp2_32x32.v
./or1200/or1200_cfgr.v
./or1200/or1200_du.v
./or1200/or1200_sb.v
./or1200/or1200_sb_fifo.v
./or1200/or1200_mult_mac.v
./or1200/or1200_qmem_top.v
./or1200/or1200_dpram_32x32.v
./or1200/or1200_spram_2048x32.v
./or1200/or1200_spram_2048x32_bw.v
./or1200/or1200_spram_2048x8.v
./or1200/or1200_spram_512x20.v
./or1200/or1200_spram_256x21.v
./or1200/or1200_spram_1024x8.v
./or1200/or1200_spram_1024x32.v
./or1200/or1200_spram_1024x32_bw.v
./or1200/or1200_spram_64x14.v
./or1200/or1200_spram_64x22.v
./or1200/or1200_spram_64x24.v
./or1200/or1200_xcv_ram32x8d.v
//
// Library files
//
//altera_mf.v
编写.do脚本文件
vlib ./work
vlog -f ./vlog.args
vsim -novopt work.or1200_sopc_tb -pli
add wave -radix hex /*
add wave -radix hex /or1200_sopc_tb/or1200_sopc_inst/or1200/*
run 20000ns
可先编译硬件vlog直至没有错误。
Model Technology ModelSim ALTERA vlog 6.4a Compiler 2008.08 Oct 22 2008
-- Compiling module or1200_sopc_tb
… …
Top level modules:
or1200_sopc_tb
or1200_immu_tlb
or1200_dmmu_tlb
or1200_sb_fifo
or1200_dpram_32x32
or1200_spram_2048x32_bw
or1200_spram_2048x8
or1200_spram_512x20
or1200_spram_256x21
or1200_spram_1024x8
or1200_spram_1024x32
or1200_spram_1024x32_bw
下面开始配置软件环境了
首先解决工具链问题
参考网页http://opencores.org/openrisc,gnu_toolchain获得,本文中采用预先编译好的工具链OpenRISC toolchain including GCC-4.2.2 with uClibc-0.9.29, GDB-6.8 and or1ksim-0.3.0, compiled under Ubuntu x86/i686 (32-bit)
$ wget ftp://ocuser:oc@195.67.9.12/toolchain/or32-elf-linux-x86.tar.bz2
解压
$ tar jxf or32-elf-linux-x86.tar.bz2
解压会产生一个新的目录,or32-elf/ 导出文件路径,把以下这句命令添加到~/.bashrc文件中
export PATH=$PATH:/opt/or32-elf/bin
测试以下,输入or32-elf-,按两下tab键
$ or32-elf-
or32-elf-addr2line or32-elf-gcov or32-elf-objdump
or32-elf-ar or32-elf-gdb or32-elf-profile
or32-elf-as or32-elf-gdbtui or32-elf-ranlib
or32-elf-c++filt or32-elf-gprof or32-elf-readelf
or32-elf-cpp or32-elf-ld or32-elf-sim
or32-elf-gcc or32-elf-mprofile or32-elf-size
or32-elf-gcc-4.2.2 or32-elf-nm or32-elf-strings
or32-elf-gccbug or32-elf-objcopy or32-elf-strip
现就可以编写程序了
构建软件工程,主要参考代码demo_or32_sw.zip,orpXL中的代码,用or1200的汇编工具可最终生成.ihex,.srec等格式的文件,但altera ram初始化时并不支持这种格式。就需要另外的转换工具,ihex2mif或者srec2mif工具来完成最后的格式转换。
用gcc编译ihex2mif.c文件把生成的可执行文件ihex2mif保存到/software文件夹下。
构建的工程目录
/software
reset.S
ram.ld
Makefile
gpio_or1200.c
board.h
orsocdef.h
ihex2mif
board.h与orsocdef.h从参考代码中拷出,并进行裁剪。链接文件ram.ld,初始化文件reset.S没有多大变动。
编写的gpio_or1200.c文件源码
#include "orsocdef.h"
#include "board.h"
int
main (void)
{
long gpio_in;
REG32 (RGPIO_OE) = 0xffffffff;
while(1){
gpio_in = REG32 (RGPIO_IN);
gpio_in = gpio_in & 0x0000ffff;
REG32 (RGPIO_OUT) = gpio_in;
}
return 0;
}
编写自己的Makefile文件
ifndef CROSS_COMPILE
CROSS_COMPILE = or32-elf-
endif
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
NM = $(CROSS_COMPILE)nm
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
INCL = board.h orsocdef.h
OBJECTS = reset.o gpio_or1200.o
CFLAGS = -g -c -Wunknown-pragmas -mhard-mul -msoft-div -msoft-float -O2
export CROSS_COMPILE
# *****************
# File Dependencies
# *****************
gpio_or1200.o : $(INCL)
reset.o : board.h
# ********************
# Rules of Compilation
# ********************
all: gpio_or1200.or32 gpio_or1200.ihex gpio_or1200.srec ram0.mif clean
%.o: %.S
@printf "\r\n\t--- Assembling $(<) ---\r\n"
$(CC) $(CFLAGS) $< -o $@
%.o: %.c
@printf "\r\n\t--- Compiling $(<) ---\r\n"
$(CC) $(CFLAGS) $< -o $@
gpio_or1200.or32: ram.ld $(OBJECTS)
$(LD) -T ram.ld $(OBJECTS) -o $@
$(OBJDUMP) -D $@ > gpio_or1200.dis
gpio_or1200.ihex: gpio_or1200.or32
$(OBJCOPY) -O ihex $< $@
gpio_or1200.srec: gpio_or1200.o
$(OBJCOPY) -O ihex $< $@
ram0.mif: gpio_or1200.ihex
./ihex2mif -f gpio_or1200.ihex -o ram0.mif
clean:
rm -f *.o *.or32 *.ihex *.srec *.dis
接下来执行
$ make all
便会生成ram0.mif文件,拷贝到ram的初始化目录。
接下来就可以进行仿真了,在dos环境下。
$ vsim –do sim.do
仿真结果(大致能看清吧)原图放到了这里
接下来,就用quartusII 建立工程吧。
仿真源代码