引言前一段时间,我们对vga_enh模块进行了单独的仿真(http://blog.csdn.net/rill_zhen/article/details/8911727),初步确认了这个模块是没有问题的。
那么,到底这个模块能不能正常work呢?本小节就解决这个问题。
1,实验步骤本小节,我们将vga_enh模块添加到ORPSoC,进行RTL仿真,并在ML501开发板上进行验证。大体过程如下:
1>修改RTL代码,将vga_enh模块挂到ORPSoC的wishbone总线上。
2>编写裸机测试程序
3>仿真
4>下板子测试
2,修改RTL代码在修改代码之前,一定要先把ORPSoC的结构弄明白,关于ORPSoC的整体结构,我们之前曾加介绍过,请参考:http://blog.csdn.net/rill_zhen/article/details/9381557
如何将vga_enh挂到总线上呢,主要有两种方式:其中一种方式是将其master接口挂到dbus_arbiter上,另外一种方式是挂在ddr2的控制器上。两种不同的挂法,示意如下:
挂在dbus_arbiter上:
直接挂在ddr2控制器上:
这两种方式都算是DMA,我们这里两种方式都支持,两种方式通过define语句决定。暂时选择第二种方式。
当然,无论采用哪种方式,其总线地址都是唯一的,我们这里分配为0x97000000.
其实,对于ML501开发板而言,其本身并没有VGA接口,而是DVI接口,由于vga_enh这个模块不仅支持VGA输出,也支持DVI输出,但是需要注意的是,如果想利用ML501的DVI接口输出,就需要配置ML501板子上的CH7301这个芯片,由于配置CH7301需要I2C总线,所以我们除了想ORPSoC中增加vga_enh模块之外,还要增加i2c控制器模块。
ORPSoC本身包含两个i2c_master_slave,为了简单起见,我们将其中一个替换成i2c_master。
由于需要修改的代码较多,这里不一一列出,可以直接使用的工程,我已上传:
http://download.csdn.net/detail/rill_zhen/6897705
3,编写测试程序无论是进行RTL仿真,还是下板验证,我们都要先编写相应的测试程序。
vga.c:
[html] view plaincopyprint?
- /*
- * file name : vga.c
- * function : vga controller test
- * date : 2014-01-10
- * author : Rill
- */
-
- #include "cpu-utils.h"
- #include "board.h"
- #include "int.h"
- #include "uart.h"
- #include "printf.h"
-
- //---VGA defines
- #define RILL_VGA_BASE 0x97000000
- #define VGA_IRQ 22
- #define FRAME_BUF_BASE 0x0 //30MB
- #define FRAME_BUF_SIZE 0x1000
-
-
- //---I2C core defines
- #define RILL_IIC_BASE 0xa0000000
- #define IIC_REG_ADR_PRER_LO 0x0
- #define IIC_REG_ADR_PRER_HI 0x1
- #define IIC_REG_ADR_CTR 0x2
-
- #define IIC_REG_ADR_RXR_W 0x3
- #define IIC_REG_ADR_SR_W 0x4
- #define IIC_REG_ADR_TXR_W 0x3
- #define IIC_REG_ADR_CR_W 0x4
-
- #define IIC_REG_ADR_RXR_R 0x3
- #define IIC_REG_ADR_SR_R 0x4
- #define IIC_REG_ADR_TXR_R 0x5
- #define IIC_REG_ADR_CR_R 0x6
-
- //-----CH7301 defines
- #define CH7301_ADR 0x76
-
- #define CH7301_REG_ADR0 0x49
- #define CH7301_REG_ADR1 0x1f
- #define CH7301_REG_ADR2 0x21
- #define CH7301_REG_ADR3 0x33
- #define CH7301_REG_ADR4 0x34
- #define CH7301_REG_ADR5 0x36
- #define CH7301_REG_ADR6 0x1c
- #define CH7301_REG_ADR7 0x48
-
- #define CH7301_REG_DATA0 0xc0
- #define CH7301_REG_DATA1 0x98
- #define CH7301_REG_DATA2 0x09
- #define CH7301_REG_DATA3 0x08
- #define CH7301_REG_DATA4 0x16
- #define CH7301_REG_DATA5 0x60
- #define CH7301_REG_DATA6 0x00
- #define CH7301_REG_DATA7 0x19
-
- //---VGA data structure
- typedef struct vga_regs
- {
- unsigned int ctrl; //0x0
- unsigned int stat; //0x4
- unsigned int htim; //0x8
- unsigned int vtim; //0xc
- unsigned int hvlen; //0x10
- unsigned int vbara; //0x14
- unsigned int vbarb; //0x18
-
- }rill_vga_regs_s;
-
-
- //----I2C core data structure
- #if 0
- typedef struct i2c_regs
- {
- unsigned char prer_lo;//3'b000
- unsigned char prer_hi;//3'b001
- unsigned char ctr;//3'b010
- unsigned char rxr;//3'b011
- unsigned char sr;//3'b100
- unsigned char txr;//3'b101
- unsigned char cr;//3'b110
- }rill_i2c_regs_s;
-
- #endif
- //===== funcs
-
- /* The vga interrupt handler. */
- void vga_interrupt(void)
- {
- int i = 0;
- i = 1;
- return;
- }
-
-
- void my_vga_setup(void)
- {
- volatile rill_vga_regs_s * vga_regs;
- unsigned int thsync = 127;
- unsigned int thgdel = 87;
- unsigned int thgate = 799;
- unsigned int thlen = 1056;
- unsigned int tvsync = 3;
- unsigned int tvgdel = 22;
- unsigned int tvgate = 599;
- unsigned int tvlen = 628;
-
- vga_regs = (rill_vga_regs_s*)(RILL_VGA_BASE);
-
- /* config vga regs*/
- //==1==-> stop vga core
- vga_regs->ctrl = 0x0;
-
- //==2==-> set vbara reg:0x
- vga_regs->vbara = FRAME_BUF_BASE;
-
- //==3==-> set vbarb reg
- vga_regs->vbarb = FRAME_BUF_BASE + FRAME_BUF_SIZE;
-
- //==4==-> set htim reg
- vga_regs->htim = (thsync << 24) | (thgdel << 16) | thgate;
-
- //==5==-> set vtim reg
- vga_regs->vtim = (tvsync << 24) | (tvgdel << 16) | tvgate;
-
- //==6==-> set hvlen reg
- vga_regs->hvlen = (thlen << 16) | tvlen;
-
- //==7==-> start vga core:0000_0000_0000_0000_0000_0110_0000_0001
- vga_regs->ctrl = 0x621;
-
-
- return;
- }
-
-
-
-
-
-
- void i2c_reg_write(unsigned int reg_wb_adr,unsigned char value)
- {
- //volatile unsigned int * i2c_reg;
- //i2c_reg = (unsigned int *)(RILL_IIC_BASE + reg_wb_adr);
- //i2c_reg = value;
- REG8(RILL_IIC_BASE + reg_wb_adr) = value;
-
- return;
- }
-
- unsigned char i2c_reg_read(unsigned int reg_wb_adr)
- {
- unsigned char ret = 0;
- //volatile unsigned int * i2c_reg;
- //ret = (unsigned int *)(RILL_IIC_BASE + reg_wb_adr);
-
- ret = REG8(RILL_IIC_BASE + reg_wb_adr);
- return ret;
- }
-
-
-
- void i2c_wait_ack(void)
- {
- volatile unsigned int tip = 0;//SR:[ack_from_wr,busy,sl,0,0,0,tip,irq]
-
- do
- {
- tip = (REG32(RILL_IIC_BASE+IIC_REG_ADR_SR_R) & 0x02000000);
- }while(tip);
- }
-
- void i2c_write(unsigned char i2c_adr,unsigned char data)
- {
- i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) & 0xfe);//present slave addr(ch7301,0x76),set write bit
- i2c_reg_write(IIC_REG_ADR_CR_W,0x90);//set commond(start,write),CR:[sta,sto,rd,wr,ack2rd,0,0,iack]
- i2c_wait_ack();
-
- i2c_reg_write(IIC_REG_ADR_TXR_W,i2c_adr);
- i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write)
- i2c_wait_ack();
-
- i2c_reg_write(IIC_REG_ADR_TXR_W,data);
- //i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write)
- //i2c_wait_ack();
- i2c_reg_write(IIC_REG_ADR_CR_W,0x50);//set commond (write,stop)
- i2c_wait_ack();
-
- return;
- }
-
-
- void i2c_read(unsigned char i2c_adr,unsigned char* data)
- {
- i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) & 0xfe);//present slave addr(ch7301,0x76),set write bit
- i2c_reg_write(IIC_REG_ADR_CR_W,0x90);//set commond(start,write),CR:[sta,sto,rd,wr,ack2rd,0,0,iack]
- i2c_wait_ack();
-
- i2c_reg_write(IIC_REG_ADR_TXR_W,i2c_adr);
- i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write)
- i2c_wait_ack();
-
- i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) | 0x01);
- i2c_reg_write(IIC_REG_ADR_CR_W,0x90);
- i2c_wait_ack();
-
- i2c_reg_write(IIC_REG_ADR_CR_W,0x28);//set commond (read,nack_read),read comolete!
- i2c_wait_ack();
- * data = i2c_reg_read(IIC_REG_ADR_RXR_R);
-
- return;
- }
-
- void my_i2c_init(void)
- {
- i2c_reg_write(IIC_REG_ADR_PRER_LO,0xff);//load prescaler lo-byte
- i2c_reg_write(IIC_REG_ADR_PRER_HI,0x00);//load prescaler hi-byte
- i2c_reg_write(IIC_REG_ADR_CTR,0x80);//enable core
- return;
- }
-
- void my_ch7301_init(void)
- {
- unsigned char data = 0;
-
- i2c_write(CH7301_REG_ADR0,CH7301_REG_DATA0);
- i2c_write(CH7301_REG_ADR1,CH7301_REG_DATA1);
- i2c_write(CH7301_REG_ADR2,CH7301_REG_DATA2);
- i2c_write(CH7301_REG_ADR3,CH7301_REG_DATA3);
- i2c_write(CH7301_REG_ADR4,CH7301_REG_DATA4);
- i2c_write(CH7301_REG_ADR5,CH7301_REG_DATA5);
- i2c_write(CH7301_REG_ADR6,CH7301_REG_DATA6);
- i2c_write(CH7301_REG_ADR7,CH7301_REG_DATA7);
-
- //read ch7301 data back
- //i2c_read(CH7301_REG_ADR0,&data);
-
- return;
- }
-
-
-
-
- void delay(unsigned int delay)
- {
- unsigned int time;
-
- time = delay;
- while(time--)
- {
- while(delay--);
- }
-
- return;
- }
-
-
- void my_i2c_setup(void)
- {
- my_i2c_init();
- my_ch7301_init();
-
- return;
- }
-
-
- int main (void)
- {
-
- /* Initialise handler vector */
- //int_init();
-
- /* Install ethernet interrupt handler, it is enabled here too */
- //int_add(VGA_IRQ, vga_interrupt, 0);
-
- /* Enable interrupts in supervisor register */
- //cpu_enable_user_interrupts();
-
- uart_init(0);
- printf("nt <1-> uart_init done!n ");
-
- my_i2c_setup();/* configure IIC & CH7301*/
- printf("nt <2-> i2c_setup done!n ");
-
- my_vga_setup(); /* Configure VGA */
- printf("nt <3-> vga_setup done!n ");
-
- return 0;
- // exit(0x8000000d);
-
- }
/** file name : vga.c* function : vga controller test* date : 2014-01-10* author : Rill*/#include "cpu-utils.h"#include "board.h"#include "int.h"#include "uart.h"#include "printf.h"//---VGA defines#define RILL_VGA_BASE 0x97000000#define VGA_IRQ 22#define FRAME_BUF_BASE 0x0 //30MB#define FRAME_BUF_SIZE 0x1000//---I2C core defines#define RILL_IIC_BASE 0xa0000000#define IIC_REG_ADR_PRER_LO 0x0#define IIC_REG_ADR_PRER_HI 0x1#define IIC_REG_ADR_CTR 0x2#define IIC_REG_ADR_RXR_W 0x3#define IIC_REG_ADR_SR_W 0x4#define IIC_REG_ADR_TXR_W 0x3#define IIC_REG_ADR_CR_W 0x4#define IIC_REG_ADR_RXR_R 0x3#define IIC_REG_ADR_SR_R 0x4#define IIC_REG_ADR_TXR_R 0x5#define IIC_REG_ADR_CR_R 0x6//-----CH7301 defines#define CH7301_ADR 0x76#define CH7301_REG_ADR0 0x49#define CH7301_REG_ADR1 0x1f#define CH7301_REG_ADR2 0x21#define CH7301_REG_ADR3 0x33#define CH7301_REG_ADR4 0x34#define CH7301_REG_ADR5 0x36#define CH7301_REG_ADR6 0x1c#define CH7301_REG_ADR7 0x48#define CH7301_REG_DATA0 0xc0#define CH7301_REG_DATA1 0x98#define CH7301_REG_DATA2 0x09#define CH7301_REG_DATA3 0x08#define CH7301_REG_DATA4 0x16#define CH7301_REG_DATA5 0x60#define CH7301_REG_DATA6 0x00#define CH7301_REG_DATA7 0x19//---VGA data structuretypedef struct vga_regs{ unsigned int ctrl; //0x0 unsigned int stat; //0x4 unsigned int htim; //0x8 unsigned int vtim; //0xc unsigned int hvlen; //0x10 unsigned int vbara; //0x14 unsigned int vbarb; //0x18}rill_vga_regs_s;//----I2C core data structure #if 0typedef struct i2c_regs{ unsigned char prer_lo;//3'b000 unsigned char prer_hi;//3'b001 unsigned char ctr;//3'b010 unsigned char rxr;//3'b011 unsigned char sr;//3'b100 unsigned char txr;//3'b101 unsigned char cr;//3'b110}rill_i2c_regs_s;#endif//===== funcs/* The vga interrupt handler. */void vga_interrupt(void){ int i = 0; i = 1; return;}void my_vga_setup(void){ volatile rill_vga_regs_s * vga_regs; unsigned int thsync = 127; unsigned int thgdel = 87; unsigned int thgate = 799; unsigned int thlen = 1056; unsigned int tvsync = 3; unsigned int tvgdel = 22; unsigned int tvgate = 599; unsigned int tvlen = 628; vga_regs = (rill_vga_regs_s*)(RILL_VGA_BASE); /* config vga regs*/ //==1==-> stop vga core vga_regs->ctrl = 0x0; //==2==-> set vbara reg:0x vga_regs->vbara = FRAME_BUF_BASE; //==3==-> set vbarb reg vga_regs->vbarb = FRAME_BUF_BASE + FRAME_BUF_SIZE; //==4==-> set htim reg vga_regs->htim = (thsync << 24) | (thgdel << 16) | thgate; //==5==-> set vtim reg vga_regs->vtim = (tvsync << 24) | (tvgdel << 16) | tvgate; //==6==-> set hvlen reg vga_regs->hvlen = (thlen << 16) | tvlen; //==7==-> start vga core:0000_0000_0000_0000_0000_0110_0000_0001 vga_regs->ctrl = 0x621; return;}void i2c_reg_write(unsigned int reg_wb_adr,unsigned char value){ //volatile unsigned int * i2c_reg; //i2c_reg = (unsigned int *)(RILL_IIC_BASE + reg_wb_adr); //i2c_reg = value; REG8(RILL_IIC_BASE + reg_wb_adr) = value; return;}unsigned char i2c_reg_read(unsigned int reg_wb_adr){ unsigned char ret = 0; //volatile unsigned int * i2c_reg; //ret = (unsigned int *)(RILL_IIC_BASE + reg_wb_adr); ret = REG8(RILL_IIC_BASE + reg_wb_adr); return ret;}void i2c_wait_ack(void){ volatile unsigned int tip = 0;//SR:[ack_from_wr,busy,sl,0,0,0,tip,irq] do { tip = (REG32(RILL_IIC_BASE+IIC_REG_ADR_SR_R) & 0x02000000); }while(tip);}void i2c_write(unsigned char i2c_adr,unsigned char data){ i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) & 0xfe);//present slave addr(ch7301,0x76),set write bit i2c_reg_write(IIC_REG_ADR_CR_W,0x90);//set commond(start,write),CR:[sta,sto,rd,wr,ack2rd,0,0,iack] i2c_wait_ack(); i2c_reg_write(IIC_REG_ADR_TXR_W,i2c_adr); i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write) i2c_wait_ack(); i2c_reg_write(IIC_REG_ADR_TXR_W,data); //i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write) //i2c_wait_ack(); i2c_reg_write(IIC_REG_ADR_CR_W,0x50);//set commond (write,stop) i2c_wait_ack(); return;}void i2c_read(unsigned char i2c_adr,unsigned char* data){ i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) & 0xfe);//present slave addr(ch7301,0x76),set write bit i2c_reg_write(IIC_REG_ADR_CR_W,0x90);//set commond(start,write),CR:[sta,sto,rd,wr,ack2rd,0,0,iack] i2c_wait_ack(); i2c_reg_write(IIC_REG_ADR_TXR_W,i2c_adr); i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write) i2c_wait_ack(); i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) | 0x01); i2c_reg_write(IIC_REG_ADR_CR_W,0x90); i2c_wait_ack(); i2c_reg_write(IIC_REG_ADR_CR_W,0x28);//set commond (read,nack_read),read comolete! i2c_wait_ack(); * data = i2c_reg_read(IIC_REG_ADR_RXR_R); return;}void my_i2c_init(void){ i2c_reg_write(IIC_REG_ADR_PRER_LO,0xff);//load prescaler lo-byte i2c_reg_write(IIC_REG_ADR_PRER_HI,0x00);//load prescaler hi-byte i2c_reg_write(IIC_REG_ADR_CTR,0x80);//enable core return;}void my_ch7301_init(void){ unsigned char data = 0; i2c_write(CH7301_REG_ADR0,CH7301_REG_DATA0); i2c_write(CH7301_REG_ADR1,CH7301_REG_DATA1); i2c_write(CH7301_REG_ADR2,CH7301_REG_DATA2); i2c_write(CH7301_REG_ADR3,CH7301_REG_DATA3); i2c_write(CH7301_REG_ADR4,CH7301_REG_DATA4); i2c_write(CH7301_REG_ADR5,CH7301_REG_DATA5); i2c_write(CH7301_REG_ADR6,CH7301_REG_DATA6); i2c_write(CH7301_REG_ADR7,CH7301_REG_DATA7); //read ch7301 data back //i2c_read(CH7301_REG_ADR0,&data); return;}void delay(unsigned int delay){ unsigned int time; time = delay; while(time--) { while(delay--); } return;}void my_i2c_setup(void){ my_i2c_init(); my_ch7301_init(); return;}int main (void){ /* Initialise handler vector */ //int_init(); /* Install ethernet interrupt handler, it is enabled here too */ //int_add(VGA_IRQ, vga_interrupt, 0); /* Enable interrupts in supervisor register */ //cpu_enable_user_interrupts(); uart_init(0); printf("nt <1-> uart_init done!n "); my_i2c_setup();/* configure IIC & CH7301*/ printf("nt <2-> i2c_setup done!n "); my_vga_setup(); /* Configure VGA */ printf("nt <3-> vga_setup done!n "); return 0; // exit(0x8000000d); }
makefile:
[html] view plaincopyprint?
- # Set the path to our board's root directory
- BOARD_SW_ROOT=../../..
-
- include $(BOARD_SW_ROOT)/Makefile.inc
-
- %.dis: %.elf
- $(Q)$(OR32_OBJDUMP) -d $< > $@
-
- %.bin: %.elf
- $(Q)$(OR32_OBJCOPY) -O binary $< $@
-
- clean:
- $(Q)rm -f *.elf *.bin *.vmem *.flashin *.dis
# Set the path to our board's root directoryBOARD_SW_ROOT=../../..include $(BOARD_SW_ROOT)/Makefile.inc%.dis: %.elf $(Q)$(OR32_OBJDUMP) -d $< > $@%.bin: %.elf $(Q)$(OR32_OBJCOPY) -O binary $< $@clean: $(Q)rm -f *.elf *.bin *.vmem *.flashin *.dis
4,RTL仿真在下板验证之前,强烈建议先进行RTL仿真。
关于ORPSoC仿真环境的构建,我们之前已经介绍过了,请参考:
http://blog.csdn.net/rill_zhen/article/details/16880801
在搭建好仿真环境之后,我们就可以进行全系统仿真了,步骤如下:
a,创建软件仿真目录和软件程序
[html] view plaincopyprint?
- cd ~/soc-designed/orpsocv2/boards/xilinx/ml501/sw/tests/
- mkdir vga
- cd vga
- mkdir sim
- cp /path/to/vga.c /path/to/Makefile ./
cd ~/soc-designed/orpsocv2/boards/xilinx/ml501/sw/tests/mkdir vgacd vgamkdir simcp /path/to/vga.c /path/to/Makefile ./
效果如下所示:
其中vga.elf文件使用“make vga.elf”命令产生的,在下板验证时使用。
b,开始仿真
[html] view plaincopyprint?
- cd ~/soc-designed/orpsocv2/boards/xilinx/ml501/sim/run/
- make rtl-test TEST=vga VCD=1 PRELOAD_RAM=1 VCD_DELAY=xxx_ps END_TIME=yyy_ps
- gtkwave ../out/vga.tar.gz
cd ~/soc-designed/orpsocv2/boards/xilinx/ml501/sim/run/make rtl-test TEST=vga VCD=1 PRELOAD_RAM=1 VCD_DELAY=xxx_ps END_TIME=yyy_psgtkwave ../out/vga.tar.gz
其中“TEST=vga”是指定本次仿真所使用的软件;“VCD=1”是指本次仿真将保存仿真波形数据到VCD文件;“PRELOAD_RAM=1”是指本次仿真将从RAM开始,具体请参考bootrom的相关代码(board.h中);“VCD_DELAY=xxx_ps”是指定VCD数据保存的开始时间,单位为ps;“END_TIME=yyy_ps”是指定仿真结束时间,当然如果软件指令执行完了,但是仿真时间还没到,也会结束仿真,可通过修改or1200_monitor.v中的相关代码来实现指令执行完之后等待END_TIME。
在仿真结束后,在../out/目录下会生成波形文件,通过gtkwave既可以打开,如果vcd文件太大,可利用modelsim的vcd2wlf工具将vcd文件转换成wlf格式,再用modelsim打开查看波形。仿真时间和转换时间都比较长,请耐心等待。
c,查看波形通过gtkwave和modelsim,产看vga和i2c_master模块的相关寄存器和端口输出,确定没有任何问题。
当然,需要注意的是,如果想仿真,就需要在bench的顶层模块例化i2c的仿真模型。
d,可以直接使用的工程可以直接使用的仿真工程,请参考:
http://download.csdn.net/detail/rill_zhen/6908497
6,下板验证在RTL仿真并确认没有问题之后,我们就可以下板验证了,在用ise综合之前要先给vga和i2c模块分配对应的引脚。
并将板子的DVI接口连接到显示器。
综合完成之后,用iMPACT将bit文件下载到ML501开发板,运行adv_jtag_bridge,运行or32-elf-gdb,将vga.elf下载到内存,并运行。
这时,我们就可以看到显示器的输出了。下图就是我的运行结果:
需要注意的是,如果这时你连接了ML501的串口到PC并打开putty的话,你还会看到如下打印信息:
这说明,我们添加的vga_enh模块,和i2c_master模块都work了!!
7,小结本小节,我们向ORPSoC中添加了vga_enh模块和i2c_master模块,并经过了仿真并最终下板验证。
|