URL
https://opencores.org/ocsvn/onewire/onewire/trunk
Subversion Repositories onewire
[/] [onewire/] [trunk/] [HDL/] [ds2405_sim.vhd] - Rev 4
Compare with Previous | Blame | View Log
---------------------------------------------------------------------------------- -- <c>2018 william b hunter -- This file is part of ow2rtd. -- -- ow2rtd is free software: you can redistribute it and/or modify -- it under the terms of the GNU Lessor General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- ow2rtd is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU Lessor General Public License -- along with ow2rtd. If not, see <https://www.gnu.org/licenses/>. ----------------------------------------------------------------------------------- -- Create Date: 10/13/2023 -- file: ds2405_sim.vhd -- description: A simulation model for the DS2405 addressable switch -- -- Generics are used to set the device ID and the timing model -- -- This only simulates the SEARCH, ROM, SKIP, CONFIG, CONV, and READ commands ----------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; ------------------------------------------------------------------------------------- -- Entity declaration ------------------------------------------------------------------------------------- entity ds2405_sim is generic ( timing : in string := "ave"; devid : in std_logic_vector(63 downto 0) := x"1234567123456705" ); port ( --global signals pio : inout std_logic; dio : inout std_logic --synchronous reset ); end ds2405_sim; --library unisim; --use unisim.vcomponents.all; library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.all; library work; architecture sim of ds2405_sim is --low time to trigger a reaset constant tmin_rstl : time := 240 us; constant tave_rstl : time := 400 us; constant tmax_rstl : time := 480 us; signal trstl : time := tmin_rstl; --high time between reset pulse and presence pulse signal tpdih : time; constant tmin_pdih : time := 15 us; constant tave_pdih : time := 45 us; constant tmax_pdih : time := 60 us; --presence pulse low time signal tpdlo : time; constant tmin_pdlo : time := 60 us; constant tave_pdlo : time := 180 us; constant tmax_pdlo : time := 240 us; --write 0 low time signal tlow0 : time; constant tmin_low0 : time := 60 us; constant tave_low0 : time := 100 us; constant tmax_low0 : time := 120 us; --write 1 low time signal tlow1 : time; constant tmin_low1 : time := 1 us; constant tave_low1 : time := 10 us; constant tmax_low1 : time := 15 us; --master write data sample time signal tsamp : time := 1 us; constant tmin_samp : time := 15 us; constant tave_samp : time := 30 us; constant tmax_samp : time := 60 us; --slave read recovery time signal trec : time := 1 us; constant tmin_rec : time := 1 us; constant tave_rec : time := 3 us; constant tmax_rec : time := 6 us; --slave read data valid time signal trdv : time := 15 us; constant tmin_rdv : time := 15 us; constant tave_rdv : time := 30 us; constant tmax_rdv : time := 60 us; --recall from eeprom timing --note: dallas part does not spec this timing signal trecall : time := 100 us; signal tcopy : time := 1 us; constant tmax_copy : time := 10 ms; constant tave_copy : time := 2 ms; constant tmin_copy : time := 1 ms; signal clk10m : std_logic; signal rstdet : std_logic := '0'; --indicates a detected a reset pulse from the master signal trise : time := now; signal tfall : time := now; signal rstdly : std_logic := '1'; --signal tdif : time; signal timertime : time; signal timer : unsigned(15 downto 0); signal timertrig : std_logic := '0'; signal timerdone : std_logic := '1'; signal switch : std_logic := '0'; type state_type is (S_IDLE, S_RSTRESP,S_RSTRESP2,S_RSTRESP3, S_GETBYTE, S_GETBYTE2, S_PARSE, S_READROM, S_READROM2, S_SRCHROM, S_SRCHROMNOT, S_SRCHROMWR, S_MATCHROM, S_MATCHROM2, S_SRCHALARM, S_SKIPROM, S_PARSE2, S_READSW, S_WRITE1, S_WRITE2, S_WRITE3, S_READ, S_READRCVR, S_CRC); signal state : state_type := S_IDLE; signal nxt_state : state_type := S_IDLE; signal dout : std_logic := 'Z'; --read output bit from slave to master signal rstdout : std_logic := '1'; --read output bit from main process signal recalldout : std_logic := '1'; --read output bit from recall process signal copydout : std_logic := '1'; --read output bit from copy process signal convdout : std_logic := '1'; --read output bit from conv process signal readdout : std_logic := '1'; -- output data from read state machine signal din : std_logic := '1'; --resolved input data bit --signal rstout : std_logic := 'Z'; signal bitcnt : integer; signal shiftbyte : std_logic_vector(7 downto 0); signal shiftid : std_logic_vector(63 downto 0); signal busy : std_logic := '0'; --These signals are for the read state machine signal bitout : std_logic := '1'; --bit value to be read by master signal wrbitin : std_logic := '0'; -- the bit value written by the master signal wrbiterr : std_logic := '0'; -- indicates a master write pulse with an illegal timing signal writedet : std_logic := '0'; -- strobe indicating the master wrote a bit signal readen : std_logic := '0'; --enables the slave responses to the master read pulses signal readdet : std_logic := '0'; -- strobe indicating the master read a bit signal readdly : std_logic := '0'; -- delayed version of din for detecting read strobes signal readbit : std_logic := '0'; -- data to output from read state machine signal crc : std_logic_vector(7 downto 0); begin trstl <= tmin_rstl when timing = "MIN" else tave_rstl when timing = "AVE" else tmax_rstl; tpdih <= tmin_pdih when timing = "MIN" else tave_pdih when timing = "AVE" else tmax_pdih; tpdlo <= tmin_pdlo when timing = "MIN" else tave_pdlo when timing = "AVE" else tmax_pdlo; tsamp <= tmin_samp when timing = "MIN" else tave_samp when timing = "AVE" else tmax_samp; trdv <= tmin_rdv when timing = "MIN" else tave_rdv when timing = "AVE" else tmax_rdv; p_clk10m : process begin clk10m <= '0'; wait for 50 ns; clk10m <= '1'; wait for 50 ns; end process; p_edges : process begin wait until din = '0'; tfall <= now; wait until din = '1'; trise <= now; end process; --this handles the master reseting this slave rstdly <= transport din after trstl; p_rst : process begin wait until rstdly = '0'; --if last transition was falling edge and it was long ago... if tfall > trise and now - tfall >= trstl then rstdet <= '1'; wait until din <= '1'; rstdet <= '0'; end if; end process; --p_readstb and p_read - work together to facilitate a read -- readen is set high to enable a read, then if din is low for 1 us the readdet signal triggers -- which causes readout to be driven low for a bit time if shift(0) is low -- after the bit time expires, din returns high, causing readdet to go low, and cycle is complete readdly <= transport din after 1us; p_readstb : process begin wait until readdly = '0'; if tfall > trise and now - tfall >= 1us and readen = '1' then readdet <= '1'; wait until din <= '1'; readdet <= '0'; end if; end process; p_read : process begin wait until readdet = '1' and readen = '1'; readdout <= readbit; wait for trdv; readdout <= '1'; end process; --this handles the master writing bits to this slave p_write : process begin wait until din = '1'; --dont detect writes during read operations if readen = '0' and readdet = '0' then if now - tfall > tmin_low0 and now-tfall < tmax_low0 then wrbitin <= '0'; writedet <= '1'; wrbiterr <= '0'; elsif now - tfall > tmin_low1 and now-tfall < tmax_low1 then wrbitin <= '1'; writedet <= '1'; wrbiterr <= '0'; elsif now - tfall < trstl then wrbiterr <= '1'; end if; end if; wait until din = '0'; writedet <= '0'; end process; p_timer : process(clk10m) begin if rising_edge(clk10m) then if timertrig = '1' then timer <= to_unsigned(integer(timertime/100 ns),16); timerdone <= '0'; elsif timer > 1 then timer <= timer -1; else timerdone <= '1'; end if; end if; end process; --this handles the master reading a bit from this slave --dout <= '0' when rdbiten = '1' and dout = '0' and now-tfall < trdv else '1'; p_state :process(clk10m) begin if rising_edge (clk10m) then if rstdet = '1' then state <= S_RSTRESP; rstdout <= '1'; readen <= '0'; else case state is when S_IDLE => rstdout <= '1'; readen <= '0'; bitcnt <= 0; shiftbyte <= x"00"; shiftid <= devid; when S_RSTRESP => readen <= '0'; bitcnt <= 0; rstdout <= '1'; shiftbyte <= x"00"; shiftid <= devid; if timertrig = '0' and din = '1' then timertime <= tpdih; timertrig <= '1'; elsif timertrig = '1' then timertrig <= '0'; state <= S_RSTRESP2; end if; when S_RSTRESP2 => if timertrig = '0' and timerdone = '1' then rstdout <= '0'; timertime <= tpdlo; timertrig <= '1'; elsif timertrig = '1' then timertrig <= '0'; state <= S_RSTRESP3; end if; when S_RSTRESP3 => if timerdone = '1' then rstdout <= '1'; state <= S_GETBYTE; nxt_state <= S_PARSE; end if; when S_GETBYTE => if writedet = '0' then state <= S_GETBYTE2; end if; when S_GETBYTE2 => if writedet = '1' then shiftbyte <= wrbitin & shiftbyte(7 downto 1); if bitcnt < 7 then bitcnt <= bitcnt + 1; state <= S_GETBYTE; else bitcnt <= 0; state <= nxt_state; end if; end if; when S_PARSE => shiftid <= devid; case shiftbyte is when x"33" => --read the rom id from the device, can only be used on single device bus state <= S_READROM; when x"55" => --match rom, used to address a single device on the bus state <= S_MATCHROM; when x"F0" => --use to find the devices on a multiple device bus state <= S_SRCHROM; when x"EC" => --search alarm, used to find devices that have the pio line pulled low if pio = '0' then state <= S_SRCHROM; else state <= S_IDLE; end if; when x"CC" => --skip rom, skips rom addressing, for single device busses or broadcast commands state <= S_GETBYTE; nxt_state <= S_PARSE2; when others => state <= S_IDLE; end case; when S_READROM => readen <= '1'; if readdet = '1' then shiftid <= shiftid(0) & shiftid(63 downto 1); if bitcnt < 55 then bitcnt <= bitcnt + 1; state <= S_READRCVR; nxt_state <= S_READROM; else state <= S_CRC; nxt_state <= S_READROM2; shiftid <= x"00000000000000" & crc; end if; end if; when S_READROM2 => state <= S_GETBYTE; nxt_state <= S_PARSE2; when S_MATCHROM => if writedet = '0' then state <= S_MATCHROM2; end if; when S_MATCHROM2 => if writedet = '1' then if wrbitin /= shiftid(0) then state <= S_IDLE; --this part is removed from search, goto idle, wait for rstdet else shiftid <= shiftid(0) & shiftid(63 downto 1); if bitcnt < 63 then bitcnt <= bitcnt + 1; state <= S_MATCHROM; else bitcnt <= 0; switch <= not switch; state <= S_READSW; end if; end if; end if; when S_READSW => shiftid <= x"000000000000000" & "000" & pio; readen <= '1'; if readdet = '1' then state <= S_READRCVR; nxt_state <= S_READSW; end if; when S_SRCHROM => readen <= '1'; readbit <= shiftid(0); if readdet = '1' then state <= S_READRCVR; nxt_state <= S_SRCHROMNOT; end if; when S_SRCHROMNOT => readen <= '1'; readbit <= not shiftid(0); if readdet = '1' then state <= S_READRCVR; nxt_state <= S_SRCHROMWR; end if; when S_SRCHROMWR => readen <= '0'; if writedet = '1' then if wrbitin /= shiftid(0) then state <= S_IDLE; --this part is removed from search, goto idle, wait for rstdet else shiftid <= shiftid(0) & shiftid(63 downto 1); if bitcnt < 63 then bitcnt <= bitcnt + 1; state <= S_SRCHROM; else bitcnt <= 0; state <= S_READSW; end if; end if; end if; when S_READRCVR => readen <= '0'; if readdet = '0' then state <= nxt_state; end if; when S_CRC => readen <= '1'; if readdet = '1' then shiftid <= shiftid(0) & shiftid(63 downto 1); if bitcnt < 7 then bitcnt <= bitcnt + 1; state <= S_READRCVR; nxt_state <= S_READ; else state <= S_READRCVR; nxt_state <= S_IDLE; bitcnt <= 0; shiftid <= x"00000000000000" & crc; end if; end if; when others => state <= S_IDLE; end case; end if; end if; end process; p_crc : process begin crc <= x"00"; wait until state = S_READ or state = S_READROM; crc <= x"00"; while state = S_READ or state = S_READROM loop wait until din = '0' or (state /= S_READ and state /= S_READROM); if din = '0' then if (crc(0) xor shiftid(0)) = '1' then crc <= ('0' & crc(7 downto 1)) xor x"8c"; else crc <= ('0' & crc(7 downto 1)); end if; end if; end loop; end process; din <= '0' when dio = '0' else '1'; dout <= rstdout and copydout and convdout and recalldout and readdout; dio <= '0' when dout = '0' else 'Z'; pio <= '0' when switch = '0' else 'H'; busy <= '0' when state = S_IDLE else '1'; end sim;