diff --git a/src/main/scala/components/memory/memory-noncombin-ports.scala b/src/main/scala/components/memory/memory-noncombin-ports.scala index d27f663a..879046a1 100644 --- a/src/main/scala/components/memory/memory-noncombin-ports.scala +++ b/src/main/scala/components/memory/memory-noncombin-ports.scala @@ -24,7 +24,7 @@ class OutstandingReq extends Bundle { class INonCombinMemPort extends ICombinMemPort { // To fake combinational writes // TODO: It may be a good idea to move this into a custom utility module - val imemBusy = Reg (new Bool) + val imemBusy = RegInit (false.B) imemBusy := DontCare when (io.pipeline.valid) { @@ -33,7 +33,9 @@ class INonCombinMemPort extends ICombinMemPort { imemBusy := false.B } - io.pipeline.good := (~ imemBusy || io.bus.response.valid) + val ready = !imemBusy || io.bus.response.valid + + io.pipeline.good := ready } /** @@ -42,19 +44,6 @@ class INonCombinMemPort extends ICombinMemPort { * The I/O for this module is defined in [[DMemPortIO]]. */ class DNonCombinMemPort extends BaseDMemPort { - // To fake combinational writes - // TODO: It may be a good idea to move this into a custom utility module - val dmemBusy = Reg (new Bool) - dmemBusy := DontCare - - io.pipeline.good := (! dmemBusy || io.bus.response.valid) - - when (io.pipeline.valid && io.pipeline.memread && !io.pipeline.memwrite) { - dmemBusy := true.B - } .elsewhen (io.bus.response.valid) { - dmemBusy := false.B - } - // A register to hold intermediate data (e.g., write data, mask mode) while the request // is outstanding to memory. val outstandingReq = RegInit(0.U.asTypeOf(Valid(new OutstandingReq))) @@ -68,7 +57,11 @@ class DNonCombinMemPort extends BaseDMemPort { // Ready if either we don't have an outstanding request or the outstanding request is a read and // it has been satisfied this cycle. Note: we cannot send a read until one cycle after the write has // been sent. - val ready = !outstandingReq.valid || (io.bus.response.valid && (outstandingReq.valid && outstandingReq.bits.operation === MemoryOperation.Read)) + val wasRequestARead = outstandingReq.valid && outstandingReq.bits.operation === MemoryOperation.Read + val ready = !outstandingReq.valid || (io.bus.response.valid && wasRequestARead) + + io.pipeline.good := ready + when (io.pipeline.valid && (io.pipeline.memread || io.pipeline.memwrite) && ready) { // Check if we aren't issuing both a read and write at the same time assert (! (io.pipeline.memread && io.pipeline.memwrite)) diff --git a/src/test/scala/components/NonCombinMemoryUnitTest.scala b/src/test/scala/components/NonCombinMemoryUnitTest.scala index 478c8bdd..3ddc67da 100644 --- a/src/test/scala/components/NonCombinMemoryUnitTest.scala +++ b/src/test/scala/components/NonCombinMemoryUnitTest.scala @@ -115,7 +115,9 @@ class AsyncMemoryUnitTester$IMemRead(m: NonCombinMemoryTestHarness, size: Int, l } // Test data port writes and instruction port reads class AsyncMemoryUnitTester$IMemWrite(m: NonCombinMemoryTestHarness, size: Int, latency: Int) extends PeekPokeTester(m) { + println ("First expect\n") expect(m.io.dmem_good, 1) + println ("Done\n") // write ascending data to memory for (i <- 0 until size/8) { poke(m.io.dmem_address, i*4) @@ -129,20 +131,25 @@ class AsyncMemoryUnitTester$IMemWrite(m: NonCombinMemoryTestHarness, size: Int, poke(m.io.dmem_valid, 0) if (latency > 1) { - // Data memory does not stall on writes - expect(m.io.dmem_good, 1) + expect(m.io.dmem_good, 0) step(latency - 1) } + // We expect not good from the dmemport, as this is the cycle used to perform a writeback + expect(m.io.dmem_good, 0) // We wait 1 extra cycle for the data memory to send the write back step(1) - // Memory should be outputting high on good + // Memory should now be good expect(m.io.dmem_good, 1) } - poke (m.io.dmem_memwrite, 0) poke (m.io.dmem_valid, 0) + // Check that data memory remains good after performing an operation + for (i <- 0 until 4) { + step(1) + expect(m.io.dmem_good, 1) + } expect (m.io.imem_good, 1) // expect ascending bytes, the first size/8 of them being incremented by 100, on instruction port @@ -164,6 +171,12 @@ class AsyncMemoryUnitTester$IMemWrite(m: NonCombinMemoryTestHarness, size: Int, } expect(m.io.imem_good, 1) } + + // Check that memory remains good after performing operations (idling) + for (i <- 0 until 4) { + step (1) + expect (m.io.imem_good, 1) + } } // Test data port reading a zeroed memory file @@ -242,10 +255,11 @@ class AsyncMemoryUnitTester$DMemWrite(m: NonCombinMemoryTestHarness, size: Int, poke(m.io.dmem_valid, 0) if (latency > 1) { // Data memory does not stall on writes - expect(m.io.dmem_good, 1) + expect(m.io.dmem_good, 0) step(latency - 1) } - // We wait 1 extra cycle for the data memory to send the write back + // Memory should not be outputting high since this is the cycle used for the writeback + expect(m.io.dmem_good, 0) step(1) expect(m.io.dmem_good, 1) @@ -300,7 +314,6 @@ class AsyncMemoryUnitTester$DMemWrite(m: NonCombinMemoryTestHarness, size: Int, */ class NonCombinMemoryTester extends ChiselFlatSpec { val latency = new Random().nextInt (4) + 3 - // imem side "DualPortedNonCombinMemory" should s"have all zeros in instruction port (with treadle and $latency latency cycles)" in { Driver(() => new NonCombinMemoryTestHarness(2048, "src/test/resources/raw/zero.hex", latency), "treadle") { @@ -311,20 +324,18 @@ class NonCombinMemoryTester extends ChiselFlatSpec { Driver(() => new NonCombinMemoryTestHarness(2048, "src/test/resources/raw/ascending.hex", latency), "treadle") { m => new AsyncMemoryUnitTester$IMemRead(m, 2048, latency) } should be (true) - } + } "DualPortedNonCombinMemory" should s"store words with data port and load with instruction port (with treadle and $latency latency cycles)" in { Driver(() => new NonCombinMemoryTestHarness(2048, "src/test/resources/raw/ascending.hex", latency), "treadle") { m => new AsyncMemoryUnitTester$IMemWrite(m, 2048, latency) } should be (true) } - // dmem side "DualPortedNonCombinMemory" should s"have all zeros in data port (with treadle and $latency latency cycles)" in { Driver(() => new NonCombinMemoryTestHarness(2048, "src/test/resources/raw/zero.hex", latency), "treadle") { m => new AsyncMemoryUnitTester$DMemZero(m, 2048, latency) } should be (true) } - "DualPortedNonCombinMemory" should s"have increasing words in data port (with treadle and $latency latency cycles)" in { Driver(() => new NonCombinMemoryTestHarness(2048, "src/test/resources/raw/ascending.hex", latency), "treadle") { m => new AsyncMemoryUnitTester$DMemRead(m, 2048, latency)