hdl.mem: ensure transparent read port model has correct latency.
This commit is contained in:
parent
48d13e47ec
commit
fa2af27bb0
|
@ -88,23 +88,38 @@ class ReadPort:
|
||||||
i_ADDR=self.addr,
|
i_ADDR=self.addr,
|
||||||
o_DATA=self.data,
|
o_DATA=self.data,
|
||||||
)
|
)
|
||||||
read_data = self.data.eq(self.memory._array[self.addr])
|
|
||||||
if self.synchronous and not self.transparent:
|
if self.synchronous and not self.transparent:
|
||||||
# Synchronous, read-before-write port
|
# Synchronous, read-before-write port
|
||||||
f.add_statements(Switch(self.en, { 1: read_data }))
|
f.add_statements(
|
||||||
|
Switch(self.en, {
|
||||||
|
1: self.data.eq(self.memory._array[self.addr])
|
||||||
|
})
|
||||||
|
)
|
||||||
f.add_driver(self.data, self.domain)
|
f.add_driver(self.data, self.domain)
|
||||||
elif self.synchronous:
|
elif self.synchronous:
|
||||||
# Synchronous, write-through port
|
# Synchronous, write-through port
|
||||||
# This model is a bit unconventional. We model transparent ports as asynchronous ports
|
# This model is a bit unconventional. We model transparent ports as asynchronous ports
|
||||||
# that are latched when the clock is high. This isn't exactly correct, but it is very
|
# that are latched when the clock is high. This isn't exactly correct, but it is very
|
||||||
# close to the correct behavior of a transparent port, and the difference should only
|
# close to the correct behavior of a transparent port, and the difference should only
|
||||||
# be observable in pathological cases of clock gating.
|
# be observable in pathological cases of clock gating. A register is injected to
|
||||||
f.add_statements(Switch(ClockSignal(self.domain),
|
# the address input to achieve the correct address-to-data latency. Also, the reset
|
||||||
{ 1: self.data.eq(self.data), 0: read_data }))
|
# value of the data output is forcibly set to the 0th initial value, if any--note that
|
||||||
|
# many FPGAs do not guarantee this behavior!
|
||||||
|
if len(self.memory.init) > 0:
|
||||||
|
self.data.reset = self.memory.init[0]
|
||||||
|
latch_addr = Signal.like(self.addr)
|
||||||
|
f.add_statements(
|
||||||
|
latch_addr.eq(self.addr),
|
||||||
|
Switch(ClockSignal(self.domain), {
|
||||||
|
0: self.data.eq(self.data),
|
||||||
|
1: self.data.eq(self.memory._array[latch_addr]),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
f.add_driver(latch_addr, self.domain)
|
||||||
f.add_driver(self.data)
|
f.add_driver(self.data)
|
||||||
else:
|
else:
|
||||||
# Asynchronous port
|
# Asynchronous port
|
||||||
f.add_statements(read_data)
|
f.add_statements(self.data.eq(self.memory._array[self.addr]))
|
||||||
f.add_driver(self.data)
|
f.add_driver(self.data)
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
|
@ -419,13 +419,14 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
||||||
self.setUp_memory()
|
self.setUp_memory()
|
||||||
with self.assertSimulation(self.m) as sim:
|
with self.assertSimulation(self.m) as sim:
|
||||||
def process():
|
def process():
|
||||||
yield
|
|
||||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||||
yield self.rdport.addr.eq(1)
|
yield self.rdport.addr.eq(1)
|
||||||
yield
|
yield
|
||||||
|
yield
|
||||||
self.assertEqual((yield self.rdport.data), 0x55)
|
self.assertEqual((yield self.rdport.data), 0x55)
|
||||||
yield self.rdport.addr.eq(2)
|
yield self.rdport.addr.eq(2)
|
||||||
yield
|
yield
|
||||||
|
yield
|
||||||
self.assertEqual((yield self.rdport.data), 0x00)
|
self.assertEqual((yield self.rdport.data), 0x00)
|
||||||
sim.add_clock(1e-6)
|
sim.add_clock(1e-6)
|
||||||
sim.add_sync_process(process)
|
sim.add_sync_process(process)
|
||||||
|
@ -493,6 +494,10 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
||||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||||
yield Delay(1e-6) # let comb propagate
|
yield Delay(1e-6) # let comb propagate
|
||||||
self.assertEqual((yield self.rdport.data), 0x33)
|
self.assertEqual((yield self.rdport.data), 0x33)
|
||||||
|
yield
|
||||||
|
yield self.rdport.addr.eq(1)
|
||||||
|
yield Delay(1e-6) # let comb propagate
|
||||||
|
self.assertEqual((yield self.rdport.data), 0x33)
|
||||||
sim.add_clock(1e-6)
|
sim.add_clock(1e-6)
|
||||||
sim.add_sync_process(process)
|
sim.add_sync_process(process)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue