OpenCores
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;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.