Hi all,
I am working on the following:
def ram(NUM_ENTRIES, clk, writeaddress, data, write, readaddress, result, READ_DURING_WRITE='Old Data'):
''' SingleClockFifo: the RAM '''
# handle structured types
if isinstance(data, (Array, StructType)):
# make a ShadowSignal aggregating everything into a single intbv
ramdata = data.tointbv()
ramresult = ramdata.copy()
# make a structured output object out of the internal intbv
# i.e. replace the elements by shadowsignals
result.fromintbv(ramresult)
else:
ramdata = data
ramresult = result
storage = Array((NUM_ENTRIES,), ramdata)
if READ_DURING_WRITE == 'New Data':
readaddressd1 = readaddress.copy()
@always(clk, readaddressd1)
def synch():
'''
SingleClockFifo: writing and reading FIFO ram
note: this infers a RAM with 'New Data' Read-During-Write Behaviour
'''
if clk.posedge:
readaddressd1.next = readaddress
if write:
storage[writeaddress].next = ramdata
# always reading ...
ramresult.next = storage[readaddressd1]
return synch
I used an @always specifically to conform to Altera’s guidelines to infer this kind of RAM: https://documentation.altera.com/#/00107487-AA$NT00064114. If I split this into an @always_seq and an @always_comb the simulation works fine.
The testbench:
def tb_ram():
Clk = Signal(bool(0))
wa = Signal(intbv()[4:])
ra = Signal(intbv()[4:])
wr = Signal(bool(0))
data = Signal(intbv()[4:])
result = Signal(intbv()[4:])
dut = ram(16, Clk, wa, data, wr, ra, result, READ_DURING_WRITE='New Data')
ClkCount = Signal(intbv(0)[8:])
tCK = 10
@instance
def genclk():
yield hdlutils.genClk(Clk, tCK, ClkCount)
@instance
def stimulusin():
wa.next = 0
ra.next = 0
yield hdlutils.delayclks(Clk, tCK, 2)
data.next = 0x1
yield hdlutils.pulsesig(Clk, tCK, wr)
wa.next += 1
yield hdlutils.delayclks(Clk, tCK, 10)
data.next = 0x2
yield hdlutils.pulsesig(Clk, tCK, wr)
wa.next += 1
yield hdlutils.delayclks(Clk, tCK, 10)
data.next = 0x3
yield hdlutils.pulsesig(Clk, tCK, wr)
wa.next += 1
data.next = 0x4
yield hdlutils.pulsesig(Clk, tCK, wr)
wa.next += 1
yield hdlutils.delayclks(Clk, tCK, 10)
ra.next += 1
yield hdlutils.delayclks(Clk, tCK, 10)
ra.next += 1
yield hdlutils.delayclks(Clk, tCK, 1)
ra.next += 1
yield hdlutils.delayclks(Clk, tCK, 10)
raise StopSimulation
return dut, genclk, stimulusin
The generated VHDL code is what I expected:
-- File: ram.vhd
-- Generated by MyHDL 1.0dev
-- BEWARE: peppered with Array, StructType,
-- advanced ShadowSignal functionality, and more
-- by Josy Boelen (josyb)
--
-- Date: Sat Feb 25 16:56:48 2017
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;
use work.pck_myhdl_10.all;
entity ram is
port(
clk : in std_logic;
writeaddress : in unsigned(3 downto 0);
data : in unsigned(3 downto 0);
write : in std_logic;
readaddress : in unsigned(3 downto 0);
result : out unsigned(3 downto 0)
);
end entity ram;
-- SingleClockFifo: the RAM
architecture Behavioural of ram is
type a16_u4 is array (0 to 16 - 1) of unsigned(3 downto 0);
signal readaddressd1 : unsigned(3 downto 0);
signal storage : a16_u4;
begin
-- SingleClockFifo: writing and reading FIFO ram
-- note: this infers a RAM with 'New Data' Read-During-Write Behaviour
synch : process(all) is
begin
if rising_edge(clk) then
readaddressd1 <= readaddress;
if bool(write) then
storage(to_integer(writeaddress)) <= data;
end if;
end if;
result <= storage(to_integer(readaddressd1));
end process synch;
end architecture Behavioural;
But the simulation triggers on the negative clock edge:
As you can see the storage is updated on the negative clock edge. Although the output port result seems to reflect the expected behaviour.
If I use the negedge nothing gets written, i.o.w. the circuit is dead.