@@ -51,6 +51,12 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
5151 parameter type acc_resp_t = logic ,
5252 parameter type pa_t = logic ,
5353 parameter type l0_pte_t = logic ,
54+ // XIF parameters
55+ parameter int unsigned XifIdWidth = 4 ,
56+ // XIF port types
57+ parameter type x_issue_req_t = logic ,
58+ parameter type x_issue_resp_t = logic ,
59+ parameter type x_result_t = logic ,
5460 parameter int unsigned NumIntOutstandingLoads = 0 ,
5561 parameter int unsigned NumIntOutstandingMem = 0 ,
5662 parameter int unsigned NumDTLBEntries = 0 ,
@@ -91,6 +97,15 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
9197 input acc_resp_t acc_prsp_i,
9298 input logic acc_pvalid_i,
9399 output logic acc_pready_o,
100+ // X Interface - Issue ports
101+ output x_issue_req_t x_issue_req_o,
102+ input x_issue_resp_t x_issue_resp_i,
103+ output logic x_issue_valid_o,
104+ input logic x_issue_ready_i,
105+ // X Interface - Result ports
106+ input x_result_t x_result_i,
107+ input logic x_result_valid_i,
108+ output logic x_result_ready_o,
94109 // / TCDM Data Interface
95110 // / Write transactions do not return data on the `P Channel`
96111 // / Transactions need to be handled strictly in-order.
@@ -148,15 +163,15 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
148163 assign simm = $signed ({ inst_data_i[31 : 25 ], inst_data_i[11 : 7 ]} );
149164 /* verilator lint_on WIDTH */
150165
151- logic [31 : 0 ] opa, opb;
166+ logic [31 : 0 ] opa, opb, opc ;
152167 logic [32 : 0 ] adder_result;
153168 logic [31 : 0 ] alu_result;
154169
155- logic [RegWidth- 1 : 0 ] rd, rs1, rs2;
156- logic stall, lsu_stall, acc_stall, nonacc_stall, fence_stall;
170+ logic [RegWidth- 1 : 0 ] rd, rs1, rs2, rs3 ;
171+ logic stall, lsu_stall, acc_stall, nonacc_stall, fence_stall, x_stall ;
157172 // Register connections
158- logic [1 : 0 ][RegWidth- 1 : 0 ] gpr_raddr;
159- logic [1 : 0 ][31 : 0 ] gpr_rdata;
173+ logic [2 : 0 ][RegWidth- 1 : 0 ] gpr_raddr;
174+ logic [2 : 0 ][31 : 0 ] gpr_rdata;
160175 logic [0 : 0 ][RegWidth- 1 : 0 ] gpr_waddr;
161176 logic [0 : 0 ][31 : 0 ] gpr_wdata;
162177 logic [0 : 0 ] gpr_we;
@@ -209,6 +224,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
209224 logic retire_load; // retire a load instruction
210225 logic retire_i; // retire the rest of the base instruction set
211226 logic retire_acc; // retire an instruction we offloaded
227+ logic retire_x; // retire a XIF-offloaded instruction
212228
213229 logic valid_instr;
214230 logic exception;
@@ -227,7 +243,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
227243 typedef enum logic [3 : 0 ] {
228244 None, Reg, IImmediate, UImmediate, JImmediate, SImmediate, SFImmediate, PC , CSR , CSRImmmediate
229245 } op_select_e ;
230- op_select_e opa_select, opb_select;
246+ op_select_e opa_select, opb_select, opc_select ;
231247
232248 logic write_rd; // write destination this cycle
233249 logic uses_rd;
@@ -338,6 +354,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
338354 `FFAR (sb_q, sb_d, '0 , clk_i, rst_i)
339355 `FFAR (fcsr_q, fcsr_d, '0 , clk_i, rst_i)
340356
357+ // TODO(abelano) Should we add a performance counter for the XIF?
341358 // performance counter
342359 `ifdef SNITCH_ENABLE_PERF
343360 logic [63 : 0 ] cycle_q;
@@ -374,6 +391,10 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
374391 // operand C is currently only used for load/store instructions
375392 assign acc_qreq_o.data_argc = ls_paddr;
376393
394+ // XIF ID counter
395+ logic [XifIdWidth- 1 : 0 ] xif_offload_counter_q;
396+ `FFLAR (xif_offload_counter_q, xif_offload_counter_q + 1 , x_issue_ready_i & x_issue_valid_o, '0 , clk_i, rst_i)
397+
377398 // ---------
378399 // L0 ITLB
379400 // ---------
@@ -441,13 +462,17 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
441462 sb_d = sb_q;
442463 if (retire_load) sb_d[lsu_rd] = 1'b0 ;
443464 // only place the reservation if we actually executed the load or offload instruction
444- if ((is_load | acc_register_rd) && ! stall && ! exception) sb_d[rd] = 1'b1 ;
465+ if ((is_load | acc_register_rd | x_issue_valid_o & x_issue_ready_i & x_issue_resp_i.writeback ) && ! stall && ! exception) sb_d[rd] = 1'b1 ;
445466 if (retire_acc) sb_d[acc_prsp_i.id[RegWidth- 1 : 0 ]] = 1'b0 ;
467+ if (retire_x) sb_d[x_result_i.rd] = 1'b0 ;
446468 sb_d[0 ] = 1'b0 ;
447469 end
448470 // TODO(zarubaf): This can probably be described a bit more efficient
449471 assign opa_ready = (opa_select != Reg) | ~ sb_q[rs1];
450472 assign opb_ready = (opb_select != Reg & opb_select != SImmediate) | ~ sb_q[rs2];
473+ assign opc_ready = (opc_select != Reg) | ~ sb_q[rs3];
474+
475+ // Here we do not use the opc_ready signal
451476 assign operands_ready = opa_ready & opb_ready;
452477 // either we are not using the destination register or we need to make
453478 // sure that its destination operand is not marked busy in the scoreboard.
@@ -460,14 +485,16 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
460485 & ((itlb_valid & itlb_ready) | ~ trans_active);
461486 // the accelerator interface stalled us. Also wait for CAQ if this is an FP load/store.
462487 assign acc_stall = acc_qvalid_o & ~ acc_qready_i | (caq_ena & ~ caq_qready);
488+ // the coprocessor is not ready yet
489+ assign x_stall = x_issue_valid_o & ~ x_issue_ready_i;
463490 // the LSU Interface didn't accept our request yet
464491 assign lsu_stall = lsu_tlb_qvalid & ~ lsu_tlb_qready;
465492 // Stall the stage if we either didn't get a valid instruction, the LSU is not ready
466493 // or we are waiting on a fence instruction.
467494 // We do not include accelerator stalls in this signal for loop-free CAQ enable control.
468495 assign nonacc_stall = ~ valid_instr | lsu_stall | fence_stall;
469496 // To get the signal for all stall conditions, add the accelerator stalls.
470- assign stall = nonacc_stall | acc_stall;
497+ assign stall = nonacc_stall | acc_stall | x_stall ;
471498
472499 // --------------------
473500 // Instruction Frontend
@@ -510,6 +537,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
510537 assign rd = inst_data_i[7 + RegWidth - 1 : 7 ];
511538 assign rs1 = inst_data_i[15 + RegWidth - 1 : 15 ];
512539 assign rs2 = inst_data_i[20 + RegWidth - 1 : 20 ];
540+ assign rs3 = inst_data_i[27 + RegWidth - 1 : 20 ];
513541
514542 always_comb begin
515543 illegal_inst = 1'b0 ;
@@ -518,6 +546,10 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
518546 alu_op = Add;
519547 opa_select = None;
520548 opb_select = None;
549+ opc_select = None;
550+
551+ x_issue_req_o = '0 ;
552+ x_issue_valid_o = '0 ;
521553
522554 flush_i_valid_o = 1'b0 ;
523555 tlb_flush = 1'b0 ;
@@ -2268,8 +2300,27 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
22682300 end else illegal_inst = 1'b1 ;
22692301 end
22702302
2271- default : begin
2272- illegal_inst = 1'b1 ;
2303+ default : begin // Offload the instruction to the coprocessor
2304+ opa_select = Reg;
2305+ opb_select = Reg;
2306+ opc_select = Reg;
2307+
2308+ x_issue_req_o.instr = inst_data_i;
2309+ x_issue_req_o.mode = priv_lvl_q;
2310+ x_issue_req_o.id = xif_offload_counter_q;
2311+ x_issue_req_o.rs = { rs3, rs2, rs1} ;
2312+ x_issue_req_o.rs_valid = {~ sb_q[rs3], ~ sb_q[rs2], ~ sb_q[rs1]} ;
2313+ x_issue_req_o.ecs = '0 ; // Not implemented
2314+ x_issue_req_o.ecs_valid = '0 ; // Not implemented
2315+
2316+ // Since we canno know whether a source register will be used or not by the processor,
2317+ // here we do not use valid_instr as in the other instructions
2318+ x_issue_valid_o = inst_ready_i
2319+ & inst_valid_o
2320+ & ((itlb_valid & itlb_ready) | ~ trans_active);
2321+
2322+ // Flag the instruction as illegal if not accepted by the coprocessor or if it requests an unsupported operation
2323+ illegal_inst = x_issue_ready_i & x_issue_valid_o & (~ x_issue_resp_i.accept | |{ x_issue_resp_i.dualwrite, x_issue_resp_i.dualread, x_issue_resp_i.loadstore, x_issue_resp_i.ecswrite} );
22732324 end
22742325 endcase
22752326
@@ -2691,7 +2742,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
26912742
26922743 snitch_regfile # (
26932744 .DataWidth ( 32 ),
2694- .NrReadPorts ( 2 ),
2745+ .NrReadPorts ( 3 ),
26952746 .NrWritePorts ( 1 ),
26962747 .ZeroRegZero ( 1 ),
26972748 .AddrWidth ( RegWidth )
@@ -2731,8 +2782,18 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
27312782 endcase
27322783 end
27332784
2785+ // The C operand is currently only used for XIF instructions
2786+ always_comb begin
2787+ unique case (opc_select)
2788+ None: opc = '0 ;
2789+ Reg: opc = gpr_rdata[2 ];
2790+ default : opc = '0 ;
2791+ endcase
2792+ end
2793+
27342794 assign gpr_raddr[0 ] = rs1;
27352795 assign gpr_raddr[1 ] = rs2;
2796+ assign gpr_raddr[2 ] = rs3;
27362797
27372798 // --------------------
27382799 // ALU
@@ -2985,8 +3046,11 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
29853046 // external interfaces
29863047 lsu_pready = 1'b0 ;
29873048 acc_pready_o = 1'b0 ;
3049+ // Always assert x_result_ready if the coprocessor does not request a write
3050+ x_result_ready_o = ~ x_result_i.we;
29883051 retire_acc = 1'b0 ;
29893052 retire_load = 1'b0 ;
3053+ retire_x = 1'b0 ;
29903054
29913055 if (retire_i) begin
29923056 gpr_we[0 ] = 1'b1 ;
@@ -3003,6 +3067,12 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #(
30033067 gpr_waddr[0 ] = acc_prsp_i.id;
30043068 gpr_wdata[0 ] = acc_prsp_i.data[31 : 0 ];
30053069 acc_pready_o = 1'b1 ;
3070+ end else if (x_result_valid_i & x_result_i.we) begin
3071+ retire_x = 1'b1 ;
3072+ gpr_we[0 ] = 1'b1 ;
3073+ gpr_waddr[0 ] = x_result_i.rd;
3074+ gpr_wdata[0 ] = x_result_i.data[31 : 0 ];
3075+ x_result_ready_o = 1'b1 ;
30063076 end
30073077 end
30083078
0 commit comments