{ "cells": [ { "cell_type": "markdown", "id": "12978dc8-fa90-4a29-aaea-a2df6e16dfd4", "metadata": {}, "source": [ "# Conditional coding style issues\n", "\n", "This is specific to RTLIL conversion and does not necessarily apply to HDL targets.\n", "\n", "There are a number of programming caveats involved with conditional statements, arising from the fact that we need to create hardware elements from a sequential programming style construct.\n", "Statements that perform without warning in Python might therefore throw warnings or even errors when inferring to a RTLIL description.\n", "\n", "Plus, implicit behaviour is in place: When a signal is not explicitely assigned to a new value during a process flow graph cycle, it is assumed that it's unaltered, or implicitely: assigned to its previous value. This is tolerated style for synchronous process descriptions.\n", "\n", "However, asynchronous processes would infer a Multiplexer logic with its output fed back to an input, i.e. a *Latch*. Inferring a latch in a clock synchronous design is normally a bad choice alias design flaw." ] }, { "cell_type": "code", "execution_count": 1, "id": "6e858f92-878b-4db1-8584-28d09ae452a3", "metadata": {}, "outputs": [], "source": [ "from cyhdl import *" ] }, { "cell_type": "markdown", "id": "37863bc8-1687-4c42-abaf-7b76d4712990", "metadata": {}, "source": [ "First, we create a generator auxiliary for conversion of a unit with a 'standard' interface:" ] }, { "cell_type": "code", "execution_count": 2, "id": "9e37207e-a32f-41be-ab79-9e7227b44411", "metadata": {}, "outputs": [], "source": [ "from yosys import display\n", "from myirl.targets import pyosys\n", "\n", "def convert(unit, name = \"test\", optimize = False, ignorefail = False):\n", " tgt = pyosys.RTLIL(name)\n", " if ignorefail:\n", " tgt.warn_combloop = 'warn'\n", " \n", " clk = ClkSignal()\n", " reset = ResetSignal(0, 1)\n", " a, q = [ Signal(intbv()[8:]) for _ in range(2) ]\n", " \n", " inst = unit(clk, reset, q, a)\n", " \n", " d = inst.elab(tgt)\n", " if optimize:\n", " d[0].run(\"opt; opt_clean\")\n", "\n", " d[0].display_rtl(unit, fmt='dot')\n", " return display.display_dot(d[0].name)" ] }, { "cell_type": "markdown", "id": "a6e43de6-091d-40d4-b62d-c1fac2ed7a7b", "metadata": {}, "source": [ "### Implicit default assignment\n", "\n", "The code below increments `w` every clock cycle only when bit 0 of `a` is set. Otherwise, it leaves it as it is. This can be seen as implicit assignment to its current value: `w.next = w`.\n", "\n", "This generates sane hardware, because Flipflops are created. Without a synchronous clock event, a latch would be created." ] }, { "cell_type": "code", "execution_count": 3, "id": "b4ee312d-5e8c-4b85-a57b-84203f8f954d", "metadata": {}, "outputs": [], "source": [ "@block\n", "def implicit_defaults_unit(clk : ClkSignal, r : ResetSignal,\n", " q : Signal.Output, a : Signal):\n", "\n", " w = Signal(intbv(0xaa)[8:])\n", "\n", " @always_seq(clk.posedge, r)\n", " def proceed():\n", " if a[0]:\n", " w.next = w + 1\n", " \n", " wires = [\n", " q.wireup(w)\n", " ]\n", "\n", " return instances()\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "9ceaeea7-719d-4ca0-87ac-ec6671ed8020", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " DEBUG components ['implicit_defaults_unitu_1u_1u_8u_8'] (EmulationModule 'implicit_defaults_unit') \n", "\u001b[32m Adding module with name `implicit_defaults_unit` \u001b[0m\n", "\u001b[7;34m FINALIZE implementation `implicit_defaults_unit` of `implicit_defaults_unit` \u001b[0m\n" ] }, { "data": { "text/html": [ "\n", "