dakies/OSS_Verilog huggingface dataset:
module corescore_intel_s10gx_devkit
(
 input  wire rstn,
 input  wire clk50
 );

  wire        clk;
  wire        rst;
  wire [7:0]  tdata;
  wire        tlast;
  wire        tvalid;
  reg         tready;
  reg [7:0]   r_dat;
  wire        r_ena;
  wire        locked;

  // ================================================================
  // Generate 16MHz from 50MHz board Clock
  // ================================================================
  intel_s10gx_pll clock_gen
  (
    .rst (~rstn),
    .refclk (clk50),
    .outclk_0 (clk),
    .locked (locked)
  );
  
  assign rst = ~locked;
  
  // ================================================================
  // CPU Magic Inside
  // ================================================================
  corescorecore corescorecore
  (
   .i_clk     (clk),
   .i_rst     (rst),
   .o_tdata   (tdata),
   .o_tlast   (tlast),
   .o_tvalid  (tvalid),
   .i_tready  (tready)
   );

  // ================================================================
  // Pipeline response as UART expects 1 clk delay after r_ena goes active
  // before you can push characters into it.
  // ================================================================
  always @(posedge clk) begin
   if (tvalid & r_ena) begin
     tready <= 1'b1;
     r_dat  <= tdata;
   end else begin
     tready <= 1'b0;
   end 
  end 	

  // ================================================================
  // Instantiate the internal JTAG-UART interface as the GX Devkit has no UART pins.
  //
  // NOTE - UART will stall indefinety when its tx-fifo is full, 
  // so you must run nios-terminal.exe to allow things to flow 
  // ================================================================
  alt_jtag_atlantic #(
  .INSTANCE_ID(0),
   .LOG2_RXFIFO_DEPTH(6),
   .LOG2_TXFIFO_DEPTH(6),
   .SLD_AUTO_INSTANCE_INDEX("YES")
  ) i_uart (
   .clk    (clk),
   .rst_n   (~rst),
   .r_dat  (r_dat),
   .r_ena  (r_ena),
   .r_val  (tready),
   // Not interested in RX 
   .t_dat  (),
   .t_dav  (1'b1),
   .t_ena  (),
   .t_pause()
  );

endmodule
module corescore_kc705
(
 input wire  i_clk_p,
 input wire  i_clk_n,
 output wire q,
 output wire o_uart_tx);

   wire      i_clk;
   wire      clk;
   wire      rst;

   //Mirror UART output to LED
   assign q = o_uart_tx;

   IBUFDS ibufds
     (.I  (i_clk_p),
      .IB (i_clk_n),
      .O  (i_clk));

   corescore_kc705_clock_gen
   clock_gen
     (.i_clk (i_clk),
      .o_clk (clk),
      .o_rst (rst));

   parameter memfile_emitter = "emitter.hex";

   wire [7:0]  tdata;
   wire        tlast;
   wire        tvalid;
   wire        tready;

   corescorecore corescorecore
     (.i_clk     (clk),
      .i_rst     (rst),
      .o_tdata   (tdata),
      .o_tlast   (tlast),
      .o_tvalid  (tvalid),
      .i_tready  (tready));

   emitter #(.memfile (memfile_emitter)) emitter
     (.i_clk     (clk),
      .i_rst     (rst),
      .i_tdata   (tdata),
      .i_tlast   (tlast),
      .i_tvalid  (tvalid),
      .o_tready  (tready),
      .o_uart_tx (o_uart_tx));

endmodule
module corescore_cyc1000
(
 input wire  i_clk,
 output wire q,
 output wire o_uart_tx);

   wire      clk;
   wire      rst;

   //Mirror UART output to LED
   assign q = o_uart_tx;

   cyc1000_clock_gen clock_gen
     (.i_clk (i_clk),
      .o_clk (clk),
      .o_rst (rst));

   parameter memfile_emitter = "emitter.hex";

   wire [7:0]  tdata;
   wire        tlast;
   wire        tvalid;
   wire        tready;

   corescorecore corescorecore
     (.i_clk     (clk),
      .i_rst     (rst),
      .o_tdata   (tdata),
      .o_tlast   (tlast),
      .o_tvalid  (tvalid),
      .i_tready  (tready));

   emitter #(.memfile (memfile_emitter)) emitter
     (.i_clk     (clk),
      .i_rst     (rst),
      .i_tdata   (tdata),
      .i_tlast   (tlast),
      .i_tvalid  (tvalid),
      .o_tready  (tready),
      .o_uart_tx (o_uart_tx));

endmodule
module corescore_storeypeak
(
 input wire  i_clk,
 output wire q,
 output wire o_uart_tx);

   wire      clk;
   wire      rst;

   //Mirror UART output to LED
   assign q = ~o_uart_tx;

   storeypeak_clock_gen clock_gen
     (.i_clk (i_clk),
      .o_clk (clk),
      .o_rst (rst));

   parameter memfile_emitter = "emitter.hex";

   wire [7:0]  tdata;
   wire        tlast;
   wire        tvalid;
   wire        tready;

   corescorecore corescorecore
     (.i_clk     (clk),
      .i_rst     (rst),
      .o_tdata   (tdata),
      .o_tlast   (tlast),
      .o_tvalid  (tvalid),
      .i_tready  (tready));

   emitter #(.memfile (memfile_emitter)) emitter
     (.i_clk     (clk),
      .i_rst     (rst),
      .i_tdata   (tdata),
      .i_tlast   (tlast),
      .i_tvalid  (tvalid),
      .o_tready  (tready),
      .o_uart_tx (o_uart_tx));

endmodule
module corescore_vcu128_clock_gen
  (input wire  i_clk,
   output wire o_clk,
   output reg  o_rst);

   wire   clkfb;
   wire   locked;
   reg 	  locked_r;

   MMCME4_ADV
     #(.DIVCLK_DIVIDE    (4),
       .CLKFBOUT_MULT_F  (32.000),
       .CLKOUT0_DIVIDE_F (50.0),
       .CLKIN1_PERIOD    (10.0), //100MHz
       .STARTUP_WAIT     ("FALSE"))
   mmcm
     (.CLKFBOUT    (clkfb),
      .CLKFBOUTB   (),
      .CLKOUT0     (o_clk),      // 16MHz
      .CLKOUT0B    (),
      .CLKOUT1     (),
      .CLKOUT1B    (),
      .CLKOUT2     (),
      .CLKOUT2B    (),
      .CLKOUT3     (),
      .CLKOUT3B    (),
      .CLKOUT4     (),
      .CLKOUT5     (),
      .CLKOUT6     (),
      .CLKIN1      (i_clk),
      .CLKIN2      (1'b0),
      .CLKINSEL    (1'b1),
      .LOCKED      (locked),
      .PWRDWN      (1'b0),
      .RST         (1'b0),
      .CLKFBIN     (clkfb));

   always @(posedge o_clk) begin
      locked_r <= locked;
      o_rst  <= !locked_r;
   end

endmodule
module de0_nano_clock_gen
  (input wire i_clk,
   input wire  i_rst,
   output wire o_clk,
   output wire o_rst);

   wire        locked;
   reg [9:0]   r;

   assign o_rst = r[9];

   always @(posedge o_clk)
     if (locked)
       r <= {r[8:0],1'b0};
     else
       r <= 10'b1111111111;

   wire [5:0] 	  clk;

   assign 	  o_clk = clk[0];

   altpll
     #(.operation_mode         ("NORMAL"),
       .clk0_divide_by         (25),
       .clk0_multiply_by       (8),
       .inclk0_input_frequency (20000))
   pll
     (.areset       (i_rst),
      .inclk        ({1'b0, i_clk}),
      .clk          (clk),
      .locked       (locked));

endmodule
module corescore_cmod_a7
(
 input wire  i_clk,
 output wire q,
 output wire o_uart_tx);

   wire      clk;
   wire      rst;

   //Mirror UART output to LED
   assign q = o_uart_tx;

   cmod_a7_clock_gen clock_gen
     (.i_clk (i_clk),
      .o_clk (clk),
      .o_rst (rst));

   parameter memfile_emitter = "emitter.hex";

   wire [7:0]  tdata;
   wire        tlast;
   wire        tvalid;
   wire        tready;

   corescorecore corescorecore
     (.i_clk     (clk),
      .i_rst     (rst),
      .o_tdata   (tdata),
      .o_tlast   (tlast),
      .o_tvalid  (tvalid),
      .i_tready  (tready));

   emitter #(.memfile (memfile_emitter)) emitter
     (.i_clk     (clk),
      .i_rst     (rst),
      .i_tdata   (tdata),
      .i_tlast   (tlast),
      .i_tvalid  (tvalid),
      .o_tready  (tready),
      .o_uart_tx (o_uart_tx));

endmodule
module corescore_fpc_iii_clock_gen( input i_clk, output o_clk, output o_rst );
    
    wire locked;

    reg[ 1:0 ] rst_reg;
    always @( posedge o_clk )
	rst_reg <= { !locked, rst_reg[ 1 ] };

    assign o_rst = rst_reg[ 0 ];

    pll pll( .clki( i_clk ), .clko( o_clk ), .locked( locked ) );
endmodule
module corescore_intel_cyc10lp_devkit
(
 input wire  clk50,
 output wire uart_txd);

   wire      clk;
   wire      rst;

   intel_cyc10lp_devkit_clock_gen clock_gen
     (.i_clk (clk50),
      .o_clk (clk),
      .o_rst (rst));

   parameter memfile_emitter = "emitter.hex";

   wire [7:0]  tdata;
   wire        tlast;
   wire        tvalid;
   wire        tready;

   corescorecore corescorecore
     (.i_clk     (clk),
      .i_rst     (rst),
      .o_tdata   (tdata),
      .o_tlast   (tlast),
      .o_tvalid  (tvalid),
      .i_tready  (tready));

   emitter #(.memfile (memfile_emitter)) emitter
     (.i_clk     (clk),
      .i_rst     (rst),
      .i_tdata   (tdata),
      .i_tlast   (tlast),
      .i_tvalid  (tvalid),
      .o_tready  (tready),
      .o_uart_tx (uart_txd));

endmodule
module base
  (input wire 	     i_clk,
   input wire 	     i_rst,
   output wire [7:0] o_tdata,
   output wire 	     o_tlast,
   output wire 	     o_tvalid,
   input wire 	     i_tready);

   parameter memfile = "";
   parameter memsize = 8192;

   wire [31:0] 	     wb_dat;
   wire 	     wb_we;
   wire 	     wb_stb;
   wire 	     wb_ack;

   wb2axis w2s
     (.i_clk (i_clk),
      .i_rst (i_rst),
      .i_wb_dat (wb_dat[8:0]),
      .i_wb_we  (wb_we),
      .i_wb_stb (wb_stb),
      .o_wb_ack (wb_ack),
      .o_tdata  (o_tdata),
      .o_tlast  (o_tlast),
      .o_tvalid (o_tvalid),
      .i_tready (i_tready));

   serving
     #(.memfile  (memfile),
       .memsize  (memsize),
       .WITH_CSR (0))
   serving
     (.i_clk       (i_clk),
      .i_rst       (i_rst),
      .i_timer_irq (1'b0),

      .o_wb_adr   (),
      .o_wb_dat   (wb_dat),
      .o_wb_sel   (),
      .o_wb_we    (wb_we),
      .o_wb_stb   (wb_stb),
      .i_wb_rdt   (32'd0),
      .i_wb_ack   (wb_ack));

endmodule
module cmod_a7_clock_gen
  (input wire  i_clk,
   output wire o_clk,
   output reg  o_rst);

   wire   clkfb;
   wire   locked;
   reg 	  locked_r;

   MMCME2_ADV #(
       .BANDWIDTH("OPTIMIZED"),
       .CLKFBOUT_MULT_F(64),
       .CLKIN1_PERIOD(83.33), // 12 MHz (not possible with PLLE2_BASE)
       .CLKOUT0_DIVIDE_F(48),
       .CLKOUT0_PHASE(1'd0),
       .DIVCLK_DIVIDE(1'd1),
       .REF_JITTER1(0.01)
   ) MMCME2_ADV (
       .CLKFBIN(clkfb),
       .CLKIN1(i_clk),
       .PWRDWN(0),
       .RST(1'b0),
       .CLKFBOUT(clkfb),
       .CLKOUT0(o_clk),
       .LOCKED(locked)
   );

   always @(posedge o_clk) begin
      locked_r <= locked;
      o_rst  <= !locked_r;
   end

endmodule
module CV_96 (
	output q,
	output uart_txd
);

wire clk;		

HPS   u0(
	.h2f_user0_clk( clk)  	//hps_0_h2f_user0_clock.clk
);
	

corescore_chameleon96  u1 (
	.i_clk   ( clk ), 
	.i_rst_n ( 1'b1),
	.q       ( q   ),
	.uart_txd( uart_txd )
);
	  

endmodule
module mux_2(in_0,in_1,out,sel);
  input in_0,in_1;
  input sel;
  output out;
  wire in_0,in_1;
  wire sel,sel_b;
  wire n_0,n_1;
  wire out;
  or OR (out, n_0, n_1);
  and AND0 (n_0, in_0, sel_b);
  and AND1 (n_1, in_1, sel);
  not NOT0 (sel_b, sel);
endmodule
module switch(in_0,in_1,out_0,out_1,key);
  input in_0,in_1;
  input key;
  output out_0,out_1;
  wire in_0,in_1;
  wire key;
  wire out_0,out_1;
  wire k_b,n_0,n_1,n_2,n_3;
  not NOT (k_b, key);
  or OR_0 (out_0, n_0, n_1);
  and AND0_0 (n_0, in_0, k_b);
  and AND1_0 (n_1, in_1, key);
  or OR_1 (out_1, n_2, n_3);
  and AND0_1 (n_2, in_0, key);
  and AND1_1 (n_3, in_1, k_b);
endmodule
module c17_assign (
    G1, G2, G3, G6, G7,
    G22, G23  );
  input  G1, G2, G3, G6, G7;
  output G22, G23;
  wire G10, G11, G16, G19;
  assign G10 = ~G1 | ~G3;
  assign G11 = ~G3 | ~G6;
  assign G16 = ~G2 | ~G11;
  assign G19 = ~G11 | ~G7;
  assign G22 = ~G10 | ~G16;
  assign G23 = ~G16 | ~G19;
endmodule
module MUX(in_0,in_1,in_2,in_3,out,key_0,key_1);
  input in_0,in_1,in_2,in_3;
  input key_0,key_1;
  output out;
  wire in_0,in_1,in_2,in_3;
  wire key_0,key_1,k_b_0,k_b_1;
  wire n_0,n_1,n_2,n_3;
  wire s_0,s_1,s_2,s_3;
  wire out;
  or OR (out, n_0, n_1, n_2, n_3);
  and AND0 (n_0, in_0, s_0);
  and AND1 (n_1, in_1, s_1);
  and AND2 (n_2, in_2, s_2);
  and AND3 (n_3, in_3, s_3);
  not NOT0 (k_b_0, key_0);
  not NOT1 (k_b_1, key_1);
  and sAND0 (s_0, k_b_1, k_b_0);
  and sAND1 (s_1, k_b_1, key_0);
  and sAND2 (s_2, key_1, k_b_0);
  and sAND3 (s_3, key_1, key_0);
endmodule
module c17_gates(G1,G16,G17,G2,G3,G4,G5);
input G1,G2,G3,G4,G5;
output G16,G17;

  wire G8,G9,G12,G15;

  nand NAND2_0(G8,G1,G3);
  nand NAND2_1(G9,G3,G4);
  nand NAND2_2(G12,G2,G9);
  nand NAND2_3(G15,G9,G5);
  nand NAND2_4(G16,G8,G12);
  nand NAND2_5(G17,G12,G15);

endmodule
module test_blackbox_io(clk, i0, o0);

    input clk, i0;
    output o0;

    ff ff0(.D(i0), .CK(clk), .Q(o0));
endmodule
module test_blackbox_io(clk, i0, i1, o0);

    input clk, i0, i1;
    output o0;

    wire w0, w1;

    xor xor0(w0, i0, i1);
    ff ff0(.D(w0), .CK(clk), .Q(w1));
    not not0(o0, w1);
endmodule
module do_not_parse_0(G2, G3);
    input G2;
    output G3;

    assign G2 = ~G3;
endmodule
module test_correct_io(G1,G2,G3,G4,G5_0,G5_1,G17,G18,G19,G20,G21,G22_0,G22_1);
  // Comments Inside Module
  input G1,G2,G3,G4;
  /* Comments Inside Module */
  input G5_0,G5_1;
  output G17, G18,G19,G20,G21;
  output G22_0,
	  G22_1;

  wire G8_0,G8_1;

  nand NAND2_0 (G8_0,G1,G3);
  nor  NOR2_0( G17,G8_1,1'b1);
  and  AND2_0(G18,  G2,G5_0);
  xor  XOR2_0(G22_0,G5_1 ,G4);

  assign G8_1 = 1'b1;
  assign G19 = G1 & G2 & (G3 ^ G4);
  assign G20 = G17 ^ (G8_0 & G5_0);
  assign G22_1 = G1 & (~G2 | 1'b1);
  assign G21 = 1'b0;

endmodule
module do_not_parse_1(G2, G3);
    input G2;
    output G3;

    assign G2 = ~G3;
endmodule
module test_module_bb(clk, G0, G1, G2_0, G2_1, G18_0, G18_1);
    input clk, G0, G1;
    input G2_0,G2_1;
    output G18_0,G18_1;
    wire G3, G4, G5;

    ff DFF_0(.CK (clk), .D (G3), .Q (G4));
    and AND2_0(G3, G0, G1);
    and AND2_1(G18_1, G5, G2_1);
    ff DFF_1(.CK (clk), .D(G2_0), .Q(G5));
    ff DFF_2(.CK (clk), .D(G5), .Q(G18_0));
endmodule
module priority_encoder #
(
    parameter WIDTH = 4,
    // LSB priority: "LOW", "HIGH"
    parameter LSB_PRIORITY = "LOW"
)
(
    input  wire [WIDTH-1:0]         input_unencoded,
    output wire                     output_valid,
    output wire [$clog2(WIDTH)-1:0] output_encoded,
    output wire [WIDTH-1:0]         output_unencoded
);

parameter LEVELS = WIDTH > 2 ? $clog2(WIDTH) : 1;
parameter W = 2**LEVELS;

// pad input to even power of two
wire [W-1:0] input_padded = {{W-WIDTH{1'b0}}, input_unencoded};

wire [W/2-1:0] stage_valid[LEVELS-1:0];
wire [W/2-1:0] stage_enc[LEVELS-1:0];

generate
    genvar l, n;

    // process input bits; generate valid bit and encoded bit for each pair
    for (n = 0; n < W/2; n = n + 1) begin : loop_in
        assign stage_valid[0][n] = |input_padded[n*2+1:n*2];
        if (LSB_PRIORITY == "LOW") begin
            assign stage_enc[0][n] = input_padded[n*2+1];
        end else begin
            assign stage_enc[0][n] = !input_padded[n*2+0];
        end
    end

    // compress down to single valid bit and encoded bus
    for (l = 1; l < LEVELS; l = l + 1) begin : loop_levels
        for (n = 0; n < W/(2*2**l); n = n + 1) begin : loop_compress
            assign stage_valid[l][n] = |stage_valid[l-1][n*2+1:n*2];
            if (LSB_PRIORITY == "LOW") begin
                assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+1] ? {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]} : {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]};
            end else begin
                assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+0] ? {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]} : {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]};
            end
        end
    end
endgenerate

assign output_valid = stage_valid[LEVELS-1];
assign output_encoded = stage_enc[LEVELS-1];
assign output_unencoded = 1 << output_encoded;

endmodule
module WGT_BUF (clk, rst_n, wgt_input, wgt_read, wgt_buf0, wgt_buf1, wgt_buf2, wgt_buf3);

input clk;
input rst_n;
input signed [7:0] wgt_input;
input wgt_read;
output signed [7:0] wgt_buf0;
output signed [7:0] wgt_buf1;
output signed [7:0] wgt_buf2;
output signed [7:0] wgt_buf3;

reg signed [7:0] wgt_buf [3:0];


integer i;

always @(posedge clk or negedge rst_n) 
    if (~rst_n) 
    begin
        for(i = 0; i < 4; i = i + 1) 
        begin
            wgt_buf[i] <= 0;
        end
    end
    else
    begin
        if(wgt_read)
        begin
            wgt_buf[3] <= wgt_buf[2];
            wgt_buf[2] <= wgt_buf[1];
            wgt_buf[1] <= wgt_buf[0];
            wgt_buf[0] <= wgt_input;
        end
        else
        begin
            wgt_buf[3] <= wgt_buf[3];
            wgt_buf[2] <= wgt_buf[2];
            wgt_buf[1] <= wgt_buf[1];
            wgt_buf[0] <= wgt_buf[0];
        end
    end

    assign wgt_buf0 = wgt_buf[0];
    assign wgt_buf1 = wgt_buf[1];
    assign wgt_buf2 = wgt_buf[2];
    assign wgt_buf3 = wgt_buf[3];

endmodule
module SYNCH_FIFO #(
    parameter data_width = 25,
    parameter addr_width = 8,
    parameter depth      = 61
) (
    /// Control signal
    input clk,
    input rd_en,
    input wr_en,
    input rst_n,
    /// status signal
    output empty,
    output full,
    /// data signal
    output reg [data_width-1:0] data_out,
    input [data_width-1:0] data_in
);
    reg [addr_width:0] cnt;
    reg [data_width-1:0] fifo_mem [0:depth-1];
    reg [addr_width-1:0] rd_ptr;
    reg [addr_width-1:0] wr_ptr;
    /// Status generation
    assign empty = (cnt == 0);
    assign full  = (cnt == depth);
    /// Updata read pointer && Read operation
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            rd_ptr   <= 0;
        else if (rd_en && !empty) begin
            if (rd_ptr == depth-1)
                rd_ptr <= 0;
            else
                rd_ptr <= rd_ptr + 1;
        end else 
            rd_ptr <= rd_ptr;
    end
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) 
            data_out <= 0;
        else if (rd_en && !empty)
            data_out <= fifo_mem[rd_ptr];
    end
    /// Update write pointer && write operation
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            wr_ptr <= 0;
        else if (wr_en  && !full) begin
            if (wr_ptr == depth-1)
                wr_ptr <= 0;
            else
                wr_ptr <= wr_ptr + 1;
        end else 
            wr_ptr <= wr_ptr;
    end

    always @(posedge clk) begin
        if (wr_en  & ~full)
            fifo_mem[wr_ptr] = data_in;
    end
    /// Update the counter
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            cnt <= 0;
        else begin
            case ({wr_en, rd_en})
                2'b00: cnt <= cnt;
                2'b01: cnt <= !empty ? cnt-1 : cnt;
                2'b10: cnt <= !full  ? cnt+1 : cnt;
                2'b11: cnt <= cnt;
            endcase
        end
    end
endmodule
module PE (clk, rst_n, ifm_input0, ifm_input1, ifm_input2, ifm_input3, 
            wgt_input0, wgt_input1, wgt_input2, wgt_input3, p_sum);

input clk;
input rst_n;
input signed [7:0] ifm_input0;
input signed [7:0] ifm_input1;
input signed [7:0] ifm_input2;
input signed [7:0] ifm_input3;

input signed [7:0] wgt_input0;
input signed [7:0] wgt_input1;
input signed [7:0] wgt_input2;
input signed [7:0] wgt_input3;

output signed [24:0] p_sum;

reg signed [15:0] product [3:0];
reg signed [16:0] pp_sum [1:0];
reg signed [24:0] p_sum;


integer i;
integer j;

always @(posedge clk or negedge rst_n) 
    if (~rst_n) 
    begin
        for(i = 0; i < 4; i = i + 1) 
        begin
            product[i] <= 0;
        end

        for(i = 0; i < 2; i = i + 1) 
        begin
            pp_sum[i] <= 0;
        end
        p_sum <= 0;
    end
    else
    begin
        product[0] <= ifm_input0 * wgt_input0;
        product[1] <= ifm_input1 * wgt_input1;
        product[2] <= ifm_input2 * wgt_input2;
        product[3] <= ifm_input3 * wgt_input3;

        pp_sum[0] <= product[0] + product[1];
        pp_sum[1] <= product[2] + product[3];
        p_sum <= pp_sum[0] + pp_sum[1];
    end


endmodule //PE
module IFM_BUF (clk, rst_n, ifm_input, ifm_read, ifm_buf0, ifm_buf1, ifm_buf2, ifm_buf3);

input clk;
input rst_n;
input signed [7:0] ifm_input;
input ifm_read;
output signed [7:0] ifm_buf0;
output signed [7:0] ifm_buf1;
output signed [7:0] ifm_buf2;
output signed [7:0] ifm_buf3;

reg signed [7:0] ifm_buf [3:0];

integer i;

always @(posedge clk or negedge rst_n) 
    if (~rst_n) 
    begin
        for(i = 0; i < 4; i = i + 1) 
        begin
            ifm_buf[i] <= 0;
        end
    end
    else
    begin
        if(ifm_read)
        begin
            ifm_buf[3] <= ifm_buf[2];
            ifm_buf[2] <= ifm_buf[1];
            ifm_buf[1] <= ifm_buf[0];
            ifm_buf[0] <= ifm_input;
        end
        else 
        begin
            ifm_buf[3] <= ifm_buf[3];
            ifm_buf[2] <= ifm_buf[2];
            ifm_buf[1] <= ifm_buf[1];
            ifm_buf[0] <= ifm_buf[0];
        end
    end

assign ifm_buf0 = ifm_buf[0];
assign ifm_buf1 = ifm_buf[1];
assign ifm_buf2 = ifm_buf[2];
assign ifm_buf3 = ifm_buf[3];

endmodule
module PSUM_ADD #(
    parameter data_width = 25
) (
    input clk,
    input rst_n,
    input signed [data_width-1:0] pe0_data,
    input signed [data_width-1:0] pe1_data,
    input signed [data_width-1:0] pe2_data,
    input signed [data_width-1:0] pe3_data,
    input signed [data_width-1:0] fifo_data,
    output signed [data_width-1:0] out
);

    reg signed [data_width-1:0] psum0;
    reg signed [data_width-1:0] psum1;
    reg signed [data_width-1:0] psum2;
    reg signed [data_width-1:0] out_r;

    assign out = out_r;
    /// Adder tree
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            psum0 <= 0;
            psum1 <= 0;
            psum2 <= 0;
            out_r   <= 0;
        end else begin
            psum0 <= pe0_data + pe1_data;
            psum1 <= pe2_data + pe3_data;
            psum2 <= psum0 + psum1;
            out_r <= fifo_data + psum2;
        end
    end
endmodule
module PSUM_BUFF #(
    parameter data_width = 25,
    parameter addr_width = 8,
    parameter depth      = 61
) (
    input clk,
    input rst_n,
    input p_valid_data,
    input p_write_zero,
    input p_init,
    input signed [data_width-1:0] pe0_data,
    input signed [data_width-1:0] pe1_data,
    input signed [data_width-1:0] pe2_data,
    input signed [data_width-1:0] pe3_data,
    output [data_width-1:0] fifo_out,
    output valid_fifo_out
);
    // wire [data_width-1:0] fifo_head;
    // reg  [data_width-1:0] fifo_head_reg;
    reg  [data_width-1:0] fifo_in;
    wire signed [data_width-1:0] adder_out;
    wire empty, full;
    reg fifo_rd_en;
    reg fifo_wr_en;
    /// Shifter register, there are four pipeline stages
    reg [3-1:0] p_valid;
    reg [3-1:0] p_write_zero_reg;

    /// Whether the output of current fifo output is valid
    assign valid_fifo_out = p_write_zero_reg;

    /// Fifo read and write
    /// When to write fifo
    /// Data that will be written to fifo
    always @(*) begin
        if (!rst_n) begin
            fifo_wr_en = 0;
            fifo_rd_en = 0;
            fifo_in = 0;
        end else if (p_init) begin
            fifo_wr_en = 1;
            fifo_rd_en = 0;
            fifo_in = 0;
        end else if (p_write_zero || p_write_zero_reg) begin
            fifo_wr_en = p_write_zero_reg;
            fifo_rd_en = p_write_zero;
            fifo_in = 0;
        end else begin
            fifo_wr_en = p_valid[2];
            fifo_rd_en = p_valid[0];
            fifo_in = adder_out;
        end
    end
    /// Whether the current input is valid data
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            p_valid <= 3'b0;
        else 
            p_valid <= {p_valid[1:0], p_valid_data};
    end
    /// Whether the current write zero is valid data
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            p_write_zero_reg <= 1'b0;
        else 
            p_write_zero_reg <= p_write_zero;
    end
    /// Adder tree
    PSUM_ADD #(.data_width(data_width)) adder_tree (
        .clk(clk),
        .rst_n(rst_n),
        .pe0_data(pe0_data),
        .pe1_data(pe1_data),
        .pe2_data(pe2_data),
        .pe3_data(pe3_data),
        .fifo_data(fifo_out),
        .out(adder_out)
    );
    /// Synchronous fifo
    SYNCH_FIFO #(
        .data_width(data_width),
        .addr_width(addr_width),
        .depth(depth)
    ) synch_fifo (
        .clk(clk),
        .rd_en(fifo_rd_en),
        .wr_en(fifo_wr_en),
        .rst_n(rst_n),
        .empty(empty),
        .full(full),
        .data_out(fifo_out),
        .data_in(fifo_in)
    );

endmodule
module SYNCH_FIFO #(
    parameter data_width = 25,
    parameter addr_width = 8,
    parameter depth      = 61
) (
    /// Control signal
    input clk,
    input rd_en,
    input wr_en,
    input rst_n,
    /// status signal
    output empty,
    output full,
    /// data signal
    output reg [data_width-1:0] data_out,
    input [data_width-1:0] data_in
);
    reg [addr_width:0] cnt;
    reg [data_width-1:0] fifo_mem [0:depth-1];
    reg [addr_width-1:0] rd_ptr;
    reg [addr_width-1:0] wr_ptr;
    /// Status generation
    assign empty = (cnt == 0);
    assign full  = (cnt == depth);
    /// Updata read pointer && Read operation
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            rd_ptr   <= 0;
        else if (rd_en && !empty) begin
            rd_ptr   <= rd_ptr + 1;
            if (rd_ptr == 60)
                rd_ptr <= 0;
        end else 
            rd_ptr   <= rd_ptr;
    end
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) 
            data_out <= 0;
        else if (rd_en && !empty)
            data_out <= fifo_mem[rd_ptr];
    end
    /// Update write pointer && write operation
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            wr_ptr <= 0;
        else if (wr_en  && !full) begin
            wr_ptr <= wr_ptr + 1;
            if (wr_ptr == 60)
                wr_ptr <= 0;
        end else 
            wr_ptr <= wr_ptr;
    end

    always @(posedge clk) begin
        if (wr_en  && !full)
            fifo_mem[wr_ptr] = data_in;
    end
    /// Update the counter
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            cnt <= 0;
        else begin
            case ({wr_en, rd_en})
                2'b00: cnt <= cnt;
                2'b01: cnt <= !empty ? cnt-1 : cnt;
                2'b10: cnt <= !full  ? cnt+1 : cnt;
                2'b11: cnt <= cnt;
            endcase
        end
    end
endmodule
module Counter(
    
    input enable,
    output [3:0] counter_out,
    input clk,
    input rst_n

);

    reg [3:0] cnt_R;

    always @(posedge clk or negedge rst_n)
    begin
	if(!rst_n)
	    cnt_R <= 'd0;
	else if(enable)
	    cnt_R <= cnt_R + 1'b1;
    end

    assign counter_out = cnt_R;


endmodule
module tb_counter();

    reg clk;
    reg rst_n;
    reg enable;
    wire [3:0] counter_tb;

    Counter dut(.enable(enable), .counter_out(counter_tb), .clk(clk), .rst_n(rst_n));



    // generate clock 
    initial begin 
	#5  clk = 1'b1;
	forever #5 clk = ~clk;
    end

    task check_count; 
	begin 
	    @(negedge clk);
	    $display("Checking counter %0d at %0t", counter_tb, $time);
	end
    endtask


    initial begin 
	#1  rst_n = 1'b1;
	enable = 0;
	#22 $display("Begin to reset the counter @%0t", $time);
	rst_n = 1'b0;
	@(posedge clk);
	@(negedge clk);
	$display("Checking the counter after reset @%0t", $time);
	$display("Counter suppose is 0 and we get %0d from dut", counter_tb);
	repeat(5) @(posedge clk);
	#0 rst_n = 1'b1;
	$display("Disable reset @%0t", $time);
	repeat(5) @(posedge clk);
	#0 enable = 1'b1;
	$display("Setting the enable signal @%0t", $time);
	$display("checking the counter for 20 cycle:");
	repeat(20) check_count;
	@(negedge clk);
	#0  enable = 1'b0;
	$display("Disable the enable signal @%0t", $time);
	$display("checking the counter for 10 cycle:");
	repeat(10) check_count;
	#20 $finish;
    end


endmodule
module TEST_FIFO ();
    reg  clk, rst_n, wr_en, rd_en;
    reg  [`BUF_DATA_WIDTH-1:0] data_in;
    reg  [`BUF_DATA_WIDTH-1:0] temp;
    wire [`BUF_DATA_WIDTH-1:0] data_out;
    wire empty;
    wire full;

    SYNCH_FIFO #(
        .data_width(`BUF_DATA_WIDTH),
        .addr_width(`BUF_ADDR_WIDTH),
        .depth(`BUF_DEPTH)
    ) synch_fifo (
        .clk(clk),
        .rd_en(rd_en),
        .wr_en(wr_en),
        .rst_n(rst_n),
        .empty(empty),
        .full(full),
        .data_out(data_out),
        .data_in(data_in)
    );
    /// Push task
    task push;
        input [`BUF_DATA_WIDTH-1:0] data;
        if (full)
            $display("Opps! Buffer already full, pop then push");
        else begin
            $display("Pushed: ", data);
            data_in = data;
            wr_en   = 1;
            @(posedge clk);
            #1 wr_en = 0;
        end
    endtask

    /// Pop task
    task pop;
        output [`BUF_DATA_WIDTH-1:0] data;
        if (empty)
            $display("Opps! Buffer is empty nothing to pop");
        else begin
            rd_en = 1;
            @(posedge clk);
            #1 rd_en = 0;
            data = data_out;
            $display("Poped: ", data);
        end
    endtask
    /// clock generation
    always #5 clk = ~clk;

    /// Run simulation
    initial begin
        clk       = 0;
        rst_n     = 1;
        rd_en     = 0;
        wr_en     = 0;
        temp      = 0;
        data_in   = 0;
        #5 rst_n  = 0;
        #10 rst_n = 1;

        push(1);
        fork
           push(2);
           pop(temp);
        join            
        push(10);
        push(20);
        push(30);
        push(40);
        push(50);
        push(60);
        push(70);
        push(80);
        push(90);
        push(100);
        push(110);
        push(120);
        push(130);

        pop(temp);
        push(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
		push(140);
        pop(temp);
        push(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        pop(temp);
        push(5);
        pop(temp);
    end

endmodule
module clkgen (
  input  wire       clk,
  output wire [2:0] cnt
);

  // Connect to system clock (with buffering)
  wire clko;
  SB_GB clk_gb (
      .USER_SIGNAL_TO_GLOBAL_BUFFER(clk),
      .GLOBAL_BUFFER_OUTPUT(clko)
  );

  // Use counter logic to divide system clock.  The clock is 48 MHz,
  // so we divide it down by 2^28.
  reg [28:0] counter = 0;
  always @(posedge clko) begin
      counter <= counter + 1;
  end
  assign cnt = counter[25:23];

endmodule
module RF(
    input write,
    input clk,
    input reset_n,
    input [1:0] addr1,
    input [1:0] addr2,
    input [1:0] addr3,
    output [15:0] data1,
    output [15:0] data2,
    input [15:0] data3
    );
    
    reg [63:0] register;
    /*
    register[63:48] == register[16*3+: 16] (addr is 2'b11)
    register[47:32] == register[16*2+: 16] (addr is 2'b10)
    register[31:16] == register[16*1+: 16] (addr is 2'b01)
    register[15: 0] == register[16*0+: 16] (addr is 2'b00)
    */
    
    always @(posedge clk) begin
        // Synchronous active low reset
    	if (!reset_n) register <= 64'b0;
    	// Synchronous data write
    	else if (write) register[16*addr3+: 16] <= data3;
    end
    
    // Asynchronous data read
    assign data1 = register[16*addr1+: 16];
    assign data2 = register[16*addr2+: 16];
    
endmodule
module ALU(
    input signed [15:0] A,
    input signed [15:0] B,
    input [3:0] OP,
    output reg signed [15:0] C,
    output branch_cond
    );
    
    always @(*) begin
        case (OP)
            0:  C = A + B;          // ADD, ADI, LWD, SWD
            1:  C = A - B;          // SUB
            2:  C = A & B;          // AND
            3:  C = A | B;          // ORR, ORI
            4:  C = ~A;             // NOT
            5:  C = ~A + 1'b1;      // TCP
            6:  C = A << 1;         // SHL
            7:  C = A >>> 1;        // SHR
            8:  C = {B[7:0], 8'b0}; // LHI
            9:  C = A - B;          // BNE
            10: C = A - B;          // BEQ
            11: C = A;              // BGZ
            12: C = A;              // BLZ
            default: C = 16'bz;
        endcase
    end
    
    // Using assign, C and bcond change at the same time.
    // The timing would have been different if they were inside a single always block. 
    assign branch_cond = OP==9  ? (C!=0) :        // BNE
                         OP==10 ? (C==0) :        // BEQ
                         OP==11 ? (C>0)  :        // BGZ                
                         OP==12 ? (C<0)  : 0;     // BLZ
    
endmodule
module ROM(
    input [3:0] one,
    input [3:0] two,
    output [`NUM_CTRL-1:0] CTRL
    );
    
    /*
    Input:
    There are at maximum two register transfers in a single state (cycle). 'one' and 'two' represent each of their RT codes.
    For states with only one RT, 'one' is 13.
    
    Output:
    CTRL = elementwise-OR( control_signal of 'one', control_signal of 'two' )
    
    Output CTRL signal bits correspond to:
    PCWriteCond, PCWrite, IorD, ReadM, WriteM, RegSrc[2], IRWrite, RegWrite, RegDst[2], PCSrc[2], ALUSrcA, ALUSrcB[2]
    */
    
    parameter [`NUM_CTRL*(`NUM_RT+1)-1:0] memory = { 
                                                    `NUM_CTRL'b0_0_0_0_0_00_0_0_00_00_0_00,     // 14: All zero. Does nothing when performed OR with something else.
                                                    `NUM_CTRL'b0_0_0_0_0_01_0_1_00_00_0_00,     // 13
                                                    `NUM_CTRL'b0_0_1_0_1_00_0_0_00_00_0_00,     // 12
                                                    `NUM_CTRL'b0_0_1_1_0_00_0_0_00_00_0_00,     // 11
                                                    `NUM_CTRL'b0_0_0_0_0_00_0_1_01_00_0_00,     // 10
                                                    `NUM_CTRL'b0_0_0_0_0_00_0_1_00_00_0_00,     //  9
                                                    `NUM_CTRL'b1_0_0_0_0_00_0_0_00_01_1_00,     //  8
                                                    `NUM_CTRL'b0_0_0_0_0_00_0_0_00_00_1_00,     //  7
                                                    `NUM_CTRL'b0_0_0_0_0_00_0_0_00_00_1_10,     //  6
                                                    `NUM_CTRL'b0_1_0_0_0_00_0_0_00_11_0_00,     //  5
                                                    `NUM_CTRL'b0_0_0_0_0_10_0_1_10_00_0_00,     //  4
                                                    `NUM_CTRL'b0_1_0_0_0_00_0_0_00_10_0_00,     //  3
                                                    `NUM_CTRL'b0_0_0_0_0_00_0_0_00_00_0_10,     //  2
                                                    `NUM_CTRL'b0_1_0_0_0_00_0_0_00_00_0_01,     //  1
                                                    `NUM_CTRL'b0_0_0_1_0_00_1_0_00_00_0_00      //  0
                                              };
    
    assign CTRL = memory[`NUM_CTRL*one+:`NUM_CTRL] | memory[`NUM_CTRL*two+:`NUM_CTRL];
    
endmodule
module external_device(
    input wire [`DEVICE_BIT_LEN - 1 :0] offset,
    output reg interrupt, 
    output reg [4 * `WORD_SIZE - 1 : 0] data);

    reg [4 * `WORD_SIZE - 1 : 0] storage [`DATA_SIZE - 1 : 0];

    initial begin
        /* Randomized storage initialization.  
        * You may want to change these for the
        * debugging */
       storage[0] <= $random;
       storage[1] <= $random;
       storage[2] <= $random;
       interrupt <= 0;

       /* Fire interrupt. You may want to change */
       #(`FIRE_TIME);
       interrupt <=  1;
       /* Interrupt duration. You may want to change */
       #(`INTTERRUPT_DURATION);
       interrupt <=  0;

       /* Randomized storage initialization.  
       * You may want to change these for the
       * debugging */
      storage[0] <= $random;
      storage[1] <= $random;
      storage[2] <= $random;

       /* Another interrupt. You may want to change */
      #(`FIRE_TIME);
      interrupt <=  1;
       /* Interrupt duration. You may want to change */
      #(`INTTERRUPT_DURATION);
      interrupt <=  0;
      
      //$finish;
  end

  /* Data to be send */
  always @(offset) begin
      if (offset < 3) data <= storage[offset];
      else data <= 16'hzzzz;
  end        
endmodule
module DMA (
    input CLK, BG,
    input [4 * `WORD_SIZE - 1 : 0] edata,
    input cmd,
    output reg BR, WR,
    output reg [`WORD_SIZE - 3 : 0] addr, // block address is used
    output reg [4 * `WORD_SIZE - 1 : 0] data,
    output [1:0] offset,
    output reg interrupt);

    reg [1:0] block;    // data is written to block address (0x1F4>>2 + block)
    reg [2:0] counter;  // counts cycles left until data write to memory completes
    
    assign offset = BG ? block : 2'bz;
    
    always @(posedge CLK) begin
        // Received DMA request. Send out bus request.
        if (cmd && !interrupt) BR <= 1;
        else BR <= 0;
        
        // Bus granted. Execute writes.
        if (BG && !interrupt) begin
            addr <= 14'h7d + block;
            data <= edata;
            if (counter == 0) begin
                counter <= `LATENCY;
                WR <= 1;
            end else begin
                counter <= counter - 1;
            end
        end else begin
            addr <= 14'bz;
            data <= 64'bz;
            WR <= 1'bz;
            interrupt <= 0;
            block <= 0;
            counter <= 0;
        end
    end
    
    // Writes are done at clock negative edge.
    always @(negedge CLK) begin
        if (BG && !interrupt && counter==1) begin
            counter <= 0;
            if (block == 2) begin
                block <= 0;
                interrupt <= 1;
                BR <= 0;
                WR <= 0;
            end else begin
                block <= block + 1;
            end
        end
    end

endmodule
module HazardDetector(
    input [15:0] inst,
    input [1:0] ID_EX_RFWriteAddress, EX_MEM_RFWriteAddress, MEM_WB_RFWriteAddress,
    input ID_EX_RegWrite, EX_MEM_RegWrite, MEM_WB_RegWrite,
    output reg DataHazard
    );
    /*
    [Hazard Detector module]
    Purpose:
        Detect data hazards in the CPU, and send out the 'Stall' signal indicating whether to stall the pipeline.
        
    Inputs:
        The instruction currently in the ID stage
        Register write enable and write address of EX, MEM, and WB stage.
    
    Output: 
        DataHazard: asserted when data hazard is detected in ID stage
    */
    
    always @(*) begin
    
        // for instructions that require both rs and rt
        // first if statement checks instruction type
        // second if statement checks data dependency
        if ((inst[15:12]==`OPCODE_R && (inst[5:0]==`FUNC_ADD || inst[5:0]==`FUNC_SUB || inst[5:0]==`FUNC_AND || inst[5:0]==`FUNC_ORR)) || inst[15:12]==`OPCODE_SWD || inst[15:12]==`OPCODE_BNE || inst[15:12]==`OPCODE_BEQ) begin 
          
            if (((ID_EX_RFWriteAddress ==inst[11:10]) && ID_EX_RegWrite) || ((EX_MEM_RFWriteAddress==inst[11:10]) && EX_MEM_RegWrite) || ((MEM_WB_RFWriteAddress==inst[11:10]) && MEM_WB_RegWrite) 
             || ((ID_EX_RFWriteAddress ==inst[9:8])   && ID_EX_RegWrite) || ((EX_MEM_RFWriteAddress==inst[9:8])   && EX_MEM_RegWrite) || ((MEM_WB_RFWriteAddress==inst[9:8])   && MEM_WB_RegWrite)) begin
                DataHazard = 1;
            end // of if statement that checks data dependency of rs and rt
            else begin
                DataHazard = 0;
            end
        end // of if statement that checks if both rs and rt are required
        
        // for instructions that require only rs
        // first if statement checks instruction type
        // second if statement checks data dependency
        else if ((inst[15:12]==`OPCODE_R && (inst[5:0]==`FUNC_NOT || inst[5:0]==`FUNC_TCP || inst[5:0]==`FUNC_SHL || inst[5:0]==`FUNC_SHR || inst[5:0]==`FUNC_WWD || inst[5:0]==`FUNC_JPR || inst[5:0]==`FUNC_JRL))
          || inst[15:12]==`OPCODE_ADI || inst[15:12]==`OPCODE_ORI || inst[15:12]==`OPCODE_LWD || inst[15:12]==`OPCODE_BGZ || inst[15:12]==`OPCODE_BLZ) begin
          
            if  (((ID_EX_RFWriteAddress==inst[11:10]) && ID_EX_RegWrite) || ((EX_MEM_RFWriteAddress==inst[11:10]) && EX_MEM_RegWrite) || ((MEM_WB_RFWriteAddress==inst[11:10]) && MEM_WB_RegWrite)) begin
                DataHazard = 1;
            end // of if statement that checks data dependency of rs
            else begin
                DataHazard = 0;
            end
        end // of if statement that checks if rs is required
        
        else begin
            DataHazard = 0;
        end
        
    end // of always @(*)
    
endmodule
module AlwaysNTPredictor (
    input [`WORD_SIZE-1:0] PC,
    input Correct,
    input [`WORD_SIZE-1:0] ActualBranchTarget,
    output [`WORD_SIZE-1:0] Prediction
    );
    /*
    [Always not-taken branch predictor module]
    Purpose:
        A placeholder(or framework) for future possibility of implementing a better branch predictor.
        Always predicts PC+1 for any jump or branch instruction.
    */
    
    assign Prediction = PC + 1;
    
endmodule
module DMA (
    input CLK, BG,
    input [4 * `WORD_SIZE - 1 : 0] edata,
    input cmd,
    output reg BR, WR,
    output reg [`WORD_SIZE - 3 : 0] addr, // block address is used
    output reg [4 * `WORD_SIZE - 1 : 0] data,
    output [1:0] offset,
    output reg interrupt);

    reg cycle_stolen;   // DMA not done yet, but cycle stolen by CPU.
    reg [1:0] block;    // data is written to block address (0x1F4>>2 + block)
    reg [2:0] counter;  // counts cycles left until data write to memory completes
    
    assign offset = BG ? block : 2'bz;
    
    always @(posedge CLK) begin
        // Received DMA request. Send out bus request.
        if (cmd && !interrupt) BR <= 1;
        else BR <= 0;
        
        // Bus granted. Execute writes.
        if (BG && !interrupt) begin
            addr <= 14'h7d + block;
            data <= edata;
            if (counter == 0) begin
                counter <= `LATENCY;
                WR <= 1;
            end else begin
                counter <= counter - 1;
            end
        end else begin
            addr <= 14'bz;
            data <= 64'bz;
            WR <= 1'bz;
            interrupt <= 0;
            counter <= 0;
            // While DMA cycle is stolen, do not reset block number.
            if (cycle_stolen==0 || cycle_stolen===1'bx) begin
                block <= 0;
            end
        end
    end
    
    // Writes are done at clock negative edge.
    always @(negedge CLK) begin
        if (BG && !interrupt && counter==1) begin
            counter <= 0;
            BR <= 0;
            WR <= 0;
            if (block == 2) begin
                cycle_stolen <= 0;
                block <= 0;
                interrupt <= 1;
            end else begin
                cycle_stolen <= 1;
                block <= block + 1;
            end
        end
    end

endmodule
module RF(
    input write,
    input clk,
    input reset_n,
    input [1:0] addr1,
    input [1:0] addr2,
    input [1:0] addr3,
    output [15:0] data1,
    output [15:0] data2,
    input [15:0] data3
    );
    
    reg [63:0] register;
    /*
    register[63:48] == register[16*3+: 16] (addr is 2'b11)
    register[47:32] == register[16*2+: 16] (addr is 2'b10)
    register[31:16] == register[16*1+: 16] (addr is 2'b01)
    register[15: 0] == register[16*0+: 16] (addr is 2'b00)
    */
    
    always @(posedge clk, negedge reset_n) begin
        // Asynchronous active low reset -> This used to be Synchronous reset; modified to asynchronous for Project 4.
    	if (!reset_n) register <= 64'b0;
    	// Synchronous data write
    	else if (write) register[16*addr3+: 16] <= data3;
    end
    
    // Asynchronous data read
    assign data1 = register[16*addr1+: 16];
    assign data2 = register[16*addr2+: 16];
    
endmodule
module ALU(
    input signed [15:0] A,
    input signed [15:0] B,
    input [3:0] OP,
    output reg [15:0] C,
    output bcond
    );
    
    always @(*) begin
        case (OP)
            0:  C = A + B;          // ADD, ADI, LWD, SWD
            1:  C = A - B;          // SUB
            2:  C = A & B;          // AND
            3:  C = A | B;          // ORR, ORI
            4:  C = ~A;             // NOT
            5:  C = ~A + 1'b1;      // TCP
            6:  C = A << 1;         // SHL
            7:  C = A >>> 1;        // SHR
            8:  C = {B[7:0], 8'b0}; // LHI
            9:  C = A - B;          // BNE
            10: C = A - B;          // BEQ
            11: C = A;              // BGZ
            12: C = A;              // BLZ
            default: C = 16'bz;
        endcase
    end
    
    // Using assign, C and bcond change at the same time.
    // The timing would have been different if they were inside a single always block. 
    assign bcond = OP==9  ? (C!=0) :        // BNE
                   OP==10 ? (C==0) :        // BEQ
                   OP==11 ? (C>0)  :        // BGZ                
                   OP==12 ? (C<0)  : 0;     // BLZ
    
endmodule
module Control(
    input [3:0] opcode,
    input [5:0] func,
    output RegDst,
    output Jump,
    output Branch,
    output MemRead,
    output MemtoReg,
    output reg [3:0] ALUOp,
    output MemWrite,
    output ALUSrc,
    output RegWrite,
    output OpenPort
    );
    
    /* 
    Receives opcode and function code of an instruction, and generates control signals.
    RegDst  : Chooses RF write address (rt or rd)
    Jump    : Whether this instruction is a jump
    Branch  : Whether this instruction is a branch
    MemRead : Whether we should read data memory
    MemtoReg: Chooses what to write to RF (ALU result or data read from memory)
    ALUOp   : Controls ALU operation. Directly connected to the input OP of the ALU. (There is no ALU control module in this CPU)
    MemWrite: Whether we should write data to memory
    ALUSrc  : Chooses ALU second input (Second RF read data or sign-extended immediate)
    RegWrite: Whether we should write data to RF
    OpenPort: Wheter to open output_port of CPU
    */
    
    assign RegDst = (opcode==`OPCODE_R);
    assign Jump = (opcode==`OPCODE_JMP || opcode==`OPCODE_JAL);
    assign Branch = (opcode==`OPCODE_BEQ || opcode==`OPCODE_BNE || opcode==`OPCODE_BGZ || opcode==`OPCODE_BLZ);
    assign MemRead = (opcode==`OPCODE_LWD || opcode==`OPCODE_SWD);
    assign MemtoReg = (opcode==`OPCODE_LWD);
    assign MemWrite = (opcode==`OPCODE_SWD);
    assign ALUSrc = !(opcode==`OPCODE_R || opcode==`OPCODE_BEQ || opcode==`OPCODE_BNE);
    assign RegWrite = !(opcode==`OPCODE_SWD || opcode==`OPCODE_BEQ || opcode==`OPCODE_BNE || opcode==`OPCODE_BGZ || opcode==`OPCODE_BLZ || opcode==`OPCODE_JMP || func==`FUNC_WWD);
    assign OpenPort = (opcode==`OPCODE_R & func==`FUNC_WWD);
    
    always @(*) begin
        if (opcode==`OPCODE_R & func<8) ALUOp = func[3:0];
        else if (opcode==`OPCODE_ADI || opcode==`OPCODE_LWD || opcode==`OPCODE_SWD) ALUOp = 0;
        else if (opcode==`OPCODE_ORI) ALUOp = 3;
        else if (opcode==`OPCODE_LHI) ALUOp = 8;
        else if (opcode==`OPCODE_BNE) ALUOp = 9;
        else if (opcode==`OPCODE_BEQ) ALUOp = 10;
        else if (opcode==`OPCODE_BGZ) ALUOp = 11;
        else if (opcode==`OPCODE_BLZ) ALUOp = 12;
        else ALUOp = 15;
    end
    
endmodule