(原创)基于wishbone总线的IP核开发与验证

摘要:介绍了Wishbone总线规范;设计了一个基于aemb系统符合Wishbone总线规范vga 输出显示的外设;设计了在vga显示器上显示ascii码字符的程序;利用uart设计了一个简单的控制shell来控制vga核的显示。

一、Wishbone总线介绍

silicore公司提出,后移交给OpenCores组织维护Wishbone总线规范是一种片上系统IP核互连体系结构。它定义了一种IP核之间公共的逻辑接口,减轻了系统组件集成的难度,提高了系统组件的可重用性、可靠性和可移植性,加快了产品市场化的速度。

Wishbone总线结构十分简单,它仅仅定义了一条高速总线。在一个复杂的系统中,可以采用两条Wishbone总线的多级总线结构:其一用于高性能系统部分,其二用于低性能外设部分,两者之间需要一个接口。这个接口虽然占用一些电路资源,但这比设计并连接两种不同的总线要简单多了。用户可以按需要自定义Wishbone标准,如字节对齐方式和标志位(TAG)的含义等,还可以加上一些其他的特性。

Wishbone总线有四种不同的IP核互连方式

Point-to-point Interconnection:用于两个IP核直接互连。

图表 1 Point-to-point Interconnection

Data Flow Interconnection:用于多个串行IP核之间的数据并发传输。

图表 2 Data Flow Interconnection

Shared Bus Interconnection:多个IP核共享一条总线。

图表 3 Shared Bus Interconnection

Crossbar Switch Interconnection:同时连接多个主从部件,提高系统地吞吐量。

图表 4 Crossbar Switch Interconnection

本文中用到的是第四种:Crossbar Interconnection (Crossbar Switch)

Wishbone总线的主要特征有:

Ø         所有应用适用于同一种总线体系结构;

Ø         是一种简单、紧凑的逻辑IP核硬件接口,只需很少的逻辑单元即可实现;

Ø         时序非常简单;

Ø         /从结构的总线,支持多个总线主设备;

Ø         8~64位数据总线(可扩充);

Ø         单周期读/写;

Ø         支持所有常用的总线数据传输协议,如单字读/写周期、块传输周期、控制操作及其它的总线事等;

Ø         支持多种IP核互连网络,如单向总线、双向总线、基于多路互用的互连网络、基于三态的互连网络等;

Ø         支持总线周期的正常结束、重试结束和错误结束;

Ø         使用用户自定义标记(TAG),确定数据传输类型、中断向量等;

Ø         仲裁器机制由用户自定义;

Ø         建立于硬件技术(FPGAASICbipolarMOS等),IP核类型(软核、固核、硬核),综合工具,布局和布线技术等。

二、Wishbone总线信号和时序

Wishbone总线信号分为4类:系统控制信号、主从共有信号、主设备信号和从设备信号。

系统控制信号

Ø         CLK_O 系统时钟输出。

Ø         RST_O 复位输出。

主从共有信号

Ø         CLK_I 时钟输入。

Ø         DAT_I() 数据输入总线。

Ø         DAT_O() 数据输出总线。

Ø         RST_I() 复位输入。

主设备信号

Ø         ACK_I 应答输入。

Ø         CYC_O 循环输出。

Ø         ERR_I 错误输入。

Ø         LOCK_O 锁定输入。

Ø         RTY_O 重试输入。

Ø         SEL_O() 选择输出总线。

Ø         STB_O() 选通输出。

Ø         WE_O 写使能输出。

从设备信号

Ø         ACK_O() 应答输出。当它有效时表明一个总线循环的正常结束。

Ø         ADR_I() 地址输入总线。总线的高端由IP Core的地址总线的宽度决定,总线的低端边界由数据端口的宽度和粒度决定。

Ø         CYC_I 循环输入。当它有效时,表明正在进行一个正确的总线循环。

Ø         ERR_O() 错误输出。

Ø         LOCK_I 锁定输入。当它有效时,表明当前的总线循环不能被打断。

Ø         RTY_O 重试输出。指示接口没有准备好接收或发送数据,并且循环应当重试。

Ø         SEL_I() 选择输入总线。

Ø         STB_I 选通输入。当它有效时,指示这个从设备被选中。

Ø         WE_I 写使能输入。指示当前的本地总线循环是READ循环还是WRITE循环。这个信号在READ循环中式无效的,在WRITE循环中是有效地。

三、Wishbone总线循环

典型的Wishbone总线循环有5中:SINGLE READ, SINGLE WRITE, BLOCK READ, BLOCK WRITE.

本文中用到的就是SINGLE READ/WRITE的方式。

以下是SINGLE READ/WRITE的时序图和SINGLE READ方式的说明,其实所有信号或信号组合都可以在Avalon总线信号找到对应。

图表 5 SINGLE READ/WRITE

SINGLE READ Cycle

 

Figure 3-3 shows a SINGLE READ cycle.  The bus protocol works as follows:

CLOCK EDGE 0: MASTER presents a valid address on [ADR_O()] and [TGA_O()].

  MASTER negates [WE_O] to indicate a READ cycle.

  MASTER presents bank select [SEL_O()] to indicate where it expects data.

  MASTER asserts [CYC_O] and [TGC_O()] to indicate the start of the cycle.

  MASTER asserts [STB_O] to indicate the start of the phase.

SETUP, EDGE 1: SLAVE decodes inputs, and responding SLAVE asserts [ACK_I].

SLAVE presents valid data on [DAT_I()] and [TGD_I()].

  SLAVE asserts [ACK_I] in response to [STB_O] to indicate valid data.

MASTER monitors [ACK_I], and prepares to latch data on [DAT_I()] and [TGD_I()].

 

  Note: SLAVE may insert wait states (-WSS-) before asserting [ACK_I], thereby allowing it to throttle the cycle speed.  Any number of wait states may be added.

CLOCK EDGE 1: MASTER latches data on [DAT_I()] and [TGD_I()].

  MASTER negates [STB_O] and [CYC_O] to indicate the end of the cycle.

  SLAVE negates [ACK_I] in response to negated [STB_O].

图表 6 Avalon simple Signal

四、基于Wishbone总线的自定义外设开发

Wishbone总线IP核的开发的过程中,除去具体逻辑不谈最重要的就是掌握Wishbone总线的时序,使处理器(本设计中是aemb)发送的数据或者信号能够正常与IP核交互。

本文中参考友晶VGA_binary的实例,创S3C2410开发板中一个LCD显示汉字的例子,以及一个清华培训的例子,做出了这样一个符合Wishbone总线规范的外设,它主要实现的功能有:

Ø         Aemb处理器可以控制VGA接口显示器上任何一点像素的亮灭;

Ø         Aemb处理器可以读出VGA缓存中任意一点像素的值;

Ø         Aemb处理器可以控制VGA接口显示器上像素亮灭时的颜色;

Ø         Aemb处理器可以在VGA接口显示器上任意一点开始显示一串ascii字符。

Ø         Aemb处理器可以由串口控制具体的在VGA显示器上的相关操作(类似于一个简单的shell

 

 

 

 

 

4.1硬件部分的设计

 

 

 

 

 

图表 7 Vga Binary Core

其中的RAM是用AlteraMegaWizard Plug-In Manager工具生成,这就注定了,它不可能足够大以至存一帧全彩色图像640 * 480 * 24 bit),但存一幅二值图像(640 * 480 = 307200 bit)是可以的。而二值图像的前景色和背景色可以通过一个Look up Taple来确定,其实别看它只存两个像素的值,其原理是和256色索引色图像表示方式,是一样的。本设计中把光标给禁掉了,因为并没有引入鼠标。

VGA Binary的低位的0x4B000的空间是留给VGA缓存的地址空间,aemb可以操作这部分空间以实现VGA显示器上的像素的亮灭;从0x4B0000x0x4B00B的这部分空间是控制寄存器的地址空间,aemb可以通过对这部分寄存器的控制实现对现实效果的控制

 

在这部分的设计过程中,遇到的主要问题是,地址的对齐方式。Avalon总线中有NativeDynamic两种地址对齐方式。Native方式会把Avalon主端口的地址直接传送给Avalon从端口不做调整,而Dynamic方式,Avalon总线则会根据数据宽度自动调整。在Wishbone总线中的地址对齐方式属于后者(或者也可以配置,只不过我不知道

这就需要程序在相应的地址空间写数据时必须是往4的倍数的地址中写,vga对应的地址空间才有可能收到。如在aemb的程序中相应的操作都应定义为如下形式

#define Vga_Pixel_On_Color_R(base,value)    (REG32(base + ((OSD_MEM_ADDR+6 ) << 2 )) = value) 

而在vga核的地址的处理中则需把低两位忽略掉

.iWR_ADDR(wb_adr_i[20:2]),

其它Wishbone总线信号的处理,严格参照图表 5 SINGLE READ/WRITE中的时序进行操作即可。

 

4.2 软件部分的设计

实现最基本的打点的操作

#define Vga_Set_Pixel(base,x,y)             (REG32(base + ((x*VGA_WIDTH+y ) << 2)) = 1)       

#define Vga_Clr_Pixel(base,x,y)             (REG32(base + ((x*VGA_WIDTH+y ) << 2)) = 0) 

其它的所有的对VGA的高级一点的操作都是基于这两个宏。

实现对控制寄存器的操作

#define Vga_Write_Ctrl(base,value)          IOWR(base, OSD_MEM_ADDR   , value)

#define Vga_Cursor_X(base,value)            IOWR(base, OSD_MEM_ADDR+1 , value)       

#define Vga_Cursor_Y(base,value)            IOWR(base, OSD_MEM_ADDR+2 , value)       

#define Vga_Cursor_Color_R(base,value)      IOWR(base, OSD_MEM_ADDR+3 , value)       

#define Vga_Cursor_Color_G(base,value)      IOWR(base, OSD_MEM_ADDR+4 , value)       

#define Vga_Cursor_Color_B(base,value)      IOWR(base, OSD_MEM_ADDR+5 , value)       

#define Vga_Pixel_On_Color_R(base,value)    IOWR(base, OSD_MEM_ADDR+6 , value)       

#define Vga_Pixel_On_Color_G(base,value)    IOWR(base, OSD_MEM_ADDR+7 , value)       

#define Vga_Pixel_On_Color_B(base,value)    IOWR(base, OSD_MEM_ADDR+8 , value)       

#define Vga_Pixel_Off_Color_R(base,value)   IOWR(base, OSD_MEM_ADDR+9 , value)       

#define Vga_Pixel_Off_Color_G(base,value)   IOWR(base, OSD_MEM_ADDR+10 , value)       

#define Vga_Pixel_Off_Color_B(base,value)   IOWR(base, OSD_MEM_ADDR+11 , value) 

本设计中使用了创维特S3C2410开发板demo中的字库。Ascii码的字库在onchip-memory中是没问题的,但汉字库就不可能了,得存在片外的存储器中(ssramsdram),这就需要用到bootloader了。

显示ASCII码字符就是,在库里找一个16*8的一个矩阵,根据它的值打点。具体的实现方法可参考博文(原创)用友晶的VGA控制器TERASIC_Binary_VGA_Controller显示汉字和ASCII码字符

再有一部分就是写个与PC机上中端的交互程序了。主要是通过uart.c程序中的基本的打印函数实现,最基本的其实就这一点代码而已。

  while(1){

  uart_putc('$');

    cnt = 0;

    while(cnt<BUFSIZE-1){

      msg[cnt] = uart_getc();

      if((int)msg[cnt]!=13){

        uart_putc(msg[cnt]);

      }

      //printf("%c",msg[cnt]);

      if((int)msg[cnt]==13){

        uart_print_str("\n");

        break;

      }

      cnt++;

    }

    msg[cnt]='\0';

    if(('c'==msg[0])&&('l'==msg[1])&&('r'==msg[2])){

      Clear_Screen();

      uart_print_str("clear screen\n");

    }else if((msg[3]==',') && (msg[7] == ',')){

      x_c[0]=msg[0];

      x_c[1]=msg[1];

      x_c[2]=msg[2];

      y_c[0]=msg[4];

      y_c[1]=msg[5];

      y_c[2]=msg[6];

 

      x = atoi(&x_c[0]);

      y = atoi(&y_c[4]);

 

      uart_print_str(&msg[8]);

      uart_print_str("\n");

      Glib_disp_ascii16x8(x,y,&msg[8]);

    }else{

        uart_print_str("Invalid command!!!\n");

        }

  }

它实现了两条控制命令,一条是clr清屏;另一条是在任意一点打印字符串。格式是

X坐标(3位),Y坐标(3位),AscII码字符串。在程序中调用了atoi函数把ascii码字符串转换成整型数坐标

 

4.3 演示效果

现在演示一下我的这个小demo

题外的工作:做一个初始化屏幕的一幅图像640*480

图表 8 vga initial figure

写个C程序把图像处理成二值的图像,并写成altera ram支持的.mif的文件格式,.hex的太复杂了不好写。初始化VGA的帧缓存器。

 

将工程生成的sof文件下载到DE2-70的板子上

hyperterminal上显示: start uart communication.并且换行显示$,等待输入命令。

vga屏幕上显示:

图表 9 initial figure on screen

输入clr,(设计了回显的功能)

hyperiterminal上显示:clear screen,换行显示$

vga屏幕上显示

图表 10 clear screen

输入命令240,160,Hello, My dear friend!!!,(格式一定要正确)

hyperterminal上显示:Hello My dear friend!!!,换行显示$

vga显示器上显示:

图表 11 print ascii string

输入clr,清屏,发现一个逻辑上的失误,输入clre也会执行清屏操作,是因为在程序中只判断了字符串的前3个字符。输入其它的字符串,会显示Invalid command!!!.

超级终端上的显示效果:

图表 12 hyperterminal display

 

五、总结

关于aemb sopc这个工作的一些想法:

现在真体会到了用不同的软核构建sopc所学到的东西aemb>or1200>niosII

可以加一个Exit命令aemb进入到了控制gpio的循环,一旦用程序同时控制多个外设,简单程序就会捉襟见肘,这时候操作系统就该出场了。

下一步的计划,继续添加各个模块实现bootoader移植ucOS之后设计一些多进程的程序。

尽量使这个系统完善,google code上共享源码。

 

参考文献:

《开源软核处理器OpenRiscSOPC设计》

wbspec_b3.pdf

mnl_avalon_spec.pdf

 
posted @ 2010-06-10 08:41  任怀鲁  阅读(3400)  评论(1编辑  收藏  举报