引言
在实现内核程序(driver)和硬件(ipcore)的memory共享时,需要解决的主要问题是如何将用kmalloc()函数获得的内核逻辑地址转换成物理地址,以供硬件(ipcore)使用,最终实现DMA操作。
内核空间的程序(driver)和ipcore的memory的共享问题已经解决,请参考:
http://blog.csdn.net/rill_zhen/article/details/9121009
这时,如果用户空间的程序(AP)想向ipcore传递数据,可以在内核空间的driver部分的read/write函数的实现时通过copy_from_user和copy_to_user两个函数与用户空间程序实现数据交换,然后通过上面的方式,再与ipcore实现数据交换。
这样做可以实现AP和ipcore的数据交换,并且在数据量比较小时队系统的影响也不大。但是,如果AP和ipcore交换的数据较大时,就会严重影响系统性能。甚至,如果不用DMA,后果就更严重。
本小节就解决这个问题。
1,三种方式的数据流向
为了更清晰的说明在AP和ipcore间的数据交换的具体过程,我假设了三种方式:
1>方式a:
1》AP和kernel通过copy_from_user和copy_to_user两个函数实现数据交换。
2》kernel和ipcore之间通过io_read32/io_write32两个函数实现数据交换。
3》CPU需要进行2次数据拷贝。
2>方式b:
1》AP和kernel通过copy_from_user和copy_to_user两个函数实现数据交换。
2》kernel和ipcore之间通过virtual_to_physical()函数将内核空间的地址转换成物理地址,然后ipcore通过DMA的方式实现数据交换。
3》CPU需要进行1次数据拷贝。
3>方式c:
1》AP和kernel通过mmap()函数将ipcore的物理地址(也可以是内核空间的逻辑地址)映射到用户空间。
如果是内核空间的逻辑地址(ipcore和内核共享SDRAM):不带显存的显卡采用的就是这种方式(framebuffer)。
2.1》kernel和ipcore之间通过virtual_to_physical()函数将内核空间的地址转换成物理地址,然后ipcore通过DMA的方式实现数据交换。
如果是ipcore的地址(ipcore有local RAM,不与内核共享SDRAM):带显存的显卡采用的就是这种方式(framebuffer)
2.2》kernel和ipcore之间通过virtual_to_physical()函数将内核空间的地址转换成物理地址,然后ipcore通过可以直接访问本地数据的方式实现数据交换。
3》CPU需要进行0次数据拷贝,即CPU不进行数据拷贝,可以完全从大量数据拷贝工作中解脱出来。
注:上述3中方式均不考虑最初的那次数据拷贝(从文件(disk)到内存(SDRAM))。
采用方式a的情况:
http://blog.csdn.net/rill_zhen/article/details/8722664
采用方式b的情况:
http://blog.csdn.net/rill_zhen/article/details/8849149
而本小节就是采用方式c中ipcore有local RAM,不与内核共享SDRAM的情况。
采为了更直观的表示上述三种情况,我做了如下对比图:
2,软件部分
1>功能概述
为了实现上面所述的方式c2的情况,软件部分的工作如下:
1》在驱动层实现mmap函数,将mkg_slave的地址空间映射给用户(主要调用io_remap_pfn_range()函数实现将ipcore的物理地址映射到用户空间)
2》在用户层调用mmap()获得对应的虚拟地址3》用户程序直接操作这个虚拟地址,就可以实现直接操作my_ram这个ipcore
2>验证
将之前驱动部分的工作(调用io_read32()/io_write32())交给用户层来做,如果ipcore工作良好,则说明这个方式是成功的。
具体信息请参考之前其他blog中的driver的内容。
3>代码实现
1》驱动层代码
3个文件:ip_mkg.c,ip_mkg.h,makefile
ip_mkg.c:
/*
*
* rill mkg driver
*
*/
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/gfp.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 <linux/delay.h>
#include <asm-generic/io.h>
#include "ip_mkg.h"
void __iomem *g_mkg_mem_base = NULL;
void __iomem *g_mkg_core_base = NULL;
static int device_open(struct inode *inode, struct file *file)
{
g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
g_mkg_core_base = ioremap (MKG_CORE_BASE, MKG_CORE_LEN);
if(NULL == g_mkg_mem_base)
{
printk(KERN_ERR "mkg mem open ioremap error!\n");
return -1;
}
else
{
printk("mkg mem ioremap addr:%d!\n",(int)g_mkg_mem_base);
}
if(NULL == g_mkg_core_base)
{
printk(KERN_ERR "mkg core open ioremap error!\n");
return -1;
}
else
{
printk("mkg core ioremap addr:%d!\n",(int)g_mkg_core_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;
}
void device_vma_open (struct vm_area_struct * vma)
{
printk("ip_mkg vma open ,virt 0x%x, phy 0x%x\n",vma->vm_start,vma->vm_pgoff<<PAGE_SHIFT);
}
void device_vma_close(struct vm_area_struct * vma)
{
printk("ip_mkg vma close \n");
}
static struct vm_operations_struct device_remap_vm_ops =
{
.open = device_vma_open,
.close = device_vma_close,
};
static int device_mmap (struct file * filp,struct vm_area_struct * vma)
{
unsigned long off;
unsigned long start;
if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
{
printk("vm_pgoff is wrong !\n");
return -EINVAL;
}
start=0x97000000;
start &= PAGE_MASK;
printk("start is 0x%x \n",start);
off=vma->vm_pgoff<<PAGE_SHIFT;
off+=start;
printk("off is 0x%x \n",off);
vma->vm_pgoff=off>>PAGE_SHIFT;
vma->vm_flags |=VM_IO | VM_RESERVED;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
printk(" vm_start: 0x%x ,off : 0x%x \n ",vma->vm_start,off>>PAGE_SHIFT);
if(io_remap_pfn_range(vma,vma->vm_start,off >> PAGE_SHIFT,vma->vm_end-vma->vm_start,vma->vm_page_prot))
{ printk("remap_pfn_range error \n");
return - EAGAIN;
}
printk("remap success \n");
// vma->vm_ops = & device_remap_vm_ops;
// device_vma_open( vma);
return 0;
}
struct file_operations our_file_ops = {
.unlocked_ioctl = device_ioctl,
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release,
.mmap = device_mmap,
.owner = THIS_MODULE,
};
int ToBigEndian(int lit_End)
{
char * p=(char *)&lit_End;
return (int)(p[0]<<24)+(int)(p[1]<<16)+(int)(p[2]<<8)+(int)(p[3]);
}
void test(void)
{
/*
int write_data[256]={
0x69016901, 0x8b014401, 0xa7011a01, 0xbd01ee00, 0xcd01bf00, 0xd7018f00, 0xdb015e00, 0xd8012e00, 0xcf010000,
0xc101d403, 0xad01ab03, 0x94018603, 0x78016503, 0x58014803, 0x35013203, 0x11012003, 0xec001403, 0xc7000e03,
0xa3000c03, 0x80001003, 0x5f001903, 0x42002503, 0x28003603, 0x12004803, 0x00005e03, 0xf3037403, 0xe9038b03,
0xe403a303, 0xe303b903, 0xe603ce03, 0xec03e203, 0xf503f203, 0x00000000, 0x0d000a00, 0x1c001200, 0x2b001700,
0x3a001800, 0x49001600, 0x56001100, 0x62000900, 0x6c000000, 0x7400f503, 0x7900e803, 0x7c00db03, 0x7b00cd03,
0x7800c003, 0x7300b303, 0x6b00a803, 0x61009f03, 0x56009703, 0x4a009203, 0x3c008f03, 0x2f008e03, 0x21009003,
0x15009503, 0x09009c03, 0x0000a403, 0xf803af03, 0xf203ba03, 0xef03c603, 0xee03d303, 0xef03e003, 0xf303ec03,
0xf903f703, 0x00000000, 0x09000700, 0x14000d00, 0x20001100, 0x2d001200, 0x3a001100, 0x46000e00, 0x52000800,
0x5c000000, 0x6400f703, 0x6b00eb03, 0x7000df03, 0x7200d103, 0x7100c403, 0x6e00b603, 0x6900aa03, 0x61009f03,
0x58009503, 0x4d008d03, 0x40008803, 0x33008503, 0x25008403, 0x18008703, 0x0b008c03, 0x00009403, 0xf7039e03,
0xef03aa03, 0xea03b703, 0xe803c603, 0xe903d503, 0xee03e403, 0xf603f303, 0x00000000, 0x0e000b00, 0x1e001400,
0x32001a00, 0x47001d00, 0x5d001c00, 0x75001700, 0x8c000d00, 0xa2000000, 0xb800ee03, 0xcb00d803, 0xdb00be03,
0xe700a103, 0xf0008003, 0xf4005d03, 0xf2003903, 0xec001403, 0xe000ef02, 0xcf00cb02, 0xb800a802, 0x9b008802,
0x7a006c02, 0x55005302, 0x2c003f02, 0x00003102, 0xd2032802, 0xa2032502, 0x71032902, 0x41033302, 0x12034302,
0xe6025902, 0xbc027502, 0x97029702, 0x7502bc02, 0x5902e602, 0x43021203, 0x33024103, 0x29027103, 0x2502a203,
0x2802d203, 0x31020000, 0x3f022c00, 0x53025500, 0x6c027a00, 0x88029b00, 0xa802b800, 0xcb02cf00, 0xef02e000,
0x1403ec00, 0x3903f200, 0x5d03f400, 0x8003f000, 0xa103e700, 0xbe03db00, 0xd803cb00, 0xee03b800, 0x0000a200,
0x0d008c00, 0x17007500, 0x1c005d00, 0x1d004700, 0x1a003200, 0x14001e00, 0x0b000e00, 0x00000000, 0xf303f603,
0xe403ee03, 0xd503e903, 0xc603e803, 0xb703ea03, 0xaa03ef03, 0x9e03f703, 0x94030000, 0x8c030b00, 0x87031800,
0x84032500, 0x85033300, 0x88034000, 0x8d034d00, 0x95035800, 0x9f036100, 0xaa036900, 0xb6036e00, 0xc4037100,
0xd1037200, 0xdf037000, 0xeb036b00, 0xf7036400, 0x00005c00, 0x08005200, 0x0e004600, 0x11003a00, 0x12002d00,
0x11002000, 0x0d001400, 0x07000900, 0x00000000, 0xf703f903, 0xec03f303, 0xe003ef03, 0xd303ee03, 0xc603ef03,
0xba03f203, 0xaf03f803, 0xa4030000, 0x9c030900, 0x95031500, 0x90032100, 0x8e032f00, 0x8f033c00, 0x92034a00,
0x97035600, 0x9f036100, 0xa8036b00, 0xb3037300, 0xc0037800, 0xcd037b00, 0xdb037c00, 0xe8037900, 0xf5037400,
0x00006c00, 0x09006200, 0x11005600, 0x16004900, 0x18003a00, 0x17002b00, 0x12001c00, 0x0a000d00, 0x00000000,
0xf203f503, 0xe203ec03, 0xce03e603, 0xb903e303, 0xa303e403, 0x8b03e903, 0x7403f303, 0x5e030000, 0x48031200,
0x36032800, 0x25034200, 0x19035f00, 0x10038000, 0x0c03a300, 0x0e03c700, 0x1403ec00, 0x20031101, 0x32033501,
0x48035801, 0x65037801, 0x86039401, 0xab03ad01, 0xd403c101, 0x0000cf01, 0x2e00d801, 0x5e00db01, 0x8f00d701,
0xbf00cd01, 0xee00bd01, 0x1a01a701, 0x44018b01
};
int read_rslt[256];
int loop1= 0;
int loop2= 0;
int loop3= 0;
int loop4= 0;
int loop5= 0;
int temp= 0;
printk("<----ip_mkg test start---->\n");
for(loop1=0;loop1<256;loop1++)
read_rslt[loop1]=0x98766789;
printk("<----the initialization of result --->\n");
for(loop2=0;loop2<256;loop2++)
{
iowrite32(write_data[loop2],g_mkg_mem_base+(loop2*4));
}
printk("<----write orignal data --->\n");
iowrite32(0x01000000,g_mkg_core_base+0x4);
printk("<---write control data --->\n"); */
unsigned int * virt_adr;
unsigned int phy_adr;
int write_done=0,read_done=0,read_value=0;
unsigned int final_phy_adr;
char *p;
int read=0;
virt_adr=kmalloc(4,GFP_DMA);
if(!virt_adr)
printk("apply for kernel memory fails !\n");
phy_adr=virt_to_phys(virt_adr);
printk("virtual address !0x%x \n ",virt_adr);
printk("original physical address !0x%x \n",phy_adr); /*
p=(char *)&phy_adr;
final_phy_adr=(unsigned int)(p[3]<<24);
printk("final physical address !0x%x \n ",final_phy_adr);
final_phy_adr=final_phy_adr+(unsigned int)(p[2]<<16);
printk("final physical address !0x%x \n ",final_phy_adr);
final_phy_adr=final_phy_adr+(unsigned int)(p[1]<<8);
printk("final physical address !0x%x \n ",final_phy_adr);
final_phy_adr=final_phy_adr+(unsigned int)(p[0]);
printk("final physical address !0x%x \n ",final_phy_adr); */
// final_phy_adr= (int)(p[0]<<24)+(int)(p[1]<<16)+(int)(p[2]<<8)+(int)(p[3]);
/* *virt_adr=0x6789abcd;
iowrite32(final_phy_adr,g_mkg_core_base+0x4);
printk("read address done !\n");
iowrite32(0x02000000,g_mkg_core_base+0x18);
printk("read commnad done !\n");
read_done=ioread32(g_mkg_core_base+0x10);
read_value=ioread32(g_mkg_core_base+0x14);
printk("<read_done flag: 0x%x >\n",read_done);
printk("<read_value flag: 0x%x >\n",read_value); */
*virt_adr=0x6789bcdf;
final_phy_adr=phy_adr;
// final_phy_adr=0x98000040;
printk("final physical address !0x%x \n ",final_phy_adr);
// test begin
// write first number : final_phy_adr
printk("test begin \n write first number : final_phy_adr\n");
iowrite32(final_phy_adr,g_mkg_core_base+0x4);
printk("write address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("write address : 0x%x \n",read);
iowrite32(0x3956abcd,g_mkg_core_base+0x8);
printk("write value done !\n");
read=ioread32(g_mkg_core_base+0x8);
printk("write value : 0x%x \n",read);
iowrite32(0x01000000,g_mkg_core_base+0x18);
printk("write command done !\n");
printk("write two number: final_phy_adr+4 \n");
// write two number: final_phy_adr+4
iowrite32(final_phy_adr+4,g_mkg_core_base+0x4);
printk("write address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("write address : 0x%x \n",read);
iowrite32(0x3956abcd,g_mkg_core_base+0x8);
printk("write value done !\n");
read=ioread32(g_mkg_core_base+0x8);
printk("write value : 0x%x \n",read);
iowrite32(0x01000000,g_mkg_core_base+0x18);
printk("write command done !\n");
// write third number: final_phy_adr-4
printk("write third number: final_phy_adr-4 \n");
iowrite32(final_phy_adr-4,g_mkg_core_base+0x4);
printk("write address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("write address : 0x%x \n",read);
iowrite32(0x3956abcd,g_mkg_core_base+0x8);
printk("write value done !\n");
read=ioread32(g_mkg_core_base+0x8);
printk("write value : 0x%x \n",read);
iowrite32(0x01000000,g_mkg_core_base+0x18);
printk("write command done !\n");
// write forth number: 0x98000040
printk("write forth number: 98000040 \n");
iowrite32(0x98000040,g_mkg_core_base+0x4);
printk("write address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("write address : 0x%x \n",read);
iowrite32(0x3956abcd,g_mkg_core_base+0x8);
printk("write value done !\n");
read=ioread32(g_mkg_core_base+0x8);
printk("write value : 0x%x \n",read);
iowrite32(0x01000000,g_mkg_core_base+0x18);
printk("write command done !\n");
read=ioread32(g_mkg_core_base+0x18);
printk("write command : 0x%x \n",read);
write_done=ioread32(g_mkg_core_base+0x0c);
// read first number : final_phy_adr
printk("read first number : final_phy_adr\n");
iowrite32(final_phy_adr,g_mkg_core_base+0x4);
printk("read address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("read address : 0x%x \n",read);
iowrite32(0x02000000,g_mkg_core_base+0x18);
printk("read commnad done !\n");
read=ioread32(g_mkg_core_base+0x18);
printk("read command : 0x%x \n",read);
read_done=ioread32(g_mkg_core_base+0x10);
read_value=ioread32(g_mkg_core_base+0x14);
printk("<write_done flag: 0x%x >\n",write_done);
printk("<read from or1200: 0x%x >\n",*virt_adr);
printk("<read_done flag: 0x%x >\n",read_done);
printk("<read_value flag: 0x%x >\n",read_value);
printk(" read second number : final_phy_adr+4\n");
// read second number : final_phy_adr+4
iowrite32(final_phy_adr+4,g_mkg_core_base+0x4);
printk("read address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("read address : 0x%x \n",read);
iowrite32(0x02000000,g_mkg_core_base+0x18);
printk("read commnad done !\n");
read=ioread32(g_mkg_core_base+0x18);
printk("read command : 0x%x \n",read);
read_done=ioread32(g_mkg_core_base+0x10);
read_value=ioread32(g_mkg_core_base+0x14);
printk("<read_done flag: 0x%x >\n",read_done);
printk("<read_value flag: 0x%x >\n",read_value);
printk(" read third number : final_phy_adr-4\n");
// read third number : final_phy_adr-4
iowrite32(final_phy_adr-4,g_mkg_core_base+0x4);
printk("read address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("read address : 0x%x \n",read);
iowrite32(0x02000000,g_mkg_core_base+0x18);
printk("read commnad done !\n");
read=ioread32(g_mkg_core_base+0x18);
printk("read command : 0x%x \n",read);
read_done=ioread32(g_mkg_core_base+0x10);
read_value=ioread32(g_mkg_core_base+0x14);
printk("<read_done flag: 0x%x >\n",read_done);
printk("<read_value flag: 0x%x >\n",read_value);
printk(" read forth number : 0x98000040\n");
// read forth number : 0x98000040
iowrite32(0x98000040,g_mkg_core_base+0x4);
printk("read address done !\n");
read=ioread32(g_mkg_core_base+0x4);
printk("read address : 0x%x \n",read);
iowrite32(0x02000000,g_mkg_core_base+0x18);
printk("read commnad done !\n");
read=ioread32(g_mkg_core_base+0x18);
printk("read command : 0x%x \n",read);
read_done=ioread32(g_mkg_core_base+0x10);
read_value=ioread32(g_mkg_core_base+0x14);
printk("<read_done flag: 0x%x >\n",read_done);
printk("<read_value flag: 0x%x >\n",read_value);
/*
iowrite32(0x40000098,g_mkg_core_base+0x4);
printk("write address done !\n");
iowrite32(0x1234abcd,g_mkg_core_base+0x8);
printk("write value done !\n");
iowrite32(0x01000000,g_mkg_core_base+0x18);
printk("write command done !\n");
iowrite32(0x40000098,g_mkg_core_base+0x4);
printk("read address done !\n");
iowrite32(0x02000000,g_mkg_core_base+0x18);
printk("read commnad done !\n");
write_done=ioread32(g_mkg_core_base+0x0c);
read_done=ioread32(g_mkg_core_base+0x10);
read_value=ioread32(g_mkg_core_base+0x14);
printk("<write_done flag: 0x%x >\n",write_done);
printk("<read_done flag: 0x%x >\n",read_done);
printk("<read_value flag: 0x%x >\n",read_value);
*/
//printk("<----write control data: 0x01000000 end value:0x%x ---->\n",ioread32(g_mkg_core_base+4));
// iowrite32(0x03000000,g_mkg_core_base+0x8);
// printk("<----write control data: 0x03000000 end value:0x%x---->\n",ioread32(g_mkg_core_base+8));
// mdelay(100);
// mdelay(100);
// mdelay(100);
// mdelay(100);
// printk("<----delay ends ---->\n");
// temp=ioread32(g_mkg_core_base);
// printk("<-------my core status:0x%x--->\n",temp);
/*
while(1)
{
temp=ioread32(g_mkg_mem_base+0x804);
if(temp==0x10101010)
break;
printk("<-------my core status:0x%x--->\n",temp);
mdelay(1);
}
printk("<----waiting ends ---->\n");
mdelay(100);
printk("<----delay ends ---->\n");
for(loop3=0;loop3<256;loop3++)
{
read_rslt[loop3]=ioread32(g_mkg_mem_base+0x00000400+(loop3*4));
}
printk("<----read rslt from ram ---->\n");
temp=ioread32(g_mkg_mem_base+0x00000800);
printk("<-------my clock cnt:0x%x--->\n",temp);
for(loop4=0;loop4<256;loop4++)
{
printk("====mem read addr==0x%x==mem value:0x%x==\n",loop4,read_rslt[loop4]);
}
*/
/*
for(loop2=0;loop2<256;loop2++)
{
temp=ioread32(temp_addr);
printk("====mem read addr==0x%x==mem value:0x%x==\n",temp_addr,temp);
temp_addr=temp_addr+4;
}
udelay(1000);
printk("<----ip_mkg read initial value ends---->\n");
temp_addr=g_mkg_mem_base;
for(loop=0;loop<256;loop++)
{
iowrite32(loop,temp_addr);
printk("====mem write addr==0x%x==mem value:0x%x==\n",temp_addr,loop);
temp_addr=temp_addr+4;
}
udelay(1000);
printk("<----ip_mkg write end---->\n\n\n");
temp_addr=g_mkg_mem_base;
for(loop1=0;loop1<256;loop1++)
{
temp=ioread32(temp_addr);
printk("====mem read addr==0x%x==mem value:0x%x==\n",temp_addr,temp);
temp_addr=temp_addr+4;
}
printk("<----ip_mkg test end---->\n");
#endif
int loop = 0;
unsigned int phy_addr1 = 0;
unsigned int phy_addr2 = 0;
int * virtual_addr1 = NULL;
int * virtual_addr2 = NULL;
printk("<----ip_mkg test start---->\n");
//=====ip_mkg reg test========================================================
#if 1
printk("reg test start==\n");
iowrite32(0x11223344,g_mkg_mem_base);
iowrite32(0x00000097,g_mkg_mem_base+0x10);
iowrite32(0x03000000,g_mkg_mem_base+4);
printk("reg test start1==\n");
printk("reg test start2==\n");
printk("reg test start3==\n");
for(loop=0;loop<7;loop++)
printk("====reg addr==0x%x==reg value:0x%x==\n",loop*4,ioread32(g_mkg_mem_base+4*loop));
#endif
//=========================================================================
//============mem write test
#if 0
printk("mem write test start==\n");
iowrite32(0x97000004,g_mkg_mem_base);
iowrite32(0x2,g_mkg_mem_base+0xc);
printk("======reg:c value:0x%x==\n",ioread32(g_mkg_mem_base+0xc));
printk("======reg:14 value:0x%x==\n",ioread32(g_mkg_mem_base+0x14));
printk("======reg:18 value:0x%x==\n",ioread32(g_mkg_mem_base+0x18));
printk("======reg:1c value:0x%x==\n",ioread32(g_mkg_mem_base+0x1c));
printk("======reg:20 value:0x%x==\n",ioread32(g_mkg_mem_base+0x20));
printk("======reg:24 value:0x%x==\n",ioread32(g_mkg_mem_base+0x24));
for(loop = 0;loop<10;loop++)
printk("wait=write=\n");
printk("wait=write=\n");
iowrite32(0x1,g_mkg_mem_base+0xc);
printk("======reg:c value:0x%x==\n",ioread32(g_mkg_mem_base+0xc));
for(loop = 0;loop<10;loop++)
printk("wait=read=\n");
printk("wait=read=\n");
printk("======reg:10 value:0x%x==\n",ioread32(g_mkg_mem_base+0x10));
printk("======reg:c value:0x%x==\n\n",ioread32(g_mkg_mem_base+0xc));
#endif
//============mem read test
#if 0
printk("mem read test start==\n");
virtual_addr1 = (int *)kmalloc(sizeof(int), GFP_KERNEL);
virtual_addr2 = (int *)kmalloc(sizeof(int), GFP_KERNEL);
*virtual_addr1 = 0x55;
*virtual_addr2 = 0x66;
phy_addr1 = virt_to_phys(virtual_addr1);
phy_addr2 = virt_to_phys(virtual_addr2);
printk("virtual addr1:0x%x==phy addr1:0x%x==\n",(int)virtual_addr1,phy_addr1);
printk("virtual addr2:0x%x==phy addr2:0x%x==\n",(int)virtual_addr2,phy_addr2);
iowrite32(phy_addr1,g_mkg_mem_base);
iowrite32(0x1,g_mkg_mem_base+0xc);
printk("wait=read=\n");
printk("======reg:0 value:0x%x==\n",ioread32(g_mkg_mem_base));
printk("======reg:c value:0x%x==\n",ioread32(g_mkg_mem_base+0xc));
printk("====phy addr1==0x%x==ram value:0x%x==\n",phy_addr1,ioread32(g_mkg_mem_base+0x10));
printk("======reg:c value:0x%x==\n\n",ioread32(g_mkg_mem_base+0xc));
iowrite32(phy_addr2,g_mkg_mem_base);
iowrite32(0x1,g_mkg_mem_base+0xc);
printk("wait=2=\n");
printk("======reg:0 value:0x%x==\n",ioread32(g_mkg_mem_base));
printk("======reg:c value:0x%x==\n",ioread32(g_mkg_mem_base+0xc));
printk("====phy addr2==0x%x==ram value:0x%x==\n",phy_addr2,ioread32(g_mkg_mem_base+0x10));
printk("======reg:c value:0x%x==\n\n",ioread32(g_mkg_mem_base+0xc));
kfree(virtual_addr1);
kfree(virtual_addr2);
#endif
printk("<----ip_mkg test end---->\n"); */
}
int init_module()
{
int ret_val;
int ret;
int ret2;
void __iomem *ret_from_request;
void __iomem *ret_from_request2;
//=== 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");
ret2 = check_mem_region(MKG_CORE_BASE, MKG_CORE_LEN);
if (ret2 < 0)
{
printk(KERN_ERR "mkg check_mem_region bussy error!\n");
return -1;
}
ret_from_request2 = request_mem_region(MKG_CORE_BASE, MKG_CORE_LEN, "ip_mkg");
//===ioremap mkg registers
g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
if(NULL == g_mkg_mem_base)
{
printk(KERN_ERR "mkg mem ioremap error!\n");
return -1;
}
else
{
;//printk("mkg ioremap addr:%d!\n",(unsigned int)g_mkg_mem_base);
}
g_mkg_core_base = ioremap(MKG_CORE_BASE,MKG_CORE_LEN);
if(NULL == g_mkg_core_base)
{
printk(KERN_ERR "mkg core ioremap error!\n");
return -1;
}
else
{
;//printk("mkg ioremap addr:%d!\n",(unsigned int)g_mkg_mem_base);
}
printk("mkg module init done!\n");
// test();
return 0;
}
void cleanup_module()
{
release_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);
release_mem_region(MKG_CORE_BASE,MKG_CORE_LEN);
unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rill zhen:rill_zhen@126.com");
ip_mkg.h:
#ifndef __IP_MKG_H__
#define __IP_MKG_H__
#define MAJOR_NUM 102
#define DEVICE_NAME "ip_mkg"
#define MKG_MEM_BASE 0x98000000
#define MKG_MEM_LEN 1024
#define MKG_CORE_BASE 0x97000000
#define MKG_CORE_LEN 1024
#define IOCTL_REG_SET 0
#define IOCTL_REG_GET 1
struct reg_data
{
unsigned short addr;
int value;
};
#endif
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 clean
else
# called from kernel build system: just declare what our modules are
obj-m := ip_mkg.o
endif
2》用户层代码
main.c:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
int main()
{
int mkg_fd=0;
mkg_fd=open("/dev/ip_mkg",O_RDWR);
char * mkg_p=0;
if(!mkg_fd)
{
printf("Error: cant open ip_mkg device.\n");
exit(1);
}
printf("The ip_mkg device is open now .\n");
mkg_p=(char *)mmap(0,sizeof(int)*256,PROT_READ | PROT_WRITE,MAP_SHARED,mkg_fd,0);
if((int)mkg_p ==-1)
{
printf("Error: fail to map device to memory .\n");
exit(4);
}
printf("Map succuss!\n");
printf("mkg_p is 0x%x \n",mkg_p);
*((unsigned int *)(mkg_p+0x4))=0x98000040;
printf("write address! 0x%x !\n",*((unsigned int *)(mkg_p+0x4)));
*((unsigned int *)(mkg_p+0x8))=0x6789bcdf;
printf("write value ! 0x%x !\n",*((unsigned int *)(mkg_p+0x8)));
*((unsigned int *)(mkg_p+0x18))=0x00000001;
printf("write command ! 0x%x ~\n",*((unsigned int *)(mkg_p+0x18)));
*((unsigned int *)(mkg_p+0x4))=0x98000040;
printf("read address! 0x%x !\n",*((unsigned int *)(mkg_p+0x4)));
*((unsigned int * )(mkg_p+0x18))=0x00000002;
printf("read command ! 0x%x ~\n",*((unsigned int *)(mkg_p+0x18)));
printf(" read done flag ! 0x%x \n",*((unsigned int *)(mkg_p+0x10)));
printf(" read value ! 0x%x \n", *((unsigned int *)(mkg_p+0x14)));
printf("write done flag ! 0x%x \n",*((unsigned int *)(mkg_p+0xc)));
munmap(mkg_p,sizeof(int)*256);
close(mkg_fd);
return 0;
}
3,硬件部分
硬件部分和之前的内容差异不大,详细信息请参考之前的内容,为了保持小节的独立性,这里直接贴出完整rtl:mycore.v,mymaster.v,myslave.v,myram.v:
mycore.v:
/*
* rill create 2013-06-25
* rillzhen@gmail.com
*/
module mycore
(
//===slave interface signals
wb_clk,
wb_rst,
wbs_d_mycore_dat_o,
wbs_d_mycore_ack_o,
wbs_d_mycore_err_o,
wbs_d_mycore_rty_o,
wbs_d_mycore_adr_i,
wbs_d_mycore_dat_i,
wbs_d_mycore_sel_i,
wbs_d_mycore_we_i,
wbs_d_mycore_cyc_i,
wbs_d_mycore_stb_i,
wbs_d_mycore_cti_i,
wbs_d_mycore_bte_i,
//===master interface signals
wbm_d_mycore_dat_i,
wbm_d_mycore_ack_i,
wbm_d_mycore_err_i,
wbm_d_mycore_rty_i,
wbm_d_mycore_adr_o,
wbm_d_mycore_dat_o,
wbm_d_mycore_sel_o,
wbm_d_mycore_we_o,
wbm_d_mycore_cyc_o,
wbm_d_mycore_stb_o,
wbm_d_mycore_cti_o,
wbm_d_mycore_bte_o
);
input wb_clk;
input wb_rst;
output [31:0] wbs_d_mycore_dat_o;
output wbs_d_mycore_ack_o;
output wbs_d_mycore_err_o;
output wbs_d_mycore_rty_o;
input [31:0] wbs_d_mycore_adr_i;
input [31:0] wbs_d_mycore_dat_i;
input [3:0] wbs_d_mycore_sel_i;
input wbs_d_mycore_we_i;
input wbs_d_mycore_cyc_i;
input wbs_d_mycore_stb_i;
input [2:0] wbs_d_mycore_cti_i;
input [1:0] wbs_d_mycore_bte_i;
input [31:0] wbm_d_mycore_dat_i;
input wbm_d_mycore_ack_i;
input wbm_d_mycore_err_i;
input wbm_d_mycore_rty_i;
output [31:0] wbm_d_mycore_adr_o;
output [31:0] wbm_d_mycore_dat_o;
output [3:0] wbm_d_mycore_sel_o;
output wbm_d_mycore_we_o;
output wbm_d_mycore_cyc_o;
output wbm_d_mycore_stb_o;
output [2:0] wbm_d_mycore_cti_o;
output [1:0] wbm_d_mycore_bte_o;
wire [31:0] address;
wire [31:0] value;
wire write;
wire read;
wire read_ack;
wire write_ack;
wire [31:0] value_ack;
myslave myslave0
(
.wb_clk(wb_clk),
.wb_rst(wb_rst),
.wb_adr_i(wbs_d_mycore_adr_i),
.wb_dat_i(wbs_d_mycore_dat_i),
.wb_sel_i(wbs_d_mycore_sel_i),
.wb_we_i(wbs_d_mycore_we_i),
.wb_cyc_i(wbs_d_mycore_cyc_i),
.wb_stb_i(wbs_d_mycore_stb_i),
.wb_cti_i(wbs_d_mycore_cti_i),
.wb_bte_i(wbs_d_mycore_bte_i),
.wb_dat_o(wbs_d_mycore_dat_o),
.wb_ack_o(wbs_d_mycore_ack_o),
.wb_err_o(wbs_d_mycore_err_o),
.wb_rty_o(wbs_d_mycore_rty_o),
.address_o(address),
.value_o(value),
.write_o(write),
.read_o(read),
.write_ack(write_ack),
.read_ack(read_ack),
.value_ack(value_ack)
);
mymaster mymaster0
(
.wb_clk (wb_clk),
.wb_rst (wb_rst),
.wb_adr_o (wbm_d_mycore_adr_o),
.wb_dat_o (wbm_d_mycore_dat_o),
.wb_sel_o (wbm_d_mycore_sel_o),
.wb_we_o (wbm_d_mycore_we_o),
.wb_cyc_o (wbm_d_mycore_cyc_o),
.wb_stb_o (wbm_d_mycore_stb_o),
.wb_cti_o (wbm_d_mycore_cti_o),
.wb_bte_o (wbm_d_mycore_bte_o),
.wb_dat_i (wbm_d_mycore_dat_i),
.wb_ack_i (wbm_d_mycore_ack_i),
.wb_err_i (wbm_d_mycore_err_i),
.wb_rty_i (wbm_d_mycore_rty_i),
//internal signals
.write_i (write),
.read_i (read),
.address_i (address),
.value_i (value),
.write_ack (write_ack),
.read_ack (read_ack),
.value_o (value_ack)
);
endmodule
/************** EOF ****************/
mymaster:
module mymaster
(
wb_clk,
wb_rst,
wb_adr_o,
wb_dat_o,
wb_sel_o,
wb_we_o,
wb_cyc_o,
wb_stb_o,
wb_cti_o,
wb_bte_o,
wb_dat_i,
wb_ack_i,
wb_err_i,
wb_rty_i,
write_i ,
read_i ,
address_i,
value_i ,
write_ack ,
read_ack,
value_o
);
//wishbone interface
input wb_clk;
input wb_rst;
input wb_ack_i;
input wb_err_i;
input wb_rty_i;
input [31:0] wb_dat_i;
output reg [31:0] wb_adr_o;
output reg [31:0] wb_dat_o;
output reg wb_cyc_o;
output reg wb_stb_o;
output reg [3:0] wb_sel_o;
output reg wb_we_o;
output reg [2:0] wb_cti_o;
output reg [1:0] wb_bte_o;
input write_i;
input read_i;
input [31:0] address_i;
input [31:0] value_i;
output reg [31:0] value_o;
output reg write_ack;
output reg read_ack;
parameter m_idle = 9'b000000001;
parameter m_write_ready = 9'b010000000;
parameter m_read_ready = 9'b100000000;
parameter m_write_begin = 9'b000000010;
parameter m_write_wait = 9'b000000100;
parameter m_write_done = 9'b000001000;
parameter m_read_begin = 9'b000010000;
parameter m_read_wait = 9'b000100000;
parameter m_read_done = 9'b001000000;
parameter cti_default = 3'b000;
parameter bte_default = 2'b00;
parameter sel_default = 4'b1111;
reg [8:0] state,next_state;
always @(posedge wb_clk)
if(wb_rst)
state<=m_idle;
else
state<=next_state;
always @(*)
case(state)
m_idle:
begin
if(write_i)
next_state=m_write_ready;
else if(read_i)
next_state=m_read_ready;
else
next_state=m_idle;
end
m_write_ready:
begin
next_state=m_write_begin;
end
m_read_ready:
begin
next_state=m_read_begin;
end
m_write_begin:
begin
next_state=m_write_wait;
end
m_write_wait:
begin
if(wb_ack_i)
next_state=m_write_done;
else
next_state=m_write_wait;
end
m_write_done:
begin
next_state=m_idle;
end
m_read_begin:
begin
next_state=m_read_wait;
end
m_read_wait:
begin
if(wb_ack_i)
next_state=m_read_done;
else
next_state=m_read_wait;
end
m_read_done:
begin
next_state=m_idle;
end
default:
begin
next_state=m_idle;
end
endcase
always @ (posedge wb_clk)
if(wb_rst)
begin
wb_adr_o<=0;
wb_dat_o<=0;
wb_sel_o<=sel_default;
wb_we_o<=0;
wb_cyc_o<=0;
wb_stb_o<=0;
wb_cti_o<=cti_default;
wb_bte_o<=bte_default;
write_ack<=0;
read_ack<=0;
value_o <=0;
end
else
begin
case(next_state)
m_idle:
begin
wb_adr_o<=0;
wb_dat_o<=0;
wb_sel_o<=sel_default;
wb_we_o<=0;
wb_cyc_o<=0;
wb_stb_o<=0;
wb_cti_o<=cti_default;
wb_bte_o<=bte_default;
write_ack<=0;
read_ack<=0;
value_o <=0;
end
m_write_ready:
begin
wb_adr_o<=0;
wb_dat_o<=0;
wb_cyc_o<=0;
wb_stb_o<=0;
wb_we_o<=0;
end
m_read_ready:
begin
wb_adr_o<=0;
wb_dat_o<=0;
wb_cyc_o<=0;
wb_stb_o<=0;
wb_we_o<=0;
end
m_write_begin:
begin
wb_adr_o<=address_i;
wb_dat_o<=value_i;
wb_cyc_o<=1'b1;
wb_stb_o<=1'b1;
wb_we_o<=1'b1;
end
m_write_wait:
begin
wb_adr_o<=wb_adr_o;
wb_dat_o<=wb_dat_o;
wb_cyc_o<=wb_cyc_o;
wb_stb_o<=wb_stb_o;
wb_we_o<=wb_we_o;
end
m_write_done:
begin
wb_adr_o<=0;
wb_dat_o<=0;
wb_cyc_o<=0;
wb_stb_o<=0;
wb_we_o<=0;
write_ack<=1'b1;
end
m_read_begin:
begin
wb_adr_o<=address_i;
wb_dat_o<=0;
wb_cyc_o<=1'b1;
wb_stb_o<=1'b1;
wb_we_o<=0;
end
m_read_wait:
begin
wb_adr_o<=wb_adr_o;
wb_dat_o<=wb_dat_o;
wb_cyc_o<=wb_cyc_o;
wb_stb_o<=wb_stb_o;
wb_we_o <=0;
end
m_read_done:
begin
wb_adr_o<=0;
wb_dat_o<=0;
wb_cyc_o<=0;
wb_stb_o<=0;
wb_we_o<=0;
read_ack<=1'b1;
value_o<=wb_dat_i;
end
default:
begin
wb_adr_o<=0;
wb_dat_o<=0;
wb_sel_o<=sel_default;
wb_we_o<=0;
wb_cyc_o<=0;
wb_stb_o<=0;
wb_cti_o<=cti_default;
wb_bte_o<=bte_default;
write_ack<=0;
read_ack<=0;
value_o <=0;
end
endcase
end
endmodule
myslave.v:
module myslave
(
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,
address_o,
value_o,
write_o,
read_o,
write_ack,
read_ack,
value_ack
);
input wb_clk;
input wb_rst;
input [31: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 [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;
output reg [31:0] address_o;
output reg [31:0] value_o;
output reg write_o;
output reg read_o;
input write_ack;
input read_ack;
input [31:0] value_ack;
parameter address_adr =8'h04;
parameter value_adr =8'h08;
parameter wr_adr =8'h18;
parameter write_done_adr =8'h0c;
parameter read_done_adr =8'h10;
parameter value_ack_adr =8'h14;
parameter err_code =32'habcd_1234;
parameter default_code =32'h4875_efad;
parameter read_command =32'h0000_0002;
parameter write_command =32'h0000_0001;
parameter s_idle =9'b000000001;
parameter s_write_done =9'b000000010;
parameter s_read_done =9'b000000100;
parameter s_read =9'b000001000;
parameter s_write =9'b000010000;
parameter s_read_pause =9'b000100000;
parameter s_write_pause1 =9'b001000000;
parameter s_write_pause2 =9'b010000000;
parameter s_write_pause3 =9'b100000000;
reg [8:0] state,next_state;
reg [31:0] value_reg;
reg write_done;
reg read_done;
reg [31:0] address_reg;
reg [31:0] value_i_reg;
reg [31:0] wr_reg;
reg [31:0] write_ack_done;
always @(posedge wb_clk)
if(wb_rst)
write_ack_done<=0;
else if(write_ack)
write_ack_done<=32'h1;
else if(write_o)
write_ack_done<=0;
assign wb_err_o=0;
assign wb_rty_o=0;
always @(posedge wb_clk)
if(wb_rst)
state<=s_idle;
else
state<=next_state;
always @(*)
begin
case(state)
s_idle:
begin
if(write_ack)
next_state=s_write_done;
else if(read_ack)
next_state=s_read_done;
else if(wb_stb_i && wb_cyc_i && wb_we_i)
next_state=s_write;
else if(wb_stb_i && wb_cyc_i && !wb_we_i)
next_state=s_read;
else
next_state=s_idle;
end
s_write_done:
begin
next_state=s_idle;
end
s_read_done:
begin
next_state=s_idle;
end
s_write:
begin
next_state=s_write_pause1;
end
s_write_pause1:
begin
next_state=s_write_pause2;
end
s_read:
begin
next_state=s_read_pause;
end
s_read_pause:
begin
next_state=s_idle;
end
s_write_pause2:
begin
next_state=s_write_pause3;
end
s_write_pause3:
begin
next_state=s_idle;
end
default:
begin
next_state=s_idle;
end
endcase
end
always @(posedge wb_clk)
if(wb_rst)
begin
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
value_reg<=0;
read_done<=0;
write_done<=0;
address_reg<=0;
value_i_reg<=0;
wr_reg <=0;
//wb_dat_o<=0;
// wb_dat_o<=err_code;
wb_dat_o<=default_code;
wb_ack_o<=0;
end
else
begin
case(next_state)
s_idle:
begin
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
// wb_dat_o<=0;
// wb_dat_o<=err_code;
wb_dat_o<=default_code;
wb_ack_o<=0;
end
s_read_done:
begin
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
//wb_dat_o<=0;
//wb_dat_o<=err_code;
wb_dat_o<=default_code;
wb_ack_o<=0;
read_done<=1'b1;
value_reg<=value_ack;
end
s_write_done:
begin
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
// wb_dat_o<=0;
// wb_dat_o<=err_code;
wb_dat_o<=default_code;
wb_ack_o<=0;
write_done<=1'b1;
end
s_read:
begin
if(wb_adr_i[7:0] == value_ack_adr)
// wb_dat_o<={value_reg[7:0],value_reg[15:8],value_reg[23:16],value_reg[31:24]};
wb_dat_o<=value_reg;
// wb_dat_o<={value_reg[7:0],value_reg[15:8],value_reg[23:16],wb_adr_i[7:0]};
else if(wb_adr_i[7:0] == write_done_adr)
// wb_dat_o<={write_done,23'b0,wb_adr_i[7:0]};
wb_dat_o<=write_ack_done;
// wb_dat_o<={write_done,23'b0,wb_adr_i[7:0]};
else if(wb_adr_i[7:0] == read_done_adr)
wb_dat_o<={read_done,31'b0};
// wb_dat_o<={read_done,23'b0,wb_adr_i[7:0]};
else if(wb_adr_i[7:0] == address_adr)
// wb_dat_o<={address_reg[7:0],address_reg[15:8],address_reg[23:16],address_reg[31:24]};
wb_dat_o<=address_reg;
//wb_dat_o<={address_reg[7:0],address_reg[15:8],address_reg[23:16],wb_adr_i[7:0]};
else if(wb_adr_i[7:0] == wr_adr)
wb_dat_o<=wr_reg;
// wb_dat_o<={wr_reg[23:0],wb_adr_i[7:0]};
else if(wb_adr_i[7:0] == value_adr)
wb_dat_o<=value_i_reg;
//wb_dat_o<={value_i_reg[31:8],wb_adr_i[7:0]};
else
// wb_dat_o<=wb_adr_i;
wb_dat_o<=err_code;
wb_ack_o<=0;
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
end
s_read_pause:
begin
// wb_dat_o<=wb_dat_o;
wb_dat_o<=wb_dat_o;
wb_ack_o<=1'b1;
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
end
s_write:
begin
if(wb_adr_i[7:0]== address_adr)
// address_reg<={wb_dat_i[7:0],wb_dat_i[15:8],wb_dat_i[23:16],wb_dat_i[31:24]};
address_reg<=wb_dat_i;
else if(wb_adr_i[7:0] == value_adr)
value_i_reg<=wb_dat_i;
else if(wb_adr_i[7:0] == wr_adr)
wr_reg <= wb_dat_i;
wb_ack_o <=0;
// wb_dat_o <=0;
wb_dat_o<=err_code;
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
end
s_write_pause1:
begin
if(wr_reg == read_command)
begin
read_o<=1'b1;
address_o<=address_reg;
// wb_ack_o<=1'b1;
// wb_dat_o<=0;
// address_reg<=0;
// wr_reg<=0;
// value_reg<=0;
// read_done<=0;
end
else if(wr_reg == write_command)
begin
write_o<=1'b1;
// address_o<={address_reg[7:0],address_reg[15:8],address_reg[23:16],address_reg[31:24]};
address_o<=address_reg;
value_o<=value_i_reg;
// wb_ack_o<=1'b1;
// wb_dat_o<=0;
// value_i_reg<=0;
// address_reg<=0;
// wr_reg <=0;
// write_done<=0;
end
else
begin
write_o<=0;
read_o<=0;
// wb_ack_o<=1'b1;
// wb_dat_o<=0;
address_o<=0;
value_o<=0;
end
end
s_write_pause2:
begin
if(wr_reg == read_command)
begin
read_o<=1'b1;
address_o<=address_reg;
// wb_ack_o<=1'b1;
// wb_dat_o<=0;
// address_reg<=0;
// wr_reg<=0;
// value_reg<=0;
// read_done<=0;
end
else if(wr_reg == write_command)
begin
write_o<=1'b1;
// address_o<={address_reg[7:0],address_reg[15:8],address_reg[23:16],address_reg[31:24]};
address_o<=address_reg;
value_o<=value_i_reg;
// wb_ack_o<=1'b1;
// wb_dat_o<=0;
// value_i_reg<=0;
// address_reg<=0;
// wr_reg <=0;
// write_done<=0;
end
else
begin
write_o<=0;
read_o<=0;
// wb_ack_o<=1'b1;
// wb_dat_o<=0;
address_o<=0;
value_o<=0;
end
end
s_write_pause3:
begin
if(wr_reg == read_command)
begin
read_o<=0;
address_o<=0;
wb_ack_o<=1'b1;
// wb_dat_o<=0;
wb_dat_o<=err_code;
address_reg<=0;
wr_reg<=0;
value_reg<=0;
read_done<=0;
end
else if(wr_reg == write_command)
begin
write_o<=0;
address_o<=0;
value_o<=0;
wb_ack_o<=1'b1;
// wb_dat_o<=0;
wb_dat_o<=err_code;
address_reg<=0;
wr_reg<=0;
value_i_reg<=0;
// write_done<=0;
end
else
begin
write_o<=0;
read_o<=0;
wb_ack_o<=1'b1;
// wb_dat_o<=0;
wb_dat_o<=err_code;
address_o<=0;
value_o<=0;
end
end
default:
begin
address_o<=0;
value_o <=0;
write_o <=0;
read_o <=0;
value_reg<=0;
read_done<=0;
write_done<=0;
address_reg<=0;
value_i_reg<=0;
wr_reg <=0;
wb_dat_o<=default_code;
// wb_dat_o<=0;
wb_ack_o<=0;
end
endcase
end
endmodule
myram.v:
module myram
(
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 wb_clk;
input wb_rst;
input [31: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 [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;
parameter myram_adr =32'h9800_0040;
parameter err_code =32'h1234_3456;
parameter ram_idle = 4'b0001;
parameter ram_read = 4'b0010;
parameter ram_write = 4'b0100;
reg [3:0] state, next_state;
reg [31:0] value;
assign wb_err_o = 0 ;
assign wb_rty_o = 0;
always @(posedge wb_clk)
if(wb_rst)
state <= ram_idle;
else
state <= next_state;
always @(*)
case(state)
ram_idle:
begin
if(wb_stb_i && wb_cyc_i && wb_we_i && (wb_adr_i == myram_adr))
next_state = ram_write;
else if (wb_stb_i && wb_cyc_i && !wb_we_i && (wb_adr_i == myram_adr))
next_state = ram_read;
else
next_state = ram_idle;
end
ram_write:
begin
next_state = ram_idle;
end
ram_read:
begin
next_state = ram_idle;
end
default:
begin
next_state = ram_idle;
end
endcase
always @ (posedge wb_clk)
if(wb_rst)
begin
wb_ack_o <=0;
wb_dat_o <=0;
value <=err_code;
end
else
begin
case(next_state)
ram_idle:
begin
wb_ack_o<=0;
wb_dat_o<=0;
end
ram_write:
begin
wb_ack_o<=1'b1;
wb_dat_o<=0;
value<=wb_dat_i;
end
ram_read:
begin
wb_ack_o<=1'b1;
wb_dat_o<=value;
end
default:
begin
wb_ack_o <= 0;
wb_dat_o <= 0;
value <= err_code;
end
endcase
end
endmodule
4,验证
经过上述的分析和实现,在进行综合,烧板,起linux,insmod,mknod,./a.out之后,就可以看到验证结果了,如下图,可以看出,AP层程序可以直接控制ipcore:
注:在AP层编写程序时,不存在大小端转换的问题,所以本小节的所有代码(包括硬件/软件)中,均没有大小端转换的内容,这是与之前内容的最大不同。
5,小结
本小节实现了用户程序直接访问ipcore的地址空间,减少了CPU的数据搬运操作,可有效提供系统的性能。
enjoy!