TA的每日心情 | 怒 2019-11-20 15:22 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
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 |
|