Skip to content

Commit

Permalink
More fixes to the memory model (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkorbel1 authored Jan 17, 2024
1 parent 77b1c9d commit 6b8326d
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 9 deletions.
13 changes: 9 additions & 4 deletions lib/src/models/memory_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,22 @@ class MemoryModel extends Memory {
}
}

// if we have at least 1 cycle, then we wait to update the data
if (readLatency > 0) {
for (final rdPort in rdPorts) {
for (final rdPort in rdPorts) {
if (readLatency > 0) {
// if we have at least 1 cycle, then we wait to update the data
if (!rdPort.en.previousValue!.isValid ||
!rdPort.en.previousValue!.toBool() ||
!rdPort.addr.previousValue!.isValid) {
unawaited(_updateRead(
rdPort, LogicValue.filled(rdPort.dataWidth, LogicValue.x)));
} else {
unawaited(_updateRead(rdPort, storage.readData(rdPort.addr.value)));
unawaited(_updateRead(
rdPort, storage.readData(rdPort.addr.previousValue!)));
}
} else {
// if we have instant read latency, we may need to update the read
// data in zero-latency after updating a write
_updateReadZeroLatency(rdPort);
}
}
});
Expand Down
190 changes: 185 additions & 5 deletions test/memory_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// ignore_for_file: avoid_types_on_closure_parameters

import 'dart:async';
import 'dart:math';

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
Expand Down Expand Up @@ -79,10 +80,10 @@ void main() {

// a little reset flow
await clk.nextNegedge;
reset.put(1);
reset.inject(1);
await clk.nextNegedge;
await clk.nextNegedge;
reset.put(0);
reset.inject(0);
await clk.nextNegedge;
await clk.nextNegedge;

Expand Down Expand Up @@ -133,10 +134,10 @@ void main() {

// a little reset flow
await clk.nextNegedge;
reset.put(1);
reset.inject(1);
await clk.nextNegedge;
await clk.nextNegedge;
reset.put(0);
reset.inject(0);
await clk.nextNegedge;
await clk.nextNegedge;

Expand All @@ -150,7 +151,7 @@ void main() {
wrPorts[0].en.put(0);
await clk.nextNegedge;

// read it back out on a different port
// read it back out
rdPorts[0].en.put(1);
rdPorts[0].addr.put(4);
await clk.waitCycles(mem.readLatency);
Expand All @@ -163,6 +164,185 @@ void main() {

await Simulator.endSimulation();
});

test('$memGenName driven by flops back to back', () async {
const numWr = 1;
const numRd = 1;

final clk = SimpleClockGenerator(10).clk;
final reset = Logic();

var wrPorts = [
for (var i = 0; i < numWr; i++)
MaskedDataPortInterface(dataWidth, addrWidth)..en.put(0)
];
var rdPorts = [
for (var i = 0; i < numRd; i++)
DataPortInterface(dataWidth, addrWidth)..en.put(0)
];

final mem = memGenFunc(clk, reset, wrPorts, rdPorts);

await mem.build();

WaveDumper(mem);

wrPorts = wrPorts.map((oldWrPort) {
final newWrPort = MaskedDataPortInterface(dataWidth, addrWidth)
..en.put(0);
oldWrPort.ports.forEach((key, value) {
value <= flop(clk, reset: reset, newWrPort.port(key));
});
return newWrPort;
}).toList();

rdPorts = rdPorts.map((oldRdPort) {
final newRdPort = DataPortInterface(dataWidth, addrWidth)..en.put(0);
oldRdPort.getPorts([DataPortGroup.control]).forEach((key, value) {
value <= flop(clk, reset: reset, newRdPort.port(key));
});
newRdPort.data <= oldRdPort.data;
return newRdPort;
}).toList();

unawaited(Simulator.run());

// a little reset flow
await clk.nextPosedge;
reset.inject(1);
await clk.nextPosedge;
await clk.nextPosedge;
reset.inject(0);
await clk.nextPosedge;
await clk.nextPosedge;

// write to addr 0x4 on port 0
wrPorts[0].en.inject(1);
wrPorts[0].mask.inject(bin('1010'));
wrPorts[0].addr.inject(4);
wrPorts[0].data.inject(0xffffffff);

await clk.nextPosedge;

// write to addr 0x5 on port 0
wrPorts[0].en.inject(1);
wrPorts[0].mask.inject(bin('0101'));
wrPorts[0].addr.inject(5);
wrPorts[0].data.inject(0x55555555);

rdPorts[0].en.inject(1);
rdPorts[0].addr.inject(4);
unawaited(clk.waitCycles(mem.readLatency + 1).then((value) async {
await clk.nextNegedge;
expect(rdPorts[0].data.value.toInt(), 0xff00ff00);
}));

await clk.nextPosedge;

wrPorts[0].en.inject(0);

rdPorts[0].en.inject(1);
rdPorts[0].addr.inject(5);
unawaited(clk.waitCycles(mem.readLatency + 1).then((value) async {
await clk.nextNegedge;
expect(rdPorts[0].data.value.toInt(), 0x00550055);
}));

await clk.nextPosedge;

rdPorts[0].en.inject(0);

await clk.waitCycles(10);

await Simulator.endSimulation();
});

test('$memGenName random and bursty streaming writes and reads',
() async {
const numWr = 3;
const numRd = numWr;

final clk = SimpleClockGenerator(10).clk;
final reset = Logic();

final wrPorts = [
for (var i = 0; i < numWr; i++)
MaskedDataPortInterface(dataWidth, addrWidth)..en.put(0)
];
final rdPorts = [
for (var i = 0; i < numRd; i++)
DataPortInterface(dataWidth, addrWidth)..en.put(0)
];

final mem = memGenFunc(clk, reset, wrPorts, rdPorts);

await mem.build();

unawaited(Simulator.run());

// a little reset flow
await clk.nextPosedge;
reset.inject(1);
await clk.nextPosedge;
await clk.nextPosedge;
reset.inject(0);
await clk.nextPosedge;
await clk.nextPosedge;

final rand = Random(123);

for (var i = 0; i < 100; i++) {
for (var p = 0; p < numWr; p++) {
final rdPort = (p + 1) % numRd;
final rdDelay = rdPort + 1;

if (i % numWr == p) {
wrPorts[p].en.inject(0);

unawaited(clk.waitCycles(rdDelay).then((value) {
rdPorts[rdPort].en.inject(0);
}));
} else {
final addr = (i * numWr + p) % numEntries;
final data = rand.nextLogicValue(width: dataWidth);
final mask = rand.nextLogicValue(width: 4);

wrPorts[p].en.inject(1);
wrPorts[p].addr.inject(addr);
wrPorts[p].data.inject(data);
wrPorts[p].mask.inject(mask);

unawaited(clk.waitCycles(rdDelay).then((value) async {
rdPorts[rdPort].en.inject(1);
rdPorts[rdPort].addr.inject(addr);

await clk.waitCycles(mem.readLatency);

await clk.nextNegedge;

final rdData = rdPorts[rdPort].data.value;
for (var m = 0; m < mask.width; m++) {
if (mask[m].toBool()) {
final actual = rdData.getRange(m * 8, (m + 1) * 8);
final expected = data.getRange(m * 8, (m + 1) * 8);
expect(
actual,
expected,
reason: '@${Simulator.time} byte $m on rd port $rdPort: '
'was $actual, expected $expected',
);
}
}
}));
}
}
await clk.nextPosedge;
}

await clk.waitCycles(mem.readLatency + numWr + 1);

await Simulator.endSimulation();
});
}
});

Expand Down

0 comments on commit 6b8326d

Please sign in to comment.