zoukankan      html  css  js  c++  java
  • OpenRisc26openrisc中断实验


     

     引言

     中断(异常)系统,可以说是计算机体系结构重要的组成部分,也是最复杂的部分。
     现在的很多外设,都提供中断处理机制,来减少CPU的一直占用时间。
     本小节就通过一个简单的例子,来说明openrisc的中断机制的使用方法。
     

     1,功能简介

     本小节实现一个wishbone slave模块(mycore),此模块接收其对应的linux driver的指令,产生中断信号。
     linux driver注册中断处理程序,记录中断发生的次数。
     本实验中,在模块加载时(insmod ip_mkg.ko)时触发一次中断。在测试程序read时触发一次中断。
     通过代码内部打印查看结果,通过cat /proc/stat查看结果。
     

     2,OR中断资源分析

     2.1 硬件部分

     
     1,通过下面的代码可以看出:
     OR最多支持的外部中断线的数目为:31.其中只有(2~31)可以使用。

     



     2,通过下面的代码可以看出:

    目前已经使用的中断线为:2~23。


     3,通过下面的综合结果可以看出:

    真正使用的为:2,4,6,14,15,16,20,21.共8根。具体如下:
    SDC:3根。
    USB:2根。
    UART:1根。
    simple_spi:1根。
    eth:1根。

    2.2 软件部分

    通过下面的linux kernel代码可以看出:
    OR的中断线有32根。(与硬件不匹配)。

     2.3 本实验使用的中断线为:24。

     

     3,实验内容

    3.1 RTL编码

    1>mycore.v

    /*
    *
    * rill create 2013-05-07
    *
    */
    
    `include "orpsoc-defines.v"
    module mycore
    (     
    	intr_o,//interrupt output
    	
    	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
    );
    output  reg					 	intr_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 parameters
    parameter addr_width = 32;
    parameter mycore_adr = 0;
    
    	
    
    //local regs
    reg [addr_width-1:0] num_1;
    reg [addr_width-1:0] num_2;
    reg [addr_width-1:0] sum;
    
    
    parameter s_idle = 3'b000;
    parameter s_read = 3'b001;
    parameter s_write = 3'b010;
    
    reg [2:0] state = s_idle;
    
    //irq status
    parameter irq_idle = 3'b000;
    parameter irq_action = 3'b001;
    
    reg [2:0] irq_state = irq_idle;
    reg [7:0] irq_done;//irq flag
    
    assign wb_err_o=0;
    assign wb_rty_o=0;
    
    
    always @(*)//sum process
    begin
    	sum = num_1 + num_2;
    end
    
    always @(posedge wb_clk)//interrupt process
    begin
    	if(wb_rst)
    		begin
    			intr_o <= 1'b0;
    		end
    	else
    		begin
    			case (irq_state)
    			irq_idle:
    				begin
    					intr_o <= 1'b0;
    					
    					if( (32'd1 == num_1) && (irq_done == 8'd0) )
    						begin
    							irq_state <= irq_action;
    							irq_done <= 8'd1;
    						end
    					else if( (32'd2 == num_1) && (irq_done == 8'd1) )
    						begin
    							irq_state <= irq_action;
    							irq_done <= 8'd2;
    						end
    					else if( (32'd3 == num_1) && (irq_done == 8'd2) )
    						begin
    							irq_state <= irq_action;
    							irq_done <= 8'd3;
    						end
    					else if( (32'd4 == num_1) && (irq_done == 8'd3) )
    						begin
    							irq_state <= irq_action;
    							irq_done <= 8'd4;
    						end
    					else
    						begin
    							irq_state <= irq_idle;
    						end
    				end
    				
    			irq_action:
    				begin
    					intr_o <= 1'b1;
    					irq_state <= irq_idle;
    				end
    				
    			default:
    				begin
    					irq_state <= irq_idle;
    					intr_o <= 1'b0;
    				end
    			endcase
    		end
    end
    
    always @(posedge wb_clk)//wishbone interface
    begin
    	if(wb_rst)
    		begin
    			state <= s_idle;
    		end
    	else
    		begin
    			case(state)
    			s_idle:
    				begin
    					wb_dat_o <= 1'b0;
    					wb_ack_o <= 1'b0;
    			
    					if(wb_stb_i && wb_cyc_i && wb_we_i)
    						begin
    							state <= s_write;
    						end
    					else if(wb_stb_i && wb_cyc_i && !wb_we_i)
    						begin
    							state <= s_read;
    						end
    					else
    						begin
    							state <= s_idle;
    						end
    				end
    	
    			s_write:
    				begin
    					if(wb_adr_i == {mycore_adr,24'h000000})
    						begin
    							num_1 <= wb_dat_i;
    							wb_ack_o <= 1'b1;
    						end
    					else if(wb_adr_i == {mycore_adr,24'h000004})
    						begin
    							num_2 <= wb_dat_i;
    							wb_ack_o <= 1'b1;
    						end
    					else 
    						begin
    							//wb_ack_o=1'b0;
    						end
    				
    					state <= s_idle;
    				end
      
    			s_read:
    				begin
    					if(wb_adr_i=={mycore_adr,24'h000000})
    						begin
    							wb_dat_o <= num_1;
    							wb_ack_o <= 1'b1;
    						end
    					else if(wb_adr_i=={mycore_adr,24'h000004})
    						begin
    							wb_dat_o <= num_2;
    							wb_ack_o <= 1'b1;
    						end
    					else if(wb_adr_i=={mycore_adr,24'h000008})
    						begin
    							wb_dat_o <= sum;
    							wb_ack_o <= 1'b1;
    						end
    					else 
    						begin
    							wb_dat_o=0;
    							wb_ack_o <= 1'b1;
    						end
    				
    					state <= s_idle;
    
    				end
    		
    		
    			default:
    				begin
    					state <= s_idle;
    				end
    		
    			endcase
    		end
    end
    
    endmodule
    
    
    /************** EOF ****************/




    2>例化:orpsoc_top.v

    3.2 RTL综合

    如下图,中断线多了一根:共9根。

    3.3 linux driver编码

    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 <asm-generic/io.h>
    
    #include "ip_mkg.h"
    
    
    #include <linux/interrupt.h>
    
    volatile int g_irq_test_counter = 0;
    
    
    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("kernel:mkg open ok!\n");
    	}
    
    	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",);*/
    		iowrite32(0x02000000,g_mkg_mem_base);
    			printk("request_irq ==2==!\n");
    			printk("mkg g_irq_test_counter:%d!\n",(int)g_irq_test_counter);
    
    	printk("kernel:mkg g_irq_test_counter:%d!\n",(int)g_irq_test_counter);
    	
    	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,
    };
    
    
    static irqreturn_t ip_mkg_irq(int irq, void *dev)
    {
    		
    	g_irq_test_counter = g_irq_test_counter+1;
    
    	return IRQ_HANDLED;
    }
    
    
    
    void test(void)
    {
    	int err = 0;
    	int loop = 0;
    	
    	printk("request_irq...\n");
    	err = request_irq(MKG_IRQ_INDEX,ip_mkg_irq,0,"ip_mkg",NULL);
    	if(err)
    	{
    		printk("request_irq error!\n");
    	}
    	else
    	{
    		printk("request_irq ok!\n");
    	}
    
    
    #if 1	
    	printk("reg test start==\n");
    	iowrite32(0x11223344,g_mkg_mem_base);
    	iowrite32(0x11223344,g_mkg_mem_base+0x4);
    
    	for(loop=0;loop<3;loop++)
    		printk("====reg addr==0x%x==reg value:0x%x==\n",loop*4,ioread32(g_mkg_mem_base+4*loop));
    #endif
    
    	iowrite32(0x01000000,g_mkg_mem_base);
    	printk("request_irq ==1==!\n");
    	printk("mkg g_irq_test_counter:%d!\n",(int)g_irq_test_counter);
    
    	/*iowrite32(0x02000000,g_mkg_mem_base);
    	printk("request_irq ==2==!\n");
    	printk("mkg g_irq_test_counter:%d!\n",(int)g_irq_test_counter);
    	
    	iowrite32(0x03000000,g_mkg_mem_base);
    	printk("request_irq ==3==!\n");
    	printk("mkg g_irq_test_counter:%d!\n",(int)g_irq_test_counter);
    	*/
    	printk("<----ip_mkg test end---->\n"); 
    	
    
    }
    
    
    
    
    
    
    int init_module()
    {
    	int ret_val;
    	int ret;
    	void __iomem *ret_from_request;
    
    
    	//=== 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 registers
    
    	g_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",(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);
    
    	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_NUM	102
    #define DEVICE_NAME	"ip_mkg"
    #define MKG_MEM_BASE 0x97000000
    #define MKG_MEM_LEN	32
    
    #define MKG_IRQ_INDEX	24
    
    
    #define IOCTL_REG_SET 0
    #define IOCTL_REG_GET 1
    
    
    
    struct 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 clean
    
    else
        # called from kernel build system: just declare what our modules are
        obj-m := ip_mkg.o
    endif


    3.4 应用层编码

    1>mkg_test.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    
    int main()
    {
    	int fd = 0;
    	int read_data = 0;
    	char buffer[10] = {0};	
    
    	fd =open("/dev/ip_mkg",O_RDWR);
    	if(0 == fd)
    	{
    		printf("file /dev/ip_mkg open error!\n");
    		return 0;
    	}
    	else
    	{
    		printf("file open ok!\n\n\n");
    	}
    	
    	read(fd,buffer,1);
    
    	close(fd);
    
    
    	return 0;
    }
    


     4,实验步骤

    1>进行RTL编码与综合
    2>编写linux下的driver
    3>编写,编译测试应用程序
    4>FPGA板上验证
    具体操作步骤请参考:
    http://blog.csdn.net/rill_zhen/article/details/8700937
    5>需要注意的是,在跑测试程序前要创建设备节点(mknod /dev/ip_mkg c 102 0)
     

     5,实验结果

    1>代码打印结果,如下图:



    2>cat /proc/stat

    3>可见driver给mycore发出了两次指令,mycore也产生了两次中断,中断处理程序也执行了两次。

    4>反面验证:除了正面显示实验正确外,还可以从反面进行验证,显示实验正确。

    1》将指令发送代码注掉,再测,没有中断产生。

    2》修改注册中断号为25,再测,也没有中断产生。


    5>需要注意的是:
    1》如果连续发送中断指令(就像driver中注释掉的那样),就可能只产生一次中断。

    2》发送中断指令后,后面的打印信息,可能不会立即更新(即,counter仍为0)。

    6,小结

    通过上述步骤,对openrisc 的外部中断的使用就比较了解了。

    这对于SOC的开发又多了一种工作机制,既可以采用轮询,也可以采用中断。

    enjoy!

  • 相关阅读:
    go http的三种实现---2
    go http的三种实现---1
    go语言递归创建目录
    Golang中的正则表达式
    go语言strings包
    go语言获取字符串元素的个数
    VBA在Excel中的应用(三)
    ASP 转换HTML特殊字符
    ASP汉字转拼音函数的方法
    用ASP实现文件下载
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3065372.html
Copyright © 2011-2022 走看看