dakies/OSS_Verilog huggingface dataset:
module dff (q, d, clk, rst);

   output         q;
   input          d;
   input          clk;
   input          rst;

   reg            state;

   assign q = state;

   always @(posedge clk)
   begin
      if (rst)
         state <= 1'b0;
      else
         state <= d;
   end

`ifdef dump_flops
   always @(posedge gpu_tb.rst)
   begin
      if ($test$plusargs("dump_flops"))
      begin
         $display("%m.state");
      end
   end
`endif
endmodule
module queue_param_1r_1w(
                        in_wr_en,
                        in_wr_addr,
                        in_wr_data,
                        in_rd_addr,
                        out_rd_data,
                        clk,
                        rst
                        );

   parameter BITS = 2;
   parameter SIZE = 4;
   parameter WIDTH = 32;

   input in_wr_en;
   input [BITS - 1:0] in_wr_addr;
   input [WIDTH - 1:0] in_wr_data;
   input [BITS - 1:0] in_rd_addr;

   output [WIDTH - 1:0] out_rd_data;
   input clk;
   input rst;

   wire [(SIZE * WIDTH) - 1:0] word_out;
   wire [SIZE - 1:0] wr_word_select;
   wire [SIZE - 1:0] wr_en_word;

   mux_param #(.BITS(BITS), .SIZE(SIZE), .WIDTH(WIDTH)) mux_rd_port (.out(out_rd_data), .in(word_out), .select(in_rd_addr));
   decoder_param #(.BITS(BITS), .SIZE(SIZE)) decoder_wr_port (.out(wr_word_select), .in(in_wr_addr));
   assign wr_en_word = {SIZE{in_wr_en}} & wr_word_select;

   reg_param #(.WIDTH(WIDTH)) word[SIZE - 1:0] (.out(word_out), .in(in_wr_data), .wr_en(wr_en_word), .clk(clk), .rst(rst));

endmodule
module register(out, in, wr_en, clk, rst);

  parameter WIDTH = 1;
  output [WIDTH-1:0] out;
  input [WIDTH-1:0] in;
  input wr_en;
  input clk;
  input rst;

  dff_en bits[WIDTH-1:0] (.q(out), .d(in), .en(wr_en), .clk(clk), .rst(rst));

endmodule
module dff_set_en_rst(
   d,
   q,
   en,
   clk,
   set,
   rst );


   output q;
   input d;
   input en;
   input clk;
   input set;
   input rst;

   wire d_int;
   reg state;

   assign d_int = en ? d : state;

   assign q = state;

   always @(posedge clk or posedge rst)
   begin
      if(rst)
      state <= 0;
      else
      state <= set? 1 : d_int;
   end

`ifdef dump_flops
   always @(posedge gpu_tb.rst)
   begin
      if ($test$plusargs("dump_flops"))
      begin
         $display("%m.state");
      end
   end
`endif
endmodule
module encoder(in,out);
input [39:0] in;
output [5:0] out;

assign out =  (in[0]==1'b1)?6'd0:
              (in[1]==1'b1)?6'd1:
			  (in[2]==1'b1)?6'd2:
			  (in[3]==1'b1)?6'd3:
			  (in[4]==1'b1)?6'd4:
			  (in[5]==1'b1)?6'd5:
			  (in[6]==1'b1)?6'd6:
			  (in[7]==1'b1)?6'd7:
			  (in[8]==1'b1)?6'd8:
			  (in[9]==1'b1)?6'd9:
			  (in[10]==1'b1)?6'd10:
			  (in[11]==1'b1)?6'd11:
			  (in[12]==1'b1)?6'd12:
			  (in[13]==1'b1)?6'd13:
			  (in[14]==1'b1)?6'd14:
			  (in[15]==1'b1)?6'd15:
			  (in[16]==1'b1)?6'd16:
			  (in[17]==1'b1)?6'd17:
			  (in[18]==1'b1)?6'd18:
			  (in[19]==1'b1)?6'd19:
			  (in[20]==1'b1)?6'd20:
			  (in[21]==1'b1)?6'd21:
			  (in[22]==1'b1)?6'd22:
			  (in[23]==1'b1)?6'd23:
			  (in[24]==1'b1)?6'd24:
			  (in[25]==1'b1)?6'd25:
			  (in[26]==1'b1)?6'd26:
			  (in[27]==1'b1)?6'd27:
			  (in[28]==1'b1)?6'd28:
			  (in[29]==1'b1)?6'd29:
			  (in[30]==1'b1)?6'd30:
			  (in[31]==1'b1)?6'd31:
			  (in[32]==1'b1)?6'd32:
			  (in[33]==1'b1)?6'd33:
			  (in[34]==1'b1)?6'd34:
			  (in[35]==1'b1)?6'd35:
			  (in[36]==1'b1)?6'd36:
			  (in[37]==1'b1)?6'd37:
			  (in[38]==1'b1)?6'd38:
			  (in[39]==1'b1)?6'd39:
			  6'b000000;
endmodule
module dff_en (q, d, en, clk, rst);

  output q;
  input d;
  input en;
  input clk;
  input rst;

  wire d_int, q1;

  assign d_int = en ? d : q1;
  assign q = q1;

  dff dff_0(.q(q1), .d(d_int), .clk(clk), .rst(rst));
  
endmodule
module priority_encoder_40to6 (
	binary_out,
	valid,
	encoder_in,
	enable
);

output[5:0] binary_out;
output valid;

input[39:0] encoder_in;
input enable;

assign valid = (|encoder_in) & enable;

assign binary_out = (!enable) ? 6'd0 : (
		(encoder_in[0]) ? 6'd0 : 
		(encoder_in[1]) ? 6'd1 : 
		(encoder_in[2]) ? 6'd2 : 
		(encoder_in[3]) ? 6'd3 : 
		(encoder_in[4]) ? 6'd4 : 
		(encoder_in[5]) ? 6'd5 : 
		(encoder_in[6]) ? 6'd6 : 
		(encoder_in[7]) ? 6'd7 : 
		(encoder_in[8]) ? 6'd8 : 
		(encoder_in[9]) ? 6'd9 : 
		(encoder_in[10]) ? 6'd10 : 
		(encoder_in[11]) ? 6'd11 : 
		(encoder_in[12]) ? 6'd12 : 
		(encoder_in[13]) ? 6'd13 : 
		(encoder_in[14]) ? 6'd14 : 
		(encoder_in[15]) ? 6'd15 : 
		(encoder_in[16]) ? 6'd16 : 
		(encoder_in[17]) ? 6'd17 : 
		(encoder_in[18]) ? 6'd18 : 
		(encoder_in[19]) ? 6'd19 : 
		(encoder_in[20]) ? 6'd20 : 
		(encoder_in[21]) ? 6'd21 : 
		(encoder_in[22]) ? 6'd22 : 
		(encoder_in[23]) ? 6'd23 : 
		(encoder_in[24]) ? 6'd24 : 
		(encoder_in[25]) ? 6'd25 : 
		(encoder_in[26]) ? 6'd26 : 
		(encoder_in[27]) ? 6'd27 : 
		(encoder_in[28]) ? 6'd28 : 
		(encoder_in[29]) ? 6'd29 : 
		(encoder_in[30]) ? 6'd30 : 
		(encoder_in[31]) ? 6'd31 : 
		(encoder_in[32]) ? 6'd32 : 
		(encoder_in[33]) ? 6'd33 : 
		(encoder_in[34]) ? 6'd34 : 
		(encoder_in[35]) ? 6'd35 : 
		(encoder_in[36]) ? 6'd36 : 
		(encoder_in[37]) ? 6'd37 : 
		(encoder_in[38]) ? 6'd38 : 
		(encoder_in[39]) ? 6'd39 : {6{1'bx}}); 

endmodule
module mux_param (out, in, select);

   parameter BITS = 2;
   parameter SIZE = 4;
   parameter WIDTH = 1;

   output [WIDTH - 1:0] out;
   input [(SIZE * WIDTH) - 1:0] in;
   input [BITS - 1:0] select;

   reg [WIDTH - 1:0] out;

   integer i;

   always @ (in or select)
      begin
         out = {WIDTH{1'bx}};
         for(i = 0; i < SIZE; i = i + 1)
         begin
            if (select == i)
            begin
               out = in[(WIDTH * (i+1)) - 1-:WIDTH];
            end
         end
      end
endmodule
module reg_40b (out, in, wr_en, clk, rst);

  output [39:0] out;
  input [39:0] in;
  input wr_en;
  input clk;
  input rst;

  dff_en bits[39:0] (.q(out), .d(in), .en(wr_en), .clk(clk), .rst(rst));

endmodule
module adder1bit (
	sum,
	cout,
	in1,
	in2,
	cin
);

output sum, cout;
input in1, in2, cin;

assign sum = in1 ^ in2 ^ cin;
assign cout = (in1 & in2) | (in2 & cin) | (cin & in1);

endmodule
module dff_set_en (q, d, en, clk, set);

  output q;
  input d;
  input en;
  input clk;
  input set;

  wire d_int, q1;

  assign d_int = en ? d : q1;
  assign q = q1;

  dff_set dff_0(.q(q1), .d(d_int), .clk(clk), .set(set));
  
endmodule
module decoder_param_en (out, in, en);

   parameter BITS = 2;
   parameter SIZE = 4;

   output [SIZE - 1:0] out;
   input [BITS - 1:0] in;
   input en;

   reg [SIZE -1: 0] out;
   integer i;

   always @ (in or en)
      begin
         for(i = 0; i < SIZE; i = i + 1)
         begin
            out[i] = en ? ((in == i) ? 1'b1 : 1'b0) : 1'b0;
         end
      end

endmodule
module flop_en (q, d, en, clk);

  output q;
  input d;
  input en;
  input clk;

  wire d_int, q1;

  assign d_int = en ? d : q1;
  assign q = q1;

  flop flop_0(.q(q1), .d(d_int), .clk(clk));
  
endmodule
module encoder_5b_3b(
    in,
    out
);

input[4:0] in;
output[2:0] out;

reg[2:0] out;

always @(in) begin
    out = 3'h0;
    
    case(in)
        5'b00001: out = 3'h0;
        5'b00010: out = 3'h1;
        5'b00100: out = 3'h2;
        5'b01000: out = 3'h3;
        5'b10000: out = 3'h4;
        default: out = 3'h0;
    endcase
end
endmodule
module nand2 (in1,in2,out);
input in1,in2;
output out;
assign out = ~(in1 & in2);
endmodule
module reg_40b_set (out, in, wr_en, clk, set);

  output [39:0] out;
  input [39:0] in;
  input wr_en;
  input clk;
  input set;

  dff_set_en bits[39:0] (.q(out), .d(in), .en(wr_en), .clk(clk), .set(set));

endmodule
module reg_40xX_2r_1w (
  rd0_addr,
  rd0_data,

  rd1_addr,
  rd1_data,

  wr_en,
  wr_addr,
  wr_data,

  clk,
  rst
);

  parameter WIDTH = 1;
  output [WIDTH-1:0] rd0_data;
  output [WIDTH-1:0] rd1_data;
  input [5:0] rd0_addr;
  input [5:0] rd1_addr;

  input [5:0] wr_addr;
  input wr_en;
  input [WIDTH-1:0] wr_data;

  input clk;
  input rst;

  wire [(40*WIDTH)-1:0] word_out;
  wire [39:0] wr_word_select;
  wire [39:0] wr_en_word;

  mux_40xX_to_1xX #(WIDTH) mux_rd0_port (.out(rd0_data), .in(word_out), .select(rd0_addr));
  mux_40xX_to_1xX #(WIDTH) mux_rd1_port (.out(rd1_data), .in(word_out), .select(rd1_addr));

  decoder_6_to_40 decoder_wr_port (.out(wr_word_select), .in(wr_addr));
  assign wr_en_word = {40{wr_en}} & wr_word_select;

  register #(WIDTH) word[39:0](.out(word_out), .in(wr_data), .wr_en(wr_en_word), .clk(clk), .rst(rst));

endmodule
module regfile(
	d_in, 
	wr_en, 
	d_out, 
	clk, 
	rst
);  
  
parameter BITWIDTH = 11;

input [BITWIDTH-1:0] d_in;
input wr_en, clk, rst;

output [BITWIDTH-1:0] d_out;

wire [BITWIDTH-1:0] out;

dff d1[BITWIDTH-1:0](.q(d_out), .d(out), .clk(clk), .rst(rst));

mux2_1 m1[BITWIDTH-1:0](.InA(d_out), .InB(d_in), .out(out), .S(wr_en));
  
endmodule
module reg_40xX_1r_1w (
  rd_addr,
  rd_data,

  wr_en,
  wr_addr,
  wr_data,

  clk,
  rst
);

  parameter WIDTH = 1;
  output [WIDTH-1:0] rd_data;
  input [5:0] rd_addr;

  input [5:0] wr_addr;
  input wr_en;
  input [WIDTH-1:0] wr_data;

  input clk;
  input rst;

  wire [(40*WIDTH)-1:0] word_out;
  wire [39:0] wr_word_select;
  wire [39:0] wr_en_word;

  mux_40xX_to_1xX #(WIDTH) mux_rd_port (.out(rd_data), .in(word_out), .select(rd_addr));
  decoder_6_to_40 decoder_wr_port (.out(wr_word_select), .in(wr_addr));
  assign wr_en_word = {40{wr_en}} & wr_word_select;

  register #(WIDTH) word[39:0](.out(word_out), .in(wr_data), .wr_en(wr_en_word), .clk(clk), .rst(rst));

endmodule
module sgpr_3to1_rd_port_mux (
  port0_rd_en,
  port0_rd_addr,

  port1_rd_en,
  port1_rd_addr,

  port2_rd_en,
  port2_rd_addr,

  port_rd_data,

  rd_addr,
  rd_data
);

  input         port0_rd_en;
  input [8:0]   port0_rd_addr;

  input         port1_rd_en;
  input [8:0]   port1_rd_addr;

  input         port2_rd_en;
  input [8:0]   port2_rd_addr;

  input [127:0] rd_data;
  output [127:0] port_rd_data;
  output [8:0]  rd_addr;

  reg [8:0]     rd_addr;

  assign port_rd_data = rd_data;

  always @ (
    port0_rd_en or
    port1_rd_en or
    port2_rd_en or
    port0_rd_addr or
    port1_rd_addr or
    port2_rd_addr
  ) begin
      casex({port2_rd_en,port1_rd_en,port0_rd_en})
        3'b001:
          begin
            rd_addr <= port0_rd_addr;
          end
        3'b010:
          begin
            rd_addr <= port1_rd_addr;
          end
        3'b100:
          begin
            rd_addr <= port2_rd_addr;
          end
        default:
          begin
            rd_addr <= {9{1'bx}};
          end
      endcase
    end

endmodule
module sgpr_simx_rd_port_mux (
  port0_rd_en,
  port0_rd_addr,

  port1_rd_en,
  port1_rd_addr,

  port2_rd_en,
  port2_rd_addr,

  port3_rd_en,
  port3_rd_addr,
  
  port4_rd_en,
  port4_rd_addr,

  port5_rd_en,
  port5_rd_addr,

  port6_rd_en,
  port6_rd_addr,

  port7_rd_en,
  port7_rd_addr,
  
  port_rd_data,

  rd_addr,
  rd_en,
  rd_data
);

  input         port0_rd_en;
  input [8:0]   port0_rd_addr;
  input         port1_rd_en;
  input [8:0]   port1_rd_addr;
  input         port2_rd_en;
  input [8:0]   port2_rd_addr;
  input         port3_rd_en;
  input [8:0]   port3_rd_addr;
  input         port4_rd_en;
  input [8:0]   port4_rd_addr;
  input         port5_rd_en;
  input [8:0]   port5_rd_addr;
  input         port6_rd_en;
  input [8:0]   port6_rd_addr;
  input         port7_rd_en;
  input [8:0]   port7_rd_addr;
  
  input [31:0]  rd_data;
  
  output [31:0] port_rd_data;
  output [8:0]  rd_addr;
  output rd_en;

  reg [8:0]     rd_addr;
  reg rd_en;

  assign port_rd_data = rd_data;
  
  always @ (
    port0_rd_en or
    port1_rd_en or
    port2_rd_en or
    port3_rd_en or
    port4_rd_en or
    port5_rd_en or
    port6_rd_en or
    port7_rd_en or
    port0_rd_addr or
    port1_rd_addr or
    port2_rd_addr or
    port3_rd_addr or
    port4_rd_addr or
    port5_rd_addr or
    port6_rd_addr or
    port7_rd_addr
  ) begin
    casex({port7_rd_en,port6_rd_en,port5_rd_en,port4_rd_en,port3_rd_en,port2_rd_en,port1_rd_en,port0_rd_en})
      8'b0000_0001:
        begin
          rd_addr <= port0_rd_addr;
          rd_en <= 1'b1;
        end
      8'b0000_0010:
        begin
          rd_addr <= port1_rd_addr;
          rd_en <= 1'b1;
        end
      8'b0000_0100:
        begin
          rd_addr <= port2_rd_addr;
          rd_en <= 1'b1;
        end
      8'b0000_1000:
        begin
          rd_addr <= port3_rd_addr;
          rd_en <= 1'b1;
        end
      8'b0001_0000:
        begin
          rd_addr <= port4_rd_addr;
          rd_en <= 1'b1;
        end
      8'b0010_0000:
        begin
          rd_addr <= port5_rd_addr;
          rd_en <= 1'b1;
        end
      8'b0100_0000:
        begin
          rd_addr <= port6_rd_addr;
          rd_en <= 1'b1;
        end
      8'b1000_0000:
        begin
          rd_addr <= port7_rd_addr;
          rd_en <= 1'b1;
        end
      8'b0000_0000:
        begin
          rd_addr <= {9{1'bx}};
          rd_en <= 1'b0;
        end
      default:
        begin
          rd_addr <= {9{1'bx}};
          rd_en <= 1'bx;
        end
    endcase
  end

endmodule
module rd_port_9_to_1 (
  port0_rd_en,
  port0_rd_addr,

  port1_rd_en,
  port1_rd_addr,

  port2_rd_en,
  port2_rd_addr,

  port3_rd_en,
  port3_rd_addr,

  port4_rd_en,
  port4_rd_addr,

  port5_rd_en,
  port5_rd_addr,

  port6_rd_en,
  port6_rd_addr,

  port7_rd_en,
  port7_rd_addr,

  port8_rd_en,
  port8_rd_addr,

  rd_addr
);

  parameter WIDTH = 1;

  input               port0_rd_en;
  input [WIDTH - 1:0] port0_rd_addr;
  input               port1_rd_en;
  input [WIDTH - 1:0] port1_rd_addr;
  input               port2_rd_en;
  input [WIDTH - 1:0] port2_rd_addr;
  input               port3_rd_en;
  input [WIDTH - 1:0] port3_rd_addr;
  input               port4_rd_en;
  input [WIDTH - 1:0] port4_rd_addr;
  input               port5_rd_en;
  input [WIDTH - 1:0] port5_rd_addr;
  input               port6_rd_en;
  input [WIDTH - 1:0] port6_rd_addr;
  input               port7_rd_en;
  input [WIDTH - 1:0] port7_rd_addr;
  input               port8_rd_en;
  input [WIDTH - 1:0] port8_rd_addr;

  output [WIDTH - 1:0]  rd_addr;

  reg [WIDTH - 1:0]     rd_addr;

   always @ (
      port0_rd_en or port1_rd_en or port2_rd_en or port3_rd_en or port4_rd_en or
      port5_rd_en or port6_rd_en or port7_rd_en or port8_rd_en or
      port0_rd_addr or port1_rd_addr or port2_rd_addr or port3_rd_addr or
      port4_rd_addr or port5_rd_addr or port6_rd_addr or port7_rd_addr or port8_rd_addr)
   begin
      casex({port8_rd_en, port7_rd_en, port6_rd_en, port5_rd_en, port4_rd_en,
            port3_rd_en, port2_rd_en, port1_rd_en, port0_rd_en})
         9'b000000001: rd_addr <= port0_rd_addr;
         9'b000000010: rd_addr <= port1_rd_addr;
         9'b000000100: rd_addr <= port2_rd_addr;
         9'b000001000: rd_addr <= port3_rd_addr;
         9'b000010000: rd_addr <= port4_rd_addr;
         9'b000100000: rd_addr <= port5_rd_addr;
         9'b001000000: rd_addr <= port6_rd_addr;
         9'b010000000: rd_addr <= port7_rd_addr;
         9'b100000000: rd_addr <= port8_rd_addr;
         default: rd_addr <= 6'bxxxxxx;
      endcase
   end

endmodule
module instr_buffer(
      fetch_rd_en,
      fetch_addr,
      fetch_tag,
      fetchwave_ack,
      wave_instr,
      wave_tag,
      clk,
      rst
 );

parameter NUMOFCU = 1;

input clk;

input rst;

input [(NUMOFCU - 1):0] fetch_rd_en;
input [(NUMOFCU*32 - 1):0] fetch_addr;
input [(NUMOFCU*39 - 1):0] fetch_tag;

output [(NUMOFCU - 1):0] fetchwave_ack;
output [(NUMOFCU*32 - 1):0] wave_instr;
output [(NUMOFCU*39 - 1):0] wave_tag;

reg [(NUMOFCU - 1):0] fetchwave_ack;
reg [(NUMOFCU*32 - 1):0] wave_instr;
reg [(NUMOFCU*39 - 1):0] wave_tag;

reg [7:0] instr_memory[10000];

///////////////////////////////
//Your code goes here - beware: script does not recognize changes
// into files. It ovewrites everithing without mercy. Save your work before running the script
///////////////////////////////

integer i;

always @ (posedge clk)
	for(i = 0; i < NUMOFCU; i++) begin
		if (~rst & fetch_rd_en[i]) begin
			wave_instr[(i*32 + 7)-:8] = instr_memory[fetch_addr[(i*32 + 31)-:32]];
			wave_instr[(i*32 + 15)-:8] = instr_memory[fetch_addr[(i*32 + 31)-:32] + 1];
			wave_instr[(i*32 + 23)-:8] = instr_memory[fetch_addr[(i*32 + 31)-:32] + 2];
			wave_instr[(i*32 + 31)-:8] = instr_memory[fetch_addr[(i*32 + 31)-:32] + 3];

			wave_tag[(i*39 + 38)-:39] = fetch_tag[(i*39 + 38)-:39];
			fetchwave_ack[i] = 1'b1;
		end
		else begin
			// if reset or ~fetch_rd_en[i]
			wave_tag[(i*39 + 38)-:39] = 39'bx;
			fetchwave_ack[i] = 1'b0;
		end
	end

endmodule
module fpga_memory
(
  // input
  // LSU
  mem_wr_en, mem_rd_en,
  mem_addr, mem_wr_data, mem_tag_req,
  
  // MB
  mb_data_in, mb_data_we, mb_ack, mb_done,
  
  clk, rst,
  // output
  // LSU
  mem_tag_resp, mem_rd_data, mem_ack,
  
  // MB
  mb_op, mb_data_out, mb_addr
);

input clk;
input rst;

input mem_wr_en;
input mem_rd_en;
input [31:0] mem_addr;
input [31:0] mem_wr_data;
input [6:0] mem_tag_req;

input [31:0] mb_data_in;
input mb_data_we;
input mb_ack;
input mb_done;

output [31:0] mem_rd_data;
output [6:0] mem_tag_resp;
output mem_ack;

output [3:0] mb_op;
output [31:0] mb_data_out;
output [31:0] mb_addr;

reg [31:0] mem_addr_reg;
//reg [31:0] mem_wr_en;
reg [31:0] mb_data_out_reg;
reg[6:0] mem_tag_req_reg;

reg[3:0] mem_state;
reg[3:0] mem_state_next;

reg [31:0] mb_data_in_reg;
reg mem_ack_reg;
reg mb_ack_reg;
reg mb_done_reg;

`define MEM_IDLE 4'b0000
`define MEM_WR_ACK_WAIT 4'b0001
`define MEM_WR_RDY_WAIT 4'b0010
`define MEM_WR_LSU_TO 4'b0011
`define MEM_RD_ACK_WAIT 4'b0100
`define MEM_RD_RDY_WAIT 4'b0101
`define MEM_RD_LSU_TO 4'b0110

assign mem_tag_resp = mem_tag_req_reg;
assign mem_rd_data = mb_data_in_reg;
assign mem_ack = mem_ack_reg;

assign mb_data_out = mb_data_out_reg;
assign mb_addr = mem_addr_reg;
assign mb_op = mem_state;

always@(posedge clk) begin
  if(rst) begin
    mem_state <= `MEM_IDLE;
    mb_data_out_reg <= 32'd0;
    mem_addr_reg <= 32'd0;
    mem_tag_req_reg <= 7'd0;
    mb_data_in_reg <= 32'd0;
    mb_ack_reg <= 1'b0;
    mb_done_reg <= 1'b0;
  end
  else begin
    mb_ack_reg <= mb_ack;
    mb_done_reg <= mb_done;
    mem_state <= mem_state_next;
    
    mb_data_out_reg <= mb_data_out_reg;
    if(mem_wr_en) begin
      mb_data_out_reg <= mem_wr_data;
    end
    
    mem_addr_reg <= mem_addr_reg;
    mem_tag_req_reg <= mem_tag_req_reg;
    if(mem_wr_en | mem_rd_en) begin
      mem_addr_reg <= mem_addr;
      mem_tag_req_reg <= mem_tag_req;
    end
    
    mb_data_in_reg <= mb_data_in_reg;
    if(mb_data_we) begin
      mb_data_in_reg <= mb_data_in;
    end
  end
end

always@(*) begin
  mem_state_next <= mem_state;
  mem_ack_reg <= 1'b0;
  case(mem_state)
    `MEM_IDLE: begin
      if(mem_wr_en) begin
        mem_state_next <= `MEM_WR_ACK_WAIT;
      end
      else if(mem_rd_en) begin
        mem_state_next <= `MEM_RD_ACK_WAIT;
      end
    end
    `MEM_WR_ACK_WAIT: begin
      if(~mb_ack_reg & mb_ack) begin
        mem_state_next <= `MEM_WR_RDY_WAIT;
      end
    end
    `MEM_WR_RDY_WAIT: begin
      if(~mb_done_reg & mb_done) begin
        mem_state_next <= `MEM_WR_LSU_TO;
      end
    end
    `MEM_WR_LSU_TO: begin
      mem_ack_reg <= 1'b1;
      mem_state_next <= `MEM_IDLE;
    end
    `MEM_RD_ACK_WAIT: begin
      if(~mb_ack_reg & mb_ack) begin
        mem_state_next <= `MEM_RD_RDY_WAIT;
      end
    end
    `MEM_RD_RDY_WAIT: begin
      if(~mb_done_reg & mb_done) begin
        mem_state_next <= `MEM_RD_LSU_TO;
      end
    end
    `MEM_RD_LSU_TO: begin
      mem_ack_reg <= 1'b1;
      mem_state_next <= `MEM_IDLE;
    end
    default: mem_state_next <= mem_state;
  endcase
end

endmodule
module reg_256x32b_3r_1w_fpga
  (/*AUTOARG*/
   // Outputs
   rd0_data, rd1_data, rd2_data,
   // Inputs
   clk, rd0_addr, rd1_addr, rd2_addr, wr0_addr, wr0_en, wr0_data
   );
   input clk;

   output [31:0] rd0_data;
   output [31:0] rd1_data;
   output [31:0] rd2_data;

   input [9:0]   rd0_addr;
   input [9:0]   rd1_addr;
   input [9:0]   rd2_addr;

   input [9:0]   wr0_addr;

   input   wr0_en;

   input [31:0]  wr0_data;

wire [31:0] block_out_a;
wire [31:0] block_out_b;
wire [31:0] block_out_c;

reg wr_en_a;

assign rd0_data = block_out_a;
assign rd1_data = block_out_b;
assign rd2_data = block_out_c;

block_ram bank0(
  .clka(clk), // input clka
  //.rsta(rst), // input rsta
  .wea(wr0_en), // input [3 : 0] wea
  .addra(wr0_addr), // input [31 : 0] addra
  .dina(wr0_data), // input [31 : 0] dina
  .douta(), // output [31 : 0] douta
  .clkb(clk), // input clkb
  //.rstb(rst), // input rstb
  .web(1'b0), // input [3 : 0] web
  .addrb(rd0_addr), // input [31 : 0] addrb
  .dinb(32'd0), // input [31 : 0] dinb
  .doutb(block_out_a) // output [31 : 0] doutb
);

block_ram bank1(
  .clka(clk), // input clka
  //.rsta(rst), // input rsta
  .wea(wr0_en), // input [3 : 0] wea
  .addra(wr0_addr), // input [31 : 0] addra
  .dina(wr0_data), // input [31 : 0] dina
  .douta(), // output [31 : 0] douta
  .clkb(clk), // input clkb
  //.rstb(rst), // input rstb
  .web(1'b0), // input [3 : 0] web
  .addrb(rd1_addr), // input [31 : 0] addrb
  .dinb(32'd0), // input [31 : 0] dinb
  .doutb(block_out_b) // output [31 : 0] doutb
);

block_ram bank2(
  .clka(clk), // input clka
  //.rsta(rst), // input rsta
  .wea(wr0_en), // input [3 : 0] wea
  .addra(wr0_addr), // input [31 : 0] addra
  .dina(wr0_data), // input [31 : 0] dina
  .douta(), // output [31 : 0] douta
  .clkb(clk), // input clkb
  //.rstb(rst), // input rstb
  .web(1'b0), // input [3 : 0] web
  .addrb(rd2_addr), // input [31 : 0] addrb
  .dinb(32'd0), // input [31 : 0] dinb
  .doutb(block_out_c) // output [31 : 0] doutb
);
   
endmodule
module reg_128x32b_3r_2w_fpga
(/*AUTOARG*/
   // Outputs
   rd0_data, rd1_data, rd2_data,
   // Inputs
   clk, rd0_addr, rd1_addr, rd2_addr, wr0_addr, wr1_addr, wr0_en,
   wr1_en, wr0_data, wr1_data
   );
input clk;

output [31:0] rd0_data;
output [31:0] rd1_data;
output [31:0] rd2_data;

input [6:0] rd0_addr;
input [6:0] rd1_addr;
input [6:0] rd2_addr;

input [6:0] wr0_addr;
input [6:0] wr1_addr;

input wr0_en;
input wr1_en;

input [31:0] wr0_data;
input [31:0] wr1_data;

wire [6:0] wr_addr;
wire [9:0] wr_addr_blk;
wire wr_en;
wire [31:0] wr_data;

wire [9:0] rd0_addr_blk;
wire [9:0] rd1_addr_blk;
wire [9:0] rd2_addr_blk;

assign rd0_addr_blk = {3'b000, rd0_addr};
assign rd1_addr_blk = {3'b000, rd1_addr};
assign rd2_addr_blk = {3'b000, rd2_addr};

assign wr_data = wr1_en ? wr1_data : wr0_data;
assign wr_addr = wr1_en ? wr1_addr : wr0_addr;
assign wr_addr_blk = {3'b000, wr_addr};
assign wr_en = wr0_en | wr1_en;

block_ram bank0(
  .clka(clk), // input clka
  //.rsta(rst), // input rsta
  .wea(wr_en), // input [3 : 0] wea
  .addra(wr_addr_blk), // input [31 : 0] addra
  .dina(wr_data), // input [31 : 0] dina
  .douta(), // output [31 : 0] douta
  .clkb(clk), // input clkb
  //.rstb(rst), // input rstb
  .web(1'b0), // input [3 : 0] web
  .addrb(rd0_addr_blk), // input [31 : 0] addrb
  .dinb(32'd0), // input [31 : 0] dinb
  .doutb(rd0_data) // output [31 : 0] doutb
);

block_ram bank1(
  .clka(clk), // input clka
  //.rsta(rst), // input rsta
  .wea(wr_en), // input [3 : 0] wea
  .addra(wr_addr_blk), // input [31 : 0] addra
  .dina(wr_data), // input [31 : 0] dina
  .douta(), // output [31 : 0] douta
  .clkb(clk), // input clkb
  //.rstb(rst), // input rstb
  .web(1'b0), // input [3 : 0] web
  .addrb(rd1_addr_blk), // input [31 : 0] addrb
  .dinb(32'd0), // input [31 : 0] dinb
  .doutb(rd1_data) // output [31 : 0] doutb
);

block_ram bank2(
  .clka(clk), // input clka
  //.rsta(rst), // input rsta
  .wea(wr_en), // input [3 : 0] wea
  .addra(wr_addr_blk), // input [31 : 0] addra
  .dina(wr_data), // input [31 : 0] dina
  .douta(), // output [31 : 0] douta
  .clkb(clk), // input clkb
  //.rstb(rst), // input rstb
  .web(1'b0), // input [3 : 0] web
  .addrb(rd2_addr_blk), // input [31 : 0] addrb
  .dinb(32'd0), // input [31 : 0] dinb
  .doutb(rd2_data) // output [31 : 0] doutb
);

endmodule
module fpu_pre_norm_mul (
			 clk,
			 rst,
			 opa_i,
			 opb_i,
			 exp_10_o,
			 fracta_24_o,
			 fractb_24_o
			 );

   parameter FP_WIDTH = 32;
   parameter MUL_SERIAL = 0; // 0 for parallel multiplier, 1 for serial
   parameter MUL_COUNT = 11; //11 for parallel multiplier, 34 for serial
   parameter FRAC_WIDTH = 23;
   parameter EXP_WIDTH = 8;
   parameter ZERO_VECTOR = 31'd0;
   parameter INF = 31'b1111111100000000000000000000000;
   parameter QNAN = 31'b1111111110000000000000000000000;
   parameter SNAN = 31'b1111111100000000000000000000001;


   input clk;
   input rst;
   
   input [FP_WIDTH-1:0] opa_i;
   input [FP_WIDTH-1:0] opb_i;
   output reg [EXP_WIDTH+1:0] exp_10_o;
   output [FRAC_WIDTH:0]      fracta_24_o;
   output [FRAC_WIDTH:0]      fractb_24_o; 

   
   wire [EXP_WIDTH-1:0]       s_expa;
   wire [EXP_WIDTH-1:0]       s_expb;
   
   wire [FRAC_WIDTH-1:0]      s_fracta;
   wire [FRAC_WIDTH-1:0]      s_fractb;

   wire [EXP_WIDTH+1:0]       s_exp_10_o;
   wire [EXP_WIDTH+1:0]       s_expa_in;
   wire [EXP_WIDTH+1:0]       s_expb_in;
   
   wire 		      s_opa_dn, s_opb_dn;

   assign s_expa = opa_i[30:23];
   assign s_expb = opb_i[30:23];
   assign s_fracta = opa_i[22:0];
   assign s_fractb = opb_i[22:0];
   
   // Output Register
   always @(posedge clk or posedge rst)
     if (rst)
       exp_10_o <= 'd0;
     else
       exp_10_o <= s_exp_10_o;
   
   // opa or opb is denormalized
   assign s_opa_dn = !(|s_expa);
   assign s_opb_dn = !(|s_expb);
   
   assign fracta_24_o = {!s_opa_dn, s_fracta};
   assign fractb_24_o = {!s_opb_dn, s_fractb};
   
   assign s_expa_in = {2'd0, s_expa} + {9'd0, s_opa_dn};
   assign s_expb_in = {2'd0, s_expb} + {9'd0, s_opb_dn};
   
   assign s_exp_10_o = s_expa_in + s_expb_in - 10'b0001111111;		

endmodule // fpu_pre_norm_mul
module fpu_addsub(
		  clk,
		  rst,
		  fpu_op_i,
		  fracta_i,
		  fractb_i,
		  signa_i,
		  signb_i,
		  fract_o,
		  sign_o);

   
   parameter FP_WIDTH = 32;
   parameter MUL_SERIAL = 0; // 0 for parallel multiplier, 1 for serial
   parameter MUL_COUNT = 11; //11 for parallel multiplier, 34 for serial
   parameter FRAC_WIDTH = 23;
   parameter EXP_WIDTH = 8;
   parameter ZERO_VECTOR = 31'd0;
   parameter INF = 31'b1111111100000000000000000000000;
   parameter QNAN = 31'b1111111110000000000000000000000;
   parameter SNAN = 31'b1111111100000000000000000000001;
   
   input clk;
   input rst;
   
   input fpu_op_i;   
   input [FRAC_WIDTH+4:0] fracta_i;
   input [FRAC_WIDTH+4:0] fractb_i;
   input 		  signa_i;
   input 		  signb_i;
   output reg [FRAC_WIDTH+4:0] fract_o;
   output reg 		       sign_o;
   
   wire [FRAC_WIDTH+4:0]       s_fracta_i;
   wire [FRAC_WIDTH+4:0]       s_fractb_i;
   wire [FRAC_WIDTH+4:0]       s_fract_o;
   wire 		       s_signa_i, s_signb_i, s_sign_o;   
   wire 		       s_fpu_op_i;
   
   wire 		       fracta_gt_fractb;
   wire 		       s_addop;
   
   assign s_fracta_i = fracta_i;
   assign s_fractb_i = fractb_i;
   assign s_signa_i  = signa_i;
   assign s_signb_i  = signb_i;
   assign s_fpu_op_i = fpu_op_i;
   
   always @(posedge clk or posedge rst)
     if (rst)
       begin
	  fract_o <= 'd0;
	  sign_o <= 1'b0;
       end
     else
       begin
	  fract_o <= s_fract_o;
	  sign_o <= s_sign_o;	
       end
   
   assign fracta_gt_fractb = s_fracta_i > s_fractb_i;
   
   // check if its a subtraction or an addition operation
   assign s_addop = ((s_signa_i ^ s_signb_i) & !s_fpu_op_i) |
		    ((s_signa_i ^~ s_signb_i) & s_fpu_op_i);
   
   // sign of result
   assign s_sign_o = ((s_fract_o == 28'd0) & !(s_signa_i & s_signb_i)) ? 1'b0 :
		     (!s_signa_i & (!fracta_gt_fractb & (fpu_op_i^s_signb_i)))|
		     (s_signa_i & (fracta_gt_fractb | (fpu_op_i^s_signb_i)));
   
   // add/substract
   assign s_fract_o = s_addop ?
		      (fracta_gt_fractb ? s_fracta_i - s_fractb_i :
		       s_fractb_i - s_fracta_i) :
		      s_fracta_i + s_fractb_i;
   
   
endmodule // fpu_addsub
module ram_2_port
  (/*AUTOARG*/
   // Outputs
   rd_word,
   // Inputs
   rst, clk, wr_en, wr_addr, wr_word, rd_en, rd_addr
   );

   parameter WORD_SIZE = 16;
   parameter ADDR_SIZE = 5;
   parameter NUM_WORDS = 2**5;

   input rst, clk;
   
   input wr_en;
   input [ADDR_SIZE-1 :0] wr_addr;
   input [WORD_SIZE-1 :0] wr_word;

   input 		  rd_en;
   input [ADDR_SIZE-1: 0] rd_addr;
   output reg [WORD_SIZE-1: 0] rd_word;

   reg [WORD_SIZE-1 :0]    ram_table[NUM_WORDS-1:0];

   always @(posedge clk or rst) begin
      if(rst) begin
	 rd_word <= 0;
      end else begin
	 if(rd_en) begin
	    rd_word <= ram_table[rd_addr];
	 end

	 if(wr_en) begin
	    ram_table[wr_addr] <= wr_word;
	 end
      end
      
   end
   
endmodule // ram_2_port
module gds_resource_table (/*AUTOARG*/
   // Outputs
   gds_res_tbl_wg_gds_size,
   // Inputs
   rst, clk, gds_res_tbl_alloc_en, gds_res_tbl_dealloc_en,
   gds_res_tbl_cu_id, gds_res_tbl_wg_id, gds_res_tbl_alloc_gds_size,
   gds_res_tbl_inflight_res_tbl_id
   ) ;

   parameter NUMBER_CU = 64;
   parameter CU_ID_WIDTH = 6;
   parameter RES_TABLE_ADDR_WIDTH = 3;

   parameter WG_SLOT_ID_WIDTH = 6;
   parameter NUMBER_WF_SLOTS = 40;

   parameter GDS_ID_WIDTH = 10;
   parameter GDS_SIZE = 1024;
   localparam NUMBER_RES_TABLES = 2**RES_TABLE_ADDR_WIDTH;
   
   input rst, clk;
   input gds_res_tbl_alloc_en, gds_res_tbl_dealloc_en;
   input [CU_ID_WIDTH-1:0] gds_res_tbl_cu_id;
   input [WG_SLOT_ID_WIDTH-1:0] gds_res_tbl_wg_id;
   input [GDS_ID_WIDTH:0] gds_res_tbl_alloc_gds_size;

   input [RES_TABLE_ADDR_WIDTH-1:0] gds_res_tbl_inflight_res_tbl_id;
   output [GDS_ID_WIDTH:0] 	    gds_res_tbl_wg_gds_size;

   wire [GDS_ID_WIDTH:0] 	    gds_dealloc_amount;
   reg [GDS_ID_WIDTH:0] 	    gds_res_tbl_wg_gds_size;
   
   // Group of rams that keep track resources used by each slot
   ram_2_port
     #(
       // Parameters
       .WORD_SIZE			(GDS_ID_WIDTH+1),
       .ADDR_SIZE			(WG_SLOT_ID_WIDTH+CU_ID_WIDTH),
       .NUM_WORDS			(NUMBER_WF_SLOTS*NUMBER_CU))
   wf_slot_gds_space_ram 
     (
      // Outputs
      .rd_word				(gds_dealloc_amount),
      // Inputs
      .rst				(rst),
      .clk				(clk),
      .wr_en				(gds_res_tbl_alloc_en),
      .wr_addr				({gds_res_tbl_wg_id,gds_res_tbl_cu_id}),
      .wr_word				(gds_res_tbl_alloc_gds_size),
      .rd_en				(gds_res_tbl_dealloc_en),
      .rd_addr				({gds_res_tbl_wg_id,gds_res_tbl_cu_id}));


   
   // reg that keeps track of the mount of gds space used
   reg[GDS_ID_WIDTH:0] 				    gds_used_space_reg;
   reg 						    gds_dealloc_en_delay;
   
   
   always @ ( posedge clk or posedge rst ) begin
      if (rst) begin
	 gds_used_space_reg <= 0;
	 gds_dealloc_en_delay <= 1'b0;
	 /*AUTORESET*/
	 // Beginning of autoreset for uninitialized flops
	 gds_res_tbl_wg_gds_size <= {(1+(GDS_ID_WIDTH)){1'b0}};
	 // End of automatics
      end
      else begin
	 gds_dealloc_en_delay <= gds_res_tbl_dealloc_en;
	 gds_res_tbl_wg_gds_size <= GDS_SIZE - gds_used_space_reg;
	 
	 if(gds_res_tbl_alloc_en && gds_dealloc_en_delay) begin
	    gds_used_space_reg <= gds_used_space_reg + gds_res_tbl_alloc_gds_size -
				  gds_dealloc_amount;
	 end
	 else if(gds_res_tbl_alloc_en) begin
	    gds_used_space_reg <= gds_used_space_reg + gds_res_tbl_alloc_gds_size;
	 end 
	 else if(gds_dealloc_en_delay) begin
	    gds_used_space_reg <= gds_used_space_reg - gds_dealloc_amount;
	 end
	 
      end
   end
   
endmodule // gds_resource_table
module cam_allocator
  (/*AUTOARG*/
   // Outputs
   res_search_out,
   // Inputs
   clk, rst, res_search_en, res_search_size, cam_wr_en, cam_wr_addr,
   cam_wr_data
   );

   parameter CU_ID_WIDTH = 6;
   parameter NUMBER_CU = 64;

   parameter RES_ID_WIDTH = 10;
   parameter NUMBER_RES_SLOTS = 1024;

   // Search port
   input clk,rst;
   
   input 		  res_search_en;
   input [RES_ID_WIDTH:0] res_search_size;

   output [NUMBER_CU-1:0]   res_search_out;
   // Write port
   input 		  cam_wr_en;
   input [CU_ID_WIDTH-1 : 0] cam_wr_addr;
   input [RES_ID_WIDTH:0]      cam_wr_data;
   
   
   reg 			       res_search_en_i;
   reg [RES_ID_WIDTH:0]        res_search_size_i;

   // Table to implement the cam
   reg [RES_ID_WIDTH:0]      cam_ram[NUMBER_CU-1 :0];
   reg [NUMBER_CU-1 :0]      cam_valid_entry;

   wire [NUMBER_CU-1 :0]     decoded_output;

   genvar 		     i;
   generate
      for (i=0; i<NUMBER_CU; i=i+1) begin : LOOKUP
	 assign decoded_output[i] = (!res_search_en_i)? 1'b0 :
				    (!cam_valid_entry[i]) ? 1'b1 :
				    (cam_ram[i] >= res_search_size_i)? 1'b1:
				    1'b0;
      end
   endgenerate
   assign res_search_out = decoded_output;

   // Always block for the memory - no reset
   always @(posedge clk) begin
      if (cam_wr_en) begin
	 cam_ram[cam_wr_addr] <= cam_wr_data;
      end
      
   end 

   // For datapath - reset
   always @(posedge clk or rst) begin
      if(rst) begin
	 cam_valid_entry <= 0;
	 res_search_en_i <= 0;
	 res_search_size_i <= 0;
      end else begin
	 res_search_en_i <= res_search_en;
	 res_search_size_i <= res_search_size;

	 if (cam_wr_en) begin
	    cam_valid_entry[cam_wr_addr] <= 1'b1;
	 end
      end
      
      
   end 
   
endmodule
module mtbuf_addr_calc (
  out_addr,
  vector_source_b,
  scalar_source_a,
  scalar_source_b,
  imm_value0,
  idx_en,
  off_en,
  tid
);

output[31:0] out_addr;

input [31:0] vector_source_b;
input [127:0] scalar_source_a;
input [31:0] scalar_source_b;

input [15:0] imm_value0;

input idx_en;
input off_en;

input[5:0] tid;

`define BASE_VALUE scalar_source_a[47:0]
`define STRIDE_VALUE scalar_source_a[61:48]

wire[47:0] out_temp;

// Simplified equation is as follows:
// address = baseAddress + baseOffset + instrOffset + vectorOffset + stride * (vectorIndex + threadID)
assign out_temp = `BASE_VALUE + scalar_source_b + imm_value0 + (off_en ? {12'b0, vector_source_b} : 48'd0) + (`STRIDE_VALUE * (tid + (idx_en ? vector_source_b : 48'b0)));

assign out_addr = out_temp[31:0];

endmodule
module ds_addr_calc (
 lds_base,
 in_addr,
 out_addr
);

input [15:0] lds_base;
input [31:0] in_addr;
output [31:0] out_addr;

assign out_addr = {16'b0,lds_base} + in_addr;

endmodule
module PS_flops_wavepool_decode (
 wave_instr_pc,
 wave_instr_valid,
 wave_instr,
 wave_wfid,
 wave_vgpr_base,
 wave_sgpr_base,
 wave_lds_base,
 flopped_instr_pc,
 flopped_instr_valid,
 flopped_instr,
 flopped_wfid,
 flopped_vgpr_base,
 flopped_sgpr_base,
 flopped_lds_base,
 clk,
 rst
);

input clk;
input rst;

input [31:0] wave_instr_pc;
input wave_instr_valid;
input [31:0] wave_instr;
input [5:0] wave_wfid;
input [9:0] wave_vgpr_base;
input [8:0] wave_sgpr_base;
input [15:0] wave_lds_base;

output [31:0] flopped_instr_pc;
output flopped_instr_valid;
output [31:0] flopped_instr;
output [5:0] flopped_wfid;
output [9:0] flopped_vgpr_base;
output [8:0] flopped_sgpr_base;
output [15:0] flopped_lds_base;

dff flop_instr_pc [31:0] (.q(flopped_instr_pc), .d(wave_instr_pc), .clk(clk), .rst(rst));
dff flop_instr_valid (.q(flopped_instr_valid), .d(wave_instr_valid), .clk(clk), .rst(rst));
dff flop_instr [31:0] (.q(flopped_instr), .d(wave_instr), .clk(clk), .rst(rst));
dff flop_wfid [5:0] (.q(flopped_wfid), .d(wave_wfid), .clk(clk), .rst(rst));
dff flop_vgpr_base [9:0] (.q(flopped_vgpr_base), .d(wave_vgpr_base), .clk(clk), .rst(rst));
dff flop_sgpr_base [8:0] (.q(flopped_sgpr_base), .d(wave_sgpr_base), .clk(clk), .rst(rst));
dff flop_lds_base [15:0] (.q(flopped_lds_base), .d(wave_lds_base), .clk(clk), .rst(rst));

endmodule
module instr_collate (
  in_wfid,
  in_instr,
  in_valid,
  in_pc,
  out_instr,
  out_valid,
  out_pc,
  in_long,
  out_long,
  clk,
  rst
);

input [5:0] in_wfid;
input [31:0] in_instr;
input in_valid;
input [31:0] in_pc;

output [63:0] out_instr;
output out_valid;
output [31:0] out_pc;

input in_long;
output out_long;

input clk;
input rst;

wire [31:0] stored_instr;
wire [31:0] stored_pc;

reg_40xX_1r_1w #(64) reg_instr_pc (
 .rd_addr(in_wfid),
 .rd_data({stored_instr,stored_pc}),
 .wr_en(in_long&in_valid),
 .wr_addr(in_wfid),
 .wr_data({in_instr,in_pc}),
 .clk(clk),
 .rst(rst)
);

reg_40xX_1r_1w #(1) reg_valid (
 .rd_addr(in_wfid),
 .rd_data(out_long),
 .wr_en(in_valid),
 .wr_addr(in_wfid),
 .wr_data(in_long),
 .clk(clk),
 .rst(rst)
);

assign out_instr = out_long ? {in_instr,stored_instr} : {32'b0,in_instr};
assign out_pc = out_long ? stored_pc : in_pc;
assign out_valid = in_valid & (~in_long);

endmodule
module adder(in,out);
input [31:0]in;
output [31:0]out;

//wire [31:0]carry;
wire carry;

//adder1bit b1 [31:0] (out, carry, in, 32'd4, {carry[30:0],1'b0});
assign {carry, out} = in + 4;

endmodule
module wavegrp_info (
	wf_wr_en,
	wr_wf_tag,
	wr_wg_wf_count,
	wr_wfid,
	halt,
	halt_wfid,
	rd_wfid,
	rd_wgid,
	rd_wf_count,
	clk,
	rst
);

input clk;
input rst;

input wf_wr_en;
input [14:0] wr_wf_tag;
input [3:0] wr_wg_wf_count;
input [5:0] wr_wfid;
input [5:0] rd_wfid;
input halt;
input [5:0] halt_wfid;

output [5:0] rd_wgid;
output [3:0] rd_wf_count;

reg [5:0] rd_wgid;
reg [3:0] rd_wf_count;

reg [879:0] write_data;
reg [39:0] write_en;
reg cam_hit;
reg [21:0] cam_data;

wire [879:0] regfile_out;

regfile #(22) wg_cnt_store[39:0] (
	write_data, write_en, regfile_out, clk, rst
);

//assign regfile_out = write_data;

integer i;

//always @(wf_wr_en or wr_wfid or wr_wf_tag /*or regfile_out*/)
always @(*)
begin
	cam_hit = 1'b0;
	cam_data = 22'b0;

	if (wf_wr_en) begin
		for(i = 0; i < 40; i=i+1) begin
			if(/*!cam_hit && */regfile_out[(i*22)+21] &&
					(regfile_out[((i*22)+20)-:11] == wr_wf_tag[14-:11]))
			begin
				cam_data = regfile_out[((i*22)+21)-:22];
				cam_hit = 1'b1;
			end
		end
	end
end

//always @(halt or halt_wfid or cam_hit /*or cam_data*/ or wf_wr_en or wr_wf_tag or wr_wfid or wr_wg_wf_count /*or regfile_out*/) begin
always @(*) begin
	write_en = 40'b0;
	write_data = regfile_out;

	if(halt) begin
		write_data[(halt_wfid*22)+21-:22] = 22'd0;
		write_en[halt_wfid] = 1'b1;
	end

	if (wf_wr_en) begin
   		if(cam_hit == 1'b1) begin
			write_data[(wr_wfid*22)+21-:22] = cam_data;
			write_en[wr_wfid] = 1'b1;
		end
		else begin
			write_data[(wr_wfid*22)+21-:22] = {
				1'b1, wr_wf_tag[14-:11], wr_wfid, wr_wg_wf_count
				};
			write_en[wr_wfid] = 1'b1;
		end
	end
end

always @(rd_wfid or regfile_out)
begin
	rd_wgid = regfile_out[(rd_wfid*22)+9-:6];
	rd_wf_count = regfile_out[(rd_wfid*22)+3-:4];
end

endmodule
module fetch_controller (
	WF_dispatch_i, 
	fetch_valid, 
	wr, 
	inst_buff_rd, 
	wave_reserve_valid
);

input WF_dispatch_i;
input fetch_valid;

output wr;
output inst_buff_rd;
output wave_reserve_valid;

assign wr = WF_dispatch_i;
assign wave_reserve_valid = fetch_valid;
assign inst_buff_rd = fetch_valid;

endmodule
module wfid_generator(
	halt, 
	WF_tag, 
	WF_id_done, 
	vacant, 
	vacant_next, 
	WF_id, 
	WF_tag_done, 
	clk, 
	wr, 
	rst
);

input clk;
input rst;
input halt;
input wr;
input [14:0] WF_tag;
input [5:0] WF_id_done; //rename
input [39:0] vacant;

output [39:0] vacant_next;
output [5:0] WF_id; //new id generated
output [14:0] WF_tag_done; //rename

encoder encoder1(vacant, WF_id);
vacant_mask_gen vmg(WF_id, vacant_next, WF_id_done, vacant, halt, wr);

regblock #(15) wf_tag_store (
	WF_tag_done, clk, rst, 
	WF_id_done, WF_id, WF_tag, wr
);

endmodule
module adder7bit (
	sum,
	cout,
	in1,
	in2
);

output[6:0] sum;
output cout;

input[6:0] in1, in2;

wire cout0, cout1, cout2, cout3, cout4, cout5;

adder1bit add0(sum[0], cout0, in1[0], in2[0], 1'b0);
adder1bit add1(sum[1], cout1, in1[1], in2[1], cout0);
adder1bit add2(sum[2], cout2, in1[2], in2[2], cout1);
adder1bit add3(sum[3], cout3, in1[3], in2[3], cout2);
adder1bit add4(sum[4], cout4, in1[4], in2[4], cout3);
adder1bit add5(sum[5], cout5, in1[5], in2[5], cout4);
adder1bit add6(sum[6], cout, in1[6], in2[6], cout5);

endmodule
module incr_wraparound_at40 (
	out_value,
	in_value
);

output[5:0] out_value;
input[5:0] in_value;

wire[5:0] inter_sum;
wire ign_cout;

adder6bit a6b(inter_sum, ign_cout, in_value, 6'b000001);

assign out_value = (inter_sum == 6'b101000) ? 6'b000000 : inter_sum;

endmodule
module regfile_clr(d_in,wr_en,d_out,clk,rst);
  
  
  parameter BITWIDTH=11;
  input [BITWIDTH-1:0]d_in;
  output [BITWIDTH-1:0]d_out;
  input wr_en,clk,rst;
  
  wire [BITWIDTH-1:0]out;
  
  dff_clr d1[BITWIDTH-1:0](.q(d_out), .d(out), .clk(clk), .rst(rst));
  
  mux2_1 m1[BITWIDTH-1:0](.InA(d_out),.InB(d_in),.out(out),.S(wr_en));
  
endmodule
module mask_gen(in,out);

input [5:0]in;
output [63:0]out;

assign out = (in == 6'd0) ? 64'h0000000000000001:
             (in == 6'd1) ? 64'h0000000000000003:
			 (in == 6'd2) ? 64'h0000000000000007:
			 (in == 6'd3) ? 64'h000000000000000f:
			 (in == 6'd4) ? 64'h000000000000001f:
			 (in == 6'd5) ? 64'h000000000000003f:
			 (in == 6'd6) ? 64'h000000000000007f:
			 (in == 6'd7) ? 64'h00000000000000ff:
			 (in == 6'd8) ? 64'h00000000000001ff:
			 (in == 6'd9) ? 64'h00000000000003ff:
			 (in == 6'd10) ? 64'h00000000000007ff:
			 (in == 6'd11) ? 64'h0000000000000fff:
			 (in == 6'd12) ? 64'h0000000000001fff:
			 (in == 6'd13) ? 64'h0000000000003fff:
			 (in == 6'd14) ? 64'h0000000000007fff:
			 (in == 6'd15) ? 64'h000000000000ffff:
			 (in == 6'd16) ? 64'h000000000001ffff:
			 (in == 6'd17) ? 64'h000000000003ffff:
			 (in == 6'd18) ? 64'h000000000007ffff:
			 (in == 6'd19) ? 64'h00000000000fffff:
			 (in == 6'd20) ? 64'h00000000001fffff:
			 (in == 6'd21) ? 64'h00000000003fffff:
			 (in == 6'd22) ? 64'h00000000007fffff:
			 (in == 6'd23) ? 64'h0000000000ffffff:
			 (in == 6'd24) ? 64'h0000000001ffffff:
			 (in == 6'd25) ? 64'h0000000003ffffff:
			 (in == 6'd26) ? 64'h0000000007ffffff:
			 (in == 6'd27) ? 64'h000000000fffffff:
			 (in == 6'd28) ? 64'h000000001fffffff:
			 (in == 6'd29) ? 64'h000000003fffffff:
			 (in == 6'd30) ? 64'h000000007fffffff:
			 (in == 6'd31) ? 64'h00000000ffffffff:
			 (in == 6'd32) ? 64'h00000001ffffffff:
			 (in == 6'd33) ? 64'h00000003ffffffff:
			 (in == 6'd34) ? 64'h00000007ffffffff:
			 (in == 6'd35) ? 64'h0000000fffffffff:
			 (in == 6'd36) ? 64'h0000001fffffffff:
			 (in == 6'd37) ? 64'h0000003fffffffff:
			 (in == 6'd38) ? 64'h0000007fffffffff:
			 (in == 6'd39) ? 64'h000000ffffffffff:
			 (in == 6'd40) ? 64'h000001ffffffffff:
			 (in == 6'd41) ? 64'h000003ffffffffff:
			 (in == 6'd42) ? 64'h000007ffffffffff:
			 (in == 6'd43) ? 64'h00000fffffffffff:
			 (in == 6'd44) ? 64'h00001fffffffffff:
			 (in == 6'd45) ? 64'h00003fffffffffff:
			 (in == 6'd46) ? 64'h00007fffffffffff:
			 (in == 6'd47) ? 64'h0000ffffffffffff:
			 (in == 6'd48) ? 64'h0001ffffffffffff:
			 (in == 6'd49) ? 64'h0003ffffffffffff:
			 (in == 6'd50) ? 64'h0007ffffffffffff:
			 (in == 6'd51) ? 64'h000fffffffffffff:
			 (in == 6'd52) ? 64'h001fffffffffffff:
			 (in == 6'd53) ? 64'h003fffffffffffff:
			 (in == 6'd54) ? 64'h007fffffffffffff:
			 (in == 6'd55) ? 64'h00ffffffffffffff:
			 (in == 6'd56) ? 64'h01ffffffffffffff:
			 (in == 6'd57) ? 64'h03ffffffffffffff:
			 (in == 6'd58) ? 64'h07ffffffffffffff:
			 (in == 6'd59) ? 64'h0fffffffffffffff:
			 (in == 6'd60) ? 64'h1fffffffffffffff:
			 (in == 6'd61) ? 64'h3fffffffffffffff:
			 (in == 6'd62) ? 64'h7fffffffffffffff:
			 (in == 6'd63) ? 64'hffffffffffffffff:
			 64'd0;
			 
endmodule
module decoder(in,out);
input [5:0] in;
output [39:0] out;

reg [39:0]out;

always@(in)
begin
 out = 40'd0;
case (in)
0: out[0]=1'b1;
1: out[1]=1'b1;
2: out[2]=1'b1;
3: out[3]=1'b1;
4: out[4]=1'b1;
5: out[5]=1'b1;
6: out[6]=1'b1;
7: out[7]=1'b1;
8: out[8]=1'b1;
9: out[9]=1'b1;
10: out[10]=1'b1;
11: out[11]=1'b1;
12: out[12]=1'b1;
13: out[13]=1'b1;
14: out[14]=1'b1;
15: out[15]=1'b1;
16: out[16]=1'b1;
17: out[17]=1'b1;
18: out[18]=1'b1;
19: out[19]=1'b1;
20: out[20]=1'b1;
21: out[21]=1'b1;
22: out[22]=1'b1;
23: out[23]=1'b1;
24: out[24]=1'b1;
25: out[25]=1'b1;
26: out[26]=1'b1;
27: out[27]=1'b1;
28: out[28]=1'b1;
29: out[29]=1'b1;
30: out[30]=1'b1;
31: out[31]=1'b1;
32: out[32]=1'b1;
33: out[33]=1'b1;
34: out[34]=1'b1;
35: out[35]=1'b1;
36: out[36]=1'b1;
37: out[37]=1'b1;
38: out[38]=1'b1;
39: out[39]=1'b1;
endcase
end
endmodule
module add_wraparound_after40 (
	out_value,
	in_value_1,
	in_value_2
);

output[5:0] out_value;
input[5:0] in_value_1, in_value_2;

wire[5:0] inter_sum;
wire[6:0] inter_sub_40;
wire cout1, cout2, is_less_than_40;

adder6bit a6b(inter_sum, cout1, in_value_1, in_value_2); // adding two inputs
adder7bit a7b(inter_sub_40, cout2, {cout1, inter_sum}, 7'b1011000); // sum - 40 is output if sum is > 40

assign is_less_than_40 = inter_sub_40[6];
assign out_value = is_less_than_40 ? inter_sum : inter_sub_40[5:0];

endmodule
module round_robin (
	fetch_valid,
	pc_select,
	queue_vfull,
	icache_ack,
	vacant,
	clk,
	rst
);

output fetch_valid;
output[5:0] pc_select;

input[39:0] queue_vfull;
input icache_ack;
input[39:0] vacant;
input clk, rst;

wire[5:0] icache_req_out, icache_req_in;
wire[5:0] icache_req_plus1, icache_req_minus1;
wire ign_cout1, ign_cout2;

wire[39:0] valid_queues_not_full;
wire can_fetch, any_to_fetch;

wire[39:0] shifted_queue;
wire[5:0] highest_pr_in, highest_pr_out, prenc_out;

//adder6bit plus1(icache_req_plus1, ign_cout1, icache_req_out, 6'b000001);
//adder6bit minus1(icache_req_minus1, ign_cout2, icache_req_out, 6'b111111);

assign {ign_cout1, icache_req_plus1} = icache_req_out + 1;
assign {ign_cout2, icache_req_minus1} = icache_req_out - 1;

mux4to1_6bit m4to1_6b(icache_req_in, icache_req_out, icache_req_plus1, icache_req_minus1,
				icache_req_out, {fetch_valid, icache_ack});

dff_en_fixed_reset_value req_ff(icache_req_out, icache_req_in, 6'b011111, 1'b1, clk, rst);
dff_en high_pr_ff[5:0](highest_pr_out, highest_pr_in, fetch_valid, clk, rst);

assign valid_queues_not_full = ~(queue_vfull | vacant);
assign can_fetch = |icache_req_out;

circular_barrel_shift cbs(shifted_queue, valid_queues_not_full, highest_pr_out);
priority_encoder_40to6 penc(prenc_out, any_to_fetch, shifted_queue, 1'b1);

assign fetch_valid = can_fetch & any_to_fetch;

add_wraparound_after40 awa(pc_select, prenc_out, highest_pr_out);
incr_wraparound_at40 iwa(highest_pr_in, pc_select);

endmodule
module dff_en_fixed_reset_value (
	out_value,
	in_value,
	reset_value,
	en,
	clk,
	rst
);

output[5:0] out_value;
input[5:0] reset_value, in_value;
input en, clk, rst;

wire[5:0] dff_in_value;

assign dff_in_value = rst ? reset_value : in_value;

dff_en ff[5:0](out_value, dff_in_value, en, clk, 1'b0);

endmodule
module dff_clr (q, d, clk, rst);

   output         q;
   input          d;
   input          clk;
   input          rst;

   reg            state;

   assign q = state;

   always @(posedge clk or posedge rst)
   begin
      state <= rst? 1 : d;
   end

`ifdef dump_flops
   always @(posedge gpu_tb.rst)
   begin
      if ($test$plusargs("dump_flops"))
      begin
         $display("%m.state");
      end
   end
`endif
endmodule
module mux4to1_6bit (
	out,
	input0,
	input1,
	input2,
	input3,
	select
);

output[5:0] out;

input[5:0] input0, input1, input2, input3;
input[1:0] select;

assign out = (input0 & {6{(select == 2'b00)}}) |
			 (input1 & {6{(select == 2'b01)}}) |
			 (input2 & {6{(select == 2'b10)}}) |
			 (input3 & {6{(select == 2'b11)}});

endmodule
module vacant_mask_gen(
	new_wfid, 
	new_vacant, 
	wf_id_done, 
	vacant, 
	halt, 
	wr
);

input [5:0] new_wfid;
input wr;
input [39:0] vacant;
input [5:0] wf_id_done;
input halt;

output [39:0] new_vacant;

wire [39:0] halt_reset_mask, masked_vacant;
wire [39:0] new_slot_mask_neg, new_slot_mask;

assign new_vacant = halt ? (masked_vacant | halt_reset_mask) : masked_vacant;
assign masked_vacant = wr ? (new_slot_mask & vacant) : vacant;
assign new_slot_mask = ~new_slot_mask_neg;

decoder_6b_40b_en halt_mask(
	.addr_in(wf_id_done), .en(1'b1), .out(halt_reset_mask)
);

decoder_6b_40b_en new_wfid_mask(
	.addr_in(new_wfid), .en(1'b1), .out(new_slot_mask_neg)
);

endmodule
module adder6bit (
	sum,
	cout,
	in1,
	in2
);

output[5:0] sum;
output cout;

input[5:0] in1, in2;

wire cout0, cout1, cout2, cout3, cout4;

adder1bit add0(sum[0], cout0, in1[0], in2[0], 1'b0);
adder1bit add1(sum[1], cout1, in1[1], in2[1], cout0);
adder1bit add2(sum[2], cout2, in1[2], in2[2], cout1);
adder1bit add3(sum[3], cout3, in1[3], in2[3], cout2);
adder1bit add4(sum[4], cout4, in1[4], in2[4], cout3);
adder1bit add5(sum[5], cout, in1[5], in2[5], cout4);

endmodule