| |
转载,请注明出处
1. LEON AMBA ARCHITECTURE
首先LEON内部总线由2部分构成,第一部分由高速的AHB总线,另外由低速的APB总线连接。AHB总线连接着CACHE、MEMORY、DSU、DCOM、APBBRIDGE等几部分。
空间分配如下:
Figure1-2 Default AHB address allocation
可以看出,外部ram空间为0x0000_0000 – 0x7fff_ffff,而0x80000_0000 – 0x8fff_ffff空间为APB的空间,也就是所有寄存器空间。0x9000_0000 – 0x9fff_ffff空间为LEON特有的调试单元DSU的空间。0Xb000_0000 – 0Xb001_ffff空间为ETH的寄存器空间。剩余的空间还可以分配给其他用户想添加的高速设备空间。
APB总线挂接了几乎所有控制单元的寄存器。它的地址分配如图1-3。可以看出,APB总线专门控制各个部分寄存器的读写工作。同时还剩余很多的空间,还可以继续的添加。
1. Ahbarb
AHBARB.vhd主要负责AHB总线的切换。
2.1 AHB MASTER
AHB MASTER的优先级是固定的,优先级由低到高。在LEON2-1.30中,proc模块为ahbmst(0),proc模块由IU0和ICACHE/DCACHE共同构成。dcom模块为ahbmst(1),该模块主要负责debug。
下面为AMBA AHM MASTER的record定义。
-----------------------------------------------------------------------------
-- Definitions for AMBA(TM) AHB Masters
-----------------------------------------------------------------------------
-- AHB master inputs (HCLK and HRESETn routed separately)
type AHB_Mst_In_Type is
record
HGRANT: Std_ULogic; -- bus grant
HREADY: Std_ULogic; -- transfer done
HRESP: Std_Logic_Vector(1 downto 0); -- response type
HRDATA: Std_Logic_Vector(HDMAX-1 downto 0); -- read data bus
end record;
-- AHB master outputs
type AHB_Mst_Out_Type is
record
HBUSREQ: Std_ULogic; -- bus request
HLOCK: Std_ULogic; -- lock request
HTRANS: Std_Logic_Vector(1 downto 0); -- transfer type
HADDR: Std_Logic_Vector(HAMAX-1 downto 0); -- address bus (byte)
HWRITE: Std_ULogic; -- read/write
HSIZE: Std_Logic_Vector(2 downto 0); -- transfer size
HBURST: Std_Logic_Vector(2 downto 0); -- burst type
HPROT: Std_Logic_Vector(3 downto 0); -- protection control
HWDATA: Std_Logic_Vector(HDMAX-1 downto 0); -- write data bus
end record;
首先ahbarb.vhd的第一个工作是完成2个MASTER的总线切换工作,即是那个MASTER现在控制总线。它的关键代码如下。这个代码挺有意思,我花了一定的时间才搞懂为什么这样写。其实我虽然高明白它怎么运行的,但是为什么要这样写,还是不太清楚,可能要等到多MASTER运行的时候就明白了。
nvalid(1 to 4) := (others => false); nvalid(5) := true;
nmst(1 to 4) := (others => 0); nmst(5) := defmast; nhmaster := r.hmaster;
if (r.hmasterlock = '0') and ( //bus unlock
(msto(r.hmaster).htrans = HTRANS_IDLE) or
( (msto(r.hmaster).htrans = HTRANS_NONSEQ) and
(msto(r.hmaster).hburst = HBURST_SINGLE) ) ) then
for i in 0 to (masters -1) loop //note: i start with 0 . master = 2
if ((rsplit(i) = '0') or not AHB_SPLIT) then
if (msto(i).hbusreq = '1') and (msto(i).htrans(1) = '1') then
nmst(2) := i; nvalid(2) := true;
end if;
if (msto(i).hbusreq = '1') then
nmst(3) := i; nvalid(3) := true;
end if;
if not ((nmst(4) = defmast) and nvalid(4)) then
nmst(4) := i; nvalid(4) := true;
end if;
end if;
end loop;
for i in 1 to 5 loop
if nvalid(i) then nhmaster := nmst(i); exit; end if; //注意这里nmst(i)不一定就等于i.
end loop;
end if;
2.2 AHB SLAVE
当然,当MASTER固定后,则开始这个MASTER的地址开始译码,找寻合适的SLAVE运行,并将SLAVE的值返回这个MASTER。这里SLAVE的地址空间由FIGURE1-2可以得到。其中SLAVE的record的格式如下
-----------------------------------------------------------------------------
-- Definitions for AMBA(TM) AHB Slaves
-----------------------------------------------------------------------------
-- AHB slave inputs (HCLK and HRESETn routed separately)
type AHB_Slv_In_Type is
record
HSEL: Std_ULogic; -- slave select
HADDR: Std_Logic_Vector(HAMAX-1 downto 0); -- address bus (byte)
HWRITE: Std_ULogic; -- read/write
HTRANS: Std_Logic_Vector(1 downto 0); -- transfer type
HSIZE: Std_Logic_Vector(2 downto 0); -- transfer size
HBURST: Std_Logic_Vector(2 downto 0); -- burst type
HWDATA: Std_Logic_Vector(HDMAX-1 downto 0); -- write data bus
HPROT: Std_Logic_Vector(3 downto 0); -- protection control
HREADY: Std_ULogic; -- transfer done
HMASTER: Std_Logic_Vector(3 downto 0); -- current master
HMASTLOCK: Std_ULogic; -- locked access
end record;
-- AHB slave outputs
type AHB_Slv_Out_Type is
record
HREADY: Std_ULogic; -- transfer done
HRESP: Std_Logic_Vector(1 downto 0); -- response type
HRDATA: Std_Logic_Vector(HDMAX-1 downto 0); -- read data bus
HSPLIT: Std_Logic_Vector(15 downto 0); -- split completion
end record;
关于SLAVE切换的代码如下。这段代码就比较简单了,关键是AHBSLVADDR的定义。这个定义可以在下面的文件中定义。
./config.vhd:
constant AHBSLVADDR : ahbslv_addr_type := ahbrange_config;
./target.vhd:
type ahbslv_addr_type is array (0 to 15) of integer range 0 to AHB_SLV_MAX;
./device.vhd:
constant ahbrange_config : ahbslv_addr_type :=
(0,0,0,0,0,0,0,0,1,2,7,7,7,7,7,7);
-- select slave
ahbaddr := haddr(31 downto (31 - ahbmin));
-- pragma translate_off
if not is_x(haddr(31 downto (31 - AHB_SLV_ADDR_MSB +1))) then
-- pragma translate_on
nslave := AHBSLVADDR(conv_integer(unsigned(haddr(31 downto (31 - AHB_SLV_ADDR_MSB +1)))));
-- pragma translate_off
end if;
-- pragma translate_on
-- if htrans = HTRANS_IDLE then nslave := AHB_SLV_MAX; end if;
hsel := (others => '0'); hsel(nslave) := '1';
好了ahbarb.vhd的工作分析完成。关于代码的风格,网上讨论很多,我就不讨论了。就目前看,它的风格,我感觉吗,不是很适合我。
2. Apbmst
这个模块是apb bridge,完成apb slave的选择,这个代码相对于ahbarb要好理解一些。首先检测Apbmst被选中,然后msbaddr一直在译码选中那个SLAVE模块。Apb slave模块的输入输出总线record定义。
-----------------------------------------------------------------------------
-- Definitions for AMBA(TM) APB Slaves
-----------------------------------------------------------------------------
-- APB slave inputs (PCLK and PRESETn routed separately)
type APB_Slv_In_Type is
record
PSEL: Std_ULogic; -- slave select
PENABLE: Std_ULogic; -- strobe
PADDR: Std_Logic_Vector(PAMAX-1 downto 0); -- address bus (byte)
PWRITE: Std_ULogic; -- write
PWDATA: Std_Logic_Vector(PDMAX-1 downto 0); -- write data bus
end record;
-- APB slave outputs
type APB_Slv_Out_Type is
record
PRDATA: Std_Logic_Vector(PDMAX-1 downto 0); -- read data bus
end record;
aph slave译码过程如下。可以看出,我们可以继续增加寄存器空间。
case msbaddr is
when "00" =>
case apbaddr is
when "00000000" | "00000001" | "00000010" =>
esel := '1'; bindex := 0; -- memory controller, 0x00 - 0x08
when "00000011" | "00000100" =>
esel := '1'; bindex := 1; -- AHB status reg., 0x
when "00000101" | "00000110" =>
esel := '1'; bindex := 2; -- cache controller, 0x14 - 0x18
when "00000111" | "00001000" =>
-- write protection, 0x
if WPROTEN then esel := '1'; bindex := 3; end if;
when "00001001" =>
-- config register, 0x24 - 0x24
if CFGREG then esel := '1'; bindex := 4; end if;
when "00010000" | "00010001" | "00010010" | "00010011" |
"00010100" | "00010101" | "00010110" | "00010111" |
"00011000" | "00011001" | "00011010" | "00011011" =>
esel := '1'; bindex := 5; -- timers, 0x40 - 0x
when "00011100" | "00011101" | "00011110" | "00011111" =>
esel := '1'; bindex := 6; -- uart1, 0x70 - 0x
when "00100000" | "00100001" | "00100010" | "00100011" =>
esel := '1'; bindex := 7; -- uart2, 0x80 - 0x
when "00100100" | "00100101" | "00100110" | "00100111" =>
esel := '1'; bindex := 8; -- interrupt ctrl 0x90 - 0x
when "00101000" | "00101001" | "00101010" | "00101011" =>
esel := '1'; bindex := 9; -- I/O port 0xA0 - 0xAC
when "00101100" | "00101101" | "00101110" | "00101111" =>
-- 2nd interrupt ctrl 0xB0 - 0xBC
if IRQ2EN then esel := '1'; bindex := 10; end if;
when "00110000" | "00110001" | "00110010" | "00110011" =>
-- DSU uart 0xC0 - 0xCC
if DEBUG_UNIT then esel := '1'; bindex := 11; end if;
when "00110100" =>
if PCIEN then -- PCI target mapping 0x0D0
esel := '1'; bindex := 12;
end if;
when thers =>
if PCIEN and ( apbaddr(9 downto 8) = "01") then
esel := '1'; bindex := 12; -- 0x100 - 0x200
end if;
if PCIARBEN and ( r.haddr(9 downto 8) = "10") then
esel := '1'; bindex := 13; -- 0x200 - 0x300
end if;
end case;
when thers =>
if PCIEN and ( r.haddr(apbmax downto apbmax-1) /= "00") then
esel := '1'; bindex := 12; -- 0x4000 - 0xFFFC
end if;
end case;
3. An analysis of the AMBA BUS
4.1 Ahb master waves.
流程如下:hbusreq,htrans,hburst,hprot --- hready ---___----,完成一个存储周期。由于AMBA是流水线方式进行总线传输,所以在hbusreq使能时,其他的信号会传输到下一级进行运算。