OpenRisc-26-openrisc中斷實驗

來源:互聯網
上載者:User

 

 引言

 中斷(異常)系統,可以說是電腦體繫結構重要的組成部分,也是最複雜的部分。

 現在的很多外設,都提供中斷處理機制,來減少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 outputwb_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 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 = 3'b000;parameter s_read = 3'b001;parameter s_write = 3'b010;reg [2:0] state = s_idle;//irq statusparameter irq_idle = 3'b000;parameter irq_action = 3'b001;reg [2:0] irq_state = irq_idle;reg [7:0] irq_done;//irq flagassign wb_err_o=0;assign wb_rty_o=0;always @(*)//sum processbeginsum = num_1 + num_2;endalways @(posedge wb_clk)//interrupt processbeginif(wb_rst)beginintr_o <= 1'b0;endelsebegincase (irq_state)irq_idle:beginintr_o <= 1'b0;if( (32'd1 == num_1) && (irq_done == 8'd0) )beginirq_state <= irq_action;irq_done <= 8'd1;endelse if( (32'd2 == num_1) && (irq_done == 8'd1) )beginirq_state <= irq_action;irq_done <= 8'd2;endelse if( (32'd3 == num_1) && (irq_done == 8'd2) )beginirq_state <= irq_action;irq_done <= 8'd3;endelse if( (32'd4 == num_1) && (irq_done == 8'd3) )beginirq_state <= irq_action;irq_done <= 8'd4;endelsebeginirq_state <= irq_idle;endendirq_action:beginintr_o <= 1'b1;irq_state <= irq_idle;enddefault:beginirq_state <= irq_idle;intr_o <= 1'b0;endendcaseendendalways @(posedge wb_clk)//wishbone interfacebeginif(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>例化: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 1printk("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));#endifiowrite32(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 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",(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_NUM102#define DEVICE_NAME"ip_mkg"#define MKG_MEM_BASE 0x97000000#define MKG_MEM_LEN32#define MKG_IRQ_INDEX24#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

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!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.