diff --git a/src/main/resources/csrc/SimMemTrace.cc b/src/main/resources/csrc/SimMemTrace.cc index 8f357f7..1857985 100644 --- a/src/main/resources/csrc/SimMemTrace.cc +++ b/src/main/resources/csrc/SimMemTrace.cc @@ -36,33 +36,47 @@ void MemTraceReader::parse() { while (infile >> line.cycle >> line.loadstore >> line.core_id >> line.thread_id >> std::hex >> line.address >> line.data >> std::dec >> line.data_size) { + line.valid = true; trace.push_back(line); } - curr_line = trace.cbegin(); + read_pos = trace.cbegin(); printf("MemTraceReader: finished parsing\n"); } -MemTraceLine MemTraceReader::tick() { +// Try to read a memory request that might have happened at a given cycle, on +// given 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 thread_id) { MemTraceLine line; + line.valid = false; printf("tick(): cycle=%ld\n", cycle); if (finished()) { - cycle++; return line; } - // Fire all requests that happend at this cycle. This is at most #lane - // requests. - line = *curr_line; - assert(line.cycle >= cycle && "missed some trace lines past their cycles"); - while (line.cycle == cycle) { - printf("fire! cycle=%ld\n", cycle); - line = *(++curr_line); + line = *read_pos; + // It should always be guaranteed that the next line is not read yet. + if (line.cycle < cycle) { + fprintf(stderr, "line.cycle=%ld, cycle=%ld\n", line.cycle, cycle); + assert(false && "some trace lines are left unread in the past"); + } + + if (line.cycle > cycle) { + // It's not ready to read this line yet. + return MemTraceLine{}; + } else if (line.cycle == cycle) { + printf("fire! cycle=%ld, valid=%d\n", cycle, line.valid); + // FIXME! Currently thread_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. + ++read_pos; } - cycle++; return line; } @@ -74,20 +88,20 @@ extern "C" void memtrace_init(const char *filename) { reader->parse(); } -extern "C" void memtrace_tick(unsigned char trace_read_ready, - unsigned long trace_read_cycle, - int trace_read_thread_id, - unsigned char *trace_read_valid, - unsigned long *trace_read_address, - unsigned char *trace_read_finished) { - printf("memtrace_tick(cycle=%ld, tid=%d)\n", trace_read_cycle, +extern "C" void memtrace_query(unsigned char trace_read_ready, + unsigned long trace_read_cycle, + int trace_read_thread_id, + unsigned char *trace_read_valid, + unsigned long *trace_read_address, + unsigned char *trace_read_finished) { + printf("memtrace_query(cycle=%ld, tid=%d)\n", trace_read_cycle, trace_read_thread_id); if (!trace_read_ready) { return; } - auto line = reader->tick(); + auto line = reader->read_trace_at(trace_read_cycle, trace_read_thread_id); *trace_read_valid = line.valid; *trace_read_address = line.address; // This means finished and valid will go up at the same cycle. Need to diff --git a/src/main/resources/csrc/SimMemTrace.h b/src/main/resources/csrc/SimMemTrace.h index 274b5f5..2f45b8d 100644 --- a/src/main/resources/csrc/SimMemTrace.h +++ b/src/main/resources/csrc/SimMemTrace.h @@ -23,19 +23,18 @@ public: MemTraceReader(const std::string &filename); ~MemTraceReader(); void parse(); - MemTraceLine tick(); - bool finished() const { return curr_line == trace.cend(); } + MemTraceLine read_trace_at(const long cycle, const int thread_id); + bool finished() const { return read_pos == trace.cend(); } std::ifstream infile; std::vector trace; - std::vector::const_iterator curr_line; - long cycle = 0; + std::vector::const_iterator read_pos; }; extern "C" void memtrace_init(const char *filename); -extern "C" void memtrace_tick(unsigned char trace_read_ready, - unsigned long trace_read_cycle, - int trace_read_thread_id, - unsigned char *trace_read_valid, - unsigned long *trace_read_address, - unsigned char *trace_read_finished); +extern "C" void memtrace_query(unsigned char trace_read_ready, + unsigned long trace_read_cycle, + int trace_read_thread_id, + unsigned char *trace_read_valid, + unsigned long *trace_read_address, + unsigned char *trace_read_finished); diff --git a/src/main/resources/vsrc/SimMemTrace.v b/src/main/resources/vsrc/SimMemTrace.v index 794045e..19960db 100644 --- a/src/main/resources/vsrc/SimMemTrace.v +++ b/src/main/resources/vsrc/SimMemTrace.v @@ -9,7 +9,7 @@ import "DPI-C" function void memtrace_init( // (1) import "DPI-C" declaration // (2) C function declaration // (3) DPI function calls inside initial/always blocks -import "DPI-C" function void memtrace_tick +import "DPI-C" function void memtrace_query ( input bit trace_read_ready, input longint trace_read_cycle, @@ -25,11 +25,11 @@ module SimMemTrace #(parameter NUM_THREADS = 4) ( // These have to match the IO port of the Chisel wrapper module. input trace_read_ready, - output trace_read_valid, + output [NUM_THREADS-1:0] trace_read_valid, output [`DATA_WIDTH*NUM_THREADS-1:0] trace_read_address, output trace_read_finished ); - bit __in_valid; + bit __in_valid[NUM_THREADS-1:0]; longint __in_address[NUM_THREADS-1:0]; bit __in_finished; string __uartlog; @@ -37,17 +37,19 @@ module SimMemTrace #(parameter NUM_THREADS = 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 __in_valid_reg; + reg [NUM_THREADS-1:0] __in_valid_reg; reg [`DATA_WIDTH-1:0] __in_address_reg [NUM_THREADS-1:0]; reg __in_finished_reg; genvar g; - assign trace_read_valid = __in_valid_reg; generate for (g = 0; g < NUM_THREADS; 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]; end endgenerate @@ -61,35 +63,38 @@ module SimMemTrace #(parameter NUM_THREADS = 4) ( // Evaluate the signals on the positive edge always @(posedge clock) begin if (reset) begin - __in_valid = 1'b0; for (integer tid = 0; tid < NUM_THREADS; tid = tid + 1) begin + __in_valid[tid] = 1'b0; __in_address[tid] = `DATA_WIDTH'b0; end __in_finished = 1'b0; cycle_counter <= `DATA_WIDTH'b0; - __in_valid_reg <= 1'b0; for (integer tid = 0; tid < NUM_THREADS; tid = tid + 1) begin + __in_valid_reg[tid] <= 1'b0; __in_address_reg[tid] <= `DATA_WIDTH'b0; end __in_finished_reg <= 1'b0; end else begin - cycle_counter <= cycle_counter + 1'b1; + cycle_counter <= next_cycle_counter; for (integer tid = 0; tid < NUM_THREADS; tid = tid + 1) begin - memtrace_tick( + memtrace_query( trace_read_ready, - cycle_counter, + // Since parsed results are latched to the output on the next + // cycle due to staging registers, we need to pass in the next cycle + // to sync up. + next_cycle_counter, tid, - __in_valid, + __in_valid[tid], __in_address[tid], __in_finished ); end - __in_valid_reg <= __in_valid; for (integer tid = 0; tid < NUM_THREADS; tid = tid + 1) begin + __in_valid_reg[tid] <= __in_valid[tid]; __in_address_reg[tid] <= __in_address[tid]; end __in_finished_reg <= __in_finished; diff --git a/src/main/scala/tilelink/Coalescing.scala b/src/main/scala/tilelink/Coalescing.scala index 2f05e57..c23ef0e 100644 --- a/src/main/scala/tilelink/Coalescing.scala +++ b/src/main/scala/tilelink/Coalescing.scala @@ -39,15 +39,11 @@ class MemTraceDriver(implicit p: Parameters) extends LazyModule { lazy val module = new Impl class Impl extends LazyModuleImp(this) with UnitTestModule { - val sim = Module(new SimMemTrace(2)) + val sim = Module(new SimMemTrace(4)) sim.io.clock := clock sim.io.reset := reset.asBool sim.io.trace_read.ready := true.B - when(sim.io.trace_read.valid) { - println("sim.io.valid!") - } - // we're finished when there is no more memtrace to read io.finished := sim.io.trace_read.finished } @@ -62,7 +58,7 @@ class SimMemTrace(num_threads: Int) val trace_read = new Bundle { val ready = Input(Bool()) - val valid = Output(Bool()) + val valid = Output(UInt(num_threads.W)) val address = Output(UInt((64 * num_threads).W)) val finished = Output(Bool()) } @@ -76,7 +72,7 @@ class SimMemTrace(num_threads: Int) class CoalescingUnitTest(txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters ) extends UnitTest(timeout) { - val coal = Module(LazyModule(new CoalescingUnit(txns)).module) + // val coal = Module(LazyModule(new CoalescingUnit(txns)).module) val driver = Module(LazyModule(new MemTraceDriver).module) driver.io.start := io.start