Код: Выделить всё
Generic (
N : positive := 8; -- 32bit serial word length is default
CPOL : std_logic := '0'; -- SPI mode selection (mode 0 default)
CPHA : std_logic := '0'; -- CPOL = clock polarity, CPHA = clock phase.
PREFETCH : positive := 2; -- prefetch lookahead cycles
SPI_2X_CLK_DIV : positive := 5); Код: Выделить всё
case (state_reg) is
when (N+1) => -- ýòî ñîñòîÿíèå âêëþ÷àåò SSEL ïðåðåä SCK this state is to enable SSEL before SCK
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
ssel_ena_next <= '1'; -- tx in progress: will assert SSEL
sck_ena_next <= '1'; -- enable SCK on next cycle (stays off on first SSEL clock cycle)
di_req_next <= '0'; -- prefetch data request: deassert when shifting data
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
state_next <= state_reg - 1; -- îáíîâëåíèå ñëåäóþùåãî ñîñòîÿíèÿ êàæäûé èìïóëüñ sck
when (N) => -- deassert 'di_rdy' and stretch do_valid
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
di_req_next <= '0'; -- prefetch data request: deassert when shifting data
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
state_next <= state_reg - 1; -- îáíîâëåíèå ñëåäóþùåãî ñîñòîÿíèÿ êàæäûé èìïóëüñ sck
when (N-1) downto (PREFETCH+3) => -- remove 'do_transfer' and shift bits
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
di_req_next <= '0'; -- prefetch data request: deassert when shifting data
do_transfer_next <= '0'; -- reset 'do_valid' transfer signal
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
state_next <= state_reg - 1; -- îáíîâëåíèå ñëåäóþùåãî ñîñòîÿíèÿ êàæäûé èìïóëüñ sck
when (PREFETCH+2) downto 2 => -- raise prefetch 'di_req_o' signal
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
di_req_next <= '1'; -- request data in advance to allow for pipeline delays
sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits
sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
state_next <= state_reg - 1; -- îáíîâëåíèå ñëåäóþùåãî ñîñòîÿíèÿ êàæäûé èìïóëüñ sck
when 1 => -- transfer rx data to do_buffer and restart if new data is written
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
di_req_next <= '1'; -- request data in advance to allow for pipeline delays
do_buffer_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift rx data directly into rx buffer
do_buffer_next(0) <= rx_bit_reg; -- shift last rx bit into rx buffer
do_transfer_next <= '1'; -- signal transfer to do_buffer
if wren = '1' then -- load tx register if valid data present at di_i
state_next <= N; -- next state is top bit of new data
sh_next <= di_reg; -- load parallel data from di_reg into shifter
sck_ena_next <= '1'; -- SCK enabled
wr_ack_next <= '1'; -- acknowledge data in transfer
else
sck_ena_next <= '0'; -- SCK disabled: tx empty, no data to send
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
state_next <= state_reg - 1; -- îáíîâëåíèå ñëåäóþùåãî ñîñòîÿíèÿ êàæäûé èìïóëüñ sck
end if;
when 0 => -- idle state: start and end of transmission
di_req_next <= '1'; -- will request data if shifter empty
sck_ena_next <= '0'; -- SCK disabled: tx empty, no data to send
if wren = '1' then -- load tx register if valid data present at di_i
spi_mosi_o <= di_reg(N-1); -- special case: shift out first tx bit from the MSb (look ahead)
ssel_ena_next <= '1'; -- enable interface SSEL
state_next <= N+1; -- start from idle: let one cycle for SSEL settling
sh_next <= di_reg; -- load bits from di_reg into shifter
wr_ack_next <= '1'; -- acknowledge data in transfer
else
spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb
ssel_ena_next <= '0'; -- deassert SSEL: interface is idle
wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages
state_next <= 0; -- when idle, keep this state
end if;
when others =>
state_next <= 0; -- state 0 is safe state
end case; автомат не определяет состояния 6, 7
т.е. state_reg = 7, выполнился соответствующий код и state_reg стал = 6
и второй раз в этот случай автомат не заходит, а кидается в when others. (он думает, что 6 не находится в диапазоне (N-1) downto (PREFETCH+3) )
если изменить
when (N-1) downto (PREFETCH+3)
на
when 7 downto 5
то работает как должен
почему так происходит?
и как бороться?
как бороться в принципе понятно - можно if сделать, но хотелось бы не трогать готовый код, может косяк в Active-Hdl?