<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 \title{Memories in myHDL}
\author{Steven K Armour}
\maketitle
Step1:  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.
Step2:  And if we try writing to the tuple we will get an error
Step5:  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
Step7:  ROMLoaded RTL
<img src='ROMLoadedRTL.png'>
ROMLoaded Synthesis
<img src='ROMLoadedSynth.png'>
Step10:  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
Step12:  ROMParmLoad RTL
<img src="ROMParmLoadRTL.png">
ROMParmLoad Synthesis
<img src="ROMParmLoadSynth.png">
Step15:  we can also create rom that insted of being asynchronous is synchronous
Step19:  ROMParmLoadSync RTL
<img src="ROMParmLoadSyncRTL.png">
ROMParmLoadSync Synthesis
<img src="ROMParmLoadSyncSynth.png">
Step21:  SeqROMEx RTL
<img src="SeqROMExRTL.png">
SeqROMEx Synthesis
<img src="SeqROMExSynth.png">
Step24:  read and write memory
Step26:  RAMConcur RTL
<img src="RAMConcurRTL.png">
RAMConcur Synthesis
<img src="RAMConcurSynth.png">
<ASSISTANT_TASK:>
Python Code:
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
#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
Explanation: \title{Memories in myHDL}
\author{Steven K Armour}
\maketitle
End of explanation
#use type casting on list genrator to store 0-9 in 8bit binary
TupleROM=tuple([bin(i, 8) for i in range(10)])
TupleROM
f'accesss location 6: {TupleROM[6]}, read contents of location 6 to dec:{int(TupleROM[6], 2)}'
Explanation: 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.
End of explanation
#TupleROM[6]=bin(16,2)
Explanation: And if we try writing to the tuple we will get an error
End of explanation
@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()
    
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()
Peeker.to_wavedrom()
Peeker.to_dataframe()
DUT.convert()
VerilogTextReader('ROMLoaded');
Explanation: 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
End of explanation
@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');
Explanation: ROMLoaded RTL
<img src='ROMLoadedRTL.png'>
ROMLoaded Synthesis
<img src='ROMLoadedSynth.png'>
End of explanation
@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()
    
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()
Peeker.to_wavedrom()
Peeker.to_dataframe()
DUT.convert()
VerilogTextReader('ROMParmLoad');
Explanation: 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
End of explanation
@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');
Explanation: ROMParmLoad RTL
<img src="ROMParmLoadRTL.png">
ROMParmLoad Synthesis
<img src="ROMParmLoadSynth.png">
End of explanation
@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()
    
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()
Peeker.to_wavedrom()
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
DUT.convert()
VerilogTextReader('ROMParmLoadSync');
Explanation: we can also create rom that insted of being asynchronous is synchronous
End of explanation
@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');
@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()
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()
Peeker.to_wavedrom()
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
DUT.convert()
VerilogTextReader('SeqROMEx');
Explanation: ROMParmLoadSync RTL
<img src="ROMParmLoadSyncRTL.png">
ROMParmLoadSync Synthesis
<img src="ROMParmLoadSyncSynth.png">
End of explanation
@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');
Explanation: SeqROMEx RTL
<img src="SeqROMExRTL.png">
SeqROMEx Synthesis
<img src="SeqROMExSynth.png">
End of explanation
@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()
    
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()
Peeker.to_wavedrom()
RAMData=Peeker.to_dataframe()
RAMData=RAMData[RAMData['clk']==1]
RAMData.drop(columns='clk', inplace=True)
RAMData.reset_index(drop=True, inplace=True)
RAMData
RAMData[RAMData['writeE']==1]
RAMData[RAMData['writeE']==0]
DUT.convert()
VerilogTextReader('RAMConcur');
Explanation: read and write memory
End of explanation
@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');
Explanation: RAMConcur RTL
<img src="RAMConcurRTL.png">
RAMConcur Synthesis
<img src="RAMConcurSynth.png">
End of explanation
<END_TASK>