📄 spi3-aciklamali.txt
字号:
signal master_mode : std_ulogic; -- Master mode when 1
signal misoe_lcl : std_ulogic; -- local version
signal mosie_lcl : std_ulogic; -- local version
signal oflow : std_ulogic;
signal open_drain : std_ulogic;
signal phase : std_ulogic;
signal polck : std_ulogic;
signal sck_r1 : std_ulogic;
signal sck_r2 : std_ulogic;
signal sck_r3 : std_ulogic; -- synchronizers
signal sel_clk : std_ulogic_vector(1 downto 0);
signal shift_reg : std_ulogic_vector(7 downto 0);
-- THE SPI shift register
signal shift_clk : std_ulogic;
signal shift_clk_negedge : std_ulogic; -- negative edge of SCK
signal shift_negative_edge_nxt : std_ulogic;
signal shift_negative_edge : std_ulogic;
signal shift_datain : std_ulogic;
signal shift_dataout : std_ulogic;
signal slvsel_r1 : std_ulogic;
signal slvsel_r2 : std_ulogic;
signal slvsel_r3 : std_ulogic; -- synchronizers
signal spi_go : std_ulogic; -- begin a transfer
signal ssel : std_ulogic_vector(7 downto 0);
-- slave select register
signal status : std_ulogic_vector(7 downto 0);
-- status register
signal tx_end : std_ulogic;
-- TX has completed, TX_RUN will go low
signal tx_run : std_ulogic; -- tx is running
signal tx_start : std_ulogic;
signal tx_start_r1 : std_ulogic;
begin ---------------------------------------------------------------
mosio <= shift_dataout when mosie_lcl='1' and open_drain='0' else
'0';
mosie <= mosie_lcl when open_drain='0' else
'1' when mosie_lcl='1' and shift_dataout='0' else
-- drive low when open drain enabled.
'0';
misoo <= shift_dataout when misoe_lcl='1' and open_drain='0' else
'0';
misoe <= misoe_lcl when open_drain='0' else
'1' when misoe_lcl='1' and shift_dataout='0' else
-- drive low when open drain enabled.
'0';
misoe_lcl <= '1' when master_mode='0' and slvsel='1' else
'0';
mosie_lcl <= '1' when master_mode='1' else
'0';
-- spi_go initiates a transfer - A write to the DOUT reg in master
-- mode ignore the CPU write if we're already running.
spi_go <= '1' when chip_sel='1' and write='1' and addr="00" and
tx_run='0' and slvsel_r3='0' else
'0';
sr_proc : process(clk) -------------Shift register----------------
begin
if (clk'event and clk='1') then
if (rst='1') then
shift_reg <= "00000000"; -- sync reset
else
if (spi_go='1') then -- don't reload while running
shift_reg <= datain; -- load with data from CPU
elsif (shift_clk='1') then
shift_reg <= shift_reg(6 downto 0) & shift_datain;
end if;
end if;
end if;
end process;
neg_proc : process(clk) ----------Hold time register--------------
begin
if (clk'event and clk='1') then -- negative edge pipeline DFF
if (rst='1') then
shift_negative_edge <= '0'; -- sync reset
elsif (shift_clk_negedge='1') then
shift_negative_edge <= shift_negative_edge_nxt;
elsif (spi_go='1') then
shift_negative_edge <= datain(7); -- preload for phase=0 mode
end if;
end if;
end process;
shift_negative_edge_nxt <= shift_reg(7) when phase='1' else
misoi when master_mode='1' else
mosii;
shift_dataout <= shift_negative_edge when phase='1' else
-- add in the negative edge dff on phase=1
shift_reg(7);
shift_datain <= shift_negative_edge when phase='0' else
-- insert the neg DFF in phase=0
misoi when master_mode='1' else
mosii;
tr_proc : process(clk) ---------------TX run------------------
-- this bit is active while a transmit is running
begin
if (clk'event and clk='1') then
if (rst='1') then
tx_run <= '0'; -- sync reset
else
if (tx_start='1') then
tx_run <= '1';
elsif (tx_end='1') then
tx_run <= '0';
end if;
end if;
end if;
end process;
bc_proc : process (clk)
begin -------------Bit counter for master mode----------------
if (clk'event and clk='1') then
if (rst='1') then -- sync reset
bit_ctr <= "000";
else
if (tx_start='1') then
bit_ctr <= ssel(7 downto 5);
elsif (shift_clk='1') then
bit_ctr <= std_ulogic_vector(unsigned(bit_ctr)-1);
end if;
end if;
end if;
end process; -- bit counter
tx_end <= '1' when master_mode='1' and bit_ctr="001"
and shift_clk='1' and tx_run='1' else
'0';
tx_start <= '1' when master_mode='1' and spi_go='1' else
'0';
gjr_proc : process (clk)
begin ---------Control Register----------------------
if (clk'event and clk='1') then
if (rst='1') then -- sync reset
ctl_reg <= "00000000";
else
if (chip_sel='1' and write='1' and addr="01") then -- load
ctl_reg <= datain;
end if;
end if;
end if;
end process;
-- map the control register to more meaningfull names
master_mode <= ctl_reg(1);
open_drain <= ctl_reg(2);
polck <= ctl_reg(3);
phase <= ctl_reg(4);
sel_clk <= ctl_reg(6 downto 5);
s_proc : process (clk)
begin ---------Slave Select Register-------------------------
if (clk'event and clk='1') then
if (rst='1') then -- sync reset
ssel <= "00000000";
else
if (chip_sel='1' and write='1' and addr="11") then -- load
ssel <= datain;
end if;
end if;
end if;
end process;
slvselo <= ssel(4 downto 0); -- drive the port
slvsele <= master_mode;
cf_proc : process (clk)
begin ---------Collision flag bit---------------------------
if (clk'event and clk='1') then
if (rst='1') then
col_flag <= '0';
else
if (master_mode='1' and slvsel_r3='1') then
col_flag <= '1';
elsif (chip_sel='1' and write='1'
and addr="10" and datain(5)='1') then
col_flag <= '0';
end if;
end if;
end if;
end process;
o_proc : process (clk)
begin ---------OFLOw flag bit------------------------------
if (clk'event and clk='1') then
if (rst='1') then
oflow <= '0';
else
if (chip_sel='1' and write='1' and addr="00" and
-- write to DOUT
(tx_run='1' or slvsel_r3='1')) then -- and we're busy
oflow <= '1';
elsif (chip_sel='1' and write='1' and addr="10"
and datain(6)='1') then
oflow <= '0';
end if;
end if;
end if;
end process;
elr_proc : process (clk)
begin ---------IRQ flag bit------------------------------
if (clk'event and clk='1') then
if (rst='1') then
irq_flag <= '0';
else
if (tx_end='1' or (slvsel_r2='0' and slvsel_r3='1')) then
irq_flag <= '1';
elsif (chip_sel='1' and write='1' and addr="10"
and datain(7)='1') then
irq_flag <= '0';
end if;
end if;
end if;
end process;
irq <= irq_flag and ctl_reg(7); -- gate with the IRQENB bit.
flops_proc : process (clk)
begin ----------------various pipeline flops---------
if (clk'event and clk='1') then
slvsel_r3 <= slvsel_r2;
slvsel_r2 <= slvsel_r1; -- synchronizers
slvsel_r1 <= slvsel;
sck_r3 <= sck_r2;
sck_r2 <= sck_r1; -- synchronizers
sck_r1 <= not scki xor polck;
-- select the desired polarity of the slave clk
tx_start_r1 <= tx_start;
end if;
end process;
dvd_proc : process (clk)
begin----------------clock divider for clk generation-------
-- create a 2x clock which creates 2 pulses.
-- One for each edge of SCK.
if (clk'event and clk='1') then
if (not (tx_run='1' and master_mode='1') or tx_end='1') then
-- divider only runs when sending data
dvd_ctr <= "00000";
dvd2 <= '0';
else
if (dvd_ctr="00000") then
if (sel_clk="00") then
dvd_ctr <= "00011";
elsif (sel_clk="01") then
dvd_ctr <= "00111";
elsif (sel_clk="10") then
dvd_ctr <= "01111";
else
dvd_ctr <= "11111";
end if;
if (tx_start_r1='0') then
dvd2 <= not dvd2;
end if;
else
dvd_ctr <= std_ulogic_vector(unsigned(dvd_ctr)-1);
end if;
end if;
end if;
end process; -- dvd
dvd_zero <= '1' when dvd_ctr="00000" else
'0';
shift_clk <= dvd_zero and dvd2 and tx_run and not tx_start_r1
-- TX_START_R1 prevents data from shifting on the first
-- clock in POLCK=1 mode which we don't want.We only get
-- 7 clocks otherwise.
when master_mode='1' else
sck_r2 and not sck_r3;
shift_clk_negedge <= dvd_zero and not dvd2 and tx_run
when master_mode='1'
else not sck_r2 and sck_r3;
with addr select
dataout <= -- dataout multiplexor for register readback
shift_reg when "00",
ctl_reg when "01",
status when "10",
ssel when "11",
"XXXXXXXX" when others;
-- assemble the bits that make up the status register
status <= irq_flag & oflow & col_flag & "000" & tx_run & slvsel_r3;
scke <= master_mode;
scko <= dvd2 xor polck;
end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -