1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
-- From Altera Solution ID rd05312011_49, need the following for Qsys to use VHDL 2008:
-- altera vhdl_input_version vhdl_2008
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.log2;
-- -----------------------------------------------------------------------------
-- Entity: rfic_spi_controller
-- Description: Avalon Memory-Mapped SPI controller for the LMS6002D.
-- Standard: VHDL-2008
--
-- WARNING: This module has not been tested with non-default generics.
-- -----------------------------------------------------------------------------
entity rfic_spi_controller is
generic(
CLOCK_DIV : positive range 2 to 16 := 2; -- Ratio of system clock to SPI clock
ADDR_WIDTH : positive := 16; -- Number of address bits in an operation
DATA_WIDTH : positive := 8 -- Number of data bits in an operation
);
port(
-- Physical Interface
sclk : out std_logic;
miso : in std_logic;
mosi : out std_logic;
cs_n : out std_logic;
-- Avalon-MM Interface
mm_clock : in std_logic; -- System clock
mm_reset : in std_logic; -- System reset
mm_read : in std_logic; -- Initiates a SPI read operation
mm_write : in std_logic; -- Initiates a SPI write operation
mm_addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); -- SPI address
mm_din : in std_logic_vector(DATA_WIDTH-1 downto 0); -- SPI write data
mm_dout : out std_logic_vector(DATA_WIDTH-1 downto 0); -- SPI read data
mm_dout_val : out std_logic; -- Read data valid.
mm_busy : out std_logic -- Indicates the module is busy processing a command
);
end entity;
architecture rfic of rfic_spi_controller is
constant RFIC_ADDR_WIDTH : positive := 15;
constant RFIC_DATA_WIDTH : positive := 8;
constant MSG_LENGTH : positive := 1 + RFIC_ADDR_WIDTH + RFIC_DATA_WIDTH;
-- FSM States
type fsm_t is (
IDLE,
SHIFT
);
-- State of internal signals
type state_t is record
state : fsm_t;
clock_count : unsigned(integer(log2(real(CLOCK_DIV)))-1 downto 0);
shift_en : std_logic;
shift_count : natural range 0 to MSG_LENGTH;
shift_out_reg : unsigned(MSG_LENGTH-1 downto 0);
shift_in_reg : unsigned(MSG_LENGTH-1 downto 0);
sclk : std_logic;
cs_n : std_logic;
read_op : std_logic;
rd_data_valid : std_logic;
end record;
constant reset_value : state_t := (
state => IDLE,
clock_count => (others => '0'),
shift_en => '0',
shift_count => 0,
shift_out_reg => (others => '0'),
shift_in_reg => (others => '0'),
sclk => '1',
cs_n => '1',
read_op => '0',
rd_data_valid => '0'
);
signal current : state_t;
signal future : state_t;
begin
sync_proc : process( mm_clock, mm_reset )
begin
if( mm_reset = '1' ) then
current <= reset_value;
elsif( rising_edge(mm_clock) ) then
current <= future;
end if;
end process;
comb_proc : process( all )
begin
-- Physical Outputs
sclk <= current.sclk;
cs_n <= current.cs_n;
mosi <= current.shift_out_reg(state_t.shift_out_reg'left);
-- Avalon-MM outputs
mm_dout <= std_logic_vector(current.shift_in_reg(RFIC_DATA_WIDTH-1 downto 0));
mm_dout_val <= current.rd_data_valid;
mm_busy <= '1';
-- Next state defaults
future <= current;
future.sclk <= '1';
future.cs_n <= '1';
future.shift_en <= '0';
future.rd_data_valid <= '0';
case( current.state ) is
when IDLE =>
future.clock_count <= (others => '0');
future.read_op <= mm_read;
mm_busy <= '0';
future.shift_count <= MSG_LENGTH;
if( (mm_read xor mm_write) = '1' ) then
future.shift_out_reg <= mm_write & unsigned(mm_addr(RFIC_ADDR_WIDTH-1 downto 0)) & unsigned(mm_din);
-- Next state logic
future.state <= SHIFT;
future.cs_n <= '0';
end if;
when SHIFT =>
future.cs_n <= '0';
future.clock_count <= current.clock_count + 1;
future.sclk <= current.clock_count(current.clock_count'left);
if( current.clock_count = 0 ) then
future.shift_en <= '1';
else
future.shift_en <= '0';
end if;
if( current.shift_en = '1' ) then
future.shift_in_reg <= current.shift_in_reg(current.shift_in_reg'left-1 downto current.shift_in_reg'right) & miso;
future.shift_out_reg <= current.shift_out_reg(current.shift_out_reg'left-1 downto current.shift_out_reg'right) & '0';
future.shift_count <= current.shift_count - 1;
if( current.shift_count = 1 ) then
-- Only assert read_valid if a read command was issued
future.rd_data_valid <= current.read_op;
future.state <= IDLE;
end if;
end if;
end case;
end process;
end architecture;
|