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