diff options
Diffstat (limited to 'fpga/usrp3/top/n3xx/dboards/common/PkgRegs.vhd')
-rw-r--r-- | fpga/usrp3/top/n3xx/dboards/common/PkgRegs.vhd | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/fpga/usrp3/top/n3xx/dboards/common/PkgRegs.vhd b/fpga/usrp3/top/n3xx/dboards/common/PkgRegs.vhd new file mode 100644 index 000000000..783e86e9c --- /dev/null +++ b/fpga/usrp3/top/n3xx/dboards/common/PkgRegs.vhd @@ -0,0 +1,314 @@ +-- +-- Copyright 2018 Ettus Research, a National Instruments Company +-- +-- SPDX-License-Identifier: LGPL-3.0-or-later +-- +-- This package contains functions for reading and writing N310 registers. + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + + +package PkgRegs is + + + -- RegPort Type Definitions : --------------------------------------------------------- + -- ------------------------------------------------------------------------------------ + + constant kAddressWidth : integer := 16; + + subtype InterfaceData_t is std_logic_vector(31 downto 0); + type RegDataAry_t is array (natural range <>) of InterfaceData_t; + constant kRegPortDataZero : InterfaceData_t := (others => '0'); + + -- The type of the signal used to communicate from the Interface + -- component to the frameworks + type RegPortIn_t is record + Address : unsigned(kAddressWidth - 1 downto 0); + Data : InterfaceData_t; + Rd : boolean; -- Must be a one clock cycle pulse + Wt : boolean; -- Must be a one clock cycle pulse + end record; + + -- The type of the signal used to communicate to the Interface + -- component from the frameworks + -- Ready is just the Ready signal from the Handshake component. + -- Address in RegPortIn_t should be valid in the cycle where Data, DataValid, + -- or Ready are being sampled by the bus communication interface. + type RegPortOut_t is record + Data : InterfaceData_t; + DataValid : boolean; -- Must be a one clock cycle pulse + Ready : boolean; -- Must be valid one clock after Wt assertion + end record; + + -- Constants for the RegPort + constant kRegPortInZero : RegPortIn_t := ( + Address => to_unsigned(0,kAddressWidth), + Data => (others => '0'), + Rd => false, + Wt => false); + + constant kRegPortOutZero : RegPortOut_t := ( + Data => (others=>'0'), + DataValid => false, + Ready => true); + + + + -- Register Offset Types : ------------------------------------------------------------ + -- ------------------------------------------------------------------------------------ + + -- Custom type for defining register spaces. Is it assumed that all defined register + -- addresses for each space are kOffset <= Address < kOffset+kWidth. Therefore when + -- Address equals kOffset+kWidth, we are not talking to this space but the space + -- above it. + type RegOffset_t is record + kOffset : integer; + kWidth : integer; + end record; + + constant kRegOffsetZero : RegOffset_t := (kOffset => 16#0#, kWidth => 16#04#); + + + + -- Access Functions : ----------------------------------------------------------------- + -- ------------------------------------------------------------------------------------ + + -- Helper function to combine register ports on their way back upstream. + function "+" (L, R : RegPortOut_t) return RegPortOut_t; + + function Mask(RegPortIn : in RegPortIn_t; + kRegisterOffset : in RegOffset_t) return RegPortIn_t; + + -- Helper functions to determine when a register is targeted by the RegPort. There + -- are three groups: RegSelected, RegWrite, and RegRead. The latter two call + -- RegSelected to determine if a register is targeted and being read or written. + -- RegSelected is also overloaded to accommodate the RegOffset_t type. + -- function RegSelected (RegPortIn : RegPortIn_t; + -- RegisterOffset : RegOffset_t) return boolean; + function RegSelected (RegOffset : integer; + RegPortIn : RegPortIn_t) return boolean; + function RegWrite (Address : integer; + RegPortIn : RegPortIn_t) return boolean; + function RegRead (Address : integer; + RegPortIn : RegPortIn_t) return boolean; + + function OrArray(ArrayIn : RegDataAry_t) return std_logic_vector; + + + + + -- Flattening Functions : ------------------------------------------------------------- + -- ------------------------------------------------------------------------------------ + + constant kFlatRegPortInSize : natural := kAddressWidth + + InterfaceData_t'length + + 2; + + subtype FlatRegPortIn_t is std_logic_vector(kFlatRegPortInSize-1 downto 0); + + constant kFlatRegPortOutSize : natural := InterfaceData_t'length + + 2; + + subtype FlatRegPortOut_t is std_logic_vector(kFlatRegPortOutSize-1 downto 0); + + function Flatten(Var : RegPortIn_t) return FlatRegPortIn_t; + function Unflatten(Var : FlatRegPortIn_t) return RegPortIn_t; + + function Flatten(Var : RegPortOut_t) return FlatRegPortOut_t; + function Unflatten(Var : FlatRegPortOut_t) return RegPortOut_t; + + + + +end PkgRegs; + + +package body PkgRegs is + + -- Combines RegPortOut_t types together + function "+" (L, R : RegPortOut_t) return RegPortOut_t + is + variable ReturnVal : RegPortOut_t; + begin + ReturnVal := kRegPortOutZero; + ReturnVal.Data := L.Data or R.Data; + ReturnVal.DataValid := L.DataValid or R.DataValid; + ReturnVal.Ready := L.Ready and R.Ready; + return ReturnVal; + end function; + + + -- This function lops off the portion of the register bus that is + -- decoded in the InAddrSpace function in order to reduce the number of bits + -- decoded by the register read logic. Also, the Rd and Wt strobes are gated + -- as well. + function Mask(RegPortIn : in RegPortIn_t; + kRegisterOffset : in RegOffset_t) return RegPortIn_t + is + variable RegPortInVar : RegPortIn_t; + variable InSpace : boolean := false; + begin + + InSpace := (RegPortIn.Address >= kRegisterOffset.kOffset) and + (RegPortIn.Address < kRegisterOffset.kOffset + kRegisterOffset.kWidth); + + -- Compare the most significant bits of the address bus downto the LSb + -- that we just calculated. + if InSpace then + -- If in address space then allow Rd and Wt to assert + RegPortInVar.Rd := RegPortIn.Rd; + RegPortInVar.Wt := RegPortIn.Wt; + else + RegPortInVar.Rd := kRegPortInZero.Rd; + RegPortInVar.Wt := kRegPortInZero.Wt; + end if; + + RegPortInVar.Data := RegPortIn.Data; + RegPortInVar.Address := RegPortIn.Address - kRegisterOffset.kOffset; + return RegPortInVar; + end function Mask; + + + -- Returns true when this chip is selected and the address matches the register. + -- Note that RegOffset is divided by 4 before being compared against the register + -- port Address value. + function RegSelected (RegOffset : integer; + RegPortIn : RegPortIn_t) return boolean is + begin + return RegPortIn.Address = to_unsigned(RegOffset, RegPortIn.Address'length); + end function RegSelected; + + -- Returns true when the register is being written. + function RegWrite (Address : integer; + RegPortIn : RegPortIn_t) return boolean is + begin + return RegSelected(Address, RegPortIn) and RegPortIn.Wt; + end function RegWrite; + + -- Returns true when the register is being read. + function RegRead (Address : integer; + RegPortIn : RegPortIn_t) return boolean is + begin + return RegSelected(Address, RegPortIn) and RegPortIn.Rd; + end function RegRead; + + -- Overloaded version of RegSelected for the RegOffset_t + -- NOTE!!! Offset <= Address < Offset+Width + -- Therefore, this function assumes that when Address = Offset+Width we are talking to + -- a different register group than the one given in RegisterOffset. + -- function RegSelected (RegPortIn : RegPortIn_t; + -- RegisterOffset : RegOffset_t) return boolean is + -- begin + -- return (RegPortIn.Address >= to_unsigned(RegisterOffset.kOffset, RegPortIn.Address'length)) and + -- (RegPortIn.Address < to_unsigned(RegisterOffset.kOffset + RegisterOffset.kWidth, RegPortIn.Address'length)); + -- end function RegSelected; + + function OrArray(ArrayIn : RegDataAry_t) return std_logic_vector + is + variable ReturnVar : std_logic_vector(ArrayIn(ArrayIn'right)'range); + begin + ReturnVar := (others => '0'); + for i in ArrayIn'range loop + ReturnVar := ReturnVar or ArrayIn(i); + end loop; + return ReturnVar; + end function OrArray; + + + function to_Boolean (s : std_ulogic) return boolean is + begin + return (To_X01(s)='1'); + end to_Boolean; + + function to_StdLogic(b : boolean) return std_ulogic is + begin + if b then + return '1'; + else + return '0'; + end if; + end to_StdLogic; + + + + ----------------------------------------------------- + -- REG PORTS (FROM PkgCommunicationInterface) + -- + -- subtype InterfaceData_t is std_logic_vector(31 downto 0); + -- + -- constant kAddressWidth : positive := kAddressWidth - 2; + -- + -- type RegPortIn_t is record + -- Address : unsigned(kAddressWidth - 1 downto 0); + -- Data : InterfaceData_t; + -- Rd : boolean; -- Must be a one clock cycle pulse + -- Wt : boolean; -- Must be a one clock cycle pulse + -- end record; + + function Flatten(Var : RegPortIn_t) return FlatRegPortIn_t is + variable Index : natural; + variable RetVar : FlatRegPortIn_t; + begin + Index := 0; + RetVar(Index) := to_StdLogic(Var.Wt); Index := Index + 1; + RetVar(Index) := to_StdLogic(Var.Rd); Index := Index + 1; + RetVar(Index + Var.Data'length - 1 downto Index) := std_logic_vector(Var.Data); + Index := Index + Var.Data'length; + RetVar(Index + Var.Address'length - 1 downto Index) := std_logic_vector(Var.Address); + Index := Index + Var.Address'length; + + return RetVar; + end function Flatten; + + function Unflatten(Var : FlatRegPortIn_t) return RegPortIn_t is + variable Index : natural; + variable RetVal : RegPortIn_t; + begin + Index := 0; + RetVal.Wt := to_Boolean(Var(Index)); Index := Index + 1; + RetVal.Rd := to_Boolean(Var(Index)); Index := Index + 1; + RetVal.Data := InterfaceData_t(Var(Index + RetVal.Data'length - 1 downto Index)); + Index := Index + RetVal.Data'length; + RetVal.Address := unsigned(Var(Index + RetVal.Address'length - 1 downto Index)); + Index := Index + RetVal.Address'length; + + return RetVal; + end function Unflatten; + + -- type RegPortOut_t is record + -- Data : InterfaceData_t; + -- DataValid : boolean; -- Must be a one clock cycle pulse + -- Ready : boolean; -- Must be valid one clock after Wt assertion + -- end record; + + function Flatten(Var : RegPortOut_t) return FlatRegPortOut_t is + variable Index : natural; + variable RetVar : FlatRegPortOut_t; + begin + Index := 0; + RetVar(Index) := to_StdLogic(Var.Ready); Index := Index + 1; + RetVar(Index) := to_StdLogic(Var.DataValid); Index := Index + 1; + RetVar(Index + Var.Data'length - 1 downto Index) := std_logic_vector(Var.Data); + Index := Index + Var.Data'length; + + return RetVar; + end function Flatten; + + function Unflatten(Var : FlatRegPortOut_t) return RegPortOut_t is + variable Index : natural; + variable RetVal : RegPortOut_t; + begin + Index := 0; + RetVal.Ready := to_Boolean(Var(Index)); Index := Index + 1; + RetVal.DataValid := to_Boolean(Var(Index)); Index := Index + 1; + RetVal.Data := InterfaceData_t(Var(Index + RetVal.Data'length - 1 downto Index)); + Index := Index + RetVal.Data'length; + + return RetVal; + end function Unflatten; + + + +end PkgRegs; |