TA的每日心情 | 怒 2019-11-20 15:22 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
' W" U& ]7 t* N& k% q
引言; p4 t1 B8 h+ P$ Y
9 u' v f2 o2 J) d* ^2 s$ v8 ^
之前的一篇文章与今天的类似:linux学习之路_编写ipcore 的linux driver,然后run helloworld
, Q6 Z) p3 ?0 A3 b
1 U( h5 W7 p' x7 f! V# `: O那篇算是一个比较详细的概述吧,那篇文章把精力主要集中在driver部分,提到ip core的编码时,一笔带过。
4 s7 G4 V$ R( ^6 ]这次进一步细化,写一个真的可以work的ip core,加到现有的ORSoC上,结合那篇文章的driver部分,一个真的可以work的东西就诞生了。& Z, L( x1 W% l% A4 P
$ C- r; p+ D; F本小节实现了一个简单的ipcore:mycore。她的功能也非常简单,实现一个加法运算。
# R0 e( R; R+ o+ G" K) Jmaster(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果。
5 a( p2 u- v: t; s) X) g+ t8 x这次试验可以看到mycore计算1+2=3。% ^6 z+ I3 E$ d" N
ok let's go!5 l+ W9 j+ F" Q- r, B; u8 x
, Z: Q3 g5 B4 K1 b4 k* g* F
1 ip core的编码和修改! }9 u+ n$ [& D3 t1 I, s% ]
要想在ORSoC里面加入自己的ipcore(本小节以‘mycore’为例),需要修改三个文件,增加一个文件。
0 N1 O7 e( h4 [ J& m, d9 `三个需要修改的文件为:arbiter_dbus.v,orpsoc-params.v,orpsoc_top.v4 @' W0 L9 k; X
一个需要增加的文件为:mycore.v
! [/ `) t! v3 q: N9 e; N" p, R如下图:这里需要注意的是,在ORSoC里面共有3个wishbone的arbiter,咱们用的是arbiter_dbus。为什么呢?很简单,instruction那个是取指令用的,很显然不能用;byte那个是8位的,我的是32位的,很显然也不能用。
) t. s, W0 ~0 o4 |) [
0 j9 ?, ]: `5 }) }
0 f. p5 Z. F. Y' e2 D! K
: W* L- I) K+ ~2 P/ K* D/ _
2 g1 M9 }( y( ?$ n+ k) t% ]8 E: t2 X; |1 M4 k& p
2 概述
4 L! e" l6 q3 ?) k9 l一般,添加自己的ipcore到ORSoC,需要三大步:' S/ z u& \$ e( b5 R# d" ~
1>编写符合wishbone inteRFace的ipcore:mycore4 P v* Q; W; } m: t
2>定义mycore中用到的parameters
# `4 x, t* ]/ k& \4 p3>增加arbiter的slave或者mater接口(本小节是slave)
7 c6 }" _; o6 d( i/ {) D4>在顶层module例化这个ipcore7 m: \$ v6 C) a# j' E. ?
2 V8 d2 C; k" w" V/ u1 @8 i) A' r% K$ g当然为了测试验证,还要9 a( k% W1 ?) v4 i0 p9 k7 V/ b( ]
5>编写她的driver。5 X$ |* A+ c' f' {+ f( z/ K
) }& m W8 K6 b( r( X( `8 I
( {9 i) W/ v& d: e: S" U3 rtl编码. e* o7 f- M% x6 p6 P
下面就逐个把需要修改的文件的内容说一下:% h( H/ e) V7 C9 p
1》编写符合wishbone interface的ipcore:mycore.v
) R# b% P& a: F4 U7 M! T* j+ k$ x+ l& ^% n: z 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 ****************/% Z) l0 C. \1 q8 ]2 y
7 ]) V" `7 G7 g8 n% [
# D, i6 K9 k3 O
: x" ~' E- S7 K* l5 p* F6 }
2》定义mycore中用到的parameters:修改orpsoc-params.v,共3个地方需要修改,如图:; T6 v5 B6 T a% K& Z% a2 _; U
! p/ D: Z2 |/ ^$ E& L1 d' k. H( G 1>修改15 T+ }4 l: P& U! x
1 V4 L" G# O# H1 I
2 q& I; I8 I0 X* I) W
4 ?5 H* f8 o6 a& l) e5 I2>修改2-35 l6 F* f: P0 u H
( _/ A& L, z8 [0 r, j) M
% A1 z- F2 F8 ]: ^
T( ?) K: p H# C! j- @' F+ X3》增加arbiter的slave或者mater接口(本小节是slave):修改arbiter_dbus.v,共13个地方需要修改,如图:- D4 S! @: b2 |$ y9 u
( u$ J/ s" A6 ?* X8 N% S 1>修改1
0 A" D* N& |6 j* v1 c# I3 [4 s5 B/ Z6 |
* z- R0 D: B$ H" s+ W0 _, w% P
) \: k* {1 c5 @+ ?" w
1>修改2* T' }) t# G$ Y$ b0 p
5 A6 E" Z+ C, e J/ q) D$ f
% E5 C: w) b! \7 z6 y/ Z; O9 N
- k- r, T3 k/ X0 d- v$ K
1>修改3& S/ t! c# {+ U8 r9 f
o! b( R! A" E" n/ ?( k1 |( R) n y
, I6 A/ o& B7 c/ Q5 X2 @; i
) I' n" A! i: H$ N( L3 J" N% A1>修改4+ D# J/ o3 ` L: p4 P1 V
: V5 z' j0 j& U4 ]
8 Y" u w7 Y* o0 {+ \
& T6 ^% ^7 S" X l1 D) u( I5 n
1>修改5
* R9 Z1 X& P; K ]& G, d/ Y/ g9 l: [( l0 E4 v
$ ~' r1 m# M4 X5 X& v
9 r: i) M' f% e$ ]% h
1>修改6-7
" O' a1 ^$ H- t1 N4 P
' m5 Y( h7 r% y6 G/ \ J2 v# B
( U8 K: \# K& F. n6 {- s5 B
0 ?/ |! m1 R" q( X1 J
1>修改8) `! p3 n. ?% N* V* l
3 `8 Z/ m4 K& y+ U& F! ?
9 {# P6 W. C" n
) F: A" {8 [) A" |3 Z# V3 K
1>修改9
7 \; M. a( q! M" I/ ?( B. l1 h8 P
+ [+ [6 l9 m- v( s8 D" [
$ O0 e: E; P5 D$ z! I+ N5 V- \: e
1 S6 p/ M% w5 Y, w0 w0 C; l5 I
1>修改10
- ^# P# m# W1 J4 `1 B: I+ W
* ~% | h' B% Y9 J/ l# g
- ^8 d+ F) {) E- }2 e) X
1 q3 y# u; Q: v9 O0 m1>修改11
6 T6 E+ A* S1 d, e! p/ r5 c8 q# v( k
% T+ @$ w4 X* j; W
2 j; Y; z0 E: t) f* {$ e" n) d5 b* ~5 \+ o; y
1>修改12/ ]* I) Q* K* p# G! h
) M5 k+ y; A8 z& a
1 ~' ~3 }5 U; e) k3 p/ ^) Q5 \
) y: U/ v/ { c8 o7 Z
1>修改13
. h+ ^+ v6 `8 s8 y( i0 O3 b
) O. |$ V5 T O0 h" M5 v$ j
: V0 U# n. ~/ i2 I: S. J0 p9 t
$ j2 x! ^- @8 f- w& [
, y0 R v9 ~: a8 \7 L8 m# Q- V& V8 O, ~1 f) \$ z
4》在顶层module例化这个ipcore:修改orpsoc_top.v,共4个地方需要修改,如图:
, p3 ^9 W7 h" r3 k
1 e6 n* }1 [1 y/ h- N# c( E1>修改1
4 |/ \8 X$ G3 M
; m- v9 m: \' `3 `% J: ]! A) F
, T& q9 m: m- |# i b4 u2 o
6 s# b, H9 T2 m: S1>修改2
* k, o2 W2 R3 o# \5 S. x7 Y/ l1 A' g2 Q9 ?, o
. Z; t- Y; c& X i. ?
8 o) h" m* T) r! g1>修改3
1 N, Y* d, Q+ t$ J/ X
' Q- N2 d. }! B
! }/ L( b( g0 ~, r* B2 V5 N
+ A6 I/ ], C0 P
1>修改4) ~5 ~0 P" Q4 S4 J9 h
) v! A/ @; e! j) z7 A% L$ J
$ e1 `1 b6 J' T; f) x
! H T, G8 h4 v/ F2 I
. k4 [ U" w/ V自此,可以通过quartusII进行综合,生成orpsoc_top.svf文件,将其burn到FPGA板子里面。* ^3 `$ s' q; Q0 S/ s1 y$ b
O6 J! _* X% f1 _0 W. W- Y
' A9 w' C" M0 T* q
4 driver# C4 s2 S/ O' K) S
0 F, v( _" f: E9 c/ M4 u
有了硬件电路,想让她工作,还要编写她的driver才行:ip_mkg.c ip_mkg.h Makefile
7 B4 c5 ]4 m, i# }+ a" y$ Q/ c; H4 G4 V$ }5 E% q
1》ip_mkg.c' V2 k4 b! p6 c5 x# n4 u" b
% e$ H2 u) o, w9 F- /*
- *
- * 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");
- , ?8 i0 A; ~' S. K0 B9 _
/ \: h# K" _5 }! R4 O# v# N$ Z
$ K7 y3 v5 F, E) o5 b8 [% m! c* L $ W9 i5 n H( q* v1 R
& b- Q$ M' p4 x. _9 p, P( }/ H2》ip_mkg.h
2 o$ {2 |5 ?7 ~1 j$ K/ a: y5 v7 ]$ K$ E }$ T
- #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$ L- {2 A3 r6 M# P: y8 @
: L: p& ]; e, ~4 q! c
) A9 d/ L+ V% A; u/ k2 L# k+ ?5 ~3 u- F5 n- U
3》Makefile) x( x, }8 N' ~, c; J6 l _4 C
1 X7 Y: t( {+ i. c* T! V
- # 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
; _' ^8 t4 g3 J$ s3 B! V$ K
9 M2 w( G+ f! Z! I# Q* [8 H/ z
( {% Y$ }2 i: p, c
" _6 }4 b! d/ h+ c5 测试( U1 e0 D9 Z/ Q& Z/ ?1 g6 O
F6 r' R# k+ l然后make生成ip_mkg.ko,并insmod进内核。就可以看到最终结果。如图,可以看到1 + 2 = 3。
% F3 D! G& Z. U* W
" e6 A. l3 G: A9 z! e4 x% w
" ^* I' U7 P7 Z& D& S2 R/ i
s( m8 d$ x' X
9 T* b( } _9 J# A0 e2 q: S; x
+ g3 j8 [' Z0 u& f/ D6 小结
2 |% ^* J q! K) P4 i/ R# L4 d# `
4 w, e0 p3 j3 E# q' A+ {6 c/ v; X* i* N自此,ORSoC就变成一个transformer了,你可以随意的添加自己想要的ipcore,以实现不同的function。
+ M! @- z, u2 y |8 w4 E, U& Z! p$ Z+ R, ^4 k7 N9 i1 C0 k
good lock,enjoy!# b; a# E6 P( L( e: l0 ^
8 }; k, R+ l) L" s' C6 U g" J( i, t' Y+ H7 J7 E" |
|
|