{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example: Hysteresis with simple FSM" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from cyhdl 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": [ "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": [ "Using default for SIZE: 6\n", " SIZE: use default 6 \n", " Writing 'hysteresis' to file /tmp/myirl_testbench_hyst_lcsl0smp/hysteresis.vhdl \n", " Writing 'testbench_hyst' to file /tmp/myirl_testbench_hyst_lcsl0smp/testbench_hyst.vhdl \n", " Creating library file module_defs.vhdl \n", "WORK DIR of instance [Instance testbench_hyst I/F: [// ID: testbench_hyst_0 ]] /tmp/myirl_testbench_hyst_lcsl0smp/\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_1348/4025283258.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 testbench_hyst is\r\n", "end entity testbench_hyst;\r\n", "\r\n", "architecture cyriteHDL of testbench_hyst is\r\n", " -- Local type declarations\r\n", " -- Signal declarations\r\n", " signal lo : std_ulogic;\r\n", " signal hi : std_ulogic;\r\n", " signal clk : std_ulogic := '0';\r\n", " signal rst : std_ulogic := '0';\r\n", " signal val : unsigned(5 downto 0);\r\n", "begin\r\n", " \r\n", " -- Instance hysteresis\r\n", " inst_hysteresis_0: entity work.hysteresis\r\n", " generic map (\r\n", " LOWER => 4,\r\n", " UPPER => 16\r\n", " )\r\n", " port map (\r\n", " clk => clk,\r\n", " reset => rst,\r\n", " a => val,\r\n", " q0 => lo,\r\n", " q1 => hi\r\n", " );\r\n", " \r\n", "CLKGEN_c17c:\r\n", " process(clk)\r\n", " begin\r\n", " clk <= not clk after 1.000000 ns;\r\n", " end process;\r\n", "\r\n", " \r\n", "stim:\r\n", " process\r\n", " variable i : integer;\r\n", " begin\r\n", " val <= \"001000\";\r\n", " rst <= '1';\r\n", " wait for 10 ns;\r\n", " rst <= '0';\r\n", " for i in 8 to (64-(1)) loop\r\n", " val <= to_unsigned(i, 6);\r\n", " wait for 2 ns;\r\n", " end loop;\r\n", " for i in 63 to (-1-(-1)) loop\r\n", " val <= to_unsigned(i, 6);\r\n", " wait for 2 ns;\r\n", " end loop;\r\n", " val <= \"001000\";\r\n", " rst <= '1';\r\n", " wait for 10 ns;\r\n", " rst <= '0';\r\n", " for i in 8 to (-1-(-1)) loop\r\n", " val <= to_unsigned(i, 6);\r\n", " wait for 5 ns;\r\n", " end loop;\r\n", " for i in 0 to (64-(1)) loop\r\n", " val <= to_unsigned(i, 6);\r\n", " wait for 2 ns;\r\n", " end loop;\r\n", " wait;\r\n", " end process;\r\n", "end architecture cyriteHDL;\r\n", "\r\n" ] } ], "source": [ "!cat {f[1]}" ] }, { "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.10.0" } }, "nbformat": 4, "nbformat_minor": 4 }