Iterating over a group of elements


#1

I am designing an interface that implements an 8-bit-to-32-bit register. Upon clear or reset, I want to reset the byte value registers to 0. I hoped to do this using an elegant approach but have only succeeded with something that feels crufty.

The overview is that you can write to any byte of the 4-byte register with data_in, when all 4 bytes have been loaded, the data valid signal is generated so that a 32-bit word my be read from data_out.

Any recommendations for a beginner?

This is the code that works. If I swap out the comments for the 4 explicit register assignements, things go badly. I’ve included the trace below the code when this happens.

def register_32(data_in=None, data_out=None, data_valid=None, byte=None, enable=None, clear=None, clock=None, reset=None):

    register = [Signal(intbv(0)[8:0]) for _ in range(4)]
    q = ConcatSignal(*register[::-1])
    flags = [Signal(bool(0)) for _ in range(4)]

    @always_comb
    def pack():
        data_out.next = q
        data_valid.next = flags[0] and flags[1] and flags[2] and flags[3]

    @always(clock.posedge, reset.posedge)
    def logic():

        if reset or clear:

#            for i in range(3):
#                register[i].next = 0

            register[0].next = 0
            register[1].next = 0
            register[2].next = 0
            register[3].next = 0

            flags[0].next = False
            flags[1].next = False
            flags[2].next = False
            flags[3].next = False

        if enable:
            register[byte].next = data_in
            flags[byte].next = True

    return pack, logic

Trace:

Traceback (most recent call last):
  File "C:/MyPython/myhdl_demo/register_32.py", line 122, in <module>
    convert()
  File "C:/MyPython/myhdl_demo/register_32.py", line 118, in convert
    toVerilog(register_32, data_in, data_out, data_valid, byte, enable, clear, clock, reset)
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_toVerilog.py", line 151, in __call__
    genlist = _analyzeGens(arglist, h.absnames)
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_analyze.py", line 164, in _analyzeGens
    v.visit(tree)
  File "C:\Python_v3.6.2\lib\ast.py", line 253, in visit
    return visitor(node)
  File "C:\Python_v3.6.2\lib\ast.py", line 261, in generic_visit
    self.visit(item)
  File "C:\Python_v3.6.2\lib\ast.py", line 253, in visit
    return visitor(node)
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_analyze.py", line 290, in visit_FunctionDef
    self.visitList(node.body)
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_misc.py", line 162, in visitList
    self.visit(n)
  File "C:\Python_v3.6.2\lib\ast.py", line 253, in visit
    return visitor(node)
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_analyze.py", line 312, in visit_If
    self.generic_visit(node)
  File "C:\Python_v3.6.2\lib\ast.py", line 261, in generic_visit
    self.visit(item)
  File "C:\Python_v3.6.2\lib\ast.py", line 253, in visit
    return visitor(node)
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_analyze.py", line 261, in visit_Assign
    self.visit(node.value)
  File "C:\Python_v3.6.2\lib\ast.py", line 253, in visit
    return visitor(node)
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_analyze.py", line 248, in visit_List
    self.raiseError(node, _error.NotSupported, "list")
  File "C:\MyPython\myhdl_demo\venv\lib\site-packages\myhdl\conversion\_misc.py", line 149, in raiseError
    raise ConversionError(kind, msg, info)
myhdl.ConversionError: in file C:/MyPython/myhdl_demo/register_32.py, line 24:
    Not supported: list

#2

I have no issues with that.
But this is with MyHDL 0.10dev.

I had to correct the coding and adapted it also to my style.

'''
Created on 22 mrt. 2018

@author: kc64 / josyb
'''

from myhdl import Signal, intbv, ConcatSignal, ResetSignal, always, always_comb, always_seq, toVHDL


def register_32(data_in, data_out, data_valid, byte, enable, clear, clock, reset):

    register4x8 = [Signal(intbv(0)[8:0]) for _ in range(4)]
    q = ConcatSignal(*register4x8[::-1])
    flags = [Signal(bool(0)) for _ in range(4)]

    @always_comb
    def pack():
        data_out.next = q
        data_valid.next = flags[0] and flags[1] and flags[2] and flags[3]

    @always(clock.posedge, reset.posedge)
    def logic():
        if reset:
            for i in range(3):
                register4x8[i].next = 0
                flags[i].next = False
            
        else:
            if clear or enable:
                if clear:
                    for i in range(3):
                        register4x8[i].next = 0
                        flags[i].next = False
    #                 register4x8[0].next = 0
    #                 register4x8[1].next = 0
    #                 register4x8[2].next = 0
    #                 register4x8[3].next = 0
    #     
    #                 flags[0].next = False
    #                 flags[1].next = False
    #                 flags[2].next = False
    #                 flags[3].next = False
                else:
                    register4x8[byte].next = data_in
                    flags[byte].next = True

    return pack, logic


data_in = Signal(intbv(0)[8:])
data_out = Signal(intbv(0)[32:])
data_valid = Signal(bool(0))
byte = Signal(intbv(0)[2:])
enable = Signal(bool(0))
clear = Signal(bool(0))
clock = Signal(bool(0))
reset = Signal(bool(0))
# reset = ResetSignal(0, 1, True)

toVHDL(register_32, data_in, data_out, data_valid, byte, enable, clear, clock, reset)

generates valid VHDL:

-- File: register_32.vhd
-- Generated by MyHDL 1.0dev
-- Date: Thu Mar 22 10:48:11 2018

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

use work.pck_myhdl_10.all;

entity register_32 is
	port(
		data_in    : in  unsigned(7 downto 0);
		data_out   : out unsigned(31 downto 0);
		data_valid : out std_logic;
		byte       : in  unsigned(1 downto 0);
		enable     : in  std_logic;
		clear      : in  std_logic;
		clock      : in  std_logic;
		reset      : in  std_logic
	);
end entity register_32;

architecture MyHDL of register_32 is

	signal q           : unsigned(31 downto 0);
	type t_array_flags is array (0 to 4 - 1) of std_logic;
	signal flags       : t_array_flags;
	type t_array_register4x8 is array (0 to 4 - 1) of unsigned(7 downto 0);
	signal register4x8 : t_array_register4x8;

begin

	q(32-1 downto 24) <= register4x8(3);
	q(24-1 downto 16) <= register4x8(2);
	q(16-1 downto 8)  <= register4x8(1);
	q(8-1 downto 0)   <= register4x8(0);

	data_out   <= q;
	data_valid <= stdl(bool(flags(0)) and bool(flags(1)) and bool(flags(2)) and bool(flags(3)));

	REGISTER_32_LOGIC : process(clock, reset) is
	begin
		if bool(reset) then
			for i in 0 to 3 - 1 loop
				register4x8(i) <= to_unsigned(0, 8);
				flags(i)       <= '0';
			end loop;
		elsif rising_edge(clock) then
			if (bool(clear) or bool(enable)) then
				if bool(clear) then
					for i in 0 to 3 - 1 loop
						register4x8(i) <= to_unsigned(0, 8);
						flags(i)       <= '0';
					end loop;
				else
					register4x8(to_integer(byte)) <= data_in;
					flags(to_integer(byte))       <= '1';
				end if;
			end if;
		end if;
	end process REGISTER_32_LOGIC;

end architecture MyHDL;

Most of us code clocked processes with the @always_seq decorator which infers the correct sequence.

'''
Created on 22 mrt. 2018

@author: josy
'''

from myhdl import Signal, intbv, ConcatSignal, ResetSignal, always, always_comb, always_seq, toVHDL


def register_32(data_in, data_out, data_valid, byte, enable, clear, clock, reset):

    register4x8 = [Signal(intbv(0)[8:0]) for _ in range(4)]
    q = ConcatSignal(*register4x8[::-1])
    flags = [Signal(bool(0)) for _ in range(4)]

    @always_comb
    def pack():
        data_out.next = q
        data_valid.next = flags[0] and flags[1] and flags[2] and flags[3]

    @always_seq(clock.posedge, reset)
    def logic():
        if clear:
            for i in range(3):
                register4x8[i].next = 0
                flags[i].next = False
        elif enable:
            register4x8[byte].next = data_in
            flags[byte].next = True

    return pack, logic


data_in = Signal(intbv(0)[8:])
data_out = Signal(intbv(0)[32:])
data_valid = Signal(bool(0))
byte = Signal(intbv(0)[2:])
enable = Signal(bool(0))
clear = Signal(bool(0))
clock = Signal(bool(0))
# reset = Signal(bool(0))
reset = ResetSignal(0, 1, True)

toVHDL(register_32, data_in, data_out, data_valid, byte, enable, clear, clock, reset)

giving this VHDL:

-- File: register_32.vhd
-- Generated by MyHDL 1.0dev
-- Date: Thu Mar 22 11:05:12 2018

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

use work.pck_myhdl_10.all;

entity register_32 is
	port(
		data_in    : in  unsigned(7 downto 0);
		data_out   : out unsigned(31 downto 0);
		data_valid : out std_logic;
		byte       : in  unsigned(1 downto 0);
		enable     : in  std_logic;
		clear      : in  std_logic;
		clock      : in  std_logic;
		reset      : in  std_logic
	);
end entity register_32;

architecture MyHDL of register_32 is

	signal q           : unsigned(31 downto 0);
	type t_array_flags is array (0 to 4 - 1) of std_logic;
	signal flags       : t_array_flags;
	type t_array_register4x8 is array (0 to 4 - 1) of unsigned(7 downto 0);
	signal register4x8 : t_array_register4x8;

begin

	q(32-1 downto 24) <= register4x8(3);
	q(24-1 downto 16) <= register4x8(2);
	q(16-1 downto 8)  <= register4x8(1);
	q(8-1 downto 0)   <= register4x8(0);

	data_out   <= q;
	data_valid <= stdl(bool(flags(0)) and bool(flags(1)) and bool(flags(2)) and bool(flags(3)));

	REGISTER_32_LOGIC : process(clock, reset) is
	begin
		if (reset = '1') then
			flags(0)       <= '0';
			flags(1)       <= '0';
			flags(2)       <= '0';
			flags(3)       <= '0';
			register4x8(0) <= to_unsigned(0, 8);
			register4x8(1) <= to_unsigned(0, 8);
			register4x8(2) <= to_unsigned(0, 8);
			register4x8(3) <= to_unsigned(0, 8);
		elsif rising_edge(clock) then
			if bool(clear) then
				for i in 0 to 3 - 1 loop
					register4x8(i) <= to_unsigned(0, 8);
					flags(i)       <= '0';
				end loop;
			elsif bool(enable) then
				register4x8(to_integer(byte)) <= data_in;
				flags(to_integer(byte))       <= '1';
			end if;
		end if;
	end process REGISTER_32_LOGIC;

end architecture MyHDL;

Regards,
Josy


#3

@josyb

Wow! Thank you for such an excellent reply–very thorough and more broadly useful than what I had hoped for.

I am not finding v0.10dev anywhere for download. I check pypi, github, and sourceforge. All seem to be offering the 0.9 version only.

Many thanks.


#4

Using git or Tortoisegit you can clone the 0.1 development repository from here: https://github.com/myhdl/myhdl.git