dakies/OSS_Verilog huggingface dataset:
module decoder #( parameter inputLen = 3,
	parameter outputLen = 1 << inputLen 
	)(
	in , 
 	decoder_out 
);

	//--------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------
	input [inputLen - 1 : 0] in;
	output [outputLen - 1 : 0] decoder_out ; 
    //--------------------------------------------------------------------------------------
    
    //-------------------------------------------------------------------------------------- 	
	assign decoder_out = (1 << in) ;
	//--------------------------------------------------------------------------------------
	
endmodule
module instCutter_new #(
    parameter fnLen = 3,
    parameter nameLen = 3,
    parameter indexLen = 8,
    parameter weightAddrLen         = 5,
	  parameter interimAddrLen        = 2,
    parameter peBusIndexLen         = 4,
  	parameter gbBusIndexLen         = 4,

    parameter instLen = fnLen + (indexLen+nameLen)*2 + 1+interimAddrLen+1+weightAddrLen+1+1+peBusIndexLen+gbBusIndexLen
//--------------------------------------------------------------------------------------
)(
  input [instLen - 1: 0]      instword,
  input                       instword_v,

  output [fnLen-1:0]          fn,
  
  output                      dest_weight_wrt,
  output [weightAddrLen-1:0]  dest_weight_Index,
	
  output                      dest_interim_wrt,
  output [interimAddrLen-1:0] dest_interim_Index,

  output                      dest_pe_bus_wrt,
  output                      dest_gb_bus_wrt,
  output [peBusIndexLen-2:0]  dest_pe_bus_Index,
  output [gbBusIndexLen-2:0]  dest_gb_bus_Index,

  output                      dest_pe_neigh_wrt,
  output                      dest_pu_neigh_wrt,

  output[nameLen - 1: 0]      src0Name,
	output[indexLen - 1: 0]     src0Index,
	output[nameLen - 1: 0]      src1Name,
	output[indexLen - 1: 0]     src1Index 

);

	//--------------------------------------------------------------------------------------

  assign {fn,src0Name,src0Index,src1Name,src1Index,dest_interim_wrt,dest_interim_Index,dest_weight_wrt,dest_weight_Index,dest_pu_neigh_wrt,dest_pe_neigh_wrt,dest_pe_bus_wrt,dest_pe_bus_Index,dest_gb_bus_wrt,dest_gb_bus_Index} = instword;
	//--------------------------------------------------------------------------------------
	/*assign fn = instword [ 6*(indexLen + nameLen) + fnLen - 1 : 6*(indexLen + nameLen) ];
	
	assign dest0Name = instword [ 6*(indexLen + nameLen) - 1 : 6*indexLen + 5*nameLen ] & {nameLen{instword_v}};
	assign dest0Index = instword [ 6*indexLen + 5*nameLen - 1 : 5*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign dest1Name = instword [ 5*(indexLen + nameLen) - 1 : 5*indexLen + 4*nameLen ] & {nameLen{instword_v}};
	assign dest1Index = instword [ 5*indexLen + 4*nameLen - 1 : 4*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign dest2Name = instword [ 4*(indexLen + nameLen) - 1 : 4*indexLen + 3*nameLen ] & {nameLen{instword_v}};
	assign dest2Index = instword [ 4*indexLen + 3*nameLen - 1 : 3*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign src0Name = instword [ 3*(indexLen + nameLen) - 1 : 3*indexLen + 2*nameLen ] & {nameLen{instword_v}};
	assign src0Index = instword [ 3*indexLen + 2*nameLen - 1 : 2*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign src1Name = instword [ 2*(indexLen + nameLen) - 1 : 2*indexLen + nameLen ] & {nameLen{instword_v}};
	assign src1Index = instword [ 2*indexLen + nameLen - 1 : indexLen + nameLen ] & {indexLen{instword_v}};
	
	assign src2Name = instword [ indexLen + nameLen - 1 : indexLen ] & {nameLen{instword_v}};
	assign src2Index = instword [indexLen - 1 : 0] & {indexLen{instword_v}};*/
	//--------------------------------------------------------------------------------------
	
endmodule
module op_selector #(
parameter LEN = 8
)(
  	sel,
  	weight,
  	data,
  	alu_out,
  	interim,
  	meta,
  	neigh,
  	bus,
  	out
);

	// *****************************************************************************
	
	
	// *****************************************************************************
	input     [2:0]        sel;
	input     [LEN-1 : 0]  weight;
	input     [LEN-1 : 0]  data;
	input     [LEN-1 : 0]  alu_out;
	input     [LEN-1 : 0]  interim;
	input     [LEN-1 : 0]  meta;
	input     [LEN-1 : 0]  neigh;
	input     [LEN-1 : 0]  bus;
	output reg   [LEN-1 : 0]  out;


	// *****************************************************************************
//	wire [LEN-1 : 0] out1;
//	wire [LEN-1 : 0] out2;
//	wire [LEN-1 : 0] out3;
//	wire [LEN-1 : 0] out4;
//	wire [LEN-1 : 0] out5;
//	wire [LEN-1 : 0] out6;

//	assign out1 = sel[0] ? weight : 0;
//	assign out2 = sel[0] ? gradient: data;
//	assign out3 = sel[0] ? meta: interim;
//	assign out4 = sel[0] ? bus: neigh;

//	assign out5 = sel[1] ? out2 : out1;
//	assign out6 = sel[1] ? out4 : out3;

//	assign out = sel[2] ? out6 : out5;
    always @(*) begin
        case(sel)
            3'b0: out = {LEN{1'b0}};
//            3'd1: out = {LEN{1'b0}};
            3'd1: out = alu_out;
            3'd2: out = weight;
            3'd3: out = data;
            3'd4: out = meta;
            3'd5: out = interim;
            3'd6: out = neigh;
            default: out = bus;
         endcase
     end
endmodule
module instCutter #(
    parameter destNum = 3, //only can write to GRADIENT, WEIGHT, INTERIM, BUS_SYSTEM, NEIGBOURS
    parameter srcNum = 3,
    parameter fnLen = 3,
    parameter nameLen = 3,
    parameter indexLen = 8,
    parameter instLen = fnLen + nameLen*destNum + nameLen*srcNum + indexLen*(srcNum+destNum)
//--------------------------------------------------------------------------------------
)(
	instword,
	instword_v,
	
	fn,
	
	dest0Name,
	dest0Index,

	dest1Name,
	dest1Index,
	
	dest2Name,
	dest2Index,

	src0Name,
	src0Index,

	src1Name,
	src1Index,

	src2Name,
	src2Index
);

	//--------------------------------------------------------------------------------------


	//--------------------------------------------------------------------------------------
	input[instLen - 1: 0] instword;
	input instword_v;
	output[fnLen - 1: 0] fn;
	output[nameLen - 1: 0]  dest0Name;
	output[indexLen - 1: 0] dest0Index;
	output[nameLen - 1: 0]  dest1Name;
	output[indexLen - 1: 0] dest1Index;
	output[nameLen - 1: 0]  dest2Name;
	output[indexLen - 1: 0] dest2Index;
	output[nameLen - 1: 0]  src0Name;
	output[indexLen - 1: 0] src0Index;
	output[nameLen - 1: 0]  src1Name;
	output[indexLen - 1: 0] src1Index;
	output[nameLen - 1: 0]  src2Name;
	output[indexLen - 1: 0] src2Index;
	//--------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------
	assign fn = instword [ 6*(indexLen + nameLen) + fnLen - 1 : 6*(indexLen + nameLen) ];
	
	assign dest0Name = instword [ 6*(indexLen + nameLen) - 1 : 6*indexLen + 5*nameLen ] & {nameLen{instword_v}};
	assign dest0Index = instword [ 6*indexLen + 5*nameLen - 1 : 5*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign dest1Name = instword [ 5*(indexLen + nameLen) - 1 : 5*indexLen + 4*nameLen ] & {nameLen{instword_v}};
	assign dest1Index = instword [ 5*indexLen + 4*nameLen - 1 : 4*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign dest2Name = instword [ 4*(indexLen + nameLen) - 1 : 4*indexLen + 3*nameLen ] & {nameLen{instword_v}};
	assign dest2Index = instword [ 4*indexLen + 3*nameLen - 1 : 3*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign src0Name = instword [ 3*(indexLen + nameLen) - 1 : 3*indexLen + 2*nameLen ] & {nameLen{instword_v}};
	assign src0Index = instword [ 3*indexLen + 2*nameLen - 1 : 2*(indexLen + nameLen) ] & {indexLen{instword_v}};
	
	assign src1Name = instword [ 2*(indexLen + nameLen) - 1 : 2*indexLen + nameLen ] & {nameLen{instword_v}};
	assign src1Index = instword [ 2*indexLen + nameLen - 1 : indexLen + nameLen ] & {indexLen{instword_v}};
	
	assign src2Name = instword [ indexLen + nameLen - 1 : indexLen ] & {nameLen{instword_v}};
	assign src2Index = instword [indexLen - 1 : 0] & {indexLen{instword_v}};
	//--------------------------------------------------------------------------------------
	
endmodule
module neigh_fifo #( parameter LEN = 16, parameter DEPTH = 4, parameter PTR = 2,
parameter NUM_PIPELINE_STAGES = 0
) (
    input clk,
    input rstn,
    input stall,
    
    input [LEN-1:0] data_in,
    input data_in_valid,
    
    input rd_rqst,
    
    output wire full,
    output [LEN-1:0] data_out,
    output  reg data_out_valid
    );
    
    wire rd_en,wr_en;
    reg data_rq,data_valid_retain;
    reg stall_d;
    wire empty;
    always @(posedge clk or negedge rstn) begin
    if(~rstn)
        stall_d <= 1'b0;
    else
        stall_d <= stall;
    end
//    assign data_out_valid = data_valid_retain || rd_en;
    always @(posedge clk or negedge rstn) begin
        if(~rstn)
            data_out_valid <= 1'b0;
        else
            data_out_valid <= (data_out_valid && stall) || rd_en;
    end
    always @(posedge clk or negedge rstn) begin
        if(~rstn) begin
            data_rq <= 1'b0;
            data_valid_retain <= 1'b0;
        end
        else if(~stall) begin
            data_rq <= rd_rqst;
            data_valid_retain <= 1'b0;
        end
        else begin
            data_rq <= rd_en ? 1'b0:data_rq;
            data_valid_retain <= data_out_valid ? 1'b1 : data_valid_retain ;
        end
    end
    
    assign rd_en = data_rq && ~empty;
    assign wr_en = data_in_valid;// && ~full;
    
    fifo_bus_read #(.DATA_LEN(LEN),
    .DEPTH(DEPTH),
    .NUM_PIPELINE_STAGES(NUM_PIPELINE_STAGES))
    fifo_wrt_to_bus 
    (
        .clk		(clk		),
        .rstn		(rstn		),
        .wr_data	(data_in	),
        .wr_en		(wr_en	),
        .rd_en		(rd_en	),
    
        .rd_data	(data_out	),
        .full		(full	),
        .empty_w		(empty	)
    );
endmodule
module mux
#(
// ******************************************************************
// PARAMETERS
// ******************************************************************
    parameter integer DATA_WIDTH  = 16,
    parameter integer NUM_DATA    = 16,
    parameter integer SHUFFLE_DATA_WIDTH = DATA_WIDTH * NUM_DATA,
    parameter integer CTRL_WIDTH         = `C_LOG_2 (NUM_DATA)
// ******************************************************************
) (
// ******************************************************************
// IO
// ******************************************************************
    input  wire [SHUFFLE_DATA_WIDTH-1:0]    DATA_IN,
    input  wire [CTRL_WIDTH        -1:0]    CTRL_IN,
    output wire [DATA_WIDTH        -1:0]    DATA_OUT
// ******************************************************************
);

// ******************************************************************
// LOCALPARAMS
// ******************************************************************
    
    
    localparam integer SHUFFLE_CTRL_WIDTH = CTRL_WIDTH * NUM_DATA;
// ******************************************************************
  `ifdef FPGA
    genvar i;
    generate
        for (i=0; i<NUM_DATA; i=i+1)
        begin : MUX
            assign DATA_OUT = (CTRL_IN == i) ? DATA_IN[i*DATA_WIDTH+:DATA_WIDTH] : {DATA_WIDTH{1'bz}};
        end
    endgenerate
  `else
    assign DATA_OUT = DATA_IN[CTRL_IN*DATA_WIDTH+:DATA_WIDTH];
  `endif

endmodule
module FlipFlop (
	clk,
	reset,
	wrt,
	dataIn,
	dataOut
);
	//--------------------------------------------------------------------------------------
	input  clk;
	input  reset;
	input  wrt;
	input  dataIn;
	output dataOut;
	
	//--------------------------------------------------------------------------------------
	reg data;
	
	always @(posedge clk) begin
		if (wrt)
			data <= dataIn;
		
		if (reset)
			data <= 1'b0;
	end
	
	assign dataOut = data;

endmodule
module mux_4x1(
  sel,
  in0,
  in1,
  in2,
  in3,
  out
);

// *****************************************************************************
parameter LEN         = 8;

// *****************************************************************************
input     [1:0]        sel;
input     [LEN-1 : 0]  in0;
input     [LEN-1 : 0]  in1;
input     [LEN-1 : 0]  in2;
input     [LEN-1 : 0]  in3;
output    [LEN-1 : 0]  out;

// *****************************************************************************
wire [LEN-1 : 0] out1;
wire [LEN-1 : 0] out2;

assign out1 = sel[0] ? in1 : in0;
assign out2 = sel[0] ? in3 : in2;

assign out = sel[1] ? out2: out1;

endmodule
module buffer #(
parameter addrLen = 6,
parameter dataLen = 32,
parameter memSize = 1 << addrLen,
parameter ram_type = "distributed"
)(
	input clk,
	input reset,
	
	input wrt,
	input [ addrLen - 1 : 0 ] wrt_addr,
	input rd_en,
	input [ addrLen - 1 : 0 ] rd_addr,
	input [ dataLen - 1 : 0 ] data_in,
	
	output reg [ dataLen - 1 : 0 ] data_out
);

	//--------------------------------------------------------------------------------------
	//(* ram_style = ram_type *)
	reg [ dataLen - 1 : 0 ] mem [ 0 : memSize - 1 ];
	//--------------------------------------------------------------------------------------
	
	always @(posedge clk) begin
    if(rd_en)
		data_out <= mem[rd_addr];
		
		if (wrt == 1) 
			mem[wrt_addr] <= data_in;
	end

endmodule
module pipeline #(

parameter NUM_BITS = 16,
parameter NUM_STAGES = 1,
parameter EN_RESET = 0
)(
input clk,
input [NUM_BITS-1:0] data_in,
input rstn,

output [NUM_BITS-1:0] data_out
);


generate
if(NUM_STAGES != 0 ) begin
    reg [NUM_BITS-1:0] data[0:NUM_STAGES];
    for(genvar gv =0;gv< NUM_STAGES;gv=gv+1)
        begin
        always @(posedge clk or negedge rstn)
            begin
                if(~rstn)
                    data[gv] <= {NUM_BITS{1'b0}};
                else
                    data[gv] <= (gv == 0) ? data_in : data[gv-1];
            end
         end
     assign data_out = data[NUM_STAGES-1];
end    
else
    assign data_out = data_in;
endgenerate

endmodule
module rdFifo #(
    parameter addrLen = 5,
	parameter dataLen = 32,
	parameter peId = 0
	)
(
	clk,
	reset,
	
	noStall,

	rd,
	
	restart,
	
	dataOut
);
	//--------------------------------------------------------------------------------------
	

	//--------------------------------------------------------------------------------------
	input clk;
	input reset;
	input noStall;
	
	input rd;
	
	input restart;
	
	output [dataLen - 1: 0] dataOut;

	//--------------------------------------------------------------------------------------
	wire headCntEn;
	wire[addrLen - 1: 0] headIn;
	wire[addrLen - 1: 0] headOut;

	wire fullEmptyBWrt;
	wire fullEmptyBIn;
	wire fullEmptyBOut;

	wire headTailEq;

	//--------------------------------------------------------------------------------------
	assign headIn = 0;
	
	Cnter #(addrLen) head (
		clk,
		reset,
		restart,
		rd,
		headIn,
		headOut
	);
	
	//--------------------------------------------------------------------------------------
	wire [dataLen - 1 : 0] dataOutBuffer;
	
	`ifdef SIMULATION
	   iBuffer_ASIC #(
			.addrLen(addrLen), 
			.dataLen(dataLen), 
			.peId(peId)
		) 
		inst_buffer (
			.clk(clk),
			.noStall(noStall),
			.rdAddr(headOut),
			.dataOut(dataOut)
		);
	`elsif FPGA
		iBuffer #(
			.addrLen(addrLen), 
			.dataLen(dataLen), 
			.peId(peId)
		) 
		inst_buffer (
			.clk(clk),
			.noStall(noStall),
			.rdAddr(headOut),
			.dataOut(dataOut)
		);
	`else
		iBuffer_ASIC #(
			.addrLen(addrLen), 
			.dataLen(dataLen), 
			.peId(peId)
		) 
		inst_buffer (
			.clk(clk),
			.noStall(noStall),
			.rdAddr(headOut),
			.dataOut(dataOut)
		);
	`endif


endmodule
module mux_2x1(
  sel,
  in0,
  in1,
  out
);

// *****************************************************************************
parameter LEN         = 8;

// *****************************************************************************
input                  sel;
input     [LEN-1 : 0]  in0;
input     [LEN-1 : 0]  in1;
output    [LEN-1 : 0]  out;

// *****************************************************************************
assign out = (sel) ? in1 : in0;

endmodule
module iBuffer #(
    parameter integer addrLen = 5,
	parameter integer dataLen = 32,
	parameter integer peId	= 1
	//parameter type	= "block"
)(
	clk,
	rdAddr,
	noStall,
	dataOut
);
	//--------------------------------------------------------------------------------------
	
	
	localparam integer unit = peId%10 + 'h30;
	localparam integer tens = peId/10%10 + 'h30;
  `ifdef FPGA
	  localparam init = {`COMPUTE_INST_INIT, "pe", tens, unit, ".txt"};
  `endif
  
  `ifdef SIMULATION
	  initial begin
		  $display ("%s", init);
	  end
  `endif

	//--------------------------------------------------------------------------------------
	input clk;
	input noStall;
	input[addrLen - 1: 0] rdAddr;
	output reg[dataLen - 1: 0] dataOut;

	//--------------------------------------------------------------------------------------
	reg[dataLen - 1: 0] mem	[0: (1 << addrLen) - 1];
	
	// ******************************************************************
	// Initialization
	// ******************************************************************
	`ifdef FPGA
    initial $readmemb (init, mem);
    wire     [dataLen-1:0]	rdata;
  
    assign rdata = mem[rdAddr];
  `else
    localparam DATA_WIDTH = dataLen;
    localparam DEPTH = (1<<addrLen);
    wire     [addrLen-1:0]        address;
    reg     [DATA_WIDTH-1:0]        rdata;

    assign address = rdAddr;

    // `include "instructions.v" // TODO
  `endif

	//-------------------------------------------------------------------------------------
 	always @(posedge clk) begin
 		if(noStall) dataOut <= rdata;
	end
	
endmodule
module DpRegFile #(	parameter addrLen = 5,
parameter dataLen = 32)(
	clk,
	reset,

	rd,
	wrt,
	
	rdAddr,
	wrtAddr,
	
	dataOut,
	dataIn
);
	//--------------------------------------------------------------------------------------


	//--------------------------------------------------------------------------------------
	input clk;
	input reset;
	
	input rd;
	input wrt;
	
	input[addrLen - 1: 0] rdAddr;
	input[addrLen - 1: 0] wrtAddr;
	
	output[dataLen - 1: 0] dataOut;
	input[dataLen - 1: 0]  dataIn;
	
	//output [dataLen - 1: 0] data0, data1, data2, data3;

	//--------------------------------------------------------------------------------------
	reg[dataLen - 1: 0] data[0: (1 << addrLen) - 1];
	
	//assign data0 = data[0];
	//assign data1 = data[1];
	//assign data2 = data[2];
	//assign data3 = data[3];
	
	//--------------------------------------------------------------------------------------
	assign dataOut = data[rdAddr];

	//--------------------------------------------------------------------------------------
	always @(posedge clk)
		if (wrt)
			data[wrtAddr] <= dataIn;

endmodule
module register # (
parameter LEN = 9
)
(
	clk, 
	dataIn,
	dataOut,
	reset,
	wrEn
);
	//--------------------------------------------------------------------------------------
	

    //--------------------------------------------------------------------------------------
    input              clk;
    input              reset;
    input              wrEn;
    input[LEN - 1: 0]  dataIn;
    output[LEN - 1: 0] dataOut;

    //--------------------------------------------------------------------------------------
    reg[LEN - 1: 0] data;

    //--------------------------------------------------------------------------------------
    always @(posedge clk) begin
    	if (reset)
        	data <= 0;
    	
    	else if (wrEn)
        	data <= dataIn; 	
    end

    //--------------------------------------------------------------------------------------
    assign dataOut = data;	

endmodule
module bufferRD #(
    parameter addrLen = 6,
	parameter dataLen = 32,
	parameter memSize = 1 << addrLen
	)(
	clk,
	reset,
	wrt,
	wrt_addr,
  rd_en,
	rd_addr0,
	rd_addr1,
	data_in,
	data_out0,
	data_out1
);

	//--------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------

	//--------------------------------------------------------------------------------------
	input clk;
	input reset;
	
	input wrt;
  input rd_en;
	
	input [ addrLen - 1 : 0 ] wrt_addr;
	input [ addrLen - 1 : 0 ] rd_addr0;
	input [ addrLen - 1 : 0 ] rd_addr1;
	input [ dataLen - 1 : 0 ] data_in;
	
	output reg [ dataLen - 1 : 0 ] data_out0;
	output reg [ dataLen - 1 : 0 ] data_out1;
	//--------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------
	reg [ dataLen - 1 : 0 ] mem [ 0 : memSize - 1 ];
	//--------------------------------------------------------------------------------------
	integer i;
	always @(posedge clk) begin
		if(reset) begin
			for(i = 0; i < 1 << addrLen; i = i + 1) mem[i] <= 0;
		end
		if (wrt) mem[wrt_addr] <= data_in;
	end

	always @(posedge clk) begin
    if(reset) begin
      data_out0 <= {dataLen{1'b0}};
      data_out1 <= {dataLen{1'b0}};
    end else if(rd_en) begin
	    data_out0 <= mem[rd_addr0];
	    data_out1 <= mem[rd_addr1];
    end
  end

endmodule
module Cnter #(parameter len = 5) (
	clk,
	reset,
	wrt,
	cnt,
	dataIn,
	dataOut
);
	//--------------------------------------------------------------------------------------
	
	
	//--------------------------------------------------------------------------------------
	input clk;
	input reset;
	input wrt;
	input cnt;
	input[len - 1: 0] dataIn;
	output[len - 1: 0] dataOut;
	
	//--------------------------------------------------------------------------------------
	reg[len - 1: 0] data;
		
	//--------------------------------------------------------------------------------------
	always @ (posedge clk) begin
		if (reset)
			data <= 0;
		
		else if (wrt)
			data <= dataIn;
		
		else if (cnt)
			data <= data + 1;

	end
	
	//--------------------------------------------------------------------------------------
	assign dataOut = data;

endmodule
module addSub #(
parameter LEN  = 9)(
	in1,
	in2,
	outAdd,
	outSub,
	overflowA,
	overflowS
);
	//--------------------------------------------------------------------------------------
 	

 	//--------------------------------------------------------------------------------------
 	input[LEN-1:0] in1;
 	input[LEN-1:0] in2;
 	output[LEN-1:0] outAdd;
	output[LEN-1:0] outSub;
 	output overflowA;
 	output overflowS;
    
  //--------------------------------------------------------------------------------------
	wire [LEN:0] addRes; 
	wire [LEN:0] subRes; 
	wire [1:0]   carry; 

    //--------------------------------------------------------------------------------------
  assign addRes = in1 + in2;   
  assign subRes = in1 - in2;

	assign carry[0] = (addRes[LEN - 1] ^ in1[LEN - 1] ^ in2[LEN - 1] ) || (in1[LEN -1] & in2[LEN - 1]);
	assign carry[1] = (subRes[LEN - 1] ^ in1[LEN - 1] ^ in2[LEN - 1] ) || (in1[LEN -1] & in2[LEN - 1]);
	
	assign outAdd = addRes[LEN - 1:0];    
	assign outSub = subRes[LEN - 1:0]; 

  //--------------------------------------------------------------------------------------
 	assign overflowA = carry[0] ^ addRes[LEN];
 	assign overflowS = carry[1] ^ subRes[LEN];
 
endmodule
module sqrt (
	in,	//in should be unsigned
  	out,
  	rout,
  	done
);
	//--------------------------------------------------------------------------------------
	parameter inLen = 32;	//length of sqrt is dataLen/2
    parameter qLen = inLen / 2;
	parameter rLen = inLen / 2 + 1;
	//--------------------------------------------------------------------------------------

	//--------------------------------------------------------------------------------------
	input [inLen - 1 : 0 ]  in;
	output [qLen - 1 : 0 ] out;
	output signed [rLen - 1 : 0] rout;
	output reg done;
	//--------------------------------------------------------------------------------------
integer i;
reg signed [rLen - 1 : 0] r;
reg [qLen - 1 : 0] q;

always @ (in) begin
    done = 0;
	r = 0;
	q = 0;

	for (i = inLen / 2 - 1; i >= 0 ; i = i - 1) begin
		#1
		if (r[rLen - 1] == 0) begin
			r = (r << 2) | (in >> (i + i) & 3);
			r = r - ((q << 2) | 1);
		end else begin
			r = (r << 2) | (in >> (i + i) & 3);
			r = r + ((q << 2) | 3);
		end

		if (r[rLen - 1] == 0) begin
			q = (q << 1) | 1;
		end else begin
			q = (q << 1) | 0;
		end
	end
    if (r<0) r= r+((q<<1)|1);
    done = 1;
end
assign out = q;
assign rout = r;

endmodule
module divider (
	in1,
  	in2,
  	out
);
	//--------------------------------------------------------------------------------------
	parameter dataLen = 32;
	parameter fractionLen = 15;
	//--------------------------------------------------------------------------------------

	//--------------------------------------------------------------------------------------
	input [dataLen - 1 : 0 ]  in1;
	input [dataLen - 1 : 0 ]  in2;
	output [dataLen - 1 : 0 ] out;
	//--------------------------------------------------------------------------------------

	assign out = in1 / in2;

endmodule
module mac #(
parameter LEN = 8)(
  in1,
  in2,
  preResult,
  out,
  overflow,
  done
);
  //--------------------------------------------------------------------------------------
  

  //--------------------------------------------------------------------------------------
  input  signed [LEN - 1: 0]    in1;
  input  signed [LEN - 1: 0]    in2;
  input  signed [LEN - 1: 0]    preResult;
  output signed [2*LEN - 1: 0]  out;
  output                        overflow;
  output                        done;

  //--------------------------------------------------------------------------------------
  //wire[2 * LEN - 1: 0] imm1;
  //wire imm2;

	wire [2*LEN - 1:0] in1_imm;
	wire [2*LEN - 1:0] in2_imm;
	wire [2*LEN - 1:0] preResult_imm;
	
	assign in1_imm = { {LEN{in1[LEN-1]}}, in1 };
	//assign in1_imm[LEN - 1 : 0] = in1;

	assign in2_imm = { {LEN{in2[LEN-1]}}, in2 };
	//assign in2_imm[LEN - 1 : 0] = in2;
	
	assign preResult_imm = { {LEN{preResult[LEN-1]}}, preResult};
	//assign preResult_imm[LEN - 1 : 0] = preResult;

  //assign out = in1_imm * in2_imm + preResult_imm;
  assign out = in1 * in2 + preResult;
  assign done = 1;

  //--------------------------------------------------------------------------------------
	//assign imm2  = |{imm1[2*LEN:LEN]}; 
	//assign out = imm2 ? ((1 << LEN) - 1) : imm1[LEN - 1: 0];

endmodule
module comp #(
parameter   LEN = 8
)(
    in1,
    in2,
    out
);

	// *****************************************************************************
	

	// *****************************************************************************
	input	[LEN - 1 : 0]   in1;
	input	[LEN - 1 : 0]   in2;
	output out;

	// *****************************************************************************
	assign out = ( in1 >= in2 ) ? 1 : 0;

endmodule
module wburst_counter #(
  parameter integer WBURST_COUNTER_LEN    = 16,
  parameter integer WBURST_LEN            = 4,
  parameter integer MAX_BURST_LEN         = 16
)(
  input  wire                             clk,
  input  wire                             resetn,
  input  wire                             write_valid,
  input  wire                             write_flush,

  output wire [WBURST_LEN-1:0]            wburst_len,
  output wire                             wburst_len_push,
  output wire                             wburst_ready,

  input  wire                             wburst_issued,
  input  wire [WBURST_LEN-1:0]            wburst_issued_len
);


  wire flush;

  reg  [WBURST_COUNTER_LEN-1:0] write_count;

  reg wr_flush_sticky;

  always @(posedge clk)
  begin
    if (resetn == 0 || write_count == 0)
      wr_flush_sticky <= 0;
    else if (write_flush)
      wr_flush_sticky <= 1;
  end

  assign flush = wr_flush_sticky && write_count!=0;

  //assign wburst_ready = ((write_count >= MAX_BURST_LEN) || wr_flush_sticky) && !wburst_ready_d && write_count != 0;
  assign wburst_ready = ((write_count >= MAX_BURST_LEN) || wr_flush_sticky) && write_count != 0;
  assign wburst_len = write_count >= MAX_BURST_LEN ? MAX_BURST_LEN - 1 :
                      write_count != 0 ? write_count - 1 : 0;
  reg wburst_ready_d;

  always @(posedge clk)
  begin
    if (resetn)
      wburst_ready_d <= wburst_ready;
    else
      wburst_ready_d <= 0;
  end

  always @(posedge clk)
  begin
    if (!resetn)
      write_count <= 0;
    else if (write_valid)
    begin
      if (wburst_issued)
        write_count <= write_count - wburst_issued_len;
      else
        write_count <= write_count + 1;
    end else begin
      if (wburst_issued)
        write_count <= write_count - wburst_issued_len - 1;
      else
        write_count <= write_count + 0;
    end
  end

  assign wburst_len_push = wburst_ready && !wburst_ready_d;

endmodule
module fifo 
#(  // Parameters
    parameter   DATA_WIDTH          = 64,
    parameter   INIT                = "init.mif",
    parameter   ADDR_WIDTH          = 4,
    parameter   RAM_DEPTH           = (1 << ADDR_WIDTH),
    parameter   INITIALIZE_FIFO     = "no",
    parameter   TYPE                = "MLAB",
    parameter   EARLY_FULL                = 0
)(  // Ports
    input  wire                         clk,
    input  wire                         reset,
    input  wire                         push,
    input  wire                         pop,
    input  wire [ DATA_WIDTH -1 : 0 ]   data_in,
    output reg  [ DATA_WIDTH -1 : 0 ]   data_out,
    output reg                          empty,
    output reg                          full
    //output reg  [ ADDR_WIDTH    : 0 ]   fifo_count
);    
 
// Port Declarations
// ******************************************************************
// Internal variables
// ******************************************************************
    reg     [ADDR_WIDTH-1:0]        wr_pointer;             //Write Pointer
    reg     [ADDR_WIDTH-1:0]        rd_pointer;             //Read Pointer
    reg  [ ADDR_WIDTH    : 0 ]   fifo_count;
	// ******************************************************************
// INSTANTIATIONS
// ******************************************************************
    `ifdef FPGA
      //(* ram_style = TYPE *)
      reg     [DATA_WIDTH-1:0]        mem[0:RAM_DEPTH-1]/*synthesis ramstyle = "MLAB" */;     //Memory

      initial begin
        if (INITIALIZE_FIFO == "yes") begin
          $readmemh(INIT, mem, 0, RAM_DEPTH-1);
        end
      end
    `else
      reg     [DATA_WIDTH-1:0]        mem[0:RAM_DEPTH-1];
    `endif

    always @ (fifo_count)
    begin : FIFO_STATUS
    	empty   = (fifo_count == 0);
    	full    = (fifo_count >= RAM_DEPTH-3-EARLY_FULL);
    end
    
    always @ (posedge clk)
    begin : FIFO_COUNTER
    	if (reset)
    		fifo_count <= 0;
    	
    	else if (push && !pop )
    		fifo_count <= fifo_count + 1;
    		
    	else if (pop && !push && !empty)
    		fifo_count <= fifo_count - 1;
    end
    
    always @ (posedge clk)
    begin : WRITE_PTR
    	if (reset) begin
       		wr_pointer <= 0;
    	end 
    	else if (push ) begin
    		wr_pointer <= wr_pointer + 1;
    	end
    end
    
    always @ (posedge clk)
    begin : READ_PTR
    	if (reset) begin
    		rd_pointer <= 0;
    	end
    	else if (pop && !empty) begin
    		rd_pointer <= rd_pointer + 1;
    	end
    end
    
    always @ (posedge clk)
    begin : WRITE
        if (push ) begin
    		mem[wr_pointer] <= data_in;
        end
    end
    
    always @ (posedge clk)
    begin : READ
        if (reset) begin
	    	data_out <= 0;
        end
        if (pop && !empty) begin
    		data_out <= mem[rd_pointer];
        end
        else begin
    		data_out <= data_out;
        end
    end

endmodule
module fifo_fwft 
// ******************************************************************
// Parameters
// ******************************************************************
#(
    parameter           INIT                = "init.mif",
    parameter integer   DATA_WIDTH          = 4,
    parameter integer   ADDR_WIDTH          = 8,
    parameter integer   RAM_DEPTH           = (1 << ADDR_WIDTH),
    parameter           INITIALIZE_FIFO     = "no",
    parameter           EARLY_FULL = 0
)
// ******************************************************************
// Port Declarations
// ******************************************************************
(
    input  wire                             clk,
    //input  wire                             pop_enable,
    input  wire                             reset,
    input  wire                             push,
    input  wire                             pop,
    input  wire [DATA_WIDTH-1:0]            data_in,
    output      [DATA_WIDTH-1:0]            data_out,
    output                                  empty,
    output                                  full
    //debug
    //output                                  fifo_pop,
    //output                                  fifo_empty,
    //output                                  dout_valid
);    
 
// ******************************************************************
// Internal variables
// ******************************************************************
    wire                             fifo_pop;
    wire                             fifo_empty;
    reg                              dout_valid;
    
// ******************************************************************
// Logic
// ******************************************************************
    assign fifo_pop    = !fifo_empty && (!dout_valid || pop);
    //assign fifo_pop    = !fifo_empty && (pop);
    //assign fifo_pop    = !fifo_empty && pop_enable && pop;
    assign empty        = !dout_valid;

    always @ (posedge clk)
    begin
        if (reset) begin
            dout_valid <= 0;
        end
        else if (fifo_pop) begin
            dout_valid <= 1;
        end
        else if (pop) begin
            dout_valid <= 0;
        end
    end
// ******************************************************************
// INSTANTIATIONS
// ******************************************************************

//-----------------------------------
// FIFO
//-----------------------------------
fifo #(
        .DATA_WIDTH         ( DATA_WIDTH   ),
        .ADDR_WIDTH         ( ADDR_WIDTH   ),
        .INIT               ( "init_x.mif" ),
        .EARLY_FULL         ( EARLY_FULL ),
        .INITIALIZE_FIFO    ( "no"         ))

    fifo_buffer(
        .clk                ( clk           ),  //input
        .reset              ( reset         ),  //input
        .push               ( push          ),  //input
        .pop                ( fifo_pop      ),  //input
        .data_in            ( data_in       ),  //input
        .data_out           ( data_out      ),  //output
        .empty              ( fifo_empty    ),  //output
        .full               ( full          )  //output
);   

endmodule
module comb#(
    parameter bitwidth  =8
)(
    input [bitwidth-1:0]data_in,
    input [bitwidth-1:0]bias,
    input valid,
    output [bitwidth-1:0]data_out
);
    wire [bitwidth-1:0] data;
    /*combination logic*/

    wire[bitwidth-1:0] temp;
                    assign temp=data_in-bias;
                    logstic logstic1(
                        .in(temp),
                        .out(data)
                    );


    assign data_out=data&valid;

endmodule
module pipe_reg_array #(
    parameter bitwidth=8
    parameter pipe=$j$
)(
    input clk,
    input rst,
    input data_in_$i$,
    output data_out_$i$
);

    $%pipe_reg #(
        .bitwidth(bitwidth),
        .pipe(pipe)
    )
    pipe_reg_$i$(
        .clk(clk),
        .rst(rst),
        .data_in(data_in_$i$),
        .data_out(data_out_$i$)
    );%$

endmodule : pipe_reg_array
module pipe_reg #(
    parameter bitwidth =8,
    parameter pipe=4
)(
    input clk,
    input rst,
    input [bitwidth-1:0]data_in,
    output  [bitwidth-1:0] data_out
);
    genvar i;
    generate
        for(i=0;i<pipe;i=i+1)begin:STAGE
            reg [bitwidth-1:0] p;
            if (i==0) begin
                always @(posedge clk)begin
                    if (rst) p<=0;
                    else p<=data_in;
                end
            end else begin
                always @(posedge clk)begin
                    if (rst) p<=0;
                    else p<=STAGE[i-1].p;
                end
            end
        end
    endgenerate

    assign data_out=STAGE[pipe-1].p;

endmodule
module sgd_unit#(
    parameter bitwidth =16,
	parameter inputBitwidth=8
)(
    input [inputBitwidth-1:0] x,
    input [bitwidth-1:0] w,
    input [bitwidth-1:0]data_in,
    input [inputBitwidth-1:0]mu,
    output [bitwidth-1:0]data_out
);
    assign data_out=w-data_in*mu*x;

endmodule
module comb_reco#(
    parameter bitwidth  =32,
	parameter inputBitwidth =16
)(
    input [bitwidth-1:0]data_in,
    input [inputBitwidth-1:0]bias,
	input [inputBitwidth-1:0]rate,
	input [inputBitwidth-1:0]mu,
    input valid,
    output [bitwidth-1:0]data_out
);

    wire [bitwidth-1:0] data;
    /*combination logic*/

    assign data=(data_in*rate-bias)*mu;


    //assign data_out=data&valid;
	assign data_out=data;
endmodule
module sgd_stage#(
    parameter bitwidth =16,
	parameter inputBitwidth=8,
    parameter stage = 0
)(
	input clk,
	input rst,
    input [inputBitwidth-1:0] x,
    input [bitwidth-1:0] w,
    input [bitwidth-1:0]data_in,
    //input [inputBitwidth-1:0]mu,
    output reg[bitwidth-1:0]data_out_r
);
	wire [bitwidth-1:0]data_out;
    wire [bitwidth-1:0]data;

    assign data=w-data_in*x;

	pipeline_reg #(
        .bitwidth(bitwidth),
        .num_stage(stage)
    )pipe_reg_sgd(
        .clk(clk),
        .rst(rst),
        .data_in(data),
        .data_out(data_out)
    );

	always @(posedge clk or posedge rst) begin
        if(rst)begin
         	data_out_r<=0;
        end else begin
    		data_out_r<=data_out;
		end
    end
endmodule
module ip#(
    parameter bitwidth =16,
	parameter inputBitwidth=8,
    parameter size=8
)(
    input[inputBitwidth*size-1:0] x,
    input[bitwidth*size-1:0] w,
    output [bitwidth-1:0]sum
);

    genvar i;
	wire [bitwidth-1:0]isum[size-1:0];
    generate
        for (i=0;i<size;i=i+1)begin: LOOP
            //wire [bitwidth-1:0]isum;
            if (i==0)begin
                assign isum[i]=w[bitwidth-1:0]*x[inputBitwidth-1:0];
            end else begin
                assign isum[i]=isum[i-1]+w[bitwidth*i+bitwidth-1:bitwidth*i]*x[inputBitwidth*i+inputBitwidth-1:inputBitwidth*i];
            end
        end
    endgenerate
    assign sum=isum[size-1];

endmodule
module comb#(
    parameter bitwidth  =32,
	parameter inputBitwidth =16
)(
    input [bitwidth-1:0]data_in,
    input [inputBitwidth-1:0]bias,
	input [inputBitwidth-1:0]mu,
    input valid,
	
    output [bitwidth-1:0]data_out
);

    wire [bitwidth-1:0] data;
    /*combination logic*/

    //linear regression
    `ifdef LINEAR
    assign data=data_in-bias;
    `endif

    //SVM
    `ifdef SVM
    assign data=((data_in*bias)>=1)?-bias:0;
    `endif

    //logistic regression
    `ifdef LOGISTIC
    wire[bitwidth-1:0] diff;
    assign diff=data_in-bias;
    sigmoid sigmoid1(
        .in(diff),
        .out(data)
    );
    `endif


    //assign data_out=data&valid;
	assign data_out=data*mu;
endmodule
module true_dual_port_ram#(
parameter addrLen = 6,
parameter dataLen = 32,
parameter memSize = 1 << addrLen
//parameter ram_type = "distributed"
)
(
	input [dataLen-1:0] data_a,
	input [addrLen-1:0] addr_a, addr_b,
	input we_a, re_b, clk,
	output reg [dataLen-1:0] q_b
);
	// Declare the RAM variable
	reg [dataLen-1:0] ram[memSize-1:0];
	
	// Port A
	always @ (posedge clk)
	begin
		if (we_a) 
		begin
			ram[addr_a] <= data_a;
		end
	end
	
	// Port B
	always @ (posedge clk)
	begin
		if (re_b)
		begin
			q_b <= ram[addr_b];
		end
		
	end
	
endmodule
module pipeline_reg #(
    parameter bitwidth =8,
    parameter num_stage=2,
    parameter en_rst = 0
)(
    input clk,
    input rst,
    input [bitwidth-1:0]data_in,
    output  [bitwidth-1:0] data_out
);
    genvar i;
    generate
        if(num_stage != 0 ) begin
            reg [bitwidth-1:0] data[0:num_stage-1];
            for(i=0;i<num_stage;i=i+1) begin:STAGE
                if ( en_rst == 0 ) begin
                    always @(posedge clk )
                        data[i] <= (i==0) ? data_in : data[i-1];
                end
                else begin
                    always @(posedge clk or posedge rst)begin
                            if(rst)
                                data[i] <= {bitwidth{1'b0}};
                            else
                                data[i] <= (i == 0) ? data_in : data[i-1];
                    end
                end
            end
            assign data_out = data[num_stage-1];
        end else
            assign data_out=data_in;
    endgenerate
endmodule
module comb_reco#(
    parameter bitwidth  =32,
	parameter inputBitwidth =16
)(
    input [bitwidth-1:0]data_in,
    input [inputBitwidth-1:0]bias,
	input [inputBitwidth-1:0]rate,
	//input [inputBitwidth-1:0]mu,
    //input valid,
    output [bitwidth-1:0]data_out
);

    wire [bitwidth-1:0] data;
    /*combination logic*/

    assign data=data_in*rate-bias;


    assign data_out=data;

endmodule
module ip#(
    parameter bitwidth =16,
	parameter inputBitwidth=8,
    parameter size=8
)(
    input[inputBitwidth*size-1:0] x,
    input[inputBitwidth*size-1:0] w,
    output [bitwidth-1:0]sum
);

    genvar i;
	wire [bitwidth-1:0]isum[size-1:0];
    generate
        for (i=0;i<size;i=i+1)begin: LOOP
            //wire [bitwidth-1:0]isum;
            if (i==0)begin
                assign isum[i]=w[inputBitwidth-1:0]*x[inputBitwidth-1:0];
            end else begin
                assign isum[i]=isum[i-1]+w[inputBitwidth*i+inputBitwidth-1:inputBitwidth*i]*x[inputBitwidth*i+inputBitwidth-1:inputBitwidth*i];
            end
        end
    endgenerate
    assign sum=isum[size-1];

endmodule
module comb#(
    parameter bitwidth  =32,
	parameter inputBitwidth =16,
	parameter fracBitwidth = 7
)(
    input [bitwidth-1:0]data_in,
    input [inputBitwidth-1:0]bias,
	input [inputBitwidth-1:0]mu,
    input valid,
	
    output [bitwidth-1:0]data_out
);

    wire [bitwidth-1:0] data;
    /*combination logic*/

    //linear regression
    `ifdef LINEAR
    assign data=data_in-bias;
    `endif

    //SVM
    `ifdef SVM
    assign data=((data_in*bias)>=(1<<fracBitwidth))?-bias:0;
    `endif

    //logistic regression
    `ifdef LOGISTIC
    wire[bitwidth-1:0] diff;
    assign diff=data_in-bias;
    sigmoid sigmoid1(
        .in(diff),
        .out(data)
    );
    `endif


    //assign data_out=data&valid;
	assign data_out=data*mu;
endmodule
module comb_reco_stage#(
    parameter bitwidth  =32,
	parameter inputBitwidth =16
)(
	input clk,
	input rst,
    input [bitwidth-1:0]data_in,
    input [inputBitwidth-1:0]bias,
	input [inputBitwidth-1:0]rate,
	input [inputBitwidth-1:0]mu,
    //input valid,
    output reg[bitwidth-1:0]grad_r
);
	wire [bitwidth-1:0]grad;
    comb_reco #(
            .bitwidth(bitwidth),
            .inputBitwidth(inputBitwidth)
        )
        comb1(
            .data_in(data_in),
            .bias(bias),
			.rate(rate),
			//.mu(mu),
            //.valid(valid),
            .data_out(grad)
        );

	always @(posedge clk or posedge rst) begin
        if (rst) grad_r<=0;
        else grad_r<=grad;
    end
endmodule
module rv32i_basereg
    (
        input wire i_clk,
        input wire i_ce_read, //clock enable for reading from basereg [STAGE 2]
        input wire[4:0] i_rs1_addr, //source register 1 address
        input wire[4:0] i_rs2_addr, //source register 2 address
        input wire[4:0] i_rd_addr, //destination register address
        input wire[31:0] i_rd, //data to be written to destination register
        input wire i_wr, //write enable
        output wire[31:0] o_rs1, //source register 1 value
        output wire[31:0] o_rs2 //source register 2 value
    );
    
    reg[4:0] rs1_addr_q, rs2_addr_q;
    reg[31:0] base_regfile[31:1]; //base register file (base_regfile[0] is hardwired to zero)
    wire write_to_basereg;
    
    always @(posedge i_clk) begin
        if(write_to_basereg) begin //only write to register if stage 5 is previously enabled (output of stage 5[WRITEBACK] is registered so delayed by 1 clk)
           base_regfile[i_rd_addr] <= i_rd; //synchronous write
        end
        if(i_ce_read) begin //only read the register if stage 2 is enabled [DECODE]
            rs1_addr_q <= i_rs1_addr; //synchronous read
            rs2_addr_q <= i_rs2_addr; //synchronous read
        end
    end
    
    assign write_to_basereg = i_wr && i_rd_addr!=0; //no need to write to basereg 0 (hardwired to zero) 
    assign o_rs1 = rs1_addr_q==0? 0: base_regfile[rs1_addr_q]; // if regfile is about to be written at the same time we read it
    assign o_rs2 = rs2_addr_q==0? 0: base_regfile[rs2_addr_q];    //then return the next value to be written to that address
    
endmodule
module rv32i_writeback (
    input wire[2:0] i_funct3, //function type 
    input wire[31:0] i_data_load, //data to be loaded to base reg
    input wire[31:0] i_csr_out, //CSR value to be loaded to basereg
    input wire i_opcode_load,
    input wire i_opcode_system, 
    // Basereg Control
    input wire i_wr_rd, //write rd to basereg if enabled (from previous stage)
    output reg o_wr_rd, //write rd to the base reg if enabled
    input wire[4:0] i_rd_addr, //address for destination register (from previous stage)
    output reg[4:0] o_rd_addr, //address for destination register
    input wire[31:0] i_rd, //value to be written back to destination register (from previous stage)
    output reg[31:0] o_rd, //value to be written back to destination register
    // PC Control
    input wire[31:0] i_pc, // pc value (from previous stage)
    output reg[31:0] o_next_pc, //new pc value
    output reg o_change_pc, //high if PC needs to jump
    // Trap-Handler
    input wire i_go_to_trap, //high before going to trap (if exception/interrupt detected)
    input wire i_return_from_trap, //high before returning from trap (via mret)
    input wire[31:0] i_return_address, //mepc CSR
    input wire[31:0] i_trap_address, //mtvec CSR
    /// Pipeline Control ///
    input wire i_ce, // input clk enable for pipeline stalling of this stage
    output reg o_stall, //informs pipeline to stall
    output reg o_flush //flush previous stages
);
//
    //determine next value of pc and o_rd
    always @* begin
        o_stall = 0; //stall when this stage needs wait time
        o_flush = 0; //flush this stage along with previous stages when changing PC
        o_wr_rd = i_wr_rd && i_ce && !o_stall;
        o_rd_addr = i_rd_addr;
        o_rd = 0;
        o_next_pc = 0;
        o_change_pc = 0;

        if(i_go_to_trap) begin
            o_change_pc = 1; //change PC only when ce of this stage is high (o_change_pc is valid)
            o_next_pc = i_trap_address;  //interrupt or exception detected so go to trap address (mtvec value)
            o_flush = i_ce;
            o_wr_rd = 0;
        end
        
        else if(i_return_from_trap) begin
            o_change_pc = 1; //change PC only when ce of this stage is high (o_change_pc is valid)
             o_next_pc = i_return_address; //return from trap via mret (mepc value)
             o_flush = i_ce;
             o_wr_rd = 0;
        end
        
        else begin //normal operation
            if(i_opcode_load) o_rd = i_data_load; //load data from memory to basereg
            else if(i_opcode_system && i_funct3!=0) begin //CSR write
                o_rd = i_csr_out; 
            end
            else o_rd = i_rd; //rd value is already computed at ALU stage
        end
        
    end
endmodule