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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x
    4 h6 Y& j( v2 c# c& `
    引言
    ; c9 ^+ ~* x$ n$ g. }+ g  k- V9 a8 ?
    + g7 k* V' H+ a" Z2 v5 L2 `之前的一篇文章与今天的类似:linux学习之路_编写ipcore 的linux driver,然后run helloworld1 Z# M& _6 a% f8 Y% M& Q7 ]/ e* s
    : J4 ?5 F" J0 c. o- c
    那篇算是一个比较详细的概述吧,那篇文章把精力主要集中在driver部分,提到ip core的编码时,一笔带过。
    4 h9 x7 R0 Q5 C这次进一步细化,写一个真的可以work的ip core,加到现有的ORSoC上,结合那篇文章的driver部分,一个真的可以work的东西就诞生了。
    1 {( w, c# O* J1 L+ t2 ]
    * k5 q2 }4 v+ V  j本小节实现了一个简单的ipcore:mycore。她的功能也非常简单,实现一个加法运算。# ^# p7 e0 y% x4 _1 P8 `
    master(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果。6 Z2 |0 j8 t/ K8 k  }9 ^! V$ C
    这次试验可以看到mycore计算1+2=3。
    / `$ F# d/ {  ~) sok let's go!
    7 u- j* @0 ]& F. f. X6 o) ]
    7 ^1 I, q# X5 g5 p. @1 ip core的编码和修改
    9 u. P* T) v/ R5 I4 ?. t要想在ORSoC里面加入自己的ipcore(本小节以‘mycore’为例),需要修改三个文件,增加一个文件。* ?1 x4 q8 {" q& X& a5 r, X
    三个需要修改的文件为:arbiter_dbus.v,orpsoc-params.v,orpsoc_top.v
    1 `8 q6 I, w2 X; O& }! ]3 @一个需要增加的文件为:mycore.v, N6 Y4 J9 K: J. \* J$ D) N6 `
    如下图:这里需要注意的是,在ORSoC里面共有3个wishbone的arbiter,咱们用的是arbiter_dbus。为什么呢?很简单,instruction那个是取指令用的,很显然不能用;byte那个是8位的,我的是32位的,很显然也不能用。
    ( i& Q7 ^% E7 Y  z/ R
    0 o* Z8 v1 B7 f2 Q
    5 L) F: B; n7 D9 l
    ; s3 _; l4 \1 m3 l1 X# V( r* j9 |
    7 S; U1 p2 K2 r: z+ k" `. L/ \' d# t
    2 概述$ v2 l8 B5 |! j. C# U" J
    一般,添加自己的ipcore到ORSoC,需要三大步:
    ' x7 \. k2 a' V1 ^' _7 B6 k1>编写符合wishbone inteRFace的ipcore:mycore
    ) y+ l( j8 t/ u2>定义mycore中用到的parameters
    " t; l4 G. b  q3>增加arbiter的slave或者mater接口(本小节是slave)
    ( K& \7 }0 W/ V( P+ W! E+ \4>在顶层module例化这个ipcore
    2 `( o4 @. d' ?( Z0 o% H2 s0 {7 d4 v* f
    当然为了测试验证,还要
    $ W) N2 ~; P) K3 O( \/ x$ J) h; J5>编写她的driver。' z9 m8 H" `( z8 B- X

    # @; p, J+ C" e- z# C( l, E- _) e" h
    3 rtl编码
    2 I8 e* i( y" b% o下面就逐个把需要修改的文件的内容说一下:$ `) F/ D1 ]$ W: n; V) H: M
    1》编写符合wishbone interface的ipcore:mycore.v' ^3 r" G8 H! l7 ~* n
    - L3 a! F, d- u3 y5 t5 o" g4 w. A
    • /*
    • *
    • * 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 ****************/8 v0 }' i) t9 S+ A* g
                     
    8 K/ p( [" S0 f. X3 s/ j# {/ B$ N& j( }+ i2 a* d% V
    * }9 D" q4 H3 S% {5 ], C! I8 q' _
    2》定义mycore中用到的parameters:修改orpsoc-params.v,共3个地方需要修改,如图:; x; @5 o) n2 F& }5 d4 L# K
    " z$ W7 r: b' b! |
    1>修改1' J1 [3 J- K. y$ v' p6 ~. e0 Q: z/ B  c
    5 O" ]# V% Z  w( S) v( C* w/ ?) ~
      m& S2 a  h: Y  R: Q
    $ o% r3 X7 G/ N8 Q# y3 p0 d
    2>修改2-3
    $ O5 F1 \9 u' L" L. e7 ^* a" a7 Q* {4 W0 q2 u& N9 L

    * Q! [) |! t" z7 i" [/ j8 P& y' E; E9 r/ ]
    3》增加arbiter的slave或者mater接口(本小节是slave):修改arbiter_dbus.v,共13个地方需要修改,如图:
    8 v- M5 C9 G4 k4 }- I; \( s# R; ?
    + @  c4 v/ ^# ?5 B1 p 1>修改1+ \& E5 }9 d- @

    ) K% o. L: Y" c, U& U- N" i, g# q6 D
    # {  g/ R9 V+ `& t) M6 O
    $ i, Y3 a! x) Q& N+ R% F# H1>修改2
    1 N! ~6 r: I  s2 d0 Z) C; T$ y% b2 F9 c2 f3 z

    3 C  z, `# A1 }1 a$ ~
    , F1 X+ |, l3 M& \1>修改3
      L0 N5 K  K1 S% `. t* n! [% D2 h4 \+ A: K
    & ?2 J1 b; N" A
    - K5 d9 I+ O7 O- z
    1>修改47 C  e' M& D- _; U* C7 W

    . s' f- d2 E* \8 f0 j # v+ ?3 \# g+ S1 x! U( _) |

    3 O5 w2 }5 u! q( x$ i- p' e- b3 O1>修改5, x" k; T( E6 P2 n! c

    4 o% H5 j  M: s5 q& y6 ] ' o) ]4 d% g" Y8 Z
      b8 j6 O9 c& g5 I' ^% V
    1>修改6-7
    ( [& A' h4 G7 K4 P) Y5 x; S7 J1 U' w7 u4 N
      `+ ?$ D6 P% ^' J5 \# g+ T
    1 r  b7 ^5 N8 m
    1>修改89 R6 n) T' x  p  n' u- k, u, I/ q" Z

    - d3 P0 }7 t1 C5 y+ v% G9 x/ ]% O
    ! W7 g# A! j1 F0 Q  D- V# v+ ?: T6 c; [$ b+ o& |; C4 K, Q: Y
    1>修改9+ k" e  }6 }* y6 a7 R( Y
    ; x9 a4 B, u1 U7 I1 k

    9 {2 F9 S  g7 U
    " ]' t# H$ F) z; k1>修改10
    1 ^' S  t# ^& K" V# T4 @- y$ |* R
    5 T: o; H) o7 }* |7 H
    4 \* D+ Z1 S2 s4 O, o5 Q
    1 B6 x! O; T/ F* b  D7 q; ?1>修改11. T2 e1 Q8 U0 a9 h
    , e0 e& e. A, E% ^, e- |( P

    4 e" S; v1 L# v! X) }
    , ~7 Y  e2 Z9 c1>修改123 b! j* Q9 [; O. A0 u+ J, b7 I9 D, t
    : q3 K) {1 D* {4 `7 Q% C

    4 Y) U1 m& ]' ]+ Z$ Z
    " s6 c, b4 B8 Z( p1>修改13) t2 }  r7 O+ ?+ A

    / I, i6 i" o$ m. {- L
    ( j4 c$ E. x& w3 I5 H4 H" a
    0 ?) a+ k, u7 h
    7 q) I8 S# j+ I* O, g3 D* A* @8 |4 ?/ i2 l
    4》在顶层module例化这个ipcore:修改orpsoc_top.v,共4个地方需要修改,如图:
    0 @3 l9 \1 u5 N1 B7 `' z! K2 |$ j9 W7 T- `
    1>修改1
    , k9 W2 j9 l! x! I$ L& X9 ^
    / t1 d" f6 R+ T5 s% J0 m+ o. j
    ! w( s6 G! y/ ~
    ) t: n8 }3 B, V+ M, N7 @/ j4 R1>修改2
    ! N8 Z) r9 U7 E0 N! T' P! m1 M
    ' Z+ [+ C, V- o* j- x: J- x, V   I! z- D4 g# J
    4 r1 J8 T; _% R+ \
    1>修改3
    % H/ N3 ~0 s; B: J8 P" w& e, Y* t' s; y- v) @6 o( \

    # i0 _2 c0 V( G  c
    / F6 c0 x4 h0 g" ~# W1>修改4; r4 N0 J; R  Q# M& T9 z/ {
    ' W0 G2 P! v8 e0 }& ]

    0 r( H0 {; h7 L6 D: x, f4 ?8 V9 r0 R

    * n( G9 B+ g8 h: i4 B9 r自此,可以通过quartusII进行综合,生成orpsoc_top.svf文件,将其burn到FPGA板子里面。% A- t/ D* U7 h0 h* R# |  U* Z

    ( F4 V( K, b. N# l  e$ w
    - {" d1 x; j( T1 {) p1 W4 driver; K- {) O% T) S+ R5 X* F' W

    " M& N6 ?, j1 A有了硬件电路,想让她工作,还要编写她的driver才行:ip_mkg.c ip_mkg.h Makefile4 U# _* w7 m/ m( D

    1 `+ s6 g+ ~# ~# R$ c! I& o1》ip_mkg.c
      E# v  ~& i5 Q$ V; k8 i9 U" l( H# {5 R( I
    • /*
    • *
    • * 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");

    • 1 h5 y& t" B; G4 K6 Y  {9 R6 ~
                            
    $ e! D; b) W  @: H- f
    5 m0 v) K/ V$ U7 }& [  _% W
    ! w. K* e& ]/ _& S7 ~7 @
    + j8 J% |& ^3 c' S2》ip_mkg.h
    . h, t- f% M+ }3 h  i& E" }- U# h0 N
    • #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;
    • };
    • #endif7 |  H7 o5 B5 f4 ^% h
          
    ' e& S+ ~& \# l, f1 X
    & _2 k& X6 z  c# W; T" k
    5 U4 @7 L" W1 V1 V3》Makefile* `1 N/ P& [: k1 |' |

    ) }$ p* P' \) ], M% K3 c
    • # 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
    • endif9 V. R% R& W4 H  s
          
    , i$ `/ B6 t) Y. |+ t. r2 P % E4 z6 ?! S( n% p0 p  k8 v

    $ ]9 q' P0 ~; \8 b5 测试
    # }1 A- @* o) F# E; t( K
    / Y! k* D. b5 f) D9 C3 s) }- P然后make生成ip_mkg.ko,并insmod进内核。就可以看到最终结果。如图,可以看到1 + 2 = 3。; n4 k  f3 d- v- R, [4 H% Z5 O
    % b! I* G1 y+ K

    / A. F# E+ B3 z! v/ V# K" e5 A+ V8 c

    , `& P8 v- S3 s1 I. e
    & h" |% o. [9 T1 N5 U; I2 q6 小结
    , x' L; G0 r  K' B6 E* v2 r( A; ], u- l1 S, ^3 r) c, u9 u7 m
    自此,ORSoC就变成一个transformer了,你可以随意的添加自己想要的ipcore,以实现不同的function。
    ! B4 b2 g2 q. }1 m* i
    " K( x, \) t) D+ L0 W) o' egood lock,enjoy!
    ! y) D2 r$ a% p5 l$ }" |% k$ m  Z( v* Q5 j8 G* H7 _( {

    8 g) z$ t1 N) J# b( h; N( j

    该用户从未签到

    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 01:05 , Processed in 0.171875 second(s), 26 queries , Gzip On.

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

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

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