library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; -- ******* Universal SPI Implementation ******* -- -- WARNING: This is work in progress! -- -- Note: SPI Master io-Procedure must be called with -- SPI clock, SPI Master io-Procedure must be -- called significantly more frequent than SPI clock -- -- => SPI Slave is not implemented yet! -- -- ******************************************** package SPI is subtype tByte is bit_vector(7 downto 0); type tModeCfg is (MODE_SPI_MASTER, MODE_SPI_SLAVE); type tClockPolarity is (CPOL_IDLE_HIGH, CPOL_IDLE_LOW); type tClockPhase is (CPHA_LEADING_SETUP, CPHA_LEADING_SAMPLE); type tState is (LEADING, TRAILING); type tModeSIO is (SPI_SIO_SEND, SPI_SIO_RECV); type tSPIdata is record -- config mode : tModeCfg; -- spi mode (master/slave) cpol : tClockPolarity; cpha : tClockPhase; initial : boolean; -- registers cnt : integer range 0 to 7; state : tState; end record; constant tSPIdata_Default : tSpiData := ( mode => MODE_SPI_MASTER, cpol => CPOL_IDLE_HIGH, cpha => CPHA_LEADING_SETUP, initial => True, cnt => 7, state => LEADING ); -- setup initial signal state procedure init ( signal data : inout tSPIdata; signal MOSI : out bit; signal MISO : in bit; signal SCK : out bit; constant mode : in tModeCfg; constant cpol : in tClockPolarity; constant cpha : in tClockPhase ); procedure initSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; constant mode : in tModeCfg; constant cpol : in tClockPolarity; constant cpha : in tClockPhase ); procedure ioMasterBase ( signal data : inout tSPIdata; signal SCK : out bit; variable done : inout boolean ); procedure ioMaster ( signal data : inout tSPIdata; signal MOSI : out bit; signal MISO : in bit; signal SCK : out bit; signal byteRecv : out tByte; signal byteSend : in tByte; signal done : inout boolean ); procedure ioMasterSendSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteSend : in tByte; signal done : inout boolean ); procedure ioMasterRecvSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteRecv : out tByte; signal done : inout boolean ); procedure ioSlave ( signal data : inout tSPIdata; signal MOSI : in bit; signal MISO : out bit; signal SCK : in bit; signal byteRecv : out tByte; signal byteSend : in tByte; signal done : inout boolean ); procedure ioSlaveSendSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteSend : in tByte; signal done : inout boolean ); procedure ioSlaveRecvSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteRecv : out tByte; signal done : inout boolean ); -- utility function to_std_logic( data : in bit ) return std_logic; -- function to_bit( data : in std_logic ) return bit; end SPI; package body SPI is procedure init( signal data : inout tSPIdata; signal MOSI : out bit; signal MISO : in bit; signal SCK : out bit; constant mode : in tModeCfg; constant cpol : in tClockPolarity; constant cpha : in tClockPhase ) is begin if data.initial then if mode = MODE_SPI_MASTER then if cpol = CPOL_IDLE_HIGH then SCK <= '1'; else SCK <= '0'; end if; end if; MOSI <= '1'; data.mode <= mode; data.cpol <= cpol; data.cpha <= cpha; data.initial <= False; end if; end init; procedure initSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; constant mode : in tModeCfg; constant cpol : in tClockPolarity; constant cpha : in tClockPhase ) is begin if data.initial then if mode = MODE_SPI_MASTER then if cpol = CPOL_IDLE_HIGH then SCK <= '1'; else SCK <= '0'; end if; end if; DIO <= 'Z'; data.mode <= mode; data.cpol <= cpol; data.cpha <= cpha; data.initial <= False; end if; end initSIO; procedure ioMasterBase ( signal data : inout tSPIdata; signal SCK : out bit; variable done : inout boolean ) is begin -- update bit counter done := False; if data.state = TRAILING then if data.cnt = 0 then -- done? done := True; -- reset internal states data.cnt <= 7; else data.cnt <= data.cnt - 1; end if; end if; -- update clock if (data.state = LEADING) and (data.cpol = CPOL_IDLE_HIGH) then SCK <= '0'; else SCK <= '1'; end if; -- update state if data.state = TRAILING then data.state <= LEADING; else data.state <= TRAILING; end if; end ioMasterBase; procedure ioMaster( signal data : inout tSPIdata; signal MOSI : out bit; signal MISO : in bit; signal SCK : out bit; signal byteRecv : out tByte; signal byteSend : in tByte; signal done : inout boolean ) is variable doneVar : boolean := False; begin if not done then if ((data.cpha = CPHA_LEADING_SETUP) and (data.state = LEADING)) or ((data.cpha = CPHA_LEADING_SAMPLE) and (data.state = TRAILING)) then -- setup MOSI <= byteSend(data.cnt); else -- sample byteRecv(data.cnt) <= MISO; end if; ioMasterBase(data, SCK, doneVar); if doneVar then done <= True; end if; end if; end ioMaster; procedure ioMasterSendSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteSend : in tByte; signal done : inout boolean ) is variable doneVar : boolean := False; begin if not done then if ((data.cpha = CPHA_LEADING_SETUP) and (data.state = LEADING)) or ((data.cpha = CPHA_LEADING_SAMPLE) and (data.state = TRAILING)) then -- setup DIO <= to_std_logic(byteSend(data.cnt)); end if; ioMasterBase(data, SCK, doneVar); if doneVar then done <= True; DIO <= 'Z'; end if; end if; end ioMasterSendSIO; procedure ioMasterRecvSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteRecv : out tByte; signal done : inout boolean ) is variable doneVar : boolean := False; begin if not done then if ((data.cpha = CPHA_LEADING_SETUP) and (data.state = TRAILING)) or ((data.cpha = CPHA_LEADING_SAMPLE) and (data.state = LEADING)) then -- sample if DIO = '1' then byteRecv(data.cnt) <= '1'; else byteRecv(data.cnt) <= '0'; end if; end if; ioMasterBase(data, SCK, doneVar); if doneVar then done <= True; end if; end if; end ioMasterRecvSIO; procedure ioSlave( signal data : inout tSPIdata; signal MOSI : in bit; signal MISO : out bit; signal SCK : in bit; signal byteRecv : out tByte; signal byteSend : in tByte; signal done : inout boolean ) is begin -- TODO: implement slave io end ioSlave; procedure ioSlaveSendSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteSend : in tByte; signal done : inout boolean ) is begin -- TODO: implement slave io end ioSlaveSendSIO; procedure ioSlaveRecvSIO ( signal data : inout tSPIdata; signal DIO : inout std_logic; signal SCK : out bit; signal byteRecv : out tByte; signal done : inout boolean ) is begin -- TODO: implement slave io end ioSlaveRecvSIO; function to_std_logic( data : in bit ) return std_logic is begin if data = '1' then return '1'; else return '0'; end if; end to_std_logic; end SPI;