Skip to content

Instantly share code, notes, and snippets.

@thetooth
Last active August 29, 2015 14:22
Show Gist options
  • Select an option

  • Save thetooth/a676fd15a9f176d2609f to your computer and use it in GitHub Desktop.

Select an option

Save thetooth/a676fd15a9f176d2609f to your computer and use it in GitHub Desktop.
Controller FSM
library ieee;
use ieee.std_logic_1164.all;
library MACHXO2;
use MACHXO2.components.all;
-- Opcode Size Description CMD Access
------------------------------------------------------------------------------------------
-- Operation codes for SPI FSM
------------------------------------------------------------------------------------------
-- INJMDR 16 Injector main delta 0xA0 Write
-- INJPDR 16 Injector preinjection delta 0xA1 Write
-- INJBEN 0 Disables timing adjustment 0xA2 Write
-- UFMADR 8 Address user flash memory 0xE0 Read/Write
-- (last page returned, write 0xFF to retain last page)
-- UFMWRR 128 Write UFM page 0xE1 Write
-- UFMRDR 128 Read UFM page 0xE2 Read
------------------------------------------------------------------------------------------
-- EFB SPI memory mapped register addresses are 0x54-0x5D
------------------------------------------------------------------------------------------
-- SPICR0 Control Reg 0 0x54 Read/Write
-- SPICR1 Control Reg1 0x55 Read/Write
-- SPICR2 Control Reg2 0x56 Read/Write
-- SPIBR Clock Pre-Scale 0x57 Read/Write
-- SPICSR Master Chip Select 0x58 Read/Write
-- SPITXDR Transmit Data 0x59 Write
-- SPISR Status 0x5A Read
-- SPIRXDR Receive Data 0x5B Read
-- SPIIRQ Interrupt Request 0x5C Read/Write
-- SPIIRQEN Interrupt Request Enable 0x5D Read/Write
entity SPICtl is
port(
-- Control Plane
clk : in std_logic;
nreset : in std_logic;
spi_clk : inout std_logic;
spi_scsn : in std_logic;
spi_irq : out std_logic;
busy_out : out std_logic;
-- Data Plane
spi_mosi : inout std_logic;
spi_miso : inout std_logic;
debug : out std_logic_vector(15 downto 0);
INJMDR : out std_logic_vector(15 downto 0)
);
end SPICtl;
architecture logic of SPICtl is
component Embedded_Function_Block
port(
wb_clk_i : in std_logic;
wb_rst_i : in std_logic;
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_adr_i : in std_logic_vector(7 downto 0);
wb_dat_i : in std_logic_vector(7 downto 0);
wb_dat_o : out std_logic_vector(7 downto 0);
wb_ack_o : out std_logic;
spi_clk : inout std_logic;
spi_miso : inout std_logic;
spi_mosi : inout std_logic;
spi_scsn : in std_logic;
spi_irq : out std_logic
);
end component;
component SPI_wbController
port(
clk : in std_logic;
nreset : in std_logic;
wb_bus_en : in std_logic;
wb_ack_o : in std_logic;
wb_valid_address : in std_logic_vector(7 downto 0);
wb_valid_data : in std_logic_vector(7 downto 0);
wb_valid_data_o : in std_logic_vector(7 downto 0);
w_enable : in std_logic;
busy : out std_logic;
wb_rst_i : out std_logic;
wb_cyc_i : out std_logic;
wb_stb_i : out std_logic;
wb_we_i : out std_logic;
wb_adr_i : out std_logic_vector(7 downto 0);
wb_dat_o : out std_logic_vector(7 downto 0);
wb_dat_i : out std_logic_vector(7 downto 0)
);
end component;
-- Local wishbone bus signals from wb state machine controller
signal w_enable : std_logic;
signal wb_rst_i : std_logic;
signal wb_cyc_i : std_logic;
signal wb_stb_i : std_logic;
signal wb_we_i : std_logic;
signal wb_adr_i : std_logic_vector(7 downto 0);
signal wb_dat_i : std_logic_vector(7 downto 0);
signal wb_dat_o : std_logic_vector(7 downto 0);
signal wb_ack_o : std_logic;
signal wb_busy : std_logic;
signal wb_bus_en : std_logic;
signal reg_address : std_logic_vector(7 downto 0);
signal tx_address : std_logic_vector(7 downto 0);
signal tx_reg : std_logic_vector(7 downto 0);
-- Encode for one hot fsm :^)
type state_type is (ready, RxRDY, get_data, get_opcode, get_INJMDR_data1, get_INJMDR_data2, TxRDY, put_data);
attribute enum_encoding : string;
attribute enum_encoding of state_type : type is "00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000";
signal state_reg, state_next, cmd_reg : state_type;
signal reg_address_ff : std_logic_vector(7 downto 0);
begin
-- The spi bus is instantiated through the EFB within IPExpress
I0 : Embedded_Function_Block
port map (wb_clk_i => clk, wb_rst_i => wb_rst_i, wb_cyc_i => wb_cyc_i, wb_stb_i => wb_stb_i,
wb_we_i => wb_we_i, wb_adr_i(7 downto 0) => wb_adr_i(7 downto 0),
wb_dat_i(7 downto 0) => wb_dat_i(7 downto 0), wb_dat_o(7 downto 0) => wb_dat_o(7 downto 0), -- This is the data that comes from the master such as an address to mux to the tx buffer to the wb_data_i
wb_ack_o => wb_ack_o, spi_clk => spi_clk, spi_miso => spi_miso,
spi_mosi => spi_mosi, spi_scsn => spi_scsn, spi_irq => spi_irq);
-- The spi controller is used to control the machxo2 wishbone bus interfacing the spi
I1 : SPI_wbController
port map ( clk => clk, nreset => nreset, wb_bus_en => wb_bus_en, wb_ack_o => wb_ack_o,
wb_valid_address(7 downto 0) => tx_address(7 downto 0),
w_enable => w_enable, busy => wb_busy,
wb_valid_data(7 downto 0) => tx_reg(7 downto 0),
wb_valid_data_o(7 downto 0) => wb_dat_o(7 downto 0),
wb_rst_i => wb_rst_i, wb_cyc_i => wb_cyc_i, wb_stb_i => wb_stb_i,
wb_we_i => wb_we_i, wb_adr_i(7 downto 0) => wb_adr_i(7 downto 0),
wb_dat_o(7 downto 0) => reg_address(7 downto 0),
wb_dat_i(7 downto 0) => wb_dat_i(7 downto 0)); -- This is the data going out to the master from the txbuffer
-- State update and timing with synch active low reset
process(clk, nreset)
begin
if(rising_edge(clk)) then
if(nreset = '0') then
state_reg <= ready;
else
state_reg <= state_next;
end if;
end if;
end process;
-- Control logic state machine, add to sensitivity list as needed when modified
process(state_reg, reg_address, reg_address_ff, wb_busy)
begin
-- default conditions
tx_address(7 downto 0) <= (others => 'Z');
tx_reg(7 downto 0) <= (others => 'Z');
-- testing
wb_bus_en <= '0';
case state_reg is
-- Initial state
------------------------------------------------------------------------------
when ready =>
wb_bus_en <= '0';
tx_address(7 downto 0) <= (others => 'Z');
tx_reg(7 downto 0) <= (others => 'Z');
if( wb_busy = '1') then
state_next <= state_reg;
else
state_next <= RxRDY;
end if;
-- Read status reg to see if reciever contains a reg address yet
------------------------------------------------------------------------------
when RxRDY =>
wb_bus_en <= '1'; -- starts wishbone controller fsm
w_enable <= '0'; -- set to read the wb
-- load wishbone status register
tx_address(7 downto 0) <= X"5A";
if(wb_busy = '1') then
state_next <= state_reg;
else
if(reg_address(3) = '1') then
state_next <= get_data;
else
state_next <= state_reg;
end if;
end if;
-- This state is used to get the address data from the master
------------------------------------------------------------------------------
when get_data =>
wb_bus_en <= '0';
w_enable <= '0';
-- load wishbone reciever register
tx_address(7 downto 0) <= X"5B";
if(wb_busy= '1') then
state_next <= state_reg;
else
if(cmd_reg = ready) then
state_next <= get_opcode;
else
state_next <= cmd_reg;
end if;
end if;
-- This state checks and stores the recieved operation code
------------------------------------------------------------------------------
when get_opcode =>
wb_bus_en <= '1';
w_enable <= '0';
tx_address(7 downto 0) <= X"5B";
reg_address_ff(7 downto 0) <= reg_address;
if( wb_busy = '1') then
state_next <= state_reg;
else
case reg_address_ff(7 downto 0) is
when X"A0" =>
cmd_reg <= get_INJMDR_data1;
state_next <= RxRDY;
when others =>
state_next <= TxRDY;
end case;
end if;
-- This state is used to latch in the data into the application register
------------------------------------------------------------------------------
when get_INJMDR_data1 =>
wb_bus_en <= '1';
w_enable <= '0';
tx_address(7 downto 0) <= X"5B";
INJMDR(15 downto 8) <= reg_address;
if( wb_busy = '1') then
state_next <= state_reg;
else
cmd_reg <= get_INJMDR_data2;
state_next <= RxRDY; -- Get next byte
end if;
when get_INJMDR_data2 =>
wb_bus_en <= '1';
w_enable <= '0';
tx_address(7 downto 0) <= X"5B";
INJMDR(7 downto 0) <= reg_address;
if( wb_busy = '1') then
state_next <= state_reg;
else
cmd_reg <= ready;
state_next <= TxRDY; -- Final transaction
end if;
-- This state checks the status of the spi transmitter to ensure its empty
------------------------------------------------------------------------------
when TxRDY =>
wb_bus_en <= '1';
w_enable <= '0';
tx_address(7 downto 0) <= X"5A";
if(wb_busy = '1') then
state_next <= state_reg;
else
if(reg_address(4) = '1') then
state_next <= put_data;
else
state_next <= state_reg;
end if;
end if;
-- This state sends the requested data to the spi transmit buffer
------------------------------------------------------------------------------
when put_data =>
wb_bus_en <= '1';
w_enable <= '1'; -- set to write to master
-- load wishbone transmitter register
tx_address(7 downto 0) <= X"59";
-- Add extra addresses and data lines to this if-elsif statement
-- when connecting more shit
--if(reg_address_ff = X"A3") then
-- tx_reg(7 downto 0) <= tx_data(7 downto 0);
--else
tx_reg(7 downto 0) <= "00000000";
--end if;
if( wb_busy = '1') then
state_next <= state_reg;
else
state_next <= RxRDY; -- ! Should be `ready`, maybe needs nreset signal
end if;
end case;
end process;
busy_out <= wb_busy;
end logic;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment