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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x

    ! O) K+ @$ q& Y. t7 I/ Z2 Y引言3 z9 W$ r# ^1 Z3 m$ o

    " u. x8 [& r' A# K& J之前的一篇文章与今天的类似:linux学习之路_编写ipcore 的linux driver,然后run helloworld- ^9 a4 n( @$ E5 @" S
    ! j' x& e: R1 p
    那篇算是一个比较详细的概述吧,那篇文章把精力主要集中在driver部分,提到ip core的编码时,一笔带过。
    & {4 v% Y% n3 q& e4 x& B& Q这次进一步细化,写一个真的可以work的ip core,加到现有的ORSoC上,结合那篇文章的driver部分,一个真的可以work的东西就诞生了。
    8 ?: f# Z7 |/ w2 C; o* @0 j; O) @
    + I5 |+ S! m4 t) V; ^! s) S: Y本小节实现了一个简单的ipcore:mycore。她的功能也非常简单,实现一个加法运算。
    8 Z' m+ X, G! g; P& Gmaster(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果。
    ) v: {. @$ h( y( K$ x这次试验可以看到mycore计算1+2=3。
    9 E- Q: e, j( }. j; n8 f' u, Sok let's go!, F% [' T$ K/ E; v. x9 y4 A* z4 y
    $ x' D0 w. s1 t& Y3 v8 g
    1 ip core的编码和修改
    1 E6 ?# j; N- a) j5 C要想在ORSoC里面加入自己的ipcore(本小节以‘mycore’为例),需要修改三个文件,增加一个文件。
    1 m( n# _4 ^6 u, K. l& Y三个需要修改的文件为:arbiter_dbus.v,orpsoc-params.v,orpsoc_top.v% D  y; w8 G  t4 Q
    一个需要增加的文件为:mycore.v7 p) d' Y$ D( F* R
    如下图:这里需要注意的是,在ORSoC里面共有3个wishbone的arbiter,咱们用的是arbiter_dbus。为什么呢?很简单,instruction那个是取指令用的,很显然不能用;byte那个是8位的,我的是32位的,很显然也不能用。
    7 I1 a" }- g  N! }7 {
    ) ?% q+ Q4 g& Z6 J$ t5 `
    ) Q( ]0 a7 {3 T( {$ ?0 Y) {. p4 N6 ^3 M: F$ s; i
    6 b; C! B. y, k& i% i% j* I

    3 Q+ @2 T2 o' X6 C, U: P2 概述
    1 G9 z4 E/ t" G1 R  {3 z一般,添加自己的ipcore到ORSoC,需要三大步:
    ' C) H+ D3 u+ B8 P4 E1>编写符合wishbone inteRFace的ipcore:mycore% M* e5 P; v; l
    2>定义mycore中用到的parameters
    5 H  j+ h# w6 N3 D/ J3>增加arbiter的slave或者mater接口(本小节是slave)9 C) Q5 g1 `2 F
    4>在顶层module例化这个ipcore( x" V3 |, R, \' z4 T  K& l
    ! b) F" q* Q, P, M! m! i
    当然为了测试验证,还要
    7 t6 O4 A# R. A5>编写她的driver。( J# \) P! u( V
    9 {, P# `8 `! I+ u) c: e$ \, e
    1 v3 o8 P- n, U0 m8 m: I
    3 rtl编码! ?, {1 y9 {# S: H& v' @
    下面就逐个把需要修改的文件的内容说一下:3 M! [3 U5 M0 O
    1》编写符合wishbone interface的ipcore:mycore.v
    1 V, q( o5 r' l' z6 V9 c) v8 R8 G* s$ S; 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 ****************/
      , c# \+ ^2 a) u2 t' _
                     ( F0 O: V" e) X+ s! m; e

    9 M. i! \( _/ E; ^! P1 g6 S% ~& Y9 X3 E
    2》定义mycore中用到的parameters:修改orpsoc-params.v,共3个地方需要修改,如图:; p1 g/ ^: {6 B* f0 z' t& n* E
    6 \+ C0 r9 S8 U
    1>修改1
    / l4 X+ Q, ^% U6 N6 u+ [
    9 |+ G) ~9 d* R8 p % X. [# {" N$ `
    . f1 x  x9 b% {! Z
    2>修改2-3
    . x5 O$ {, D; s- e7 f* \! b; b, q  Q  Z6 C& u2 p
    & ^2 T* }' v7 g. c, Q/ F

    + f( J! h" N/ ?: n) k% f( J- B" k- i3》增加arbiter的slave或者mater接口(本小节是slave):修改arbiter_dbus.v,共13个地方需要修改,如图:) m7 V3 J  H0 p
    ( D  E0 _2 b' u8 w3 n, J5 \- v
    1>修改1! ^- a3 Z% E& P$ L9 f* J
    + d2 O! h, O! v
    7 C# S5 |  Z4 u: x4 x

    3 x- t6 {1 B2 P( V) Z1>修改2
    / }0 @( s, L& j* x0 E/ M6 T' C( z' c0 H2 X

    : k1 T' p5 X6 n, B( D) o
    3 v4 p" ]1 \( t5 Y7 N1>修改3- |8 ]1 g8 Q  a+ x% R6 G
    ; i* H: J7 I& b- P* n

    1 ?& }0 e7 c' _6 j8 {  q( B; J7 f
    & J+ d9 ~* J& q  ~; X% l! a& e1>修改45 y+ P  b& [( ?* m
    ) U4 \" E, t9 i0 P# K3 ]

    8 U, W8 G# u/ I* e
    , L8 Z/ m* W) ?7 t7 U1>修改5& W4 _7 r. y9 R$ {! K  ]7 z
    2 X! ]$ ~7 D8 ?* c
    7 J$ d" i: U% E/ e% j

    - C& {9 v* n, N2 \" U1>修改6-7
    : b- ?) B. M9 U
    - G. D' V9 @6 O( z: P' p
    ( S; ?2 Z+ X7 R3 H; L: T" t+ ], H* y1 G: B% i7 e8 O
    1>修改87 ]8 T; f* @! S

    ; u8 T8 q1 @* u0 L! R 1 r" p- w- V: ~+ i. ^6 L; X

    , h8 @* g' |. r5 |8 B1>修改9
    % G1 i7 L! `& A3 R7 }( V7 V& q7 f; `  b- g

    . N- F& g- W+ W; j! H0 x, v( e. O, h3 {- I1 m! \$ A
    1>修改10
    / o0 e! f& x4 m2 @0 x
    ' y( m5 |& c0 `5 s
    ) X( \& H1 o7 \2 j9 }2 _4 u* d; D
    ) W) q5 H2 x7 r, I1>修改11
    " _& Q* L8 S: z! ^* j* e; d1 O& E6 Z- q% N0 W5 t

    5 ?1 t6 K% n6 J9 U% f
    9 n9 P) c3 U+ u3 ?4 @( ]1 ^3 X1>修改12
    $ g! Y, K, K0 D3 I) U! f# W8 d, V4 _! f5 m. a* J
    * {, N% n  S$ q+ h' O
    0 N7 H$ N/ ]& t) K' u3 C
    1>修改13
    9 U+ D$ `& B6 z- v6 C  d- t+ g( h: C$ b
    1 R: K/ y9 i' Q  y1 h# ]

    ) v2 w! w5 z/ }( R! E! P % n6 _& v, ]. W7 m3 ?1 J/ q' y4 Q

    3 L6 j) g% M$ t) _6 l" v1 B4》在顶层module例化这个ipcore:修改orpsoc_top.v,共4个地方需要修改,如图:8 _9 `7 V  R0 H( ?, ?8 U
    . m  ]- n& x. _% a- Y
    1>修改19 _2 x/ w6 S; X9 J
    & [+ R7 l+ o# E$ C. d' k  u& @

    & G/ a- B& X6 P& N; T* _# {+ p: b# T( i( ~4 y3 @: r
    1>修改2# P" B/ s, }/ t4 e% D
    : D; h5 X! l& l2 y

    / L& \  S. }& g7 Y! E/ m* [2 n( F+ E1 R, g
    1>修改3
    # h: ~2 Q6 A) B$ B6 U0 g* Y
    % h4 [* M: r5 I" j ; M; ~# J- k' z: O) |

    / r  d& l4 ?) Z  U1>修改47 F, q/ L9 [7 x
    & w0 u: \1 {& {4 h0 M
    7 q( x+ I( `, B" j5 C1 I6 ?
    ! X( p, w  q1 e$ ]; i

    ; z4 ]' `0 e* S5 {% m9 N/ ^  T* u自此,可以通过quartusII进行综合,生成orpsoc_top.svf文件,将其burn到FPGA板子里面。
    & Z. F( c- d  @+ M9 H  y  M7 d) J* \- S4 {9 L( W" N. D
    7 _2 G2 _; ^- U+ P+ z* Z3 q
    4 driver
    3 |0 n: x* |; x  h( W' Y5 ^2 Z8 Q* v2 H, @- F
    有了硬件电路,想让她工作,还要编写她的driver才行:ip_mkg.c ip_mkg.h Makefile
    & c$ G. p, E) i( I! ?% r/ o. p# f# X
    2 e3 B1 m; E; n# S1》ip_mkg.c0 ]9 Q& B* q) p, J

    7 o* X% [; r0 r! z1 P" ]! Z
    • /*
    • *
    • * 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 x5 u% v  n* J) V
                            # z$ f' P& P: o$ ~  Y+ a2 M

    2 O9 U  P0 U! s4 _. u; `: t
    ' {+ ~. {$ a2 D5 o
    9 f1 |' N7 O- W) u' ?+ `) M2》ip_mkg.h
    3 d" {% W( z2 d% `
    & [" K) c" _* P6 D5 f3 S
    • #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
      3 u8 |1 o8 q& V, f1 E
          " X0 f  y  _2 L+ Q

    % ?2 o. ~" t* u# }  b+ Z0 C8 F3 ?9 D4 V' y% N
    3》Makefile
    & R8 x* w6 v7 R4 v( |7 o- t* `2 \/ v% e9 T% B  M+ ?
    • # 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& d8 Q# H7 K+ n* z& e7 q+ T0 e: j
          
    ; A! [. o7 X% t " N2 A5 I* t3 q# D/ n* W

    , b* x# N; _  p2 j5 测试
    3 ]; S! H! P$ p+ G2 i9 L0 K( k
    2 S. Q9 \" w, Q  U5 Z然后make生成ip_mkg.ko,并insmod进内核。就可以看到最终结果。如图,可以看到1 + 2 = 3。
    / a# p3 {9 q- w( i2 M
    / s* M3 i! R1 `* l4 e/ k' a5 J
    # h, R4 }! _% i& \6 w' m& Q4 y# d% x9 c% G# G  M) Z% _) l6 ~
    $ u# J" Z0 ?8 i) N( J) A
    ) k- O9 a& a/ t$ ]. B1 C! o
    6 小结8 w0 D7 w$ E/ |- {8 n

    7 }- Z: M- h4 S" b自此,ORSoC就变成一个transformer了,你可以随意的添加自己想要的ipcore,以实现不同的function。
    7 A! L2 f* D3 `
    ! u; J2 ~1 _5 L) B1 i6 w+ w) `good lock,enjoy!( S( @+ H1 k- D: Y) r( X- @7 k

    ( r% f3 [+ L" E: _1 G1 q) v9 [3 q5 ^& M# {4 p) q% e! G

    该用户从未签到

    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-8-17 21:19 , Processed in 0.140625 second(s), 26 queries , Gzip On.

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

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

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