(原创)LEON3入门教程(四):基于AMBA APB总线的七段数码管IP核设计

摘要:这一小节将介绍下如何设计用户自定义的APB IP,并将IP嵌入到SOPC中去。一个APB IP核的主要分为三个部分:逻辑单元、寄存器单元和接口单元。所设计的IP是一个简单的七段数码管显示IP,只有一个寄存器ledindata_reg,实现数码管显示,比较简单实用,可以类比到更多的寄存器设计中。IP设计后,对其进行仿真测试和软件测试,验证其功能。该IP没有中断功能,如果需要添加中断请参考AMBA协议。

  更多更新请关注我的博客:@超群天晴 http://www.cnblogs.com/surpassal/

相关阅读

(原创)LEON3入门教程(一):什么是LEON3?需要哪些开发工具和软件?

(原创)LEON3入门教程(二):Cygwin和GRtools的安装与配置

(原创)LEON3入门教程(三):基于LEON3的SOPC设计:HELLOWORLD和流水灯

 

一、AMBA APB总线和APB IP核

ARM研发的AMBA(Advanced Microcontroller Bus Architecture)提供一种特殊的机制,可将RISC处理器集成在其它IP芯核和外设中,2.0版AMBA标准定义了三组总线:AHB(AMBA高性能总线)、ASB(AMBA系统总线)、和APB(AMBA外设总线)。3.0版本将支持AXI。APB总线用于提供低带宽的接口用作外围总线,适合挂接一般的外围设备。

图1 是一个简单的APB总线读操作的时序图。图中第一个时钟周期是SETUP周期,第二个时钟周期是ENABLE周期,地址、控制信号在两个周期内都是有效的。PENABLE信号在传输结束的时候将被置无效。PWRITE信号维持不变,直到不第同的读写传输发生的时候改变。写操作的时序基本相同,只是PWDATA数据信号现在SETUP周期内和地址、控制信号一同给出。

图1 APB总线的简单读操作时序

一个APB IP核的主要分为三个部分:逻辑单元、寄存器单元和接口单元。其中逻辑单元完成任务逻辑的实现。对于七段数码管来说,就是完成对输入数值的显示;接口单元完成对AMBA APB总线协议的支持,包括读写协议、时序等;寄存器单元完成地址和寄存器的衍射,将AMBA APB上的地址空间对应到需要的寄存器上,这样CPU对这些地址的操作,也就完成了对相应寄存器的操作,最终实现对逻辑单元的输入输出控制等。一个APB IP的结构框图如图2所示。

 图 2 一个APB IP核的结构框图 

二、 IP核的设计和测试

1 逻辑设计

由于DE2-70上的七段数码管是共阳的,所以设计的是BCD输码入的共阳七段数码管。实现代码如下。

 1 --超群天晴 @ NEU
 2 library ieee; 
 3 use ieee.std_logic_1164.all; 
 4 use ieee.std_logic_unsigned.all; 
 5 
 6 ENTITY led IS
 7 PORT(
 8     indata:IN STD_LOGIC_VECTOR (3 DOWNTO 0);
 9     outdata:OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
10     );
11 END led;
12 
13 ARCHITECTURE rtl OF led IS
14 BEGIN
15     process(indata)--
16     begin       
17         
18         --共阳
19         CASE indata IS---26 27 28 29---0000EDCB --100509
20             WHEN "0000"=>outdata<="11000000";--0
21             WHEN "0001"=>outdata<="11111001";--1
22             WHEN "0010"=>outdata<="10100100";--2
23             WHEN "0011"=>outdata<="10110000";--3
24             WHEN "0100"=>outdata<="10011001";--4
25             WHEN "0101"=>outdata<="10010010";--5
26             WHEN "0110"=>outdata<="10000010";--6
27             WHEN "0111"=>outdata<="11111000";--7
28             WHEN "1000"=>outdata<="10000000";--8
29             WHEN "1001"=>outdata<="10010000";--9
30             WHEN "1010"=>outdata<="10001000";--A
31             WHEN "1011"=>outdata<="10000011";--b
32             WHEN "1100"=>outdata<="11000110";--C
33             WHEN "1101"=>outdata<="10100001";--D
34             WHEN "1110"=>outdata<="10000110";--E
35             WHEN "1111"=>outdata<="10001110";--F
36             when others=>outdata<="11000000";--0;--0
37         END CASE;
38     END process;
39 end;

 

2  AMBA APB总线接口和寄存器设计

由于只需要对这个IP进行读操作,也不需要添加中断等其他功能,故只需要一个寄存器来存放输入数据即可。这里定义ledindata_reg,是对于IP基地址偏移为0(也就是基地址)的寄存器,作为处理器写数据的输入。

 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3 library grlib;
 4 use grlib.amba.all;
 5 use grlib.stdlib.all;
 6 use grlib.devices.all;
 7 
 8 
 9 entity apbseg is
10     generic (
11                 pindex    : integer := 1         ;-- slave bus index
12                 paddr    : integer := 16#240#;-- slave address
13                 pmask    : integer := 16#fff#; --choose the minimun size 256byte
14                 pirq    : integer := 0        ---interrupt index
15             );           
16     port     (
17                 rst     : in  std_ulogic;
18                 clk     : in  std_ulogic;
19                 apbi    : in  apb_slv_in_type;     -- APB slave inputs
20                 apbo    : out apb_slv_out_type;     -- APB slave outputs
21                 led_out    : out std_logic_vector(7 downto 0)
22             );
23 end entity;
24 
25 architecture rtl of apbseg is
26 
27 component led 
28 port(
29         indata:in std_logic_vector (3 downto 0);
30         outdata:out std_logic_vector (7 downto 0)
31     );
32 end component;
33 
34 constant REVISION : integer := 0;
35 constant pconfig : apb_config_type :=
36          (
37              0 => ahb_device_reg ( VENDOR_OPENCHIP, OPENCHIP_APBGPIO, 0, REVISION, pirq),
38              1 => apb_iobar(paddr, pmask)
39          );
40          
41 signal ledindata_reg :std_logic_vector(3 downto 0);
42 signal apb_write_reg :std_logic_vector(3 downto 0);
43 
44 begin
45 
46     --the main process
47     p:process(rst, apbi)
48     
49     --variable rdata : std_logic_vector(31 downto 0) := (others => '0');
50     variable write_temp: std_logic_vector(31 downto 0);--apb write data temp
51     
52     begin        
53     
54         -- reset operation
55         if rst = '0' then
56             write_temp:= (others => '0');
57         end if;
58             
59         --write
60         if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then -- 
61             case apbi.paddr(3 downto 2) is
62             when "00" =>
63                 write_temp:= apbi.pwdata;
64             when others =>
65                 null;
66             end case;
67             
68             apb_write_reg<=write_temp(3 downto 0);        
69 end if;
70 
71     end process;
72 
73     --clk process
74     regs : process(clk)
75     begin
76         if rising_edge(clk) then
77             ledindata_reg <= apb_write_reg;--一定要时钟才会跟新数据
78         end if;
79     end process;
80     
81     --reconglise the vendor
82     apbo.pconfig <= pconfig;
83     
84     --instant the entity
85     led1:led
86     port map(
87                 indata=>ledindata_reg,
88                 outdata=>led_out
89             );
90     
91 end architecture;

 

3 仿真测试

为了确保所定义的IP核能按照设计的工作,在将IP核嵌入到SOPC之前,需要对IP核的功能经行仿真。如图4所示(由于用的是Quartus II 9.0,并没有使用modelsim仿真)。

当APB的写信号有效后,APB数据线上的数据写入到ledindata_reg寄存器中,输出引脚输出对应共阳数码管的码值。例如APB总线上的数据是15时,输出引脚输出的就是10001110;当APB 总线上的数据是10000000时,IP输出引脚输出的就是10000000。仿真测试说明这个定义的IP核能正常工作。

 

图 4 IP核的仿真图 

三、 将IP核嵌入到SOPC中

1 库文件准备

1、添加自定义IP库。为了方便IP核的管理和使用,需要添加自定义的IP库。在lib目录下新建文件夹,这里新建的是一个名为rcq的文件夹,作为自己的IP库。再在rcq里面新建一个名为seg的文件夹,作为七段数码管的IP库。将前面编写的led.vhd 和 apbseg.vhd放到seg中。

2、编写包文件。在seg文件夹中新建名为seg.vhd文件作为包文件。seg.vhd的内容如下:

 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3 library grlib;
 4 use grlib.amba.all;
 5 use grlib.stdlib.all;
 6 use grlib.devices.all;
 7 
 8 package seg is
 9 
10 type matrix_type is array (7 downto 0) of std_logic_vector (7 downto 0);
11 
12 component apbseg is
13     generic (
14                 pindex    : integer := 1         ;-- slave bus index
15                 paddr    : integer := 16#240#;-- slave address
16                 pmask    : integer := 16#fff#; --choose the minimun size 256byte
17                 pirq    : integer := 0        ---interrupt index
18             );           
19     port     (
20                 rst     : in  std_ulogic;
21                 clk     : in  std_ulogic;
22                 apbi    : in  apb_slv_in_type;     -- APB slave inputs
23                 apbo    : out apb_slv_out_type;     -- APB slave outputs
24                 led_out    : out std_logic_vector(7 downto 0)
25             );
26             
27 end component;
28 
29 end package;

 3、另外,还需要修改leon3mp.qsf文件。在leon3mp.qsf中添加如下三行语句:

1 set_global_assignment -name VHDL_FILE http://www.cnblogs.com/lib/rcq/seg/seg.vhd -library rcq
2 set_global_assignment -name VHDL_FILE http://www.cnblogs.com/lib/rcq/seg/apbseg.vhd -library rcq
3 set_global_assignment -name VHDL_FILE http://www.cnblogs.com/lib/rcq/seg/led.vhd -library rcq

这样Quartus II 在综合的时候,就能找到前面定义的rcq 库中的所有设计文件。

2 添加IP

LEON 的配置和设计都是通过修改或者编写源代码来实现的。这里通过修改顶层文件的方式将IP添加到SOPC系统中。鉴于前面已经将一个简单的SOPC系统成功运行起来,这里在前面的基础上,只修改顶层leon3mp.vhd文件,将这个七段数码管的IP添加进去。

自定义的IP符合AMBA APB 总线协议,所以将其添加到APB总线上很容易。需要添加8个数码管,使用for generate语句生成。实现代码如下:

 1 -----------------------------------------------------------------------
 2 ---  HEX                        ---------------------------------------
 3 -----------------------------------------------------------------------
 4     x:for i in 0 to 7
 5     generate
 6         hex:apbseg
 7         generic map(
 8                     pindex    => SEG_INDEX+i,-- slave bus index
 9                     paddr    => SEG_INDEX+i-- slave address
10                 )         
11         port map(
12                     rst     => rstn,
13                     clk     => clkm,
14                     apbi    => apbi,     -- APB slave inputs
15                     apbo    => apbo(SEG_INDEX+i),     -- APB slave outputs
16                     led_out    => hex_temp(i)
17                 );
18     end generate;
19         
20     hexo_d_pad:outpadv 
21         generic map (width =>7, tech => padtech) 
22         port map (oHEX0_D, hex_temp(0)(6 downto 0));    
23     hexo_dp_pad:outpad
24         generic map (tech => padtech) 
25         port map (oHEX0_DP, hex_temp(0)(7));    
26     
27     hex1_d_pad:outpadv 
28         generic map (width =>7, tech => padtech) 
29         port map (oHEX1_D, hex_temp(1)(6 downto 0));    
30     hex1_dp_pad:outpad
31         generic map (tech => padtech) 
32         port map (oHEX1_DP, hex_temp(1)(7));
33         
34     hex2_d_pad:outpadv 
35         generic map (width =>7, tech => padtech) 
36         port map (oHEX2_D, hex_temp(2)(6 downto 0));    
37     hex2_dp_pad:outpad
38         generic map (tech => padtech) 
39         port map (oHEX2_DP, hex_temp(2)(7));
40         
41     hex3_d_pad:outpadv 
42         generic map (width =>7, tech => padtech) 
43         port map (oHEX3_D, hex_temp(3)(6 downto 0));    
44     hex3_dp_pad:outpad
45         generic map (tech => padtech) 
46         port map (oHEX3_DP, hex_temp(3)(7));
47     
48     hex4_d_pad:outpadv 
49         generic map (width =>7, tech => padtech) 
50         port map (oHEX4_D, hex_temp(4)(6 downto 0));    
51     hex4_dp_pad:outpad
52         generic map (tech => padtech) 
53         port map (oHEX4_DP, hex_temp(4)(7));
54     
55     hex5_d_pad:outpadv 
56         generic map (width =>7, tech => padtech) 
57         port map (oHEX5_D, hex_temp(5)(6 downto 0));    
58     hex5_dp_pad:outpad
59         generic map (tech => padtech) 
60         port map (oHEX5_DP, hex_temp(5)(7));
61     
62     hex6_d_pad:outpadv 
63         generic map (width =>7, tech => padtech) 
64         port map (oHEX6_D, hex_temp(6)(6 downto 0));    
65     hex6_dp_pad:outpad
66         generic map (tech => padtech) 
67         port map (oHEX6_DP, hex_temp(6)(7));
68     
69     hex7_d_pad:outpadv 
70         generic map (width =>7, tech => padtech) 
71         port map (oHEX7_D, hex_temp(7)(6 downto 0));    
72     hex7_dp_pad:outpad
73         generic map (tech => padtech) 
74         port map (oHEX7_DP, hex_temp(7)(7));

注意:在AMBA设计的时候,默认APB 外设最多为16个,如果之前已经设计了很多APB 外设,在添加8个数码管的IP的时候,会出现错误。这种情况下,就需要修改AMBA的设计文件了。

3 测试硬件

启动Quartus II ,对修改后的工程进行编译综合、下载。

为了检测新生成的SOPC系统是否是符合要求的,可以使用GRTools中的Grmon工具测试硬件。

启动Grmon,在Action菜单下选择Connect to target,连接到目标。

 图 5 Grmon连接到目标

如果连接成功,就能看到控制台输出如下信息:

 1 GRMON LEON debug monitor v1.1.35b evaluation version
 2 
 3  Copyright (C) 2004,2005 Gaisler Research - all rights reserved.
 4  For latest updates, go to http://www.gaisler.com/
 5  Comments or bug-reports to support@gaisler.com
 6 
 7  This evaluation version will expire on 27/5/2010
 8  using Altera JTAG cable
 9  Selected cable 1 - USB-Blaster [USB-0]
10 JTAG chain:
11 @1: EP2C70 (0x020B60DD)
12 
13  GRLIB build version: 4104
14 
15  initialising 
16  detected frequency:  50 MHz
17 
18  Component                            Vendor
19  LEON3 SPARC V8 Processor             Gaisler Research
20  Unknown device                       Gaisler Research
21  AHB/APB Bridge                       Gaisler Research
22  LEON3 Debug Support Unit             Gaisler Research
23  32-bit PC133 SDRAM Controller        Gaisler Research
24  Generic APB UART                     Gaisler Research
25  Multi-processor Interrupt Ctrl       Gaisler Research
26  Modular Timer Unit                   Gaisler Research
27  General purpose I/O port             Gaisler Research
28  General purpose I/O port             Gaisler Research
29  Unknown device                       Unknown vendor
30  Unknown device                       Unknown vendor
31  Unknown device                       Unknown vendor
32  Unknown device                       Unknown vendor
33  Unknown device                       Unknown vendor
34  Unknown device                       Unknown vendor
35  Unknown device                       Unknown vendor
36  Unknown device                       Unknown vendor
37 
38  Use command 'info sys' to print a detailed report of attached cores
39 
40 
41 Grmon>

 可以看到,系统中出现了8个 Unkown device,这个8个Unkown device就是自定义的8个数码管IP核,由于是用户自定义的,Vendor(提供商)和ID都是未知的,所以Grmon用 Unkown device 来表示。这表明我们自定义的数码管IP核已经添加到这个SOPC中。这时如果输入info sys 命令,获取系统更多的信息。

 1 Grmon> info sys
 2 00.01:003   Gaisler Research  LEON3 SPARC V8 Processor (ver 0x0)
 3              ahb master 0
 4 01.01:01c   Gaisler Research  Unknown device (ver 0x1)
 5              ahb master 1
 6 01.01:006   Gaisler Research  AHB/APB Bridge (ver 0x0)
 7              ahb: 80000000 - 80100000
 8 02.01:004   Gaisler Research  LEON3 Debug Support Unit (ver 0x1)
 9              ahb: 90000000 - a0000000
10              AHB trace 128 lines, stack pointer 0x43fffff0
11              CPU#0 win 8, hwbp 2, itrace 128, V8 mul/div, lddel 1
12                    icache 2 * 8 kbyte, 32 byte/line lru
13                    dcache 2 * 4 kbyte, 16 byte/line lru
14 03.01:009   Gaisler Research  32-bit PC133 SDRAM Controller (ver 0x1)
15              ahb: 40000000 - 50000000
16              ahb: fff00100 - fff00200
17              32-bit sdram: 1 * 64 Mbyte @ 0x40000000, col 9, cas 2, ref 7.8 us
18 01.01:00c   Gaisler Research  Generic APB UART (ver 0x1)
19              irq 2
20              apb: 80000100 - 80000200
21              baud rate 38343
22 02.01:00d   Gaisler Research  Multi-processor Interrupt Ctrl (ver 0x3)
23              apb: 80000200 - 80000300
24 03.01:011   Gaisler Research  Modular Timer Unit (ver 0x0)
25              irq 8
26              apb: 80000300 - 80000400
27              8-bit scaler, 2 * 32-bit timers, divisor 50
28 05.01:01a   Gaisler Research  General purpose I/O port (ver 0x1)
29              apb: 80000500 - 80000600
30 06.01:01a   Gaisler Research  General purpose I/O port (ver 0x1)
31              apb: 80000600 - 80000700
32 08.07:001   Unknown vendor  Unknown device (ver 0x0)
33              apb: 80000800 - 80000900
34 09.07:001   Unknown vendor  Unknown device (ver 0x0)
35              apb: 80000900 - 80000a00
36 0a.07:001   Unknown vendor  Unknown device (ver 0x0)
37              apb: 80000a00 - 80000b00
38 0b.07:001   Unknown vendor  Unknown device (ver 0x0)
39              apb: 80000b00 - 80000c00
40 0c.07:001   Unknown vendor  Unknown device (ver 0x0)
41              apb: 80000c00 - 80000d00
42 0d.07:001   Unknown vendor  Unknown device (ver 0x0)
43              apb: 80000d00 - 80000e00
44 0e.07:001   Unknown vendor  Unknown device (ver 0x0)
45              apb: 80000e00 - 80000f00
46 0f.07:001   Unknown vendor  Unknown device (ver 0x0)
47              apb: 80000f00 - 80001000
48 
49 Grmon>

 这可更详细地看到,这8个IP的地址,分别是0x80000800、0x80000900、0x80000a00…0x80000f00。这些地址对应的寄存器就是前面在定义IP时候定义的输入数据寄存器。

四、 使用LEON IDE 测试IP核

知道了自定义IP核的地址和相关寄存器,就可以编程软件测试程序使用定义的IP核了。由于我们定义的数码管的IP核只有一个数据寄存器,只需要对它写值就可以进行测试了。

1 新建工程

(原创)LEON3入门教程(三):基于LEON3的SOPC设计以及HELLOWORLD和流水灯介绍的一样,我们使用LEON IDE建立测试工程,为Seg_test。添加一个main.c文件,内容为:

 1 /*
 2  * main.c
 3  *
 4  *  Created on: 2010-3-27
 5  *      Author: 超群天晴
 6  */
 7 
 8 
 9 // LED
10 #define LEDG_BASE 0x80000600
11 
12 // REG LEDG
13 #define LEDG_DATA_IN      (*(unsigned int volatile *)(LEDG_BASE            ))
14 #define LEDG_DATA_OUT      (*(unsigned int volatile *)(LEDG_BASE + 4        ))
15 #define LEDG_DIR          (*(unsigned int volatile *)(LEDG_BASE + 8        ))
16 #define LEDG_INT_MASK      (*(unsigned int volatile *)(LEDG_BASE + 0xC    ))
17 #define LEDG_INT_POL      (*(unsigned int volatile *)(LEDG_BASE + 0x10    ))
18 #define LEDG_INT_EDGE      (*(unsigned int volatile *)(LEDG_BASE + 0x14    ))
19 #define LEDG_BYPASS      (*(unsigned int volatile *)(LEDG_BASE + 0x18    ))
20 
21 
22 // HEX
23 #define HEX_BASE 0x80000800
24 
25 #define HEX0_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x000))
26 #define HEX1_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x100))
27 #define HEX2_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x200))
28 #define HEX3_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x300))
29 #define HEX4_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x400))
30 #define HEX5_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x500))
31 #define HEX6_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x600))
32 #define HEX7_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x700))
33 
34 
35 void delay1s(void);
36 int main(void)
37 {
38     unsigned char i=0;
39 
40     unsigned char led1=0;
41 
42     LEDG_DIR=0xffffffff;//output mode
43 
44     led1=0xf0;
45 
46     while(1)
47     {
48         for(i=0;i<16;i++)
49         {
50             LEDG_DATA_OUT=led1;
51 
52             HEX0_DATA=i;
53             HEX1_DATA=i;
54             HEX2_DATA=i;
55             HEX3_DATA=i;
56             HEX4_DATA=i;
57             HEX5_DATA=i;
58             HEX6_DATA=i;
59             HEX7_DATA=i;
60 
61             delay1s();
62 
63             led1=~led1;//    取反
64         }
65     }
66 
67     return 1;
68 }
69 
70 void delay1s(void)
71 {
72     int i,j;
73     for(i=0;i<1000;i++)
74         for(j=0;j<500;j++);
75 }

 

2 编译、运行测试程序

程序运行后,可以看到8个数码管交替显示0~F

图6 数码管IP测试结果

 

 

=======================

完整工程和代码可以从这里获取:LEON3-lab2.rar

 

 

posted on 2012-10-24 10:14  超群天晴  阅读(5323)  评论(5编辑  收藏  举报

导航