OpenRisc-21-添加自己的slave IP core到ORSoC并测试

来源:互联网 发布:怎么设计淘宝首页 编辑:程序博客网 时间:2024/05/16 13:20

OpenRisc-21-添加自己的IP core到ORSoC并测试

引言
我之前写过一篇类似文章:

http://blog.csdn.net/rill_zhen/article/details/8700937

那篇算是一个比较详细的概述吧,那篇文章把精力主要集中在driver部分,提到ip core的编码时,一笔带过。
这次进一步细化,写一个真的可以work的ip core,加到现有的ORSoC上,结合那篇文章的driver部分,一个真的可以work的东西就诞生了。

本小节实现了一个简单的ipcore:mycore。她的功能也非常简单,实现一个加法运算。
master(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果。
这次试验可以看到mycore计算1+2=3。
ok let's go!

 

21.1 ip core的编码和修改
要想在ORSoC里面加入自己的ipcore(本小节以‘mycore’为例),需要修改三个文件,增加一个文件。
三个需要修改的文件为:arbiter_dbus.v,orpsoc-params.v,orpsoc_top.v
一个需要增加的文件为:mycore.v
如下图:这里需要注意的是,在ORSoC里面共有3个wishbone的arbiter,咱们用的是arbiter_dbus。为什么呢?很简单,instruction那个是取指令用的,很显然不能用;byte那个是8位的,我的是32位的,很显然也不能用。

 

 

 

21.2 概述
一般,添加自己的ipcore到ORSoC,需要三大步:
1>编写符合wishbone interface的ipcore:mycore
2>定义mycore中用到的parameters
3>增加arbiter的slave或者mater接口(本小节是slave)
4>在顶层module例化这个ipcore

当然为了测试验证,还要
5>编写她的driver。

 

 

21.3 rtl编码
下面就逐个把需要修改的文件的内容说一下:
1》编写符合wishbone interface的ipcore:mycore.v

 


 

/*** rill create 2013-03-26**/`include "orpsoc-defines.v"module mycore(     wb_clk,wb_rst,wb_dat_i,wb_adr_i,wb_sel_i,wb_cti_i,wb_bte_i,wb_we_i,wb_cyc_i,wb_stb_i,wb_dat_o,wb_ack_o,wb_err_o,                    wb_rty_o);input [addr_width-1:0]      wb_adr_i;input     wb_stb_i;input     wb_cyc_i;input [2:0]     wb_cti_i;input [1:0]     wb_bte_i;input           wb_clk;input           wb_rst;input [31:0] wb_dat_i;input [3:0] wb_sel_i;input wb_we_i;output reg [31:0]  wb_dat_o;output reg        wb_ack_o;output                wb_err_o;output   wb_rty_o;//external parametersparameter addr_width = 32;parameter mycore_adr = 0;//local regsreg [addr_width-1:0] num_1;reg [addr_width-1:0] num_2;reg [addr_width-1:0] sum;parameter s_idle = 2'b000;parameter s_read = 2'b001;parameter s_write = 2'b010;reg [2:0] state = s_idle;assign wb_err_o=0;assign wb_rty_o=0;always @(*)beginsum = num_1 + num_2;endalways @(posedge wb_clk)beginif(wb_rst)beginstate <= s_idle;endelsebegincase(state)s_idle:beginwb_dat_o <= 1'b0;wb_ack_o <= 1'b0;if(wb_stb_i && wb_cyc_i && wb_we_i)beginstate <= s_write;endelse if(wb_stb_i && wb_cyc_i && !wb_we_i)beginstate <= s_read;endelsebeginstate <= s_idle;endends_write:beginif(wb_adr_i == {mycore_adr,24'h000000})beginnum_1 <= wb_dat_i;wb_ack_o <= 1'b1;endelse if(wb_adr_i == {mycore_adr,24'h000004})beginnum_2 <= wb_dat_i;wb_ack_o <= 1'b1;endelse begin//wb_ack_o=1'b0;endstate <= s_idle;end  s_read:beginif(wb_adr_i=={mycore_adr,24'h000000})beginwb_dat_o <= num_1;wb_ack_o <= 1'b1;endelse if(wb_adr_i=={mycore_adr,24'h000004})beginwb_dat_o <= num_2;wb_ack_o <= 1'b1;endelse if(wb_adr_i=={mycore_adr,24'h000008})beginwb_dat_o <= sum;wb_ack_o <= 1'b1;endelse beginwb_dat_o=0;wb_ack_o <= 1'b1;endstate <= s_idle;enddefault:beginstate <= s_idle;endendcaseendendendmodule/************** EOF ****************/


 

 

 


2》定义mycore中用到的parameters:修改orpsoc-params.v,共3个地方需要修改,如图:

 1>修改1

2>修改2-3

 

3》增加arbiter的slave或者mater接口(本小节是slave):修改arbiter_dbus.v,共13个地方需要修改,如图:

 1>修改1

1>修改2

1>修改3

1>修改4

1>修改5

1>修改6-7

1>修改8

1>修改9

1>修改10

1>修改11

1>修改12

1>修改13

 


4》在顶层module例化这个ipcore:修改orpsoc_top.v,共4个地方需要修改,如图:

1>修改1

1>修改2

1>修改3

1>修改4


自此,可以通过quartusII进行综合,生成orpsoc_top.svf文件,将其burn到FPGA板子里面。此步请参考:

http://blog.csdn.net/rill_zhen/article/details/8535317

 

http://blog.csdn.net/rill_zhen/article/details/8558463


21.4 driver
有了硬件电路,想让她工作,还要编写她的driver才行:ip_mkg.c ip_mkg.h Makefile


1》ip_mkg.c

 

 

/*** rill mkg driver**/#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/fs.h>#include <asm/uaccess.h> /* get_user and put_user *///#include <linux/clk.h>//#include <linux/ioport.h>#include <asm/io.h> /*ioremap*/#include <linux/platform_device.h> /*cleanup_module*/#include "ip_mkg.h"void__iomem *g_mkg_mem_base = NULL;static int device_open(struct inode *inode, struct file *file){g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);if(NULL == g_mkg_mem_base){printk(KERN_ERR "mkg open ioremap error!\n");return -1;}else{printk("mkg ioremap addr:%d!\n",(int)g_mkg_mem_base);}return 0;}static int device_release(struct inode *inode, struct file *file){return 0;}static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset){/*int ret_val = 0;char * data = NULL;data = (char*)kmalloc(4, GFP_KERNEL);if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0) ioread32(g_mkg_mem_base+length);printk("============read:%d\n",);*/return 1;}static ssize_t device_write(struct file *filp, const char *buffer, size_t count, loff_t *offset){//iowrite32(2,g_mkg_mem_base);return 1;}long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param){#if 0   int ret_val = 0;   unsigned int ret = 0;   struct reg_data *new_regs;   printk("ioctl======\n");   switch(ioctl_num)   {      case IOCTL_REG_SET:  { new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL); if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)  {    kfree(new_regs);    printk(KERN_ERR " error copy line_datafrom user.\n");return -1; }//iowrite16(new_regs->value,g_mkg_mem_base+new_regs->addr); kfree(new_regs);     } break;case IOCTL_REG_GET:{ new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL); if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)  {    kfree(new_regs);    printk(KERN_ERR " error copy line_datafrom user.\n");return -1; }//ret = ioread16(g_mkg_mem_base+new_regs->addr); kfree(new_regs);return ret;}break;         }#endif  return -1;}struct file_operations our_file_ops = {  .unlocked_ioctl = device_ioctl,  .read = device_read,  .write = device_write,  .open = device_open,  .release = device_release,  .owner = THIS_MODULE,};int init_module(){int ret_val;int ret;void __iomem *ret_from_request;int loop = 5;//=== Allocate character device ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &our_file_ops);if (ret_val < 0){printk(KERN_ALERT " device %s failed(%d)\n", DEVICE_NAME, ret_val);return ret_val;}ret = check_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);if (ret < 0) {printk(KERN_ERR "mkg check_mem_region bussy error!\n");return -1;}ret_from_request = request_mem_region(MKG_MEM_BASE, MKG_MEM_LEN, "ip_mkg");//===ioremap mkg registersg_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);if(NULL == g_mkg_mem_base){printk(KERN_ERR "mkg ioremap error!\n");return -1;}else{;//printk("mkg ioremap addr:%d!\n",g_mkg_mem_base);}printk("mkg module init done!\n");iowrite32(0x1,g_mkg_mem_base);printk("mkg write1!\n");iowrite32(0x2,g_mkg_mem_base+4);printk("mkg write2!\n");while(loop--)printk("======%d======read:%d\n",loop,ioread32(g_mkg_mem_base+4*loop));return 0;}void cleanup_module(){release_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);unregister_chrdev(MAJOR_NUM, DEVICE_NAME);}MODULE_LICENSE("GPL");MODULE_AUTHOR("Rill zhen:rill_zhen@126.com");


 

 

 

 

2》ip_mkg.h

 

 

#ifndef __IP_MKG_H__#define __IP_MKG_H__#define MAJOR_NUM102#define DEVICE_NAME"ip_mkg"#define MKG_MEM_BASE 0x97000000#define MKG_MEM_LEN32#define IOCTL_REG_SET 0#define IOCTL_REG_GET 1struct reg_data {unsigned short addr;int value;};#endif


 

 

 

 

3》Makefile

 

 

# To build modules outside of the kernel tree, we run "make"# in the kernel source tree; the Makefile these then includes this# Makefile once again.# This conditional selects whether we are being included from the# kernel Makefile or not.ifeq ($(KERNELRELEASE),)    # Assume the source tree is where the running kernel was built    # You should set KERNELDIR in the environment if it's elsewhere    KERNELDIR ?= /home/openrisc/soc-design/linux    # The current directory is passed to sub-makes as argument    PWD := $(shell pwd)modules:make -C $(KERNELDIR) M=$(PWD) modules ARCH=openrisc CROSS_COMPILE=or32-linux-modules_install:make -C $(KERNELDIR) M=$(PWD) modules_install ARCH=openrisc CROSS_COMPILE=or32-linux-clean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers.PHONY: modules modules_install cleanelse    # called from kernel build system: just declare what our modules are    obj-m := ip_mkg.oendif


 

 

 

 

 

 

21.5 测试
然后make生成ip_mkg.ko,并insmod进内核。就可以看到最终结果。如图,可以看到1 + 2 = 3。

 

 

 

21.6 小结

自此,ORSoC就变成一个transformer了,你可以随意的添加自己想要的ipcore,以实现不同的function。

good lock,enjoy!

 

 

原创粉丝点击