diff --git a/src/main/resources/csrc/SimMemTrace.cc b/src/main/resources/csrc/SimMemTrace.cc index 99bf113..5f7a9ee 100644 --- a/src/main/resources/csrc/SimMemTrace.cc +++ b/src/main/resources/csrc/SimMemTrace.cc @@ -64,7 +64,8 @@ void MemTraceReader::parse() { // given SIMD lane (= "thread"). In case no request happened at that point, // return an empty line with .valid = false. MemTraceLine MemTraceReader::read_trace_at(const long cycle, - const int lane_id) { + const int lane_id, + unsigned char trace_read_ready) { MemTraceLine line; line.valid = false; @@ -79,7 +80,9 @@ MemTraceLine MemTraceReader::read_trace_at(const long cycle, // the next line is in the future. if (line.cycle < cycle) { // fprintf(stderr, "line.cycle=%ld, cycle=%ld\n", line.cycle, cycle); + printf("cycle=%ld, some lines are left in past Fatal", cycle); assert(false && "some trace lines are left unread in the past"); + return MemTraceLine{}; } if (line.lane_id != lane_id) { @@ -90,22 +93,29 @@ MemTraceLine MemTraceReader::read_trace_at(const long cycle, // read it right now. return MemTraceLine{}; } else if (line.cycle == cycle && line.lane_id == lane_id) { - printf("fire! cycle=%ld, valid=%d, %s addr=%lx, size=%d \n", cycle, - line.valid, (line.is_store ? "STORE" : "LOAD"), line.address, - line.log_data_size); - // FIXME! Currently lane_id is assumed to be in round-robin order, e.g. - // 0->1->2->3->0->..., both in the trace file and the order the caller calls - // this function. If this is not true, we cannot simply monotonically - // increment read_pos. + if (trace_read_ready){ + printf("Fire! cycle=%ld, valid=%d, %s addr=%lx, size=%d \n", cycle, + line.valid, (line.is_store ? "STORE" : "LOAD"), line.address, + line.log_data_size); - // Only advance pointer when cycle and threa_id both match - // now increaseing sequence is fine (0, 1, 3), but unordered is not fine (0, 3, 1) - ++read_pos; + // FIXME! Currently lane_id is assumed to be in round-robin order, e.g. + // 0->1->2->3->0->..., both in the trace file and the order the caller calls + // this function. If this is not true, we cannot simply monotonically + // increment read_pos. + // Only advance pointer when cycle and threa_id both match + // now increaseing sequence is fine (0, 1, 3), but unordered is not fine (0, 3, 1) + ++read_pos; + } + else { // we do not want to advance read_pos + printf("All Lanes Blocked on this cycle! cycle=%ld \n", cycle); + } + + return line; + + } } - - return line; -} + extern "C" void memtrace_init(const char *filename) { #ifndef NO_VPI @@ -145,11 +155,14 @@ extern "C" void memtrace_query(unsigned char trace_read_ready, // printf("memtrace_query(cycle=%ld, tid=%d)\n", trace_read_cycle, // trace_read_lane_id); + /* we can't return immediately, even if trace is ready, we still want to find out + if we are suppose to generate valid req on this clock cycle if (!trace_read_ready) { return; } + */ - auto line = reader->read_trace_at(trace_read_cycle, trace_read_lane_id); + auto line = reader->read_trace_at(trace_read_cycle, trace_read_lane_id, trace_read_ready); *trace_read_valid = line.valid; *trace_read_address = line.address; *trace_read_is_store = line.is_store; diff --git a/src/main/resources/csrc/SimMemTrace.h b/src/main/resources/csrc/SimMemTrace.h index a857b5b..9b90918 100644 --- a/src/main/resources/csrc/SimMemTrace.h +++ b/src/main/resources/csrc/SimMemTrace.h @@ -19,7 +19,7 @@ public: MemTraceReader(const std::string &filename); ~MemTraceReader(); void parse(); - MemTraceLine read_trace_at(const long cycle, const int lane_id); + MemTraceLine read_trace_at(const long cycle, const int lane_id, unsigned char trace_read_ready); bool finished() const { return read_pos == trace.cend(); } std::ifstream infile; diff --git a/src/main/resources/vsrc/SimMemTrace.v b/src/main/resources/vsrc/SimMemTrace.v index ab99b70..4d630fd 100644 --- a/src/main/resources/vsrc/SimMemTrace.v +++ b/src/main/resources/vsrc/SimMemTrace.v @@ -51,39 +51,37 @@ module SimMemTrace #(parameter FILENAME = "undefined", NUM_LANES = 4) ( // Cycle counter that is used to query C parser whether we have a request // coming in at the current cycle. - reg [`DATA_WIDTH-1:0] cycle_counter; - wire [`DATA_WIDTH-1:0] next_cycle_counter; - assign next_cycle_counter = cycle_counter + 1'b1; + // registers that stage outputs of the C parser - reg [NUM_LANES-1:0] __in_valid_reg; - reg [`DATA_WIDTH-1:0] __in_address_reg [NUM_LANES-1:0]; + reg [NUM_LANES-1:0] __in_valid_wire; + reg [`DATA_WIDTH-1:0] __in_address_wire [NUM_LANES-1:0]; - reg [NUM_LANES-1:0] __in_is_store_reg; - reg [`LOGSIZE_WIDTH-1:0] __in_size_reg [NUM_LANES-1:0]; - reg [`DATA_WIDTH-1:0] __in_data_reg [NUM_LANES-1:0]; - reg __in_finished_reg; + reg [NUM_LANES-1:0] __in_is_store_wire; + reg [`LOGSIZE_WIDTH-1:0] __in_size_wire [NUM_LANES-1:0]; + reg [`DATA_WIDTH-1:0] __in_data_wire [NUM_LANES-1:0]; + reg __in_finished_wire; genvar g; generate for (g = 0; g < NUM_LANES; g = g + 1) begin - assign trace_read_valid[g] = __in_valid_reg[g]; - assign trace_read_address[`DATA_WIDTH*(g+1)-1:`DATA_WIDTH*g] = __in_address_reg[g]; + assign trace_read_valid[g] = __in_valid_wire[g]; + assign trace_read_address[`DATA_WIDTH*(g+1)-1:`DATA_WIDTH*g] = __in_address_wire[g]; - assign trace_read_is_store[g] = __in_is_store_reg[g]; - assign trace_read_size[`LOGSIZE_WIDTH*(g+1)-1:`LOGSIZE_WIDTH*g] = __in_size_reg[g]; - assign trace_read_data[`DATA_WIDTH*(g+1)-1:`DATA_WIDTH*g] = __in_data_reg[g]; + assign trace_read_is_store[g] = __in_is_store_wire[g]; + assign trace_read_size[`LOGSIZE_WIDTH*(g+1)-1:`LOGSIZE_WIDTH*g] = __in_size_wire[g]; + assign trace_read_data[`DATA_WIDTH*(g+1)-1:`DATA_WIDTH*g] = __in_data_wire[g]; end endgenerate - assign trace_read_finished = __in_finished_reg; + assign trace_read_finished = __in_finished_wire; initial begin /* $value$plusargs("uartlog=%s", __uartlog); */ memtrace_init(FILENAME); end - always @(posedge clock) begin + always @(*) begin if (reset) begin for (integer tid = 0; tid < NUM_LANES; tid = tid + 1) begin __in_valid[tid] = 1'b0; @@ -96,21 +94,20 @@ module SimMemTrace #(parameter FILENAME = "undefined", NUM_LANES = 4) ( __in_finished = 1'b0; - cycle_counter <= `DATA_WIDTH'b0; + //cycle_counter <= `DATA_WIDTH'b0; // setting default value for register to avoid latches for (integer tid = 0; tid < NUM_LANES; tid = tid + 1) begin - __in_valid_reg[tid] <= 1'b0; - __in_address_reg[tid] <= `DATA_WIDTH'b0; + __in_valid_wire[tid] = 1'b0; + __in_address_wire[tid] = `DATA_WIDTH'b0; - __in_is_store_reg[tid] = 1'b0; - __in_size_reg[tid] = `LOGSIZE_WIDTH'b0; - __in_data_reg[tid] = `DATA_WIDTH'b0; + __in_is_store_wire[tid] = 1'b0; + __in_size_wire[tid] = `LOGSIZE_WIDTH'b0; + __in_data_wire[tid] = `DATA_WIDTH'b0; end - __in_finished_reg <= 1'b0; + __in_finished_wire = 1'b0; end else begin - cycle_counter <= next_cycle_counter; // Getting values from C function into pseudeo register for (integer tid = 0; tid < NUM_LANES; tid = tid + 1) begin @@ -135,14 +132,14 @@ module SimMemTrace #(parameter FILENAME = "undefined", NUM_LANES = 4) ( // Connect values from pseudo register into verilog register for (integer tid = 0; tid < NUM_LANES; tid = tid + 1) begin - __in_valid_reg[tid] <= __in_valid[tid]; - __in_address_reg[tid] <= __in_address[tid]; + __in_valid_wire[tid] = __in_valid[tid]; + __in_address_wire[tid] = __in_address[tid]; - __in_is_store_reg[tid] <= __in_is_store[tid]; - __in_size_reg[tid] <= __in_size[tid]; - __in_data_reg[tid] <= __in_data[tid]; + __in_is_store_wire[tid] = __in_is_store[tid]; + __in_size_wire[tid] = __in_size[tid]; + __in_data_wire[tid] = __in_data[tid]; end - __in_finished_reg <= __in_finished; + __in_finished_wire = __in_finished; end end endmodule diff --git a/src/main/scala/tilelink/Coalescing.scala b/src/main/scala/tilelink/Coalescing.scala index 08f118d..3f3755f 100644 --- a/src/main/scala/tilelink/Coalescing.scala +++ b/src/main/scala/tilelink/Coalescing.scala @@ -58,6 +58,7 @@ case class CoalescerConfig( def maxCoalLogSize: Int = coalLogSizes.max } + object defaultConfig extends CoalescerConfig( numLanes = 4, queueDepth = 1, @@ -643,6 +644,7 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig) extends val respQueueNoncoalPort = 0 val respQueueUncoalPortOffset = 1 + (outer.node.in zip outer.node.out).zipWithIndex.foreach { case (((tlIn, edgeIn), (tlOut, _)), 0) => // TODO: not necessarily 1 master edge assert( @@ -1011,7 +1013,7 @@ class MemTraceDriver(config: CoalescerConfig, filename: String)(implicit val clientParam = Seq( TLMasterParameters.v1( name = "MemTraceDriver" + i.toString, - sourceId = IdRange(0, 0x10) + sourceId = IdRange(0, 0x100) // visibility = Seq(AddressSet(0x0000, 0xffffff)) ) ) @@ -1050,21 +1052,25 @@ class MemTraceDriverImp(outer: MemTraceDriver, config: CoalescerConfig, traceFil extends LazyModuleImp(outer) with UnitTestModule { - val globalClkCounter = RegInit(0.U(64.W)) - val traceReadCycle = RegInit(0.U(64.W)) - globalClkCounter := globalClkCounter + 1.U - traceReadCycle := traceReadCycle + 1.U + val globalClkCounter = RegInit(1.U(64.W)) + val traceReadCycle = RegInit(1.U(64.W)) + val downstreamSQready = WireInit(true.B) + //make the downstream only ready 1/4 of the time + //This is to test Tracer System's ability to hold on requests + //FIXME + downstreamSQready := (globalClkCounter(1,0) =/= 0.U) + //Connect Signals to Verilog BlackBox val sim = Module(new SimMemTrace(traceFile, config.numLanes)) sim.io.clock := clock sim.io.reset := reset.asBool - // , change ready to be base on down stream - sim.io.trace_read.ready := true.B + sim.io.trace_read.ready := downstreamSQready + //FIXME - 1.U hardcoded, currently there is a delay between chisel and verilog sim.io.trace_read.cycle := traceReadCycle - // Split output of SimMemTrace, which is flattened across all lanes, - // back to each lane's. + // Read output from Verilog BlackBox + // Split output of SimMemTrace, which is flattened across all lanes,back to each lane's. val laneReqs = Wire(Vec(config.numLanes, new TraceLine)) val addrW = laneReqs(0).address.getWidth val sizeW = laneReqs(0).size.getWidth @@ -1079,6 +1085,20 @@ class MemTraceDriverImp(outer: MemTraceDriver, config: CoalescerConfig, traceFil req.data := sim.io.trace_read.data(dataW * (i + 1) - 1, dataW * i) } + globalClkCounter := globalClkCounter + 1.U + val existValidReq = WireInit(false.B) + existValidReq := laneReqs.map(_.valid).reduce(_||_) + val validReqBlocked = WireInit(false.B) + validReqBlocked := !downstreamSQready && existValidReq + //Debug + dontTouch(downstreamSQready) + dontTouch(existValidReq) + dontTouch(validReqBlocked) + // Do Not Update TraceReadCycle if downstream is blocking + when(!validReqBlocked){ + traceReadCycle := traceReadCycle + 1.U + } + // To prevent collision of sourceId with a current in-flight message, // just use a counter that increments indefinitely as the sourceId of new // messages. @@ -1181,6 +1201,7 @@ class MemTraceDriverImp(outer: MemTraceDriver, config: CoalescerConfig, traceFil // } } + class SimMemTrace(filename: String, numLanes: Int) extends BlackBox( Map("FILENAME" -> filename, "NUM_LANES" -> numLanes)