找回密码
 注册
关于网站域名变更的通知
查看: 432|回复: 3
打印 上一主题 下一主题

linux学习之路_添加自己的slave IP core到ORSoC并测试

[复制链接]
  • TA的每日心情

    2019-11-20 15:22
  • 签到天数: 2 天

    [LV.1]初来乍到

    跳转到指定楼层
    1#
    发表于 2021-9-8 13:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

    EDA365欢迎您登录!

    您需要 登录 才可以下载或查看,没有帐号?注册

    x

    9 f) c3 t. Y8 t: y3 _  Y引言
    5 \+ k# P7 F4 V6 V+ k! f% U) S5 J3 z7 ]
    之前的一篇文章与今天的类似:linux学习之路_编写ipcore 的linux driver,然后run helloworld
    6 R# R4 e1 a# M3 S. p
    ' ^" n. b, ^+ X% F那篇算是一个比较详细的概述吧,那篇文章把精力主要集中在driver部分,提到ip core的编码时,一笔带过。
    6 J; k) Z, W$ h! ]这次进一步细化,写一个真的可以work的ip core,加到现有的ORSoC上,结合那篇文章的driver部分,一个真的可以work的东西就诞生了。' }- v1 P- _. q4 D. ]& r% j; ^

    2 a6 B# W$ [, j- m0 Y本小节实现了一个简单的ipcore:mycore。她的功能也非常简单,实现一个加法运算。
    , h2 J  J: e) A" i' R6 m% kmaster(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果。, _( h' F$ Q& ~
    这次试验可以看到mycore计算1+2=3。
    ; c2 n, B/ @! X: L( j( m: Q5 b0 A$ Fok let's go!$ o+ X) Y* m3 G0 A- m; o

    ) P: M* `# R- X( w1 ip core的编码和修改# a* x- Q0 F: a
    要想在ORSoC里面加入自己的ipcore(本小节以‘mycore’为例),需要修改三个文件,增加一个文件。$ q" R- A* f2 a1 P$ ~) J" r$ M
    三个需要修改的文件为:arbiter_dbus.v,orpsoc-params.v,orpsoc_top.v% w  g3 H7 ~) M# d, N
    一个需要增加的文件为:mycore.v
    $ _, d% Q0 _- a' z% j如下图:这里需要注意的是,在ORSoC里面共有3个wishbone的arbiter,咱们用的是arbiter_dbus。为什么呢?很简单,instruction那个是取指令用的,很显然不能用;byte那个是8位的,我的是32位的,很显然也不能用。$ Y, e$ }7 S  T+ h  r  z2 P
    9 Z4 s6 Q3 q/ x: f: Z# A

    " i, ^1 X. F% k6 h. {7 Y1 d: E2 @6 e# B# ]: j) v' v- o

    $ K8 H! q7 s2 m& K7 J. ^' J) R7 k% u  B1 ^0 r
    2 概述+ G  w% z( Y) g! `+ B
    一般,添加自己的ipcore到ORSoC,需要三大步:# j2 Y1 R/ }1 H
    1>编写符合wishbone inteRFace的ipcore:mycore2 s, c3 o8 Q& G6 R( U3 U) _8 [
    2>定义mycore中用到的parameters
    ; m* B: T" e- t  d3>增加arbiter的slave或者mater接口(本小节是slave)8 C( D% c/ \7 M* l- l4 H; ]8 N
    4>在顶层module例化这个ipcore) z9 D* f4 ~; P  [, S! v. D
    * j3 K/ K9 K, \" A
    当然为了测试验证,还要
    1 C* P! ?- s6 W5>编写她的driver。' O  \/ m1 ~$ K
    ! w- T7 u+ X: P5 d: \( \

    ) J3 v3 e1 K& @* [: {3 rtl编码
    + l: M* {  C5 R8 e4 y6 Q+ [下面就逐个把需要修改的文件的内容说一下:
    . u- f2 N! g0 |1》编写符合wishbone interface的ipcore:mycore.v
    + m' I* H' q% E7 H. e7 z0 m# z
    % M' I2 E, Z  V9 G% H& K0 z" L! M$ @
    • /*
    • *
    • * 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 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 = 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 @(*)
    • begin
    •         sum = num_1 + num_2;
    • end
    • always @(posedge wb_clk)
    • 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 ****************/$ T, B6 R% b+ u/ K: J) c; D
                     
    4 P, L8 L. N+ s) B! k9 D
    4 F4 l6 Z* x; ~& J9 \! v( y: J9 L$ ~# m( I4 ?
    2》定义mycore中用到的parameters:修改orpsoc-params.v,共3个地方需要修改,如图:3 p0 \/ N* |0 t% j( W- j" O
      K& E0 ^" [2 ]) N
    1>修改1
    4 ?2 L: T5 i& s  e, s/ Z, @
    & L# O8 h; J0 ?  c3 Q # \# Z+ |9 y8 A/ Y* s  V
    9 y4 ~) r5 {  V/ i" v0 p
    2>修改2-3
    , P6 _" H& k/ t, `) |- O' M
    6 q( [6 P+ ]- r5 J* D( G " @4 \0 X! v. M0 u/ v1 p+ h
    5 K3 l6 S* w3 e
    3》增加arbiter的slave或者mater接口(本小节是slave):修改arbiter_dbus.v,共13个地方需要修改,如图:
    2 `# _, Y, B: J* j7 {9 l" \5 a5 Y! d+ j/ y4 G# T
    1>修改15 w& _! J- ?; T5 ~5 i4 `
    ! B) ^% M* \$ }3 Y8 G3 E; o
    " f8 S9 k. A% n* O8 ~
    3 b0 l5 E: i! c8 h& Q
    1>修改2
    0 F7 A7 J( ^' e# `2 G
    $ \& |8 @$ s. c' ^ 3 P! o/ |  G4 b" K- i
    % V, E7 ~$ p- i; E5 v1 O
    1>修改3( E9 i  f( T: z+ u1 \8 m- y

    8 K+ ^, ~: k' Z# a * t) l1 @- `0 a3 q- t; I

    & n; Q' q7 [, ]+ L  l) r) i& G, C1>修改41 y- C5 X! |9 Y
    * [3 [7 r! X3 @% E3 [1 K
    5 ]/ B( J* |4 n9 J

    # {# I, l; t$ x& h. g. h8 j: u2 c1>修改5# s! \! c3 p% N% [
    0 f7 v; _3 t) E! l
    & C' @7 N6 T, |, S6 }0 M, F6 H
    " Y. A2 d" k: q7 W
    1>修改6-7* I  y  g* j. [3 Z7 s

    : d* m" v7 K9 }/ h2 f. u
    - y! G% S3 {, G9 s4 G( [
    2 A8 C& N2 m) S1>修改85 i  ?/ S% E8 d- F. b3 _2 M

    ; L* Y0 G" |! O! T! }
    # S% _) V) H( o# w( [$ N
    / G% s: ]# k7 e1 Z+ `1>修改9
    1 G6 r; R. ^+ p6 b% h3 x, ]" f1 G
    4 _- K" \4 ]- m$ D* i
    ( f7 I) m- b) R- D: g& c9 E- p6 s+ n1 O
    1>修改10; v7 G2 ~+ w5 g( _! D' I7 a2 r7 H
    6 ]. e. z' I( m5 y) ^3 n

    , x5 U" i8 p$ Q% g0 _- g/ n; E# D% u! w3 N- X6 A9 Z- W* R
    1>修改11
    , B) R" Q7 O* b& a4 B$ P- E' L; d! @5 B7 o: l( ~

    ; u4 I: }0 j8 J& i$ T8 N6 J
    - E( p* o4 |6 V- Y) m1>修改12
    4 n7 J3 x3 [+ s  i0 t! W) K+ q5 n% \" k" S4 n2 H! n7 |2 a
    1 j2 V) j4 |/ ]* y1 d: D* u/ C  N

    / w' B# ~$ ^( v1>修改138 G9 z. X( P  s* G$ m1 r
    5 C, r% b- b% h/ @1 \

    . V- F8 e& g$ u4 N# k2 Y8 N; o$ o" _3 i& r/ W

    ! `+ D9 m; I) ?4 H# Z9 E
    ; R) N" g9 r$ f$ `4》在顶层module例化这个ipcore:修改orpsoc_top.v,共4个地方需要修改,如图:
    ( c% C& b% l6 s6 S/ ?% ?3 H
    3 E  ]1 |& H4 P+ e0 f4 |# o1>修改1, a0 d# O! Y" B7 F
    2 b% f' J5 V: e! H& t, U- x

    7 f) K! `$ w5 Z3 C5 {" A" N1 B, {9 @8 A3 I: q$ j' ~% u5 }
    1>修改29 P# ]% ]! Q1 u" e; N
    2 G6 O" D% k2 K) ~, x
    2 j$ h8 z' }, ^0 ~8 \1 j
    6 d6 n7 l3 p! i' L' r1 N# r) f
    1>修改3
    5 Q+ t8 c: s# B% r8 B$ {  c& i  C2 L0 c  a

    & X/ F* E8 \) U6 _
    ( u2 q/ _; _4 N; W1>修改4* z  A+ Z' H  B7 C/ _. W$ k

    4 s& R( K- w2 B0 e( } . R) E! C/ L# E* U  p

    . y1 w: f! j8 }  b) h
    * R2 E7 p% F! Z% ^" G  q自此,可以通过quartusII进行综合,生成orpsoc_top.svf文件,将其burn到FPGA板子里面。! m6 T; J* n8 R9 h
    8 ~% e1 V, `2 I8 Y- N

    8 v0 U$ O( n, v; g; H  m4 o4 driver
    # c) r, H. E5 z2 _9 K3 a
    # n  ~9 s3 J+ h  J有了硬件电路,想让她工作,还要编写她的driver才行:ip_mkg.c ip_mkg.h Makefile
    3 e9 A" a( y/ U" G
    $ N/ J. s* e3 g4 `; e" ~1 V4 f1》ip_mkg.c
    8 l: ^! Y5 u0 s. h+ C* B
    8 `1 |* ~; F4 k7 w+ ~0 ^
    • /*
    • *
    • * 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 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",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");

    • 0 W: i4 Q/ K. s' A" J
                            " j: l* ^: V: U$ F

    * m" L6 O3 [. s! h" \1 [
    . T2 B! J- W2 |: l- U$ J* ]- k8 S1 m  r
    2》ip_mkg.h4 S3 s9 I) O7 E& m6 ^$ b* S. v
    9 V8 _7 s! Z5 o* |( l8 |
    • #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 IOCTL_REG_SET 0
    • #define IOCTL_REG_GET 1
    • struct reg_data
    • {
    •         unsigned short addr;
    •         int value;
    • };
    • #endif
      6 V, x; E* \: a0 s
          
    + O  Q$ p' u- [' y& R6 r, c
    / H+ _7 j2 j/ ?- H$ ^' q1 }% v! R
    4 h- m7 w7 S$ A" ]( N4 U% d3》Makefile
    / Q* z  U5 ]* |1 B2 |5 Q" K. o" B& d6 o4 f7 N
    • # 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
      % k( H; D# A9 J5 U; r1 O: B4 k
          
    , ?) t! ~. D) `  O/ I  Y: Y
    8 p& A( L* h- O
    9 H# A4 T% g0 J" `% T& g5 测试' ]; v4 C; m; }2 [  I: M
    - ?. }& D, }  w8 v! e
    然后make生成ip_mkg.ko,并insmod进内核。就可以看到最终结果。如图,可以看到1 + 2 = 3。
    ' ]7 s2 t6 T: w( |/ O) D3 z' ~5 r4 K4 k6 z9 [" L% C
    & e# k( }& N* l# c) K+ m
    1 {. R  q: |% g5 Q! ]# f+ \
    ; e4 o. I: a3 K# N

    * ]) _7 G: ^  J% x# _5 e& n* p  l6 小结
    & G  b7 o6 K8 W* `; F
    7 e! x, U. R0 t- `" Y3 u$ t8 k# p自此,ORSoC就变成一个transformer了,你可以随意的添加自己想要的ipcore,以实现不同的function。
    ' R" d0 D8 T2 u9 G5 F$ A% M9 z) {+ N/ i; E6 n6 b' A4 u5 f
    good lock,enjoy!+ `; u2 a8 j, c# b

    ' o2 i" d/ {. T- G6 E- L# V
    , o$ v$ @* u/ s" R' b2 `

    该用户从未签到

    2#
    发表于 2021-9-8 15:17 | 只看该作者
    添加自己的slave IP core到ORSoC并测试

    该用户从未签到

    3#
    发表于 2021-9-8 15:18 | 只看该作者
    添加自己的slave IP core到ORSoC并测试

    该用户从未签到

    4#
    发表于 2021-9-8 15:19 | 只看该作者
    master(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-11-24 02:54 , Processed in 0.187500 second(s), 26 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表