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