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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x
    ' ^; r- C1 K. Z; O2 @" q
    引言
    ! R' r' A/ C4 H! m
    ' F& \; U' [8 p6 Q. ^5 {8 T之前的一篇文章与今天的类似:linux学习之路_编写ipcore 的linux driver,然后run helloworld
    ; A8 G8 P$ s) w* {' L
    ! S9 k' Y) ~8 o/ Y那篇算是一个比较详细的概述吧,那篇文章把精力主要集中在driver部分,提到ip core的编码时,一笔带过。- L* |. A: h' n* v: f% c, v
    这次进一步细化,写一个真的可以work的ip core,加到现有的ORSoC上,结合那篇文章的driver部分,一个真的可以work的东西就诞生了。
      k  x+ Y! P& R% y* l! Z2 `; f7 h- Y5 q+ h1 E7 I% J  l
    本小节实现了一个简单的ipcore:mycore。她的功能也非常简单,实现一个加法运算。
    7 q! j2 ]1 M7 y' F% Bmaster(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果。( c/ a1 }( N7 `
    这次试验可以看到mycore计算1+2=3。
    / Z; B6 [3 s4 v8 i! xok let's go!
    * D* D3 [0 n/ d9 z+ C5 W/ O
    . i: P3 M/ q! w* x. [; b  b1 ip core的编码和修改
    6 s7 g+ |$ Z( K$ |9 n要想在ORSoC里面加入自己的ipcore(本小节以‘mycore’为例),需要修改三个文件,增加一个文件。: i) o7 X5 A# q2 |# x. X
    三个需要修改的文件为:arbiter_dbus.v,orpsoc-params.v,orpsoc_top.v) [# c2 A* \. @4 a* E: J
    一个需要增加的文件为:mycore.v
    5 R- Q+ ]/ c! F' @. k. a' R1 m如下图:这里需要注意的是,在ORSoC里面共有3个wishbone的arbiter,咱们用的是arbiter_dbus。为什么呢?很简单,instruction那个是取指令用的,很显然不能用;byte那个是8位的,我的是32位的,很显然也不能用。
      q! G  V) R' b- t  h# \5 c$ e' z- p, v- w

    8 s) Y; Z) J, ]) R6 l! d- \  c

    4 P0 M, @, Q, {- X
    6 I; c0 l  i! o3 z2 概述5 Y- T! [4 p3 D7 J) j1 N
    一般,添加自己的ipcore到ORSoC,需要三大步:; Q- u$ P9 ?+ F# x' V  y
    1>编写符合wishbone inteRFace的ipcore:mycore$ [6 q1 _) ~: i8 ?. i6 c7 w) d( p
    2>定义mycore中用到的parameters
    ; t7 N( _# q- R# h' v3>增加arbiter的slave或者mater接口(本小节是slave)2 P* D4 \* H5 d( z9 ?4 h
    4>在顶层module例化这个ipcore6 Y  l4 y$ Q+ |  D; J& ]7 N; M% R

    9 n1 r5 k! Y8 V) j1 {, v当然为了测试验证,还要
    / s' V' t$ v# m: K- I5>编写她的driver。/ {# [1 g- `" v8 q; V3 R% W% H1 p

    . }1 Q& `: b* d5 R. q, h) }- e8 w: \( j2 S( C! o% @
    3 rtl编码
    , [! U7 C0 p1 d# ~. {下面就逐个把需要修改的文件的内容说一下:; G  d4 b* {$ \. K" u) l+ e
    1》编写符合wishbone interface的ipcore:mycore.v; f! {1 N, e0 a% L1 C% X

    ; w2 c  [: |- R- \# C# L. w5 ~
    • /*
    • *
    • * 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 ****************/
      0 p( C6 D8 y# t8 K; L6 ~
                     
    ' h0 Z  J4 B" o& |: n* {* F/ {
    4 _0 E) M7 e0 O' J) t- M: E
    3 E) T! S6 X: L. s2》定义mycore中用到的parameters:修改orpsoc-params.v,共3个地方需要修改,如图:
    ( ]3 j; a7 v1 V. [/ t7 \( y' `. f: z& s. W
    1>修改16 d5 H8 V5 {; U# ?" \
    ' b* G% @' K- A

    ! t( s, w: B7 m5 j0 J6 }- ]
    5 W+ @3 y+ e" w7 f2>修改2-3
    & o; n! X& Z2 x# W& g" J, I, n2 d* q1 Q
    3 A! c' |% b: t/ V/ n
    + a' Z8 M# e' a: ?7 t
    3》增加arbiter的slave或者mater接口(本小节是slave):修改arbiter_dbus.v,共13个地方需要修改,如图:
    4 v% z, o' ^5 U) O$ V9 P+ M/ D
    2 W0 h/ ]" O/ {4 V 1>修改1
    0 d  n. R$ z' H: T# q& i
    1 |3 w! ~) B7 |& t. | 9 I- r: y4 W5 M! _/ t
    2 u, Q* P& G3 O- ?# n
    1>修改2
    8 m: ~. F% W& ^' ?9 I& L2 C
    ' Y$ z* R7 R0 `. Y7 _, T% f
    5 V& V+ g# S! w- P
    ; e( h6 Y% j1 {# r$ M) ], ~1>修改3
    : |0 J9 [7 Y, z. Z" F5 E7 ^" G( O. F" y7 D0 v
    ; z, L: x0 b7 b. }# f. H
    . e! b- h2 `# Z, t6 }: a. I
    1>修改4
    + _& j& S; A- \6 s: S# }5 W, ?0 m1 d9 u% G3 q1 {2 R
    : N* Y& @6 S! m  W: \& Z3 d' l
    * A0 X$ [# Z+ Y3 ^, w7 d
    1>修改5
    # [8 s! T4 o  ^* o. R/ B# f% b/ n3 D1 x$ w' `; \4 k4 L7 O# Y

    $ t& P. G3 }8 ^% t* f3 b) ~$ Z; Y+ ^8 W9 i9 p5 l( b
    1>修改6-7
    4 I* B1 n4 @& |# a6 p- l
    $ {- h8 b( z8 b* {# F
    ) u% [; i  r; B
    * [% r) j. ~3 s4 \% F: I5 c7 K1>修改8
    , t' t; J% v. d. ?
    % e" o+ O7 ?' P6 Z
    + H/ C% W  u: T. ]* f" \& z) f7 ^7 b! U# R4 d* d8 o8 h
    1>修改97 J9 U: f7 p2 a1 g" ]+ T% K* F# n+ h1 I

    / y0 P  k. ^9 p# s: M
    6 q) W; {, l0 l0 B/ \5 E; J) S0 W5 l4 s
    % a0 \7 {. z% H9 M1>修改10
    1 O4 S0 _8 K. o( z8 ?0 N- U; O0 {9 w# H% S* |

    1 t# G/ p4 ~" c$ p8 q4 e3 c/ P& g* P( B6 F
    1>修改11
    0 h8 X3 \& i$ J2 B; M/ E. p8 {6 F- C
    ( \* F# Z) q$ t7 a

    : M% k& Z# m! u% I5 ~1>修改12
    ; q, h6 q; b/ Q+ ]
    ' s7 G1 I6 E$ y ! [" F, `  x9 T: v8 [
    " V- B5 ?0 _2 o/ B, E0 m0 {& }
    1>修改13! x# }3 P' J& p9 w

    7 q. B- ~# ?* w" v1 E + S& A# F8 [. n7 z: z7 B9 Q+ h- ]

    " l! v& ~$ V4 c, @7 t . _3 a; ?1 D& M- n

    5 o9 `2 Q6 Y0 ^6 E  X3 I+ q) }( }9 ^5 P4》在顶层module例化这个ipcore:修改orpsoc_top.v,共4个地方需要修改,如图:6 N( Q, I/ G+ s/ @7 S- G! {' K* q
    / h8 p. k8 b/ v+ X- h
    1>修改1
    & w$ C2 p: j$ z5 l! J( [' F3 a$ K
    7 T1 x  B) b. v+ R% L+ I6 q
    - \( w: _0 h% ?* o+ |6 \" P9 m2 R+ S7 O" g: ^
    1>修改2
    : j6 ~; \/ r" w, m- [  z1 h' s' a9 @+ B+ X

    / Z8 x  M) e) x' Y: E1 Y& j; k5 g4 z0 c
    1>修改3- e7 H) R$ ?- L1 o, M. u

    : J. w9 ^4 @, H& W; L( k
    ) h4 m' d0 t+ g) C9 d! J7 ]) T$ n3 v
    1>修改4. ?1 w8 U( Z5 X. M4 g2 X8 d

    , X7 `+ H  d" h1 ]+ k5 @ 4 `: L* {, E% [7 _) z6 v

    - [. P( m4 G% t7 d) {% j1 H  f, ?3 S( E! T: G# K
    自此,可以通过quartusII进行综合,生成orpsoc_top.svf文件,将其burn到FPGA板子里面。
    ) y2 ?. S* j' I' c: \/ b- b0 R
    ' I8 d+ N+ R& }% j3 n/ M+ x$ `$ [9 |$ Q# r, l9 N& h% k
    4 driver6 V6 z5 j. W$ m1 j% C7 J* \

    : J" E6 s7 \+ k9 Y" r) |有了硬件电路,想让她工作,还要编写她的driver才行:ip_mkg.c ip_mkg.h Makefile" X8 I7 b# U& m9 l5 M

    ! m" O! d7 x' @4 E* q1》ip_mkg.c8 J9 C8 |) {& Q  Q' X. i
    . [4 P2 @' u5 m3 l: }) ?1 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");

    • * H, s6 y/ J) }  ]& U
                            
    : }. u& Q  r3 d+ k$ b8 c! @9 }+ j# E& N( X2 h: r! A  ?
    8 r5 _% l# R" r7 ]9 f1 M1 R
    ; H; e* R/ S! e$ y( L3 J! i, F1 u
    2》ip_mkg.h
    ! p! m% T7 h  T4 _; b- Q1 a6 i" E9 l  t0 |
    • #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% H, z$ G0 W% d
          
    8 z0 ?+ ~2 p( p2 w. q1 T* l+ D* v/ t2 W% e# a

    ; u; i/ v6 S; a. u8 ~8 C3》Makefile3 [9 A6 g$ u% e2 }$ A1 O

    * d7 a1 Y: E8 E6 w# S! X& G
    • # 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) x* |% @7 {8 x
          1 g7 y: N- Z3 z* j1 h1 R' s
    ! W3 q: |6 R  `. _0 l' Z4 I/ l
    & J% [# `! b3 D5 X8 p8 l
    5 测试
    $ j7 Q6 ?! a* N7 t# u( l8 z0 i
    2 i4 Q& [4 ~/ N0 p& i然后make生成ip_mkg.ko,并insmod进内核。就可以看到最终结果。如图,可以看到1 + 2 = 3。
    - G8 ^4 }) d0 ]0 K8 O
    2 M" H  K" d9 t1 p0 b
    & S* r3 Z0 {2 _; W- _3 v3 ]" @5 Q9 A) p& w
    9 @6 y: l$ D, U( L

    # Z! K8 u( k: r0 {0 B  a6 小结
    % q3 a6 w) s0 D( S
    9 m1 y( D, o4 V$ l  u! J0 m8 _自此,ORSoC就变成一个transformer了,你可以随意的添加自己想要的ipcore,以实现不同的function。
    7 `: c: g9 q; R
    7 b: C7 k/ m0 L$ [$ l1 fgood lock,enjoy!" s8 ~% N6 M9 ?% _6 Y8 {4 b8 H
    5 O) |9 a/ g$ @: o& y: t

    $ o- I* ^4 m# U5 n2 E

    该用户从未签到

    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-6-22 09:20 , Processed in 0.093750 second(s), 26 queries , Gzip On.

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

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

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