# Example: Hysteresis with simple FSM¶

In :
from myirl.emulation.myhdl import *


We create a little state machine with three states as shown below. Note: Upon reset, the @always_seq logic implicitely resets state variable to NEUTRAL state.

In :
@block
def hysteresis(
clk : ClkSignal,
reset : ResetSignal,
a   : Signal,
q0  : Signal.Output,
q1  : Signal.Output,
*,
LOWER : int = 0,
UPPER : int = 255
):
t_state = enum('NEUTRAL', 'OVER', 'UNDER', name='t_state')

state = Signal(t_state.NEUTRAL)

@always_seq(clk.posedge, reset)
def worker():
if state == t_state.OVER:
if a < LOWER:
state.next = t_state.UNDER
elif state == t_state.UNDER:
if a > UPPER:
state.next = t_state.OVER
else:
if a < LOWER:
state.next = t_state.UNDER
elif a > UPPER:
state.next = t_state.OVER

@always_comb
def assign():
if state == t_state.OVER:
q0.next = False
q1.next = True
elif state == t_state.UNDER:
q0.next = True
q1.next = False
else:
q0.next = False
q1.next = False

return instances()


Then we create a test bench with a bit of ramping stimulus:

In :
from myirl.test.common_test import run_ghdl, gen_osc

@block
def testbench_hyst(SIZE = 6):
clk = ClkSignal()
rst = ResetSignal(0, 1, isasync = False)
val = Signal(intbv()[SIZE:])
lo, hi = [ Signal(bool()) for i in range(2) ]

inst = hysteresis(clk = clk, reset = rst, a = val, q0 = lo, q1 = hi,
LOWER = 4, UPPER = 16)

cg = gen_osc(clk, CYCLE = 1)

N = 2 ** SIZE

@instance
def stim():
val.next = 8
rst.next = True
yield delay(10)
rst.next = False
for i in range(8, N):
val.next = i
yield delay(2)

for i in range(N-1, -1, -1):
val.next = i
yield delay(2)

val.next = 8
rst.next = True
yield delay(10)
rst.next = False

for i in range(8, -1, -1):
val.next = i
yield delay(5)

for i in range(0, N):
val.next = i
yield delay(2)

return instances()

In :
from myirl import targets

def test():
tb = testbench_hyst()
files = tb.elab(targets.VHDL, elab_all = True)
run_ghdl(files, tb, vcdfile='hyst.vcd', debug=True)
return files

In :
f = test()

Using default for SIZE: 6
SIZE: use default 6
Creating process 'hysteresis/worker' with sensitivity (clk'rising, <reset>)
Creating sequential 'testbench_hyst/stim'
Elaborating component hysteresis_s1_s1_s6_s1_s1_4_16
Writing 'hysteresis' to file /tmp/myirl_top_testbench_hyst_fu_w7x72/hysteresis.vhdl
Elaborating component testbench_hyst_6
Writing 'testbench_hyst' to file /tmp/myirl_top_testbench_hyst_fu_w7x72/testbench_hyst.vhdl
Creating library file /tmp/myirl_module_defs_xeeh4rwe/module_defs.vhdl
==== COSIM stdout ====

==== COSIM stderr ====

==== COSIM stdout ====
analyze /home/testing/.local/lib/python3.9/site-packages/myirl-0.0.0-py3.9-linux-x86_64.egg/myirl/targets/../test/vhdl/txt_util.vhdl
analyze /home/testing/.local/lib/python3.9/site-packages/myirl-0.0.0-py3.9-linux-x86_64.egg/myirl/targets/libmyirl.vhdl
analyze /tmp/myirl_top_testbench_hyst_fu_w7x72/hysteresis.vhdl
analyze /tmp/myirl_top_testbench_hyst_fu_w7x72/testbench_hyst.vhdl
elaborate testbench_hyst

==== COSIM stderr ====

==== COSIM stdout ====
/tmp/testbench_hyst:info: simulation stopped by --stop-time @1us

==== COSIM stderr ====



As a result, the wave trace (download hyst.vcd) displays as follows in GTKwave: In :
!cat {f}

-- File generated from source:
--     /tmp/ipykernel_10240/1616138709.py
-- (c) 2016-2021 section5.ch
-- Modifications may be lost, edit the source file instead.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

library work;

use work.txt_util.all;
use work.myirl_conversion.all;

entity hysteresis is
generic (
LOWER: natural := 0;
UPPER: natural := 255
);
port (
clk : in std_ulogic;
reset : in std_ulogic;
a : in unsigned(5 downto 0);
q0 : out std_ulogic;
q1 : out std_ulogic
);
end entity hysteresis;

architecture MyIRL of hysteresis is
-- Local type declarations
type t_state is (
t_state_NEUTRAL,
t_state_OVER,
t_state_UNDER
);
-- Signal declarations
signal state : t_state;
begin

worker:
process(clk, reset)
begin
if rising_edge(clk) then
if reset = '1' then
state <= t_state_NEUTRAL;
else
if (state = t_state_OVER) then
if (LOWER > a) then
state <= t_state_UNDER;
end if;
elsif (state = t_state_UNDER) then
if (a > UPPER) then
state <= t_state_OVER;
end if;
elsif (LOWER > a) then
state <= t_state_UNDER;
elsif (a > UPPER) then
state <= t_state_OVER;
end if;
end if;
end if;
end process;

assign:
process(state)
begin
if (state = t_state_OVER) then
q0 <= '0';
q1 <= '1';
elsif (state = t_state_UNDER) then
q0 <= '1';
q1 <= '0';
else
q0 <= '0';
q1 <= '0';
end if;
end process;

end architecture MyIRL;


In [ ]: