\title{Memories in myHDL} \author{Steven K Armour} \maketitle


In [1]:
from myhdl import *
from myhdlpeek import Peeker
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sympy import *
init_printing()

import random

#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information myhdl, myhdlpeek, numpy, pandas, matplotlib, sympy, random


Out[1]:
SoftwareVersion
Python3.6.4 64bit [GCC 7.2.0]
IPython6.2.1
OSLinux 4.13.0 45 generic x86_64 with debian stretch sid
myhdl0.10
myhdlpeek0.0.6
numpy1.13.3
pandas0.21.1
matplotlib2.1.1
sympy1.1.1
randomThe 'random' distribution was not found and is required by the application
Fri Jun 29 23:35:28 2018 MDT

In [2]:
#helper  functions to read in the .v and .vhd generated files into python
def VerilogTextReader(loc, printresult=True):
    with open(f'{loc}.v', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
    return VerilogText

def VHDLTextReader(loc, printresult=True):
    with open(f'{loc}.vhd', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
    return VerilogText

RTL and Implimentation Schamatics are from Xilinx Vivado 2016.1

Read Only Memory (ROM)

ROM is a memory structure that holds static information that can only be read from. In other words, these are hard-coded instruction memory. That should never change. Furthermore, this data is held in a sort of array; for example, we can think of a python tuple as a sort of read-only memory since the content of a tuple is static and we use array indexing to access a certain portions of the memory.


In [3]:
#use type casting on list genrator to store 0-9 in 8bit binary
TupleROM=tuple([bin(i, 8) for i in range(10)])
TupleROM


Out[3]:
('00000000',
 '00000001',
 '00000010',
 '00000011',
 '00000100',
 '00000101',
 '00000110',
 '00000111',
 '00001000',
 '00001001')

In [4]:
f'accesss location 6: {TupleROM[6]}, read contents of location 6 to dec:{int(TupleROM[6], 2)}'


Out[4]:
'accesss location 6: 00000110, read contents of location 6 to dec:6'

And if we try writing to the tuple we will get an error


In [5]:
#TupleROM[6]=bin(16,2)

Random and Sequntial Access Memory

So to start off with the Random in RAM does not mean Random in a proplositc sence. It refares to Random as in you can randomly access any part of the data array opposed to the now specility sequantil only memory wich are typicly made with a counter or stat machine to sequance that acation

HDL Memeorys

in HDL ROM the data is stored a form of a D flip flop that are structerd in a sort of two diminal array where one axis is the address and the other is the content and we use a mux to contorl wich address "row" we are trying to read. There fore we have two signals: address and content. Where the address contorls the mux.

ROM Preloaded


In [6]:
@block
def ROMLoaded(addr, dout):
    """
    A ROM laoded with data already incoded in the structer
    insted of using myHDL inchanced parmter loading
    
    I/O:
        addr(Signal>4): addres; range is from 0-3
        dout(Signal>4): data at each address
    """
    
    @always_comb
    def readAction():
        if addr==0:
            dout.next=3
        elif addr==1:
            dout.next=2
        elif addr==2:
            dout.next=1
        
        elif addr==3:
            dout.next=0
    
    return instances()

myHDL Testing


In [7]:
Peeker.clear()
addr=Signal(intbv(0)[4:]); Peeker(addr, 'addr')
dout=Signal(intbv(0)[4:]); Peeker(dout, 'dout')

DUT=ROMLoaded(addr, dout)

def ROMLoaded_TB():
    """Python Only Testbench  for `ROMLoaded`"""
    @instance
    def stimules():
        for i in range(3+1):
            addr.next=i
            yield delay(1)
        raise StopSimulation()
        
    return instances()

sim = Simulation(DUT, ROMLoaded_TB(), *Peeker.instances()).run()

In [8]:
Peeker.to_wavedrom()



In [9]:
Peeker.to_dataframe()


Out[9]:
addr dout
0 0 3
1 1 2
2 2 1
3 3 0

Verilog Code


In [10]:
DUT.convert()
VerilogTextReader('ROMLoaded');


***Verilog modual from ROMLoaded.v***

 // File: ROMLoaded.v
// Generated by MyHDL 0.10
// Date: Wed Jun 27 16:44:05 2018


`timescale 1ns/10ps

module ROMLoaded (
    addr,
    dout
);
// A ROM laoded with data already incoded in the structer
// insted of using myHDL inchanced parmter loading
// 
// I/O:
//     addr(Signal>4): addres; range is from 0-3
//     dout(Signal>4): data at each address

input [3:0] addr;
output [3:0] dout;
reg [3:0] dout;




always @(addr) begin: ROMLOADED_READACTION
    case (addr)
        'h0: begin
            dout = 3;
        end
        'h1: begin
            dout = 2;
        end
        'h2: begin
            dout = 1;
        end
        'h3: begin
            dout = 0;
        end
    endcase
end

endmodule

ROMLoaded RTL ROMLoaded Synthesis

Verilog Testbench


In [11]:
@block
def ROMLoaded_TBV():
    """Verilog Only Testbench  for `ROMLoaded`"""
    clk = Signal(bool(0))
    addr=Signal(intbv(0)[4:])
    dout=Signal(intbv(0)[4:])
    
    DUT=ROMLoaded(addr, dout)
    
    @instance
    def clk_signal():
        while True:
            clk.next = not clk
            yield delay(10)

    
    @instance
    def stimules():
        for i in range(3+1):
            addr.next=i
            #yield delay(1)
            yield clk.posedge
        raise StopSimulation

    
    @always(clk.posedge)
    def print_data():
        print(addr,  dout)
    
    return instances()

#create instaince of TB
TB=ROMLoaded_TBV()
#convert to verilog with reintilzed values
TB.convert(hdl="Verilog", initial_values=True)
#readback the testbench results
VerilogTextReader('ROMLoaded_TBV');


<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
***Verilog modual from ROMLoaded_TBV.v***

 // File: ROMLoaded_TBV.v
// Generated by MyHDL 0.10
// Date: Wed Jun 27 16:44:08 2018


`timescale 1ns/10ps

module ROMLoaded_TBV (

);
// Verilog Only Testbench  for `ROMLoaded`


reg [3:0] addr = 0;
reg [3:0] dout = 0;
reg clk = 0;



always @(addr) begin: ROMLOADED_TBV_ROMLOADED0_0_READACTION
    case (addr)
        'h0: begin
            dout = 3;
        end
        'h1: begin
            dout = 2;
        end
        'h2: begin
            dout = 1;
        end
        'h3: begin
            dout = 0;
        end
    endcase
end


initial begin: ROMLOADED_TBV_CLK_SIGNAL
    while (1'b1) begin
        clk <= (!clk);
        # 10;
    end
end


initial begin: ROMLOADED_TBV_STIMULES
    integer i;
    for (i=0; i<(3 + 1); i=i+1) begin
        addr <= i;
        @(posedge clk);
    end
    $finish;
end


always @(posedge clk) begin: ROMLOADED_TBV_PRINT_DATA
    $write("%h", addr);
    $write(" ");
    $write("%h", dout);
    $write("\n");
end

endmodule

ROM Preloaded via Parmter

With myHDL we can dynamicaly load the contents that will be hard coded in the convertion to verilog/VHDL wich is an ammazing benfict for devlopment as is sean here


In [12]:
@block
def ROMParmLoad(addr, dout, CONTENT):
    """
    A ROM laoded with data from CONTENT input tuple
    
    I/O:
        addr(Signal>4): addres; range is from 0-3
        dout(Signal>4): data at each address
    Parm:
        CONTENT: tuple size 4 with contende must be no larger then 4bit
    """
    @always_comb
    def readAction():
        dout.next=CONTENT[int(addr)]
    
    return instances()

myHDL Testing


In [13]:
Peeker.clear()
addr=Signal(intbv(0)[4:]); Peeker(addr, 'addr')
dout=Signal(intbv(0)[4:]); Peeker(dout, 'dout')
CONTENT=tuple([i for i in range(4)][::-1])

DUT=ROMParmLoad(addr, dout, CONTENT)

def ROMParmLoad_TB():
    """Python Only Testbench  for `ROMParmLoad`"""
    @instance
    def stimules():
        for i in range(3+1):
            addr.next=i
            yield delay(1)
        raise StopSimulation()

        
    return instances()

sim = Simulation(DUT, ROMParmLoad_TB(), *Peeker.instances()).run()

In [14]:
Peeker.to_wavedrom()



In [15]:
Peeker.to_dataframe()


Out[15]:
addr dout
0 0 3
1 1 2
2 2 1
3 3 0

Verilog Code


In [16]:
DUT.convert()
VerilogTextReader('ROMParmLoad');


***Verilog modual from ROMParmLoad.v***

 // File: ROMParmLoad.v
// Generated by MyHDL 0.10
// Date: Tue Jun 26 23:15:16 2018


`timescale 1ns/10ps

module ROMParmLoad (
    addr,
    dout
);
// A ROM laoded with data from CONTENT input tuple
// 
// I/O:
//     addr(Signal>4): addres; range is from 0-3
//     dout(Signal>4): data at each address
// Parm:
//     CONTENT: tuple size 4 with contende must be no larger then 4bit

input [3:0] addr;
output [3:0] dout;
reg [3:0] dout;




always @(addr) begin: ROMPARMLOAD_READACTION
    case (addr)
        0: dout = 3;
        1: dout = 2;
        2: dout = 1;
        default: dout = 0;
    endcase
end

endmodule

ROMParmLoad RTL ROMParmLoad Synthesis

Verilog Testbench


In [17]:
@block
def ROMParmLoad_TBV():
    """Verilog Only Testbench  for `ROMParmLoad`"""
    clk=Signal(bool(0))
    addr=Signal(intbv(0)[4:])
    dout=Signal(intbv(0)[4:])
    CONTENT=tuple([i for i in range(4)][::-1])

    DUT=ROMParmLoad(addr, dout, CONTENT)
    
    @instance
    def clk_signal():
        while True:
            clk.next = not clk
            yield delay(1)

    @instance
    def stimules():
        for i in range(3+1):
            addr.next=i
            yield clk.posedge
        raise StopSimulation


        
    @always(clk.posedge)
    def print_data():
        print(addr,  dout)
    
    return instances()

#create instaince of TB
TB=ROMParmLoad_TBV()
#convert to verilog with reintilzed values
TB.convert(hdl="Verilog", initial_values=True)
#readback the testbench results
VerilogTextReader('ROMParmLoad_TBV');


<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
***Verilog modual from ROMParmLoad_TBV.v***

 // File: ROMParmLoad_TBV.v
// Generated by MyHDL 0.10
// Date: Tue Jun 26 23:15:24 2018


`timescale 1ns/10ps

module ROMParmLoad_TBV (

);



reg [3:0] addr = 0;
reg [3:0] dout = 0;
reg clk = 0;



always @(addr) begin: ROMPARMLOAD_TBV_ROMPARMLOAD0_0_READACTION
    case (addr)
        0: dout = 3;
        1: dout = 2;
        2: dout = 1;
        default: dout = 0;
    endcase
end


initial begin: ROMPARMLOAD_TBV_CLK_SIGNAL
    while (1'b1) begin
        clk <= (!clk);
        # 1;
    end
end


initial begin: ROMPARMLOAD_TBV_STIMULES
    integer i;
    for (i=0; i<(3 + 1); i=i+1) begin
        addr <= i;
        @(posedge clk);
    end
    $finish;
end


always @(posedge clk) begin: ROMPARMLOAD_TBV_PRINT_DATA
    $write("%h", addr);
    $write(" ");
    $write("%h", dout);
    $write("\n");
end

endmodule

we can also create rom that insted of being asynchronous is synchronous


In [18]:
@block
def ROMParmLoadSync(addr, dout, clk, rst, CONTENT):
    """
    A ROM laoded with data from CONTENT input tuple
    
    I/O:
        addr(Signal>4): addres; range is from 0-3
        dout(Signal>4): data at each address
        clk (bool): clock feed
        rst (bool): reset
    Parm:
        CONTENT: tuple size 4 with contende must be no larger then 4bit
    """
    @always(clk.posedge)
    def readAction():
        if rst:
            dout.next=0
        else:
            dout.next=CONTENT[int(addr)]
    
    return instances()

In [19]:
Peeker.clear()
addr=Signal(intbv(0)[4:]); Peeker(addr, 'addr')
dout=Signal(intbv(0)[4:]); Peeker(dout, 'dout')
clk=Signal(bool(0)); Peeker(clk, 'clk')
rst=Signal(bool(0)); Peeker(rst, 'rst')
CONTENT=tuple([i for i in range(4)][::-1])

DUT=ROMParmLoadSync(addr, dout, clk, rst, CONTENT)

def ROMParmLoadSync_TB():
    """Python Only Testbench  for `ROMParmLoadSync`"""
    
    @always(delay(1))
    def ClkGen():
        clk.next=not clk
    
    @instance
    def stimules():
        for i in range(3+1):
            yield clk.posedge
            addr.next=i
        
        for i in range(4):
            yield clk.posedge
            rst.next=1                        
            addr.next=i

        raise StopSimulation()

        
    return instances()

sim = Simulation(DUT, ROMParmLoadSync_TB(), *Peeker.instances()).run()

In [20]:
Peeker.to_wavedrom()



In [21]:
ROMData=Peeker.to_dataframe()
#keep only clock high
ROMData=ROMData[ROMData['clk']==1]
ROMData.drop(columns='clk', inplace=True)
ROMData.reset_index(drop=True, inplace=True)
ROMData


Out[21]:
addr dout rst
0 0 3 0
1 1 3 0
2 2 2 0
3 3 1 0
4 0 0 1
5 1 0 1
6 2 0 1

In [22]:
DUT.convert()
VerilogTextReader('ROMParmLoadSync');


***Verilog modual from ROMParmLoadSync.v***

 // File: ROMParmLoadSync.v
// Generated by MyHDL 0.10
// Date: Tue Jun 26 23:45:38 2018


`timescale 1ns/10ps

module ROMParmLoadSync (
    addr,
    dout,
    clk,
    rst
);
// A ROM laoded with data from CONTENT input tuple
// 
// I/O:
//     addr(Signal>4): addres; range is from 0-3
//     dout(Signal>4): data at each address
//     clk (bool): clock feed
//     rst (bool): reset
// Parm:
//     CONTENT: tuple size 4 with contende must be no larger then 4bit

input [3:0] addr;
output [3:0] dout;
reg [3:0] dout;
input clk;
input rst;




always @(posedge clk) begin: ROMPARMLOADSYNC_READACTION
    if (rst) begin
        dout <= 0;
    end
    else begin
        case (addr)
            0: dout <= 3;
            1: dout <= 2;
            2: dout <= 1;
            default: dout <= 0;
        endcase
    end
end

endmodule

ROMParmLoadSync RTL ROMParmLoadSync Synthesis


In [23]:
@block
def ROMParmLoadSync_TBV():
    """Python Only Testbench  for `ROMParmLoadSync`"""
    
    addr=Signal(intbv(0)[4:])
    dout=Signal(intbv(0)[4:])
    clk=Signal(bool(0))
    rst=Signal(bool(0))
    CONTENT=tuple([i for i in range(4)][::-1])

    DUT=ROMParmLoadSync(addr, dout, clk, rst, CONTENT)

    
    @instance
    def clk_signal():
        while True:
            clk.next = not clk
            yield delay(1)

    @instance
    def stimules():
        for i in range(3+1):
            yield clk.posedge
            addr.next=i
        
        for i in range(4):
            yield clk.posedge
            rst.next=1                        
            addr.next=i
        raise StopSimulation


        
    @always(clk.posedge)
    def print_data():
        print(addr,  dout, rst)
    
    return instances()

#create instaince of TB
TB=ROMParmLoadSync_TBV()
#convert to verilog with reintilzed values
TB.convert(hdl="Verilog", initial_values=True)
#readback the testbench results
VerilogTextReader('ROMParmLoadSync_TBV');


<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
***Verilog modual from ROMParmLoadSync_TBV.v***

 // File: ROMParmLoadSync_TBV.v
// Generated by MyHDL 0.10
// Date: Tue Jun 26 23:46:29 2018


`timescale 1ns/10ps

module ROMParmLoadSync_TBV (

);
// Python Only Testbench  for `ROMParmLoadSync`


reg [3:0] addr = 0;
reg [3:0] dout = 0;
reg clk = 0;
reg rst = 0;



always @(posedge clk) begin: ROMPARMLOADSYNC_TBV_ROMPARMLOADSYNC0_0_READACTION
    if (rst) begin
        dout <= 0;
    end
    else begin
        case (addr)
            0: dout <= 3;
            1: dout <= 2;
            2: dout <= 1;
            default: dout <= 0;
        endcase
    end
end


initial begin: ROMPARMLOADSYNC_TBV_CLK_SIGNAL
    while (1'b1) begin
        clk <= (!clk);
        # 1;
    end
end


initial begin: ROMPARMLOADSYNC_TBV_STIMULES
    integer i;
    for (i=0; i<(3 + 1); i=i+1) begin
        @(posedge clk);
        addr <= i;
    end
    for (i=0; i<4; i=i+1) begin
        @(posedge clk);
        rst <= 1;
        addr <= i;
    end
    $finish;
end


always @(posedge clk) begin: ROMPARMLOADSYNC_TBV_PRINT_DATA
    $write("%h", addr);
    $write(" ");
    $write("%h", dout);
    $write(" ");
    $write("%h", rst);
    $write("\n");
end

endmodule


In [30]:
@block
def SeqROMEx(clk, rst, dout):
    """
    Seq Read Only Memory Ex
    I/O:
        clk (bool): clock
        rst (bool): rst on counter
        dout (signal >4): data out
    """
    Count=Signal(intbv(0)[3:])
    
    @always(clk.posedge)
    def counter():
        if rst:
            Count.next=0
        elif Count==3:
            Count.next=0
            
        else:
            Count.next=Count+1
    
    @always(clk.posedge)
    def Memory():
        if Count==0:
            dout.next=3
        elif Count==1:
            dout.next=2
        elif Count==2:
            dout.next=1
        elif Count==3:
            dout.next=0
    
    return instances()

In [31]:
Peeker.clear()
dout=Signal(intbv(0)[4:]); Peeker(dout, 'dout')
clk=Signal(bool(0)); Peeker(clk, 'clk')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=SeqROMEx(clk, rst, dout)

def SeqROMEx_TB():
    """Python Only Testbench  for `SeqROMEx`"""

    @always(delay(1))
    def ClkGen():
        clk.next=not clk
    
    @instance
    def stimules():
        for i in range(5+1):
            yield clk.posedge
        
        for i in range(4):
            yield clk.posedge
            rst.next=1                        

        raise StopSimulation()

        
    return instances()

sim = Simulation(DUT, SeqROMEx_TB(), *Peeker.instances()).run()

In [32]:
Peeker.to_wavedrom()



In [33]:
SROMData=Peeker.to_dataframe()
#keep only clock high
SROMData=SROMData[SROMData['clk']==1]
SROMData.drop(columns='clk', inplace=True)
SROMData.reset_index(drop=True, inplace=True)
SROMData


Out[33]:
dout rst
0 3 0
1 2 0
2 1 0
3 0 0
4 3 0
5 2 0
6 1 1
7 0 1
8 3 1

In [34]:
DUT.convert()
VerilogTextReader('SeqROMEx');


***Verilog modual from SeqROMEx.v***

 // File: SeqROMEx.v
// Generated by MyHDL 0.10
// Date: Wed Jun 27 00:03:18 2018


`timescale 1ns/10ps

module SeqROMEx (
    clk,
    rst,
    dout
);
// Seq Read Only Memory Ex
// I/O:
//     clk (bool): clock
//     rst (bool): rst on counter
//     dout (signal >4): data out

input clk;
input rst;
output [3:0] dout;
reg [3:0] dout;

reg [2:0] Count = 0;



always @(posedge clk) begin: SEQROMEX_COUNTER
    if (rst) begin
        Count <= 0;
    end
    else if ((Count == 3)) begin
        Count <= 0;
    end
    else begin
        Count <= (Count + 1);
    end
end


always @(posedge clk) begin: SEQROMEX_MEMORY
    case (Count)
        'h0: begin
            dout <= 3;
        end
        'h1: begin
            dout <= 2;
        end
        'h2: begin
            dout <= 1;
        end
        'h3: begin
            dout <= 0;
        end
    endcase
end

endmodule

SeqROMEx RTL SeqROMEx Synthesis


In [45]:
@block
def SeqROMEx_TBV():
    """Verilog Only Testbench  for `SeqROMEx`"""
    
    dout=Signal(intbv(0)[4:])
    clk=Signal(bool(0))
    rst=Signal(bool(0))

    DUT=SeqROMEx(clk, rst, dout)
    
    @instance
    def clk_signal():
        while True:
            clk.next = not clk
            yield delay(1)
    
    
    @instance
    def stimules():
        for i in range(5+1):
            yield clk.posedge
        
        for i in range(4):
            yield clk.posedge
            rst.next=1                        

        raise StopSimulation()
        
    @always(clk.posedge)
    def print_data():
        print(clk, rst, dout)
    

        
    return instances()



#create instaince of TB
TB=SeqROMEx_TBV()
#convert to verilog with reintilzed values
TB.convert(hdl="Verilog", initial_values=True)
#readback the testbench results
VerilogTextReader('SeqROMEx_TBV');


<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
***Verilog modual from SeqROMEx_TBV.v***

 // File: SeqROMEx_TBV.v
// Generated by MyHDL 0.10
// Date: Wed Jun 27 01:09:28 2018


`timescale 1ns/10ps

module SeqROMEx_TBV (

);
// Verilog Only Testbench  for `SeqROMEx`


reg [3:0] dout = 0;
reg clk = 0;
wire rst;
reg [2:0] SeqROMEx0_0_1_2_3_Count = 0;

assign rst = 1'd0;


always @(posedge clk) begin: SEQROMEX_TBV_SEQROMEX0_0_1_2_3_COUNTER
    if (rst) begin
        SeqROMEx0_0_1_2_3_Count <= 0;
    end
    else if ((SeqROMEx0_0_1_2_3_Count == 3)) begin
        SeqROMEx0_0_1_2_3_Count <= 0;
    end
    else begin
        SeqROMEx0_0_1_2_3_Count <= (SeqROMEx0_0_1_2_3_Count + 1);
    end
end


always @(posedge clk) begin: SEQROMEX_TBV_SEQROMEX0_0_1_2_3_MEMORY
    case (SeqROMEx0_0_1_2_3_Count)
        'h0: begin
            dout <= 3;
        end
        'h1: begin
            dout <= 2;
        end
        'h2: begin
            dout <= 1;
        end
        'h3: begin
            dout <= 0;
        end
    endcase
end


initial begin: SEQROMEX_TBV_CLK_SIGNAL
    while (1'b1) begin
        clk <= (!clk);
        # 1;
    end
end


initial begin: SEQROMEX_TBV_STIMULES
    integer i;
    for (i=0; i<(5 + 1); i=i+1) begin
        @(posedge clk);
    end
    for (i=0; i<4; i=i+1) begin
        @(posedge clk);
    end
    $finish;
end


always @(posedge clk) begin: SEQROMEX_TBV_PRINT_DATA
    $write("%h", clk);
    $write(" ");
    $write("%h", rst);
    $write(" ");
    $write("%h", dout);
    $write("\n");
end

endmodule

/home/iridium/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py:349: ToVerilogWarning: Signal is not driven: rst
  category=ToVerilogWarning

read and write memory


In [36]:
@block
def RAMConcur(addr, din, writeE, dout, clk):
    """
    Random access read write memeory
    I/O:
        addr(signal>4): the memory cell arrdress
        din (signal>4): data to write into memeory
        writeE (bool): write enable contorl; false is read only
        dout (signal>4): the data out
        clk (bool): clock
        
    Note:
        this is only a 4 byte memory
    """
    #create the memeory list (1D array)
    memory=[Signal(intbv(0)[4:]) for i in range(4)]
    
    @always(clk.posedge)
    def writeAction():
        if writeE:
            memory[addr].next=din
    
    @always_comb
    def readAction():
        dout.next=memory[addr]
    
    return instances()

In [37]:
Peeker.clear()
addr=Signal(intbv(0)[4:]); Peeker(addr, 'addr')
din=Signal(intbv(0)[4:]); Peeker(din, 'din')
writeE=Signal(bool(0)); Peeker(writeE, 'writeE')
dout=Signal(intbv(0)[4:]); Peeker(dout, 'dout')
clk=Signal(bool(0)); Peeker(clk, 'clk')
CONTENT=tuple([i for i in range(4)][::-1])

DUT=RAMConcur(addr, din, writeE, dout, clk)

def RAMConcur_TB():
    """Python Only Testbench  for `RAMConcur`"""

    
    @always(delay(1))
    def ClkGen():
        clk.next=not clk
    
    @instance
    def stimules():
        # do nothing
        for i in range(1):
            yield clk.posedge
        
        #write memory
        for i in range(4):
            yield clk.posedge
            writeE.next=True
            addr.next=i
            din.next=CONTENT[i]
        
        #do nothing
        for i in range(1):
            yield clk.posedge
            writeE.next=False
            
        #read memory
        for i in range(4):
            yield clk.posedge
            addr.next=i

        # rewrite memory
        for i in range(4):
            yield clk.posedge
            writeE.next=True
            addr.next=i
            din.next=CONTENT[-i]
        
        #do nothing
        for i in range(1):
            yield clk.posedge
            writeE.next=False
        
        #read memory
        for i in range(4):
            yield clk.posedge
            addr.next=i
        
        raise StopSimulation()
        
        

        
    return instances()

sim = Simulation(DUT, RAMConcur_TB(), *Peeker.instances()).run()

In [38]:
Peeker.to_wavedrom()



In [39]:
RAMData=Peeker.to_dataframe()
RAMData=RAMData[RAMData['clk']==1]
RAMData.drop(columns='clk', inplace=True)
RAMData.reset_index(drop=True, inplace=True)
RAMData


Out[39]:
addr din dout writeE
0 0 0 0 0
1 0 3 0 1
2 1 2 0 1
3 2 1 0 1
4 3 0 0 1
5 3 0 0 0
6 0 0 3 0
7 1 0 2 0
8 2 0 1 0
9 3 0 0 0
10 0 3 3 1
11 1 0 2 1
12 2 1 1 1
13 3 2 0 1
14 3 2 2 0
15 0 2 3 0
16 1 2 0 0
17 2 2 1 0

In [40]:
RAMData[RAMData['writeE']==1]


Out[40]:
addr din dout writeE
1 0 3 0 1
2 1 2 0 1
3 2 1 0 1
4 3 0 0 1
10 0 3 3 1
11 1 0 2 1
12 2 1 1 1
13 3 2 0 1

In [41]:
RAMData[RAMData['writeE']==0]


Out[41]:
addr din dout writeE
0 0 0 0 0
5 3 0 0 0
6 0 0 3 0
7 1 0 2 0
8 2 0 1 0
9 3 0 0 0
14 3 2 2 0
15 0 2 3 0
16 1 2 0 0
17 2 2 1 0

In [42]:
DUT.convert()
VerilogTextReader('RAMConcur');


***Verilog modual from RAMConcur.v***

 // File: RAMConcur.v
// Generated by MyHDL 0.10
// Date: Wed Jun 27 00:31:42 2018


`timescale 1ns/10ps

module RAMConcur (
    addr,
    din,
    writeE,
    dout,
    clk
);
// Random access read write memeory
// I/O:
//     addr(signal>4): the memory cell arrdress
//     din (signal>4): data to write into memeory
//     writeE (bool): write enable contorl; false is read only
//     dout (signal>4): the data out
//     clk (bool): clock
//     
// Note:
//     this is only a 4 byte memory

input [3:0] addr;
input [3:0] din;
input writeE;
output [3:0] dout;
wire [3:0] dout;
input clk;

reg [3:0] memory [0:4-1];

initial begin: INITIALIZE_MEMORY
    integer i;
    for(i=0; i<4; i=i+1) begin
        memory[i] = 0;
    end
end




always @(posedge clk) begin: RAMCONCUR_WRITEACTION
    if (writeE) begin
        memory[addr] <= din;
    end
end



assign dout = memory[addr];

endmodule

RAMConcur RTL RAMConcur Synthesis


In [47]:
@block
def RAMConcur_TBV():
    """Verilog Only Testbench  for `RAMConcur`"""
    addr=Signal(intbv(0)[4:])
    din=Signal(intbv(0)[4:])
    writeE=Signal(bool(0))
    dout=Signal(intbv(0)[4:])
    clk=Signal(bool(0))
    CONTENT=tuple([i for i in range(4)][::-1])

    DUT=RAMConcur(addr, din, writeE, dout, clk)

    
    @instance
    def clk_signal():
        while True:
            clk.next = not clk
            yield delay(1)
            
    @instance
    def stimules():
        # do nothing
        for i in range(1):
            yield clk.posedge
        
        #write memory
        for i in range(4):
            yield clk.posedge
            writeE.next=True
            addr.next=i
            din.next=CONTENT[i]
        
        #do nothing
        for i in range(1):
            yield clk.posedge
            writeE.next=False
            
        #read memory
        for i in range(4):
            yield clk.posedge
            addr.next=i

        # rewrite memory
        for i in range(4):
            yield clk.posedge
            writeE.next=True
            addr.next=i
            din.next=CONTENT[-i]
        
        #do nothing
        for i in range(1):
            yield clk.posedge
            writeE.next=False
        
        #read memory
        for i in range(4):
            yield clk.posedge
            addr.next=i
        
        raise StopSimulation()
        
         
    @always(clk.posedge)
    def print_data():
        print(addr, din, writeE, dout, clk)
        

        
    return instances()

#create instaince of TB
TB=RAMConcur_TBV()
#convert to verilog with reintilzed values
TB.convert(hdl="Verilog", initial_values=True)
#readback the testbench results
VerilogTextReader('RAMConcur_TBV');


<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
<class 'myhdl._Signal._Signal'> <class '_ast.Name'>
***Verilog modual from RAMConcur_TBV.v***

 // File: RAMConcur_TBV.v
// Generated by MyHDL 0.10
// Date: Wed Jun 27 01:12:16 2018


`timescale 1ns/10ps

module RAMConcur_TBV (

);
// Verilog Only Testbench  for `RAMConcur`


reg [3:0] addr = 0;
wire [3:0] dout;
reg clk = 0;
reg [3:0] din = 0;
reg writeE = 0;
reg [3:0] RAMConcur0_0_1_2_memory [0:4-1];

initial begin: INITIALIZE_RAMCONCUR0_0_1_2_MEMORY
    integer i;
    for(i=0; i<4; i=i+1) begin
        RAMConcur0_0_1_2_memory[i] = 0;
    end
end




always @(posedge clk) begin: RAMCONCUR_TBV_RAMCONCUR0_0_1_2_WRITEACTION
    if (writeE) begin
        RAMConcur0_0_1_2_memory[addr] <= din;
    end
end



assign dout = RAMConcur0_0_1_2_memory[addr];


initial begin: RAMCONCUR_TBV_CLK_SIGNAL
    while (1'b1) begin
        clk <= (!clk);
        # 1;
    end
end


initial begin: RAMCONCUR_TBV_STIMULES
    integer i;
    for (i=0; i<1; i=i+1) begin
        @(negedge clk);
    end
    for (i=0; i<4; i=i+1) begin
        @(posedge clk);
        writeE <= 1'b1;
        addr <= i;
        case (i)
            0: din <= 3;
            1: din <= 2;
            2: din <= 1;
            default: din <= 0;
        endcase
    end
    for (i=0; i<1; i=i+1) begin
        @(posedge clk);
        writeE <= 1'b0;
    end
    for (i=0; i<4; i=i+1) begin
        @(posedge clk);
        addr <= i;
    end
    for (i=0; i<4; i=i+1) begin
        @(posedge clk);
        writeE <= 1'b1;
        addr <= i;
        case ((-i))
            0: din <= 3;
            1: din <= 2;
            2: din <= 1;
            default: din <= 0;
        endcase
    end
    for (i=0; i<1; i=i+1) begin
        @(posedge clk);
        writeE <= 1'b0;
    end
    for (i=0; i<4; i=i+1) begin
        @(posedge clk);
        addr <= i;
    end
    $finish;
end


always @(posedge clk) begin: RAMCONCUR_TBV_PRINT_DATA
    $write("%h", addr);
    $write(" ");
    $write("%h", din);
    $write(" ");
    $write("%h", writeE);
    $write(" ");
    $write("%h", dout);
    $write(" ");
    $write("%h", clk);
    $write("\n");
end

endmodule


In [ ]: