{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example: Hysteresis with simple FSM" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from myirl.emulation.myhdl import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "@block\n", "def hysteresis(\n", " clk : ClkSignal,\n", " reset : ResetSignal,\n", " a : Signal,\n", " q0 : Signal.Output,\n", " q1 : Signal.Output,\n", " *,\n", " LOWER : int = 0,\n", " UPPER : int = 255\n", "):\n", " t_state = enum('NEUTRAL', 'OVER', 'UNDER', name='t_state')\n", " \n", " state = Signal(t_state.NEUTRAL)\n", " \n", " @always_seq(clk.posedge, reset)\n", " def worker(): \n", " if state == t_state.OVER:\n", " if a < LOWER:\n", " state.next = t_state.UNDER \n", " elif state == t_state.UNDER:\n", " if a > UPPER:\n", " state.next = t_state.OVER\n", " else:\n", " if a < LOWER:\n", " state.next = t_state.UNDER\n", " elif a > UPPER:\n", " state.next = t_state.OVER\n", " \n", " @always_comb\n", " def assign():\n", " if state == t_state.OVER:\n", " q0.next = False\n", " q1.next = True\n", " elif state == t_state.UNDER:\n", " q0.next = True\n", " q1.next = False\n", " else:\n", " q0.next = False\n", " q1.next = False\n", "\n", " return instances()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we create a test bench with a bit of ramping stimulus:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from myirl.test.common_test import run_ghdl, gen_osc\n", "\n", "@block\n", "def testbench_hyst(SIZE = 6):\n", " clk = ClkSignal()\n", " rst = ResetSignal(0, 1, isasync = False)\n", " val = Signal(intbv()[SIZE:])\n", " lo, hi = [ Signal(bool()) for i in range(2) ]\n", " \n", " inst = hysteresis(clk = clk, reset = rst, a = val, q0 = lo, q1 = hi,\n", " LOWER = 4, UPPER = 16)\n", "\n", " cg = gen_osc(clk, CYCLE = 1)\n", " \n", " N = 2 ** SIZE\n", " \n", " @instance\n", " def stim():\n", " val.next = 8\n", " rst.next = True\n", " yield delay(10)\n", " rst.next = False\n", " for i in range(8, N):\n", " val.next = i\n", " yield delay(2)\n", "\n", " for i in range(N-1, -1, -1):\n", " val.next = i\n", " yield delay(2)\n", "\n", " val.next = 8\n", " rst.next = True\n", " yield delay(10)\n", " rst.next = False\n", " \n", " for i in range(8, -1, -1):\n", " val.next = i\n", " yield delay(5)\n", " \n", " for i in range(0, N):\n", " val.next = i\n", " yield delay(2)\n", " \n", " return instances()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from myirl import targets\n", "\n", "def test():\n", " tb = testbench_hyst()\n", " files = tb.elab(targets.VHDL, elab_all = True)\n", " run_ghdl(files, tb, vcdfile='hyst.vcd', debug=True)\n", " return files" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FALLBACK: UNHANDLED ROOT CLASS , create new context\n", "Using default for SIZE: 6\n", " SIZE: use default 6 \n", " Writing 'hysteresis' to file /tmp/myirl_testbench_hyst_6t78zkvg/hysteresis.vhdl \n", " Writing 'testbench_hyst' to file /tmp/myirl_testbench_hyst_6t78zkvg/testbench_hyst.vhdl \n", " Creating library file /tmp/myirl_module_defs_f_k2slc6/module_defs.vhdl \n", "==== COSIM stdout ====\n", "/tmp/testbench_hyst:info: simulation stopped by --stop-time @1us\n", "\n" ] } ], "source": [ "f = test()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a result, the wave trace (download [hyst.vcd](hyst.vcd)) displays as follows in GTKwave:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Wave trace](wave.png)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-- File generated from source:\r\n", "-- /tmp/ipykernel_30046/1616138709.py\r\n", "-- (c) 2016-2022 section5.ch\r\n", "-- Modifications may be lost, edit the source file instead.\r\n", "\r\n", "library IEEE;\r\n", "use IEEE.std_logic_1164.all;\r\n", "use IEEE.numeric_std.all;\r\n", "\r\n", "library work;\r\n", "\r\n", "use work.txt_util.all;\r\n", "use work.myirl_conversion.all;\r\n", "\r\n", "entity hysteresis is\r\n", " generic (\r\n", " LOWER: natural := 0;\r\n", " UPPER: natural := 255\r\n", " );\r\n", " port (\r\n", " clk : in std_ulogic;\r\n", " reset : in std_ulogic;\r\n", " a : in unsigned(5 downto 0);\r\n", " q0 : out std_ulogic;\r\n", " q1 : out std_ulogic\r\n", " );\r\n", "end entity hysteresis;\r\n", "\r\n", "architecture myhdl_emulation of hysteresis is\r\n", " -- Local type declarations\r\n", " type t_state is (\r\n", " t_state_NEUTRAL,\r\n", " t_state_OVER,\r\n", " t_state_UNDER\r\n", " );\r\n", " -- Signal declarations\r\n", " signal state : t_state;\r\n", "begin\r\n", " \r\n", "worker:\r\n", " process(clk, reset)\r\n", " begin\r\n", " if rising_edge(clk) then\r\n", " if reset = '1' then\r\n", " state <= t_state_NEUTRAL;\r\n", " else\r\n", " if (state = t_state_OVER) then\r\n", " if (LOWER > a) then\r\n", " state <= t_state_UNDER;\r\n", " end if;\r\n", " elsif (state = t_state_UNDER) then\r\n", " if (a > UPPER) then\r\n", " state <= t_state_OVER;\r\n", " end if;\r\n", " elsif (LOWER > a) then\r\n", " state <= t_state_UNDER;\r\n", " elsif (a > UPPER) then\r\n", " state <= t_state_OVER;\r\n", " end if;\r\n", " end if;\r\n", " end if;\r\n", " end process;\r\n", " \r\n", "assign:\r\n", " process(state)\r\n", " begin\r\n", " if (state = t_state_OVER) then\r\n", " q0 <= '0';\r\n", " q1 <= '1';\r\n", " elsif (state = t_state_UNDER) then\r\n", " q0 <= '1';\r\n", " q1 <= '0';\r\n", " else\r\n", " q0 <= '0';\r\n", " q1 <= '0';\r\n", " end if;\r\n", " end process;\r\n", "\r\n", "end architecture myhdl_emulation;\r\n", "\r\n" ] } ], "source": [ "!cat {f[0]}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.2" } }, "nbformat": 4, "nbformat_minor": 4 }