TA的每日心情 | 怒 2019-11-20 15:22 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
9 f) c3 t. Y8 t: y3 _ Y引言
5 \+ k# P7 F4 V6 V+ k! f% U) S5 J3 z7 ]
之前的一篇文章与今天的类似:linux学习之路_编写ipcore 的linux driver,然后run helloworld
6 R# R4 e1 a# M3 S. p
' ^" n. b, ^+ X% F那篇算是一个比较详细的概述吧,那篇文章把精力主要集中在driver部分,提到ip core的编码时,一笔带过。
6 J; k) Z, W$ h! ]这次进一步细化,写一个真的可以work的ip core,加到现有的ORSoC上,结合那篇文章的driver部分,一个真的可以work的东西就诞生了。' }- v1 P- _. q4 D. ]& r% j; ^
2 a6 B# W$ [, j- m0 Y本小节实现了一个简单的ipcore:mycore。她的功能也非常简单,实现一个加法运算。
, h2 J J: e) A" i' R6 m% kmaster(CPU)设置mycore的第一个寄存器,和第二个寄存器,mycore将两个寄存器的值相加放在第三个寄存器中,CPU读第三个寄存器来获得计算结果。, _( h' F$ Q& ~
这次试验可以看到mycore计算1+2=3。
; c2 n, B/ @! X: L( j( m: Q5 b0 A$ Fok let's go!$ o+ X) Y* m3 G0 A- m; o
) P: M* `# R- X( w1 ip core的编码和修改# a* x- Q0 F: a
要想在ORSoC里面加入自己的ipcore(本小节以‘mycore’为例),需要修改三个文件,增加一个文件。$ q" R- A* f2 a1 P$ ~) J" r$ M
三个需要修改的文件为:arbiter_dbus.v,orpsoc-params.v,orpsoc_top.v% w g3 H7 ~) M# d, N
一个需要增加的文件为:mycore.v
$ _, d% Q0 _- a' z% j如下图:这里需要注意的是,在ORSoC里面共有3个wishbone的arbiter,咱们用的是arbiter_dbus。为什么呢?很简单,instruction那个是取指令用的,很显然不能用;byte那个是8位的,我的是32位的,很显然也不能用。$ Y, e$ }7 S T+ h r z2 P
9 Z4 s6 Q3 q/ x: f: Z# A
" i, ^1 X. F% k6 h. {7 Y1 d: E2 @6 e# B# ]: j) v' v- o
$ K8 H! q7 s2 m& K7 J. ^' J) R7 k% u B1 ^0 r
2 概述+ G w% z( Y) g! `+ B
一般,添加自己的ipcore到ORSoC,需要三大步:# j2 Y1 R/ }1 H
1>编写符合wishbone inteRFace的ipcore:mycore2 s, c3 o8 Q& G6 R( U3 U) _8 [
2>定义mycore中用到的parameters
; m* B: T" e- t d3>增加arbiter的slave或者mater接口(本小节是slave)8 C( D% c/ \7 M* l- l4 H; ]8 N
4>在顶层module例化这个ipcore) z9 D* f4 ~; P [, S! v. D
* j3 K/ K9 K, \" A
当然为了测试验证,还要
1 C* P! ?- s6 W5>编写她的driver。' O \/ m1 ~$ K
! w- T7 u+ X: P5 d: \( \
) J3 v3 e1 K& @* [: {3 rtl编码
+ l: M* { C5 R8 e4 y6 Q+ [下面就逐个把需要修改的文件的内容说一下:
. u- f2 N! g0 |1》编写符合wishbone interface的ipcore:mycore.v
+ m' I* H' q% E7 H. e7 z0 m# z
% M' I2 E, Z V9 G% H& K0 z" L! 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 ****************/$ T, B6 R% b+ u/ K: J) c; D
4 P, L8 L. N+ s) B! k9 D
4 F4 l6 Z* x; ~& J9 \! v( y: J9 L$ ~# m( I4 ?
2》定义mycore中用到的parameters:修改orpsoc-params.v,共3个地方需要修改,如图:3 p0 \/ N* |0 t% j( W- j" O
K& E0 ^" [2 ]) N
1>修改1
4 ?2 L: T5 i& s e, s/ Z, @
& L# O8 h; J0 ? c3 Q
# \# Z+ |9 y8 A/ Y* s V
9 y4 ~) r5 { V/ i" v0 p
2>修改2-3
, P6 _" H& k/ t, `) |- O' M
6 q( [6 P+ ]- r5 J* D( G
" @4 \0 X! v. M0 u/ v1 p+ h
5 K3 l6 S* w3 e
3》增加arbiter的slave或者mater接口(本小节是slave):修改arbiter_dbus.v,共13个地方需要修改,如图:
2 `# _, Y, B: J* j7 {9 l" \5 a5 Y! d+ j/ y4 G# T
1>修改15 w& _! J- ?; T5 ~5 i4 `
! B) ^% M* \$ }3 Y8 G3 E; o
" f8 S9 k. A% n* O8 ~
3 b0 l5 E: i! c8 h& Q
1>修改2
0 F7 A7 J( ^' e# `2 G
$ \& |8 @$ s. c' ^
3 P! o/ | G4 b" K- i
% V, E7 ~$ p- i; E5 v1 O
1>修改3( E9 i f( T: z+ u1 \8 m- y
8 K+ ^, ~: k' Z# a
* t) l1 @- `0 a3 q- t; I
& n; Q' q7 [, ]+ L l) r) i& G, C1>修改41 y- C5 X! |9 Y
* [3 [7 r! X3 @% E3 [1 K
5 ]/ B( J* |4 n9 J
# {# I, l; t$ x& h. g. h8 j: u2 c1>修改5# s! \! c3 p% N% [
0 f7 v; _3 t) E! l
& C' @7 N6 T, |, S6 }0 M, F6 H
" Y. A2 d" k: q7 W
1>修改6-7* I y g* j. [3 Z7 s
: d* m" v7 K9 }/ h2 f. u
- y! G% S3 {, G9 s4 G( [
2 A8 C& N2 m) S1>修改85 i ?/ S% E8 d- F. b3 _2 M
; L* Y0 G" |! O! T! }
# S% _) V) H( o# w( [$ N
/ G% s: ]# k7 e1 Z+ `1>修改9
1 G6 r; R. ^+ p6 b% h3 x, ]" f1 G
4 _- K" \4 ]- m$ D* i
( f7 I) m- b) R- D: g& c9 E- p6 s+ n1 O
1>修改10; v7 G2 ~+ w5 g( _! D' I7 a2 r7 H
6 ]. e. z' I( m5 y) ^3 n
, x5 U" i8 p$ Q% g0 _- g/ n; E# D% u! w3 N- X6 A9 Z- W* R
1>修改11
, B) R" Q7 O* b& a4 B$ P- E' L; d! @5 B7 o: l( ~
; u4 I: }0 j8 J& i$ T8 N6 J
- E( p* o4 |6 V- Y) m1>修改12
4 n7 J3 x3 [+ s i0 t! W) K+ q5 n% \" k" S4 n2 H! n7 |2 a
1 j2 V) j4 |/ ]* y1 d: D* u/ C N
/ w' B# ~$ ^( v1>修改138 G9 z. X( P s* G$ m1 r
5 C, r% b- b% h/ @1 \
. V- F8 e& g$ u4 N# k2 Y8 N; o$ o" _3 i& r/ W
! `+ D9 m; I) ?4 H# Z9 E
; R) N" g9 r$ f$ `4》在顶层module例化这个ipcore:修改orpsoc_top.v,共4个地方需要修改,如图:
( c% C& b% l6 s6 S/ ?% ?3 H
3 E ]1 |& H4 P+ e0 f4 |# o1>修改1, a0 d# O! Y" B7 F
2 b% f' J5 V: e! H& t, U- x
7 f) K! `$ w5 Z3 C5 {" A" N1 B, {9 @8 A3 I: q$ j' ~% u5 }
1>修改29 P# ]% ]! Q1 u" e; N
2 G6 O" D% k2 K) ~, x
2 j$ h8 z' }, ^0 ~8 \1 j
6 d6 n7 l3 p! i' L' r1 N# r) f
1>修改3
5 Q+ t8 c: s# B% r8 B$ { c& i C2 L0 c a
& X/ F* E8 \) U6 _
( u2 q/ _; _4 N; W1>修改4* z A+ Z' H B7 C/ _. W$ k
4 s& R( K- w2 B0 e( }
. R) E! C/ L# E* U p
. y1 w: f! j8 } b) h
* R2 E7 p% F! Z% ^" G q自此,可以通过quartusII进行综合,生成orpsoc_top.svf文件,将其burn到FPGA板子里面。! m6 T; J* n8 R9 h
8 ~% e1 V, `2 I8 Y- N
8 v0 U$ O( n, v; g; H m4 o4 driver
# c) r, H. E5 z2 _9 K3 a
# n ~9 s3 J+ h J有了硬件电路,想让她工作,还要编写她的driver才行:ip_mkg.c ip_mkg.h Makefile
3 e9 A" a( y/ U" G
$ N/ J. s* e3 g4 `; e" ~1 V4 f1》ip_mkg.c
8 l: ^! Y5 u0 s. h+ C* B
8 `1 |* ~; F4 k7 w+ ~0 ^- /*
- *
- * 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 W: i4 Q/ K. s' A" J " j: l* ^: V: U$ F
* m" L6 O3 [. s! h" \1 [
. T2 B! J- W2 |: l- U$ J* ]- k8 S1 m r
2》ip_mkg.h4 S3 s9 I) O7 E& m6 ^$ b* S. v
9 V8 _7 s! Z5 o* |( l8 |
- #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
6 V, x; E* \: a0 s
+ O Q$ p' u- [' y& R6 r, c
/ H+ _7 j2 j/ ?- H$ ^' q1 }% v! R
4 h- m7 w7 S$ A" ]( N4 U% d3》Makefile
/ Q* z U5 ]* |1 B2 |5 Q" K. o" B& d6 o4 f7 N
- # 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
% k( H; D# A9 J5 U; r1 O: B4 k
, ?) t! ~. D) ` O/ I Y: Y
8 p& A( L* h- O
9 H# A4 T% g0 J" `% T& g5 测试' ]; v4 C; m; }2 [ I: M
- ?. }& D, } w8 v! e
然后make生成ip_mkg.ko,并insmod进内核。就可以看到最终结果。如图,可以看到1 + 2 = 3。
' ]7 s2 t6 T: w( |/ O) D3 z' ~5 r4 K4 k6 z9 [" L% C
& e# k( }& N* l# c) K+ m
1 {. R q: |% g5 Q! ]# f+ \
; e4 o. I: a3 K# N
* ]) _7 G: ^ J% x# _5 e& n* p l6 小结
& G b7 o6 K8 W* `; F
7 e! x, U. R0 t- `" Y3 u$ t8 k# p自此,ORSoC就变成一个transformer了,你可以随意的添加自己想要的ipcore,以实现不同的function。
' R" d0 D8 T2 u9 G5 F$ A% M9 z) {+ N/ i; E6 n6 b' A4 u5 f
good lock,enjoy!+ `; u2 a8 j, c# b
' o2 i" d/ {. T- G6 E- L# V
, o$ v$ @* u/ s" R' b2 ` |
|