MyHDL

How to simulate for the ROM type design

It is my myhdl case, I want to use Python generate some data pattern , then put it into ROM


from myhdl import Signal, ResetSignal, modbv,intbv
from myhdl import block, always_seq, Signal, modbv ,always_comb
from myhdl import enum,toVerilog,toVHDL
from myhdl import always

def rom(clk,dout, addr,reset_n, CONTENT):

    #clk = Signal(bool(0))
    #reset_n = Signal(bool(0))


    @always(clk.posedge,reset_n.negedge)
    def regout():
        if reset_n == 0 :
            dout.next = 0
        else :
            dout.next=CONTENT[int(addr)]
        
    return regout

romc=[]

for i in range(256): romc.append(i*2)

CONTENT = tuple(romc)
clk = Signal(bool(0))
reset_n = Signal(bool(0))
dout = Signal(intbv(0)[8:])
addr = Signal(intbv(0)[8:])

toVerilog(rom,clk, dout, addr,reset_n, CONTENT)

This is my test_rom.py myhdl code, it is for the test bech. but I find the monitor function always output the fixed number, it is not what I defined with Python


#it is test_rom.py

import random
from myhdl import block, instance, Signal, intbv, delay,ResetSignal,always
from myhdl import *
from rom import rom

random.seed(5)
randrange = random.randrange

@block
def test_rom():
    clk = Signal(bool(0))
    reset_n = ResetSignal(0,active = 0, async= True)
    dout=Signal(intbv(0)[8:])
    addr=Signal(intbv(1)[8:])
    #CONTENT=Signal(intbv(1)[8:])
    #dout, addr= [Signal(intbv(1)[8:]) for i in range(2)]
    
    romc=[]
    for i in range(125):
        romc.append(2*i)        
           
    CONTENT = tuple(romc)
    
    print(CONTENT)
    

	
    HALF_PERIOD = delay(5)
	#DUT instance
    rom_1 = rom(clk, dout, addr, reset_n,CONTENT)
    
    @always(HALF_PERIOD)
    def clockGen():
        clk.next = not clk

    @instance
    def stimulus():
        reset_n.next = 1
        delay(20)
        reset_n.next = 0
        delay(20)
        reset_n.next = 1
        for i in range(200):
            addr.next= randrange(256)
            yield delay(10)

        raise StopSimulation()

#monitor likes signalTAP 
			
    @instance
    def monitor():
        print("clock  addr  dout")
        yield reset_n.posedge
        while 1:
            yield clk.posedge
            yield delay(10)
            print("  %s    %s	%s"%(int(clk),int(addr),dout))		

    return clockGen, stimulus,monitor

tb = test_rom()
tb.config_sim(trace=True)
tb.run_sim()

I have the following question: rom.py, I list it , test_rom.py , I list it, but I find the monitor output the ROM value is 0, what is my issue?

I put the data “2*i” into address “i” ,

D:\Tools\Python_tools\Python_examples\Python_examples\myHDL\rom\rom.py:40: UserWarning:
toVerilog(): Deprecated usage: See http://dev.myhdl.org/meps/mep-114.html
toVerilog(rom,clk, dout, addr,reset_n, CONTENT)
(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248)
clock addr dout
0 183 00
0 14 00
0 238 00
0 127 00
0 26 00
0 80 00
0 57 00
0 190 00
0 240 00
0 126 00
0 194 00
0 52 00
0 127 00
0 6 00
0 110 00
0 208 00
0 143 00
0 93 00
0 199 00
0 81 00
0 36 00
0 71 00
0 227 00
0 64 00
0 67 00
0 0 00
0 2 00
0 107 00
0 110 00
0 84 00
0 85 00
0 148 00
0 160 00
0 101 00
0 104 00
0 93 00
0 100 00
0 196 00
0 152 00
0 11 00
0 184 00
0 212 00
0 84 00
0 74 00
0 135 00
0 33 00
0 169 00
0 154 00
0 1 00
0 173 00
0 33 00
0 158 00
0 181 00
0 156 00
0 246 00
0 161 00
0 94 00
0 246 00
0 241 00
0 90 00
0 29 00
0 131 00
0 11 00
0 183 00
0 206 00
0 9 00
0 214 00
0 187 00
0 192 00
0 4 00
0 231 00
0 23 00
0 92 00
0 100 00
0 60 00
0 125 00
0 236 00
0 176 00
0 181 00
0 128 00
0 236 00
0 55 00
0 188 00
0 151 00
0 18 00
0 221 00
0 46 00
0 106 00
0 174 00
0 185 00
0 75 00
0 174 00
0 141 00
0 47 00
0 159 00
0 162 00
0 156 00
0 90 00
0 40 00
0 76 00
0 158 00
0 247 00
0 82 00
0 24 00
0 41 00
0 207 00
0 16 00
0 121 00
0 176 00
0 128 00
0 233 00
0 215 00
0 74 00
0 28 00
0 16 00
0 252 00
0 171 00
0 106 00
0 66 00
0 67 00
0 211 00
0 54 00
0 86 00
0 222 00
0 190 00
0 76 00
0 30 00
0 215 00
0 150 00
0 72 00
0 232 00
0 86 00
0 232 00
0 249 00
0 162 00
0 245 00
0 140 00
0 149 00
0 240 00
0 206 00
0 75 00
0 57 00
0 193 00
0 91 00
0 255 00
0 173 00
0 92 00
0 45 00
0 251 00
0 139 00
0 184 00
0 32 00
0 182 00
0 17 00
0 156 00
0 186 00
0 143 00
0 248 00
0 135 00
0 150 00
0 174 00
0 91 00
0 5 00
0 242 00
0 128 00
0 166 00
0 140 00

Could you please tell me what is my issue? why I can not get the defined data , thank you

Please, reformat your message correctly. It is unreadable like it is.

Thank your comment, I did not know if the code is okay, I edit it in notepad++,

What I mean is you have to use markdown tags to make your Python code appear correctly in your post.
Please see here : https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code

Hi, It is very appreciated for your help and support. Wisdom

Much better :slight_smile:

Which version of MyHDL do you use ?
It looks like you have mixed V0.9 and V0.10 syntaxes.

DrPi

In fact, I do not know what is obvious difference between V0.9 and V0.10, I install V0.10, because I search some demo code to learn, then I rewrite some code to practice. Thank you

Try:
print(" %s %s %s"%(int(clk),int(addr),int(dout)))

I try with your comment, can not work, I guess the CONTENT is right Value, but maybe the rom_1 can not accept the tuple? but I have not solution to correct it.

  1. The main difference with V0.10 is the use of @block decorator.
    In your rom.py file, the definition of rom is missing the decorator.

  2. The toVerilog() function is obsolete now. You should use convert() instead.

  3. Be careful that when importing rom.py, the conversion is done automatically.

  4. reset_n should be of kind ResetSignal()
    It is used like this : @always(clk.posedge,reset_n)

  5. You can’t use CONTENT as is. It can work in simulation but it will not work when converting. The ROM array must be a list of Signal().

Here is a corrected code (not tested) :

@block
def rom(clk, dout, addr, reset_n, CONTENT):
    # Do some verifications
    assert 2**len(addr) >= len(CONTENT)

    # Create and initialise ROM array
    CONTENT.extend([0]*(2**len(addr) - len(CONTENT))])
    rom_array = [Signal(CONTENT[i])[len(dout):] for i in range(len(CONTENT)]

    @always(clk.posedge, reset_n) # When reset_n is asserted (0), dout is set to its initial state
    def regout():
        dout.next = rom_array[addr]
        
    return regout

if __name__ == "__main__" :
    rom_content = [2*i for i in range(125)]
     
    clk  = Signal(bool(0))
    dout = Signal(intbv(0)[8:])
    addr = Signal(intbv(0)[8:])
    reset_n = ResetSignal(0, active=0, async=True)
    rom_inst = rom(clk, dout, addr, reset_n, rom_content)

    rom_inst.convert(hdl='VERILOG', name="rom", path="./vhdl", initial_values=True)
def rom(clk, dout, addr, reset_n, CONTENT):
    # Do some verifications
    assert 2**len(addr) >= len(CONTENT)

    # Create and initialise ROM array
    CONTENT=[]
    CONTENT.extend([0]*(2**len(addr)))
    
    rom_array=[]
    for i in range(len(CONTENT)):
        rom_array.append(Signal(CONTENT[i]))
    
    #rom_array = [Signal(CONTENT[i])[8:] for i in range(len(CONTENT))]

    @always(clk.posedge, reset_n) # When reset_n is asserted (0), dout is set to its initial state
    def regout():
        dout.next = rom_array[addr]
        
    return regout

if __name__ == "__main__" :
    rom_content = [2*i for i in range(125)]
     
    clk  = Signal(bool(0))
    dout = Signal(intbv(0)[8:])
    addr = Signal(intbv(0)[8:])
    reset_n = ResetSignal(0, active=0, async=True)
    rom_inst = rom(clk, dout, addr, reset_n, rom_content)

    rom_inst.convert(hdl='VERILOG', name="rom", path="./vhdl", initial_values=True)

I use your code to test, it can not work, I revise some code as upper text. I list the questions

File “D:/Tools/Python_tools/Python_examples/Python_examples/myHDL/rom/rom.py”, line 46, in
rom_inst.convert(hdl=‘Verilog’, name=“rom”, initial_values=True)

AttributeError: ‘_Always’ object has no attribute 'conv

This one works. I’ve corrected the few errors in my first example.

from myhdl import block, Signal, ResetSignal, intbv, always_seq

@block
def rom(clk, dout, addr, reset_n, CONTENT):
    # Do some verifications
    assert 2**len(addr) >= len(CONTENT)

    # Create and initialise ROM array
    CONTENT.extend([0]*(2**len(addr) - len(CONTENT)))
    rom_array = [Signal(intbv(CONTENT[i])[len(dout):]) for i in range(len(CONTENT))]

    @always_seq(clk.posedge, reset_n) # When reset_n is asserted (0), dout is set to its initial state
    def regout():
        dout.next = rom_array[addr]
        
    return regout

if __name__ == "__main__" :
    rom_content = [2*i for i in range(125)]
     
    clk  = Signal(bool(0))
    dout = Signal(intbv(0)[8:])
    addr = Signal(intbv(0)[8:])
    reset_n = ResetSignal(0, active=0, async=True)
    rom_inst = rom(clk, dout, addr, reset_n, rom_content)

    rom_inst.convert(hdl='VERILOG', name="rom", path=".", initial_values=True)
    rom_inst.convert(hdl='VHDL', name="rom", path=".", initial_values=True)

The source file for the test is the following :

from myhdl import block, Signal, ResetSignal, intbv
from myhdl import always, instance, delay, StopSimulation
from rom import rom
import random

random.seed(5)
randrange = random.randrange

@block
def test_rom():
    clk  = Signal(bool(0))
    dout = Signal(intbv(0)[8:])
    addr = Signal(intbv(1)[8:])
    reset_n = ResetSignal(0, active=0, async=True)

    rom_content = [2*i for i in range(125)]
    print(rom_content)
    	
    HALF_PERIOD = delay(5)
    #DUT instance
    rom_inst = rom(clk, dout, addr, reset_n, rom_content)
    
    @always(HALF_PERIOD)
    def clockGen():
        clk.next = not clk

    @instance
    def stimulus():
        reset_n.next = 1
        delay(20)
        reset_n.next = 0
        delay(20)
        reset_n.next = 1
        for i in range(200):
            addr.next= randrange(256)
            yield delay(10)

        raise StopSimulation()

    #monitor likes signalTAP 
    @instance
    def monitor():
        print("clock  addr  dout")
        yield reset_n.posedge
        while 1:
            yield clk.posedge
            yield delay(10)
            print("  %s    %s	%s" % (int(clk), int(addr), int(dout)))

    return rom_inst, clockGen, stimulus, monitor

tb = test_rom()
tb.config_sim(trace=True)
tb.run_sim()

Your error was rom_inst (rom_1) was missing in the returned instances of test_rom().

Hi, DrPi

Thank your help

I had imported the Verilog HDL that generated by myhdl, but I have not find the init value of the ROM, I complier it with Quartus , the Place and Route report have not the RAM block. I like myhdl that can help us to generate or use numpy function directly. if I can not get the ROM pattern based on myhdl, even it simulate successfully for result. It can not works.

I must use external text file, for example, rom0.mem to put the ROM, my idea is that as follows

myhdl can generate the ROM file that had included the ROM pattern , the pattern was generated by Python numpy or other function that return the list.
myhdl convert the design to Verilog code , the code have pointed the ROM pattern external file. and generate the ROM pattern text file.

it will improve the productivity. because it can be synthesis with FPGA tools based on RAM block resource.

Thank you
Wisdom

// File: .\rom.v
// Generated by MyHDL 0.10
// Date: Sat Mar  9 07:42:27 2019


`timescale 1ns/10ps

module rom
#(
  parameter RAM_INIT_FILE	= "rom_a00.mem"
  )
 (
    clk,
    dout,
    addr,
    reset_n
);


input clk;
output [7:0] dout;
reg [7:0] dout;
input [7:0] addr;
input reset_n;

reg [7:0] rom_array [0:256-1];
	initial
	begin
	// By default the Efinix memory will initialize to 0
		if (RAM_INIT_FILE != "")
		begin
			$readmemh(RAM_INIT_FILE, rom_array);
		end
	end



always @(posedge clk, negedge reset_n) begin: ROM_REGOUT
    if (reset_n == 0) begin
        dout <= 0;
    end
    else begin
        dout <= rom_array[addr];
    end
end

endmodule

I had pasted my Verilog file, it be generated by myhdl based on V0.10, but I must assign the mem init text file manually . it is not good way. maybe myhdl can have better solution for the ROM, RAM type design convert method. anyway, I expect I can have some effort for the myhdl.

By the way, I found some engineer use the myhdl in China some forum.

You are right, the ROM array is not initialized in the velilog file.
Can you use VHDL instead of Verilog ? The ROM initialization works correctly with VHDL converter.

You can try the following :

from myhdl import block, Signal, ResetSignal, intbv, always_seq

@block
def rom(clk, dout, addr, reset_n, CONTENT):
    # Do some verifications
    assert 2**len(addr) >= len(CONTENT)

    # Create and initialise ROM array
    CONTENT.extend([0]*(2**len(addr) - len(CONTENT)))
    #rom_array = [Signal(intbv(CONTENT[i])[len(dout):]) for i in range(len(CONTENT))]
    rom_array = tuple(CONTENT)

    @always_seq(clk.posedge, reset_n) # When reset_n is asserted (0), dout is set to its initial state
    def regout():
        dout.next = rom_array[addr]
        
    return regout

if __name__ == "__main__" :
    rom_content = [2*i for i in range(125)]
     
    clk  = Signal(bool(0))
    dout = Signal(intbv(0)[8:])
    addr = Signal(intbv(0)[8:])
    reset_n = ResetSignal(0, active=0, async=True)
    rom_inst = rom(clk, dout, addr, reset_n, rom_content)

    rom_inst.convert(hdl='VERILOG', name="rom", path=".", initial_values=True)
    #rom_inst.convert(hdl='VHDL', name="rom", path=".", initial_values=True)

The use of a tuple instead of a list, for ROM storage, will infer a case. This will work both in simulation and conversion.
I recommend you check the synthesizer you use will convert the case to a ROM.

You can also use the following code :

from myhdl import block, Signal, ResetSignal, intbv, always_seq

@block
def rom(clk, dout, addr, reset_n, CONTENT):
    # Do some verifications
    assert 2**len(addr) >= len(CONTENT)

    # Create and initialise ROM array
    CONTENT.extend([0]*(2**len(addr) - len(CONTENT)))
    rom_array = [Signal(intbv(CONTENT[i])[len(dout):]) for i in range(len(CONTENT))]
    rom_array[0].driven = 'reg'

    @always_seq(clk.posedge, reset_n) # When reset_n is asserted (0), dout is set to its initial state
    def regout():
        dout.next = rom_array[addr]
        
    return regout

if __name__ == "__main__" :
    rom_content = [2*i for i in range(125)]
     
    clk  = Signal(bool(0))
    dout = Signal(intbv(0)[8:])
    addr = Signal(intbv(0)[8:])
    reset_n = ResetSignal(0, active=0, async=True)
    rom_inst = rom(clk, dout, addr, reset_n, rom_content)

    rom_inst.convert(hdl='VERILOG', name="rom", path=".", initial_values=True)
    rom_inst.convert(hdl='VHDL', name="rom", path=".", initial_values=True)

The workaround is the line with rom_array[0].driven = 'reg'