dakies/OSS_Verilog huggingface dataset:
module fallthrough_small_fifo
    #(parameter WIDTH = 72,
      parameter MAX_DEPTH_BITS = 3,
      parameter PROG_FULL_THRESHOLD = 2**MAX_DEPTH_BITS - 1)
    (

     input [WIDTH-1:0] din,     // Data in
     input          wr_en,   // Write enable

     input          rd_en,   // Read the next word

     output [WIDTH-1:0]  dout,    // Data out
     output         full,
     output         nearly_full,
     output         prog_full,
     output reg     empty,

     input          reset,
     input          clk
     );

   reg  fifo_rd_en, empty_nxt;

   small_fifo
     #(.WIDTH (WIDTH),
       .MAX_DEPTH_BITS (MAX_DEPTH_BITS),
       .PROG_FULL_THRESHOLD (PROG_FULL_THRESHOLD))
       fifo
        (.din           (din),
         .wr_en         (wr_en),
         .rd_en         (fifo_rd_en),
         .dout          (dout),
         .full          (full),
         .nearly_full   (nearly_full),
         .prog_full     (prog_full),
         .empty         (fifo_empty),
         .reset         (reset),
         .clk           (clk)
         );

   always @(*) begin
      empty_nxt  = empty;
      fifo_rd_en = 0;
      case (empty)
         1'b1: begin
            if(!fifo_empty) begin
               fifo_rd_en = 1;
               empty_nxt  = 0;
            end
         end

         1'b0: begin
            if(rd_en) begin
               if(fifo_empty) begin
                  empty_nxt = 1;
               end
               else begin
                  fifo_rd_en = 1;
               end
            end
         end
      endcase // case(empty)
   end // always @ (*)

   always @(posedge clk) begin
      if(reset) begin
         empty <= 1'b1;
      end
      else begin
         empty <= empty_nxt;
      end
   end

   // synthesis translate_off
   always @(posedge clk)
   begin
      if (wr_en && full) begin
         $display("%t ERROR: Attempt to write to full FIFO: %m", $time);
      end
      if (rd_en && empty) begin
         $display("%t ERROR: Attempt to read an empty FIFO: %m", $time);
      end
   end // always @ (posedge clk)
   // synthesis translate_on

endmodule // fallthrough_small_fifo_v2
module small_fifo
    #(parameter WIDTH = 72,
      parameter MAX_DEPTH_BITS = 3,
      parameter PROG_FULL_THRESHOLD = 2**MAX_DEPTH_BITS - 1
      )
    (

     input [WIDTH-1:0] din,     // Data in
     input          wr_en,   // Write enable

     input          rd_en,   // Read the next word

     output reg [WIDTH-1:0]  dout,    // Data out
     output         full,
     output         nearly_full,
     output         prog_full,
     output         empty,

     input          reset,
     input          clk
     );


parameter MAX_DEPTH        = 2 ** MAX_DEPTH_BITS;

reg [WIDTH-1:0] queue [MAX_DEPTH - 1 : 0];
reg [MAX_DEPTH_BITS - 1 : 0] rd_ptr;
reg [MAX_DEPTH_BITS - 1 : 0] wr_ptr;
reg [MAX_DEPTH_BITS : 0] depth;

// Sample the data
always @(posedge clk)
begin
   if (wr_en)
      queue[wr_ptr] <= din;
   if (rd_en)
      dout <=
	      // synthesis translate_off
	      #1
	      // synthesis translate_on
	      queue[rd_ptr];
end

always @(posedge clk)
begin
   if (reset) begin
      rd_ptr <= 'h0;
      wr_ptr <= 'h0;
      depth  <= 'h0;
   end
   else begin
      if (wr_en) wr_ptr <= wr_ptr + 'h1;
      if (rd_en) rd_ptr <= rd_ptr + 'h1;
      if (wr_en & ~rd_en) depth <=
				   // synthesis translate_off
				   #1
				   // synthesis translate_on
				   depth + 'h1;
      else if (~wr_en & rd_en) depth <=
				   // synthesis translate_off
				   #1
				   // synthesis translate_on
				   depth - 'h1;
   end
end

//assign dout = queue[rd_ptr];
assign full = depth == MAX_DEPTH;
assign prog_full = (depth >= PROG_FULL_THRESHOLD);
assign nearly_full = depth >= MAX_DEPTH-1;
assign empty = depth == 'h0;

// synthesis translate_off
always @(posedge clk)
begin
   if (wr_en && depth == MAX_DEPTH && !rd_en)
      $display($time, " ERROR: Attempt to write to full FIFO: %m");
   if (rd_en && depth == 'h0)
      $display($time, " ERROR: Attempt to read an empty FIFO: %m");
end
// synthesis translate_on

endmodule // small_fifo
module blk_mem_gen_1 #(
    parameter ADDR_BITS = 4,
    parameter DATA_BITS = 625
)
(
    input [(ADDR_BITS - 1):0] addra,
    input clka,
    input [(DATA_BITS - 1):0] dina,
    input ena,
    input wea,

    input [(ADDR_BITS - 1):0] addrb,
    input clkb,
    output [(DATA_BITS - 1):0] doutb,
    input enb
);
    ram_blk #(
        .ADDR_BITS(ADDR_BITS),
        .DATA_BITS(DATA_BITS)
    ) ram (
        .addra(addra),
        .clka(clka),
        .dina(dina),
        .ena(ena),
        .wea(wea),
        .addrb(addrb),
        .clkb(clkb),
        .doutb(doutb),
        .enb(enb)
    );
endmodule
module blk_mem_gen_3 #(
    parameter ADDR_BITS = 5,
    parameter DATA_BITS = 193
)
(
    input [(ADDR_BITS - 1):0] addra,
    input clka,
    input [(DATA_BITS - 1):0] dina,
    input ena,
    input wea,

    input [(ADDR_BITS - 1):0] addrb,
    input clkb,
    output [(DATA_BITS - 1):0] doutb,
    input enb
);

    ram_blk #(
        .ADDR_BITS(ADDR_BITS),
        .DATA_BITS(DATA_BITS)
    ) ram (
        .addra(addra),
        .clka(clka),
        .dina(dina),
        .ena(ena),
        .wea(wea),
        .addrb(addrb),
        .clkb(clkb),
        .doutb(doutb),
        .enb(enb)
    );
endmodule
module page_tbl_16w_32d #(
    parameter ADDR_BITS = 5,
    parameter DATA_BITS = 16
)
(
    input [(ADDR_BITS - 1):0] addra,
    input clka,
    input [(DATA_BITS - 1):0] dina,
    input ena,
    input wea,

    input [(ADDR_BITS - 1):0] addrb,
    input clkb,
    output [(DATA_BITS - 1):0] doutb,
    input enb
);
    ram_blk #(
        .ADDR_BITS(ADDR_BITS),
        .DATA_BITS(DATA_BITS)
    ) ram (
        .addra(addra),
        .clka(clka),
        .dina(dina),
        .ena(ena),
        .wea(wea),
        .addrb(addrb),
        .clkb(clkb),
        .doutb(doutb),
        .enb(enb)
    );
endmodule
module ram_dp #
(
    parameter DATA_WIDTH = 32,
    parameter ADDR_WIDTH = 10
)
(
    // port A
    input  wire                    a_clk,
    input  wire                    a_we,
    input  wire [ADDR_WIDTH-1:0]   a_addr,
    input  wire [DATA_WIDTH-1:0]   a_din,
    output wire [DATA_WIDTH-1:0]   a_dout,

    // port B
    input  wire                    b_clk,
    input  wire                    b_we,
    input  wire [ADDR_WIDTH-1:0]   b_addr,
    input  wire [DATA_WIDTH-1:0]   b_din,
    output wire [DATA_WIDTH-1:0]   b_dout
);

reg [DATA_WIDTH-1:0] a_dout_reg = {DATA_WIDTH{1'b0}};

reg [DATA_WIDTH-1:0] b_dout_reg = {DATA_WIDTH{1'b0}};

// (* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0];

assign a_dout = a_dout_reg;

assign b_dout = b_dout_reg;

integer i, j;

initial begin
    // two nested loops for smaller number of iterations per loop
    // workaround for synthesizer complaints about large loop counts
    for (i = 0; i < 2**ADDR_WIDTH; i = i + 2**(ADDR_WIDTH/2)) begin
        for (j = i; j < i + 2**(ADDR_WIDTH/2); j = j + 1) begin
            mem[j] = 0;
        end
    end
end

// port A
always @(posedge a_clk) begin
    a_dout_reg <= mem[a_addr];
    if (a_we) begin
        mem[a_addr] <= a_din;
        a_dout_reg <= a_din;
    end
end

// port B
always @(posedge b_clk) begin
    b_dout_reg <= mem[b_addr];
    if (b_we) begin
        mem[b_addr] <= b_din;
        b_dout_reg <= b_din;
    end
end

endmodule
module blk_mem_gen_0 #(
    parameter ADDR_BITS = 5,
    parameter DATA_BITS = 32
)
(
    input [(ADDR_BITS - 1):0] addra,
    input clka,
    input [(DATA_BITS - 1):0] dina,
    input ena,
    input wea,

    input [(ADDR_BITS - 1):0] addrb,
    input clkb,
    output [(DATA_BITS - 1):0] doutb,
    input enb
);
    ram_blk #(
        .ADDR_BITS(ADDR_BITS),
        .DATA_BITS(DATA_BITS)
    ) ram (
        .addra(addra),
        .clka(clka),
        .dina(dina),
        .ena(ena),
        .wea(wea),
        .addrb(addrb),
        .clkb(clkb),
        .doutb(doutb),
        .enb(enb)
    );

endmodule
module ram_blk #(
    parameter ADDR_BITS = 5,
    parameter DATA_BITS = 32
)
(
    input [(ADDR_BITS - 1):0] addra,
    input clka,
    input [(DATA_BITS - 1):0] dina,
    input ena,
    input wea,

    input [(ADDR_BITS - 1):0] addrb,
    input clkb,
    output [(DATA_BITS - 1):0] doutb,
    input enb
);

    reg [(DATA_BITS - 1):0] ram [(ADDR_BITS - 1):0];
    //reg [(ADDR_BITS - 1):0] read_addrb;
    reg [(DATA_BITS - 1):0] doutb_r;
 
    always @(posedge clka) begin
        if (ena) begin
            if (wea)
                ram[addra] <= dina;
            //read_addra <= addra;
        end
    end

    /*always @(posedge clkb) begin
        if (enb)  
            doutb_r <= ram[addrb];  
    end
    assign doutb = doutb_r;
    */
  //assign douta = ram[read_addra];
  assign doutb = ram[addrb];
  //
endmodule
module cam_simple #(
    parameter DATA_WIDTH = 64,
    parameter ADDR_WIDTH = 5,
    parameter SLICE_WIDTH = 9
)
(
    input  wire                     clk,
    input  wire                     rst,

    input  wire [ADDR_WIDTH-1:0]    write_addr,
    input  wire [DATA_WIDTH-1:0]    write_data,
    input  wire                     write_delete,
    input  wire                     write_enable,
    output wire                     write_busy,

    input  wire [DATA_WIDTH-1:0]    compare_data,
    output wire [2**ADDR_WIDTH-1:0] match_many,
    output wire [2**ADDR_WIDTH-1:0] match_single,
    output wire [ADDR_WIDTH-1:0]    match_addr,
    output wire                     match
);

localparam RAM_DEPTH = 2**ADDR_WIDTH;

reg [RAM_DEPTH - 1 : 0]match_many_raw;
reg valids[RAM_DEPTH];
reg [DATA_WIDTH-1:0]keys[RAM_DEPTH];

// reads
integer k;
always @(posedge clk) begin
    for (k = 0; k < RAM_DEPTH; k = k + 1) begin
        match_many_raw[k] <= valids[k] && (keys[k] == compare_data);
    end
end

// writes
integer i;
always @(posedge clk) begin
    if (rst) begin
        for (i = 0; i < RAM_DEPTH; i = i + 1) begin
            valids[i] <= 0;
            keys[i] <= 0;
        end
    end else if (write_enable) begin
        if (write_delete) begin
            valids[write_addr] <= 0;
        end else begin
            keys[write_addr] <= write_data;
            valids[write_addr] <= 1;
        end
    end
end

priority_encoder #(
    .WIDTH(RAM_DEPTH),
    .LSB_PRIORITY("HIGH")
)
priority_encoder_inst (
    .input_unencoded(match_many_raw),
    .output_valid(match),
    .output_encoded(match_addr),
    .output_unencoded(match_single)
);

endmodule
module parse_act_ram_ip #(
    parameter ADDR_BITS = 5,
    parameter DATA_BITS = 160
)
(
    input [(ADDR_BITS - 1):0] addra,
    input clka,
    input [(DATA_BITS - 1):0] dina,
    input ena,
    input wea,

    input [(ADDR_BITS - 1):0] addrb,
    input clkb,
    output [(DATA_BITS - 1):0] doutb,
    input enb
);
    ram_blk #(
        .ADDR_BITS(ADDR_BITS),
        .DATA_BITS(DATA_BITS)
    ) ram (
        .addra(addra),
        .clka(clka),
        .dina(dina),
        .ena(ena),
        .wea(wea),
        .addrb(addrb),
        .clkb(clkb),
        .doutb(doutb),
        .enb(enb)
    );
endmodule
module alu_1 #(
    parameter STAGE_ID = 0,
    parameter ACTION_LEN = 25,
    parameter DATA_WIDTH = 48  //data width of the ALU
)
(
    input clk,
    input rst_n,

    //input from sub_action
    input [ACTION_LEN-1:0]            action_in,
    input                             action_valid,
    input [DATA_WIDTH-1:0]            operand_1_in,
    input [DATA_WIDTH-1:0]            operand_2_in,

    //output to form PHV
    output reg [DATA_WIDTH-1:0]       container_out,
    output reg                        container_out_valid

);

/*
4 operations to support:

1,2. add/sub:   0001/0010
              extract 2 operands from pkt header, add(sub) and write back.

3,4. addi/subi: 0011/0100
              extract op1 from pkt header, op2 from action, add(sub) and write back.
*/


localparam IDLE_S=3'd0, 
		   WAIT1_S=3'd1, 
		   WAIT2_S=3'd2, 
		   WAIT3_S=3'd3, 
		   OUTPUT_S=3'd4;

reg [2:0]					state, state_next;
reg [DATA_WIDTH-1:0]		container_out_r;
reg							container_out_valid_next;

always @(*) begin
	state_next = state;
	container_out_r = container_out;
	container_out_valid_next = 0;

	case (state)
		IDLE_S: begin
			if (action_valid) begin
				state_next = OUTPUT_S;
				case(action_in[24:21])
            	    4'b0001, 4'b1001: begin
            	        container_out_r = operand_1_in + operand_2_in;
            	    end
            	    4'b0010, 4'b1010: begin
            	        container_out_r = operand_1_in - operand_2_in;
            	    end
					4'b1110: begin
						container_out_r = operand_2_in;
					end
            	    //if its an empty (default) action
            	    default: begin
            	        container_out_r = operand_1_in;
            	    end
            	endcase
			end
		end
		WAIT1_S: begin
			// empty cycle
			state_next = WAIT2_S;
		end
		WAIT2_S: begin
			state_next = WAIT3_S;
		end
		WAIT3_S: begin
			state_next = OUTPUT_S;
		end
		OUTPUT_S: begin
			container_out_valid_next = 1;
			state_next = IDLE_S;
		end
	endcase
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		container_out <= 0;
		container_out_valid <= 0;
		state <= IDLE_S;
	end
	else begin
		state <= state_next;
		container_out_valid <= container_out_valid_next;
		container_out <= container_out_r;
	end
end


endmodule
module alu_3 #(
    parameter STAGE_ID = 0,
    parameter ACTION_LEN = 25,
    parameter META_LEN = 256
)(
    input                               clk,
    input                               rst_n,
    //the input data shall be metadata & com_ins
    input [META_LEN-1:0]       			comp_meta_data_in,
    input                               comp_meta_data_valid_in,
    input [ACTION_LEN-1:0]              action_in,
    input                               action_valid_in,

    //output is the modified metadata plus comp_ins
    output reg [META_LEN-1:0]  			comp_meta_data_out,
    output reg                          comp_meta_data_valid_out     
);

//need delay for one cycle before the result pushed out
/*
action format:
    [24:20]: opcode;
    [19:12]: dst_port;
    [11]:    discard_flag;
    [10:5]:  next_table_id;
    [4:0]:   reserverd_bit;
*/
/*
metadata fields that are related:
    TODO: next table id is not supported yet.
    [255:250]: next_table_id;
    [249:129]: reservered for other use;
    [128]:     discard_field;
    [127:0]:   copied from NetFPGA's md;
    
*/

localparam IDLE_S=3'd0,
		   WAIT1_S=3'd1,
		   WAIT2_S=3'd2, 
		   WAIT3_S=3'd3, 
		   OUTPUT_S=3'd4;

reg [2:0]						state, state_next;
reg [META_LEN-1:0]		comp_meta_data_out_r;
reg								comp_meta_data_valid_next;

always @(*) begin
	state_next = state;
	comp_meta_data_out_r = comp_meta_data_out;
	comp_meta_data_valid_next = 0;

	case (state)
		IDLE_S: begin
			if (action_valid_in) begin
				state_next = OUTPUT_S;
				case(action_in[24:21])
            	    4'b1100: begin // dst_port
            	        comp_meta_data_out_r[255:32] = {action_in[10:5],comp_meta_data_in[249:32]};
            	        comp_meta_data_out_r[31:24]  = action_in[20:13];
            	        comp_meta_data_out_r[23:0]   = comp_meta_data_in[23:0];
            	    end
            	    4'b1101: begin // discard
            	        comp_meta_data_out_r[255:129] = {action_in[10:5],comp_meta_data_in[249:129]};
            	        comp_meta_data_out_r[128] = action_in[12];
            	        comp_meta_data_out_r[127:0] = comp_meta_data_in[127:0];
            	    end
            	    default: begin
            	        comp_meta_data_out_r = comp_meta_data_in;
            	    end
            	endcase
			end
		end
		WAIT1_S: begin
			// empty cycle
			state_next = WAIT2_S;
		end
		WAIT2_S: begin
			state_next = WAIT3_S;
		end
		WAIT3_S: begin
			state_next = OUTPUT_S;
		end
		OUTPUT_S: begin
			comp_meta_data_valid_next = 1;
			state_next = IDLE_S;
		end
	endcase
end

always @(posedge clk) begin
	if (~rst_n) begin
		comp_meta_data_out <= 0;
		comp_meta_data_valid_out <= 0;
		state <= IDLE_S;
	end
	else begin
		state <= state_next;
		comp_meta_data_out <= comp_meta_data_out_r;
		comp_meta_data_valid_out <= comp_meta_data_valid_next;
	end
end

endmodule
module payload_crc_acc(

   input    wire        clk,
   input    wire        rst,
   input    wire [63:0] udp_data,
   input    wire        udp_data_valid,
   input    wire        last_data,
   output   reg[15:0]   udp_crc,
   output   reg         udp_crc_valid

);

   reg  [31:0] sum_a;
   reg  [31:0] sum_b;
   wire [16:0] result_a;
   wire [16:0] result_b;
   wire [17:0] result;
   reg         last_reg;
   reg         last_detect;

   always @(posedge clk) begin
      if (rst) begin
         sum_a    <= 0;
         sum_b    <= 0;
         udp_crc <= 0;
         udp_crc_valid <= 0;
      end
      else begin
         if (udp_data_valid) begin
            sum_a <= udp_data[15:0] + udp_data[31:16] + sum_a;
            sum_b <= udp_data[47:32] + udp_data[63:48] + sum_b;
         end
         if (last_detect) begin
            udp_crc <= (result[15:0] + result[17:16]);
            udp_crc_valid <= 1;
            sum_a <=0;
            sum_b <=0;
         end
         else udp_crc_valid <= 0;
      end
   end
   
   assign result_a = (sum_a[15:0] + sum_a[31:16]);
   assign result_b = (sum_b[15:0] + sum_b[31:16]);
   assign result = result_a[15:0] + result_b[15:0] + result_a[16] + result_b[16];
   
   always @(posedge clk) begin 
       if (rst) begin
           last_reg <= 0;
           last_detect <= 0;
       end else begin
         last_reg <= last_data;
         last_detect <= last_data & !last_reg;
      end
   end
   
   
endmodule
module outbond_header_crc(
   input clk,                         
   input reset,                       
   input [159:0] header,              
   input header_valid,                
   output [15:0] checksum,            
   output checksum_valid              

);


   localparam WAIT_HEADER          =0;    
   localparam CHECKSUM_CALCULATE   =1;    
   localparam RESULT               =2;    
   
   reg [2:0]       state;                 
   reg [127:0]     header_sreg;           
   reg [2:0]       shift_cntr;            
   reg [31:0]      header_data;           
   reg             crc_reset;             
   
   
   
   always @(posedge clk) begin
      if (reset) begin                                   
         // reset
         header_sreg<=0;
         header_data<=0;
         shift_cntr<=0;
         crc_reset<=0;
         state<=WAIT_HEADER;
         shift_cntr<=0;
   
      end
      else 
      case (state)
         WAIT_HEADER:begin                                     
            if (header_valid) begin                            
               state <= CHECKSUM_CALCULATE;                    
               header_data<=header[31:0];                      
               header_sreg<=header[159:32];                    
               crc_reset<=0;                                   
               
            end 
            else begin                                         
               crc_reset<=1;                                   
               state <= WAIT_HEADER;                           
            end
         end //WAIT_HEADER:begin
   
         CHECKSUM_CALCULATE: begin                   
            header_data<=header_sreg[31:0];                    
            header_sreg<={32'b0, header_sreg[127:32]};         
            shift_cntr<=shift_cntr+1;                          
            if (shift_cntr==4) begin                           
               state<= WAIT_HEADER;                            
               crc_reset<=1;                                   
            end 
         end //CHECKSUM_CALCULATE: begin
   
         default: state<= WAIT_HEADER;                         
      endcase
   end
   
   
   
   checksum_acc checksum_acc_i(
           .clk(clk),                      
           .valid(checksum_valid),         
           .checksum(checksum[15:0]),      
           .header(header_data),           
           .reset(crc_reset)               
      
   );
   
   
endmodule
module checksum_acc(
   input          clk,
   output[15:0]   checksum,
   input [31:0]   header,
   output         valid,
   input          reset
);

   reg [31:0] checksum_int;
   reg [2:0] header_count;
   
   always @(posedge clk)
   if (reset) begin
      checksum_int <= 0;
      header_count <= 0;
   end
   else
      if (header_count != 5)
      begin
         header_count <= header_count + 1'b1;
         checksum_int <= checksum_int + header[15:0] + header[31:16];
      end

   wire [16:0]  summ = checksum_int[31:16] + checksum_int[15:0];
   assign checksum = ~(summ[15:0] + summ[16]);
   
   assign valid = (header_count==5);
endmodule
module payload_crc_acc_A(

   input    wire        clk,
   input    wire        rst,
   input    wire [63:0] udp_data,
   input   wire         udp_data_valid,
   input    wire        eop,
   input    wire        sop,
   output   reg[15:0]   udp_crc,
   output   reg         udp_crc_valid

);

   reg [31:0] sum_a;
   reg [31:0] sum_b;
   wire [16:0] result_a;
   wire [16:0] result_b;
   wire [17:0] result;
   reg last_detect;
   
   always @(posedge clk) begin
      if (rst) begin
         sum_a    <= 0;
         sum_b    <= 0;
         udp_crc <= 0;
         udp_crc_valid <= 0;
      end
      else begin
         if (udp_data_valid) begin
            sum_a <= udp_data[15:0] + udp_data[31:16]  + (sop? 16'b0 : sum_a);
            sum_b <= udp_data[47:32] + udp_data[63:48] + (sop? 16'b0 : sum_b);
         end
         if (last_detect) begin
            udp_crc <= (result[15:0] + result[17:16]);
            udp_crc_valid <= 1;
         end
         else udp_crc_valid <= 0;
      end
   end
   
   assign result_a = (sum_a[15:0] + sum_a[31:16]);
   assign result_b = (sum_b[15:0] + sum_b[31:16]);
   assign result   = result_a[15:0] + result_b[15:0] + result_a[16] + result_b[16];
   
   always @(posedge clk) begin 
       if (rst) begin
           last_detect <= 0;
       end else begin
         last_detect <= eop;
      end
   end

endmodule
module ip_header_checksum(
   input           clk,           
   output[15:0]    checksum,       
   input [31:0]    header,         
   output          valid,          
   input           reset           
   );

   reg [31:0] checksum_int;        
   reg [2:0] header_count;        

always @(posedge clk)
   if (reset) begin                
      checksum_int <= 0;
      header_count <= 0;
   end
   else
      if (header_count < 5)      
      begin
         header_count <= header_count + 1'b1;                            
         checksum_int <= checksum_int + header[15:0] + header[31:16];    
      end

   wire [16:0]  summ = checksum_int[31:16] + checksum_int[15:0];
   assign checksum = ~(summ[15:0] + summ[16]);

   assign valid = (header_count==5);                                      

endmodule
module fwft_fifo #(
   parameter DATA_WIDTH = 64

    ) (
    input wire RST,
    input wire CLK,
    output wire [DATA_WIDTH-1:0] DO,
    output wire EMPTY,
    output wire FULL,
    input wire [DATA_WIDTH-1:0] DI,
    input wire RDEN,
    input wire WREN
    );


   localparam FIFO_SIZE = (DATA_WIDTH > 36) ? "36Kb" : "18Kb";

   wire empty_int;
   wire rd_en_int;
   reg dout_valid =0;
    
   FIFO_SYNC_MACRO  #(
      .DEVICE("7SERIES"),           // Target Device: "7SERIES" 
      .ALMOST_EMPTY_OFFSET(9'h080), // Sets the almost empty threshold
      .ALMOST_FULL_OFFSET(9'h080),  // Sets almost full threshold
      .DATA_WIDTH(DATA_WIDTH),      // Valid values are 1-72 (37-72 only valid when FIFO_SIZE="36Kb")
      .DO_REG(0),                   // Optional output register (0 or 1)
      .FIFO_SIZE (FIFO_SIZE)        // Target BRAM: "18Kb" or "36Kb" 
   ) FIFO_SYNC_MACRO_inst (   
      .ALMOSTEMPTY(),               // 1-bit output almost empty
      .ALMOSTFULL(),                // 1-bit output almost full
      .DO(DO),                      // Output data, width defined by DATA_WIDTH parameter
      .EMPTY(empty_int),            // 1-bit output empty
      .FULL(FULL),                  // 1-bit output full
      .RDCOUNT(),                   // Output read count, width determined by FIFO depth
      .RDERR(),                     // 1-bit output read error
      .WRCOUNT(),                   // Output write count, width determined by FIFO depth
      .WRERR(),                     // 1-bit output write error
      .CLK(CLK),                    // 1-bit input clock
      .DI(DI),                      // Input data, width defined by DATA_WIDTH parameter
      .RDEN(rd_en_int),             // 1-bit input read enable
      .RST(RST),                    // 1-bit input reset
      .WREN(WREN)                   // 1-bit input write enable
   );

   assign rd_en_int = !empty_int && (!dout_valid || RDEN);
   assign EMPTY = !dout_valid;

   always @(posedge CLK) begin
      if (RST)
         dout_valid <= 0;
      else
         begin
            if (rd_en_int)
               dout_valid <= 1;
            else if (RDEN)
               dout_valid <= 0;
         end 
   end

endmodule
module tb_tst_6502;
    reg clk;
    reg clk_2x;
    reg reset;
	wire [3:0] vdac;
	wire [7:0] gpio_o;
	reg [7:0] gpio_i;
	reg RX;
    wire TX;
	wire snd_l, snd_r, snd_nmute;
    wire spi0_mosi, spi0_miso, spi0_sclk, spi0_cs0;
	wire ps2_clk, ps2_dat;
	wire rgb0, rgb1, rgb2;
	wire [3:0] tst;
	
    // clock sources
    always
        #31.25 clk = ~clk;
    always
		#15.625 clk_2x = ~clk_2x;
	
    // reset
    initial
    begin
`ifdef icarus
  		$dumpfile("tb_tst_6502.vcd");
		$dumpvars;
`endif
        
        // init regs
        clk = 1'b0;
        clk_2x = 1'b0;
        reset = 1'b1;
        RX = 1'b1;
        
        // release reset
        #1000
        reset = 1'b0;
        
`ifdef icarus
        // stop after 1 sec
		#10000000 $finish;
`endif
    end
    
    // Unit under test
    tst_6502 uut(
        .clk(clk),              // 16MHz CPU clock
        .clk_2x(clk_2x),        // 32MHz Video clock
        .reset(reset),          // Low-true reset
		.vdac(vdac),			// video DAC
        .gpio_o(gpio_o),        // gpio
        .gpio_i(gpio_i),
        .RX(RX),                // serial
        .TX(TX),
		.snd_l(snd_l),			// audio
		.snd_r(snd_r),
		.snd_nmute(snd_nmute),
		.spi0_mosi(spi0_mosi),	// SPI core 0
		.spi0_miso(spi0_miso),
		.spi0_sclk(spi0_sclk),
		.spi0_cs0(spi0_cs0),
		.ps2_clk(ps2_clk),		// PS/2 Keyboard port
		.ps2_dat(ps2_dat),
		.rgb0(rgb0),			// LED drivers
		.rgb1(rgb1),
		.rgb2(rgb2),
		.tst(tst)				// diagnostic port
    );
endmodule
module acia_rx(
	input clk,				  // system clock
	input rst,				  // system reset
	input rx_serial,		  // raw serial input
	output reg [7:0] rx_dat,  // received byte
	output reg rx_stb,        // received data available
	output reg rx_err         // received data error
);
	// sym rate counter for 115200bps @ 16MHz clk
    parameter SCW = 8;
	parameter sym_cnt = 139;
	
	// input sync & deglitch
	reg [7:0] in_pipe;
	reg in_state;
	wire all_zero = ~|in_pipe;
	wire all_one = &in_pipe;
	always @(posedge clk)
		if(rst)
		begin
			// assume RX input idle at start
			in_pipe <= 8'hff;
			in_state <= 1'b1;
		end
		else
		begin
			// shift in a bit
			in_pipe <= {in_pipe[6:0],rx_serial};
	
			// update state
			if(in_state && all_zero)
				in_state <= 1'b0;
			else if(!in_state && all_one)
				in_state <= 1'b1;
		end

	// receive machine
	reg [8:0] rx_sr;
	reg [3:0] rx_bcnt;
	reg [SCW-1:0] rx_rcnt;
	reg rx_busy;
	always @(posedge clk)
		if(rst)
		begin
			rx_busy <= 1'b0;
			rx_stb <= 1'b0;
			rx_err <= 1'b0;
		end
		else
		begin
			if(!rx_busy)
			begin
				if(!in_state)
				begin
					// found start bit - wait 1/2 bit to sample
					rx_bcnt <= 4'h9;
					rx_rcnt <= sym_cnt/2;
					rx_busy <= 1'b1;
				end
				
				// clear the strobe
				rx_stb <= 1'b0;
			end
			else
			begin
				if(~|rx_rcnt)
				begin
					// sample data and restart for next bit
					rx_sr <= {in_state,rx_sr[8:1]};
					rx_rcnt <= sym_cnt;
					rx_bcnt <= rx_bcnt - 1;
					
					if(~|rx_bcnt)
					begin
						// final bit - check for err and finish
						rx_dat <= rx_sr[8:1];
						rx_busy <= 1'b0;
						if(in_state && ~rx_sr[0])
						begin
							// framing OK
							rx_err <= 1'b0;
							rx_stb <= 1'b1;
						end
						else
							// framing err
							rx_err <= 1'b1;
					end
				end
				else
					rx_rcnt <= rx_rcnt - 1;
			end
		end
endmodule
module ram_32kb(
    input clk,
    input sel,
    input we,
	input [7:0] wp,
    input [14:0] addr,
    input [7:0] din,
    output reg [7:0] dout
);

	// write protect 4k blocks
	reg wp_we;
	always @(*)
		case(addr[14:12])
			3'd0:wp_we = (~wp[0] & we);
			3'd1:wp_we = (~wp[1] & we);
			3'd2:wp_we = (~wp[2] & we);
			3'd3:wp_we = (~wp[3] & we);
			3'd4:wp_we = (~wp[4] & we);
			3'd5:wp_we = (~wp[5] & we);
			3'd6:wp_we = (~wp[6] & we);
			3'd7:wp_we = (~wp[7] & we);
		endcase
			
//`define SIMULATE
`ifdef SIMULATE
	integer i;
    reg [7:0] memory[0:32767];
	
	// clear RAM to avoid simulation errors
	initial
		for (i = 0; i < 32768; i = i +1)
			memory[i] <= 0;
    
    // synchronous write
    always @(posedge clk)
        if(sel & wp_we)
            memory[addr] <= din;
    
    // synchronous read
    always @(posedge clk)
        dout <= memory[addr];
`else
	wire [15:0] data;
	
    // instantiate the big RAM
	SB_SPRAM256KA mem (
		.ADDRESS(addr[14:1]),
		.DATAIN({din,din}),
		.MASKWREN(addr[0]?4'b1100:4'b0011),
		.WREN(wp_we),
		.CHIPSELECT(sel),
		.CLOCK(clk),
		.STANDBY(1'b0),
		.SLEEP(1'b0),
		.POWEROFF(1'b1),
		.DATAOUT(data)
	);
    
    // pipeline the output select
    reg hilo_sel;
    always @(posedge clk)
        hilo_sel <= addr[0];
	
	always @(*)
		dout = hilo_sel ? data[15:8] : data[7:0];
`endif
endmodule
module satsu(in, out);
	parameter isz = 17;				// input data width
	parameter osz = 12;				// output data width
	parameter warn = 1;				// enable runtime warnings
	
	input signed [isz-1:0] in;		// input data to be saturated
	output [osz-1:0] out;	// output data after saturation
	
	// Check low & high saturation conditions
	wire min =  in[isz-1];
	wire max = ~in[isz-1] &  |in[isz-2:osz];
	
	reg [osz-1:0] out;
	
	// select output
	always @(min or max or in)
		case({max,min})
			2'b01:		out = {osz{1'b0}};		// zero
			2'b10:		out = {osz{1'b1}};		// max pos
			default:	out = in[osz-1:0];		// pass thru
		endcase
	
	// runtime warnings
	// synthesis translate_off
		always @(min or max)
		if(warn & (min | max))
			$display("%m: saturation @ time %d (%d <> %d)", $time, in, (1<<(osz-1)));
	// synthesis translate_on
endmodule
module vram_32kb(
    input clk,
    input we,
    input [14:0] addr,
    input [7:0] din,
    output reg [7:0] dout_byte,
	output [15:0] dout_word
);

	wire [15:0] data;
	
    // instantiate the big RAM
	SB_SPRAM256KA mem (
		.ADDRESS(addr[14:1]),
		.DATAIN({din,din}),
		.MASKWREN(addr[0]?4'b1100:4'b0011),
		.WREN(we),
		.CHIPSELECT(1'b1),
		.CLOCK(clk),
		.STANDBY(1'b0),
		.SLEEP(1'b0),
		.POWEROFF(1'b1),
		.DATAOUT(data)
	);
    
    // pipeline the output select
    reg hilo_sel;
    always @(posedge clk)
        hilo_sel <= addr[0];
	
	always @(*)
		dout_byte = hilo_sel ? data[15:8] : data[7:0];
	
	assign dout_word = data;
endmodule
module acia_tx(
	input clk,				// system clock
	input rst,				// system reset
	input [7:0] tx_dat,		// transmit data byte
	input tx_start,			// trigger transmission
	output tx_serial,		// tx serial output
	output reg tx_busy		// tx is active (not ready)
);
	// sym rate counter for 115200bps @ 16MHz clk
    parameter SCW = 8;		// rate counter width
	parameter sym_cnt = 139;	// rate count value
	
	// transmit machine
	reg [8:0] tx_sr;
	reg [3:0] tx_bcnt;
	reg [SCW-1:0] tx_rcnt;
	always @(posedge clk)
	begin
		if(rst)
		begin
			tx_sr <= 9'h1ff;
			tx_bcnt <= 4'h0;
			tx_rcnt <= {SCW{1'b0}};
			tx_busy <= 1'b0;
		end
		else
		begin
			if(!tx_busy)
			begin
				if(tx_start)
				begin
					// start transmission
					tx_busy <= 1'b1;
					tx_sr <= {tx_dat,1'b0};
					tx_bcnt <= 4'd9;
					tx_rcnt <= sym_cnt;
				end
			end
			else
			begin
				if(~|tx_rcnt)
				begin
					// shift out next bit and restart
					tx_sr <= {1'b1,tx_sr[8:1]};
					tx_bcnt <= tx_bcnt - 1;
					tx_rcnt <= sym_cnt;
					
					if(~|tx_bcnt)
					begin
						// done - return to inactive state
						tx_busy <= 1'b0;
					end
				end
				else
					tx_rcnt <= tx_rcnt - 1;
			end	
		end
	end
	
	// hook up output
	assign tx_serial = tx_sr;
endmodule
module ps2_tx(
		input clk,
		input rst,
		input tx_ena,
		input [7:0] tx_data,
		input ps2_clk_ena,
		input ps2_clk_sync,
		input ps2_dat_sync,
		output reg tx_active,
		output reg tx_err,
		output reg ps2_clk_oe,
		output reg ps2_dat_oe
);
	// state machine
	localparam ST_WAIT = 4'h0;
	localparam ST_RQST = 4'h1;
	localparam ST_STRT = 4'h2;
	localparam ST_DAT0 = 4'h3;
	localparam ST_DAT1 = 4'h4;
	localparam ST_DAT2 = 4'h5;
	localparam ST_DAT3 = 4'h6;
	localparam ST_DAT4 = 4'h7;
	localparam ST_DAT5 = 4'h8;
	localparam ST_DAT6 = 4'h9;
	localparam ST_DAT7 = 4'hA;
	localparam ST_PRTY = 4'hB;
	localparam ST_STOP = 4'hC;
	localparam ST_WACK = 4'hD;
	localparam ST_WOFF = 4'hE;
	reg [3:0] tx_state;
	reg [17:0] timer;
	reg [8:0] tx_sreg;
	always @(posedge clk)
		if(rst)
		begin
			tx_state <= ST_WAIT;
			tx_active <= 1'b0;
			tx_err <= 1'b0;
			ps2_clk_oe <= 1'b0;
			ps2_dat_oe <= 1'b0;
		end
		else
			case(tx_state)
				ST_WAIT:
					// wait for tx write
					if(tx_ena)
					begin
						// move to REQUEST state
						tx_state <= ST_RQST;
						timer <= 18'd1599;
						tx_active <= 1'b1;
						tx_sreg <= {~(^tx_data),tx_data};
						ps2_clk_oe <= 1'b1;
					end
				
				ST_RQST:
					// pull clock low & wait 100us to start
					if(timer == 18'd0)
					begin
						// move to START state
						tx_state <= ST_STRT;
						timer <= 18'd238399;	// 14.9ms
						ps2_clk_oe <= 1'b0;
						ps2_dat_oe <= 1'b1;
					end
					else
						// decrement timer
						timer <= timer - 18'd1;
				
				ST_STRT, ST_DAT0, ST_DAT1, ST_DAT2, ST_DAT3, ST_DAT4,
				ST_DAT5, ST_DAT6, ST_DAT7, ST_PRTY, ST_STOP:
					// wait for clk falling edge to shift out data
					if(ps2_clk_ena)
					begin
						tx_state <= tx_state + 4'h1;
						if(tx_state == ST_STRT)
							timer <= 18'd31999;	// 2ms
						if(tx_state == ST_STOP)
							ps2_dat_oe <= 1'b0;
						else
							ps2_dat_oe <= ~tx_sreg[0];
						tx_sreg <= {1'b1,tx_sreg[8:1]};
					end
					else
					begin
						// in START state wait 15ms max for clock edge
						// in all other states wait 2ms max
						if(timer == 18'd0)
						begin
							// timeout - set err and return to wait
							tx_state <= ST_WAIT;
							tx_err <= 1'b1;
							tx_active <= 1'b0;
						end
						else
							timer <= timer - 18'd1;
					end
				
				ST_WACK:
					// wait for ACK (dat = 0)
					if(ps2_dat_sync == 1'b0)
					begin
						tx_state <= ST_WOFF;
					end
					else
					begin
						// in all other states wait 2ms max
						if(timer == 18'd0)
						begin
							// timeout - set err and return to wait
							tx_state <= ST_WAIT;
							tx_err <= 1'b1;
							tx_active <= 1'b0;
						end
						else
							timer <= timer - 18'd1;
					end
				
				ST_WOFF:
					// wait for device to release bus (clk,dat = 1)
					if((ps2_clk_sync == 1'b1)&&(ps2_dat_sync == 1'b1))
					begin
						tx_state <= ST_WAIT;
						tx_err <= 1'b0;
						tx_active <= 1'b0;
					end
				
				default:
				begin
					// exit illegal state
					tx_state <= ST_WAIT;
					tx_active <= 1'b0;
					tx_err <= 1'b0;
					ps2_clk_oe <= 1'b0;
					ps2_dat_oe <= 1'b0;
				end
			endcase
endmodule
module wishbone(
	input clk,				// system clock
	input rst,				// system reset
	input cs,				// chip select
	input we,				// write enable
	input [7:0] addr,		// register select
	input [7:0] din,		// data bus input
	output reg [7:0] dout,	// data bus output
	output reg rdy,			// low-true processor stall
	
	output reg wb_stbo,			// wishbone STB
	output reg [7:0] wb_adro,	// wishbone Address
	output reg wb_rwo,			// wishbone read/write
	output reg [7:0] wb_dato,	// wishbone data out
	input wb_acki,				// wishbone ACK
	input [7:0] wb_dati			// wishbone data in
	);
	
	// start bus transactions
	reg [3:0] timeout;		// 16-clock timeout counter
	always @(posedge clk)
		if(rst == 1'b1)
		begin
			// clear all at reset
			dout <= 8'h55;
			rdy <= 1'b1;
			timeout <= 4'h0;
			wb_stbo <= 1'b0;
			wb_adro <= 8'h00;
			wb_rwo <= 1'b1;
			wb_dato <= 8'h00;
		end
		else
		begin
			if(rdy == 1'b1)
			begin
				// No transaction pending - start new one
				if(cs == 1'b1)
				begin
					wb_stbo <= 1'b1;
					wb_adro <= addr;
					wb_rwo <= we;
					rdy <= 1'b0;
					timeout <= 4'hf;
					
					if(we == 1'b1)
					begin
						// write cycle
						wb_dato <= din;
					end
				end
			end
			else
			begin
				// Transaction in process
				if((wb_acki == 1'b1) || (|timeout == 1'b0))
				begin
					// finish cycle
					wb_stbo <= 1'b0;
					rdy <= 1'b1;
					if((wb_rwo == 1'b0) && (|timeout == 1'b1))
					begin
						// finish read cycle
						dout <= wb_dati;
					end
				end
				
				// update timeout counter
				timeout <= timeout - 4'h1;
			end
		end
endmodule
module snd(
	input clk,				// system clock
	input rst,				// system reset
	input cs,				// chip select
	input we,				// write enable
	input [3:0] addr,		// register select
	input [7:0] din,		// data bus input
	output reg [7:0] dout,	// data bus output
	output snd_l,			// left 1-bit DAC output
	output snd_r,			// right 1-bit DAC output
	output snd_nmute		// /mute output
);
	// write control registers
	reg [7:0] f_lo[3:0];
	reg [15:0] frq[3:0];
	reg [2:0] wave[3:0];
	reg [7:0] gain[3:0];
	integer i;
	always @(posedge clk)
		if(rst)
		begin
			for(i=0;i<=3;i=i+1)
			begin
				f_lo[i] <= 8'h00;
				frq[i] <= 16'h0000;
			end
		end
		else if(cs & we)
			case(addr[1:0])
				2'h0: f_lo[addr[3:2]] <= din;
				2'h1: frq[addr[3:2]] <= {din,f_lo[addr[3:2]]};
				2'h2: wave[addr[3:2]] <= din[2:0];
				2'h3: gain[addr[3:2]] <= din;
			endcase
	
	// read registers
	always @(posedge clk)
		if(cs & !we)
			case(addr[1:0])
				2'h0: dout <= frq[addr[3:2]][7:0];
				2'h1: dout <= frq[addr[3:2]][15:8];
				2'h2: dout <= {5'h00,wave[addr[3:2]]};
				2'h3: dout <= gain[addr[3:2]];
				default: dout <= 8'h00;
			endcase
	
	// sine LUT
	reg signed [15:0] sine_lut[255:0];
	initial
		$readmemh("../src/sine.hex", sine_lut, 0);
		
	// NCOs and SD acc
	reg [1:0] seq, seq_d1;
	reg [23:0] phs[3:0];
	reg carry;
	reg [19:0] noise[3:0];
	reg [16:0] seq_phs;
	reg [15:0] sine;
	reg [15:0] wv;
	reg [7:0] seq_gain;
	reg [23:0] wv_scl;
	reg [16:0] sd_acc;
	always @(posedge clk)
		if(rst)
		begin
			seq <= 2'b00;
			
			for(i=0;i<=3;i=i+1)
				phs[i] <= 24'h000000;
			
			sd_acc <= 17'h00000;
		end
		else 			
		begin
			// sequential count to index all four voices
			seq <= seq + 2'b01;
			
			// 24-bit NCO with carry output
			{carry,phs[seq]} <= {1'b0,phs[seq]} + {9'h00,frq[seq]};
			
			// select phase
			seq_d1 <= seq;
			seq_phs <= phs[seq][23:7];
			
			// sine shaping
			sine <= sine_lut[phs[seq][23:16]];
			
			// 16-bit noise generation from 2^20-1 LFSR
			if(carry)
				noise[seq] <= 
					{
						noise[seq][3:0],		// top 4 are just shifted
						~(noise[seq][19:4]^noise[seq][16:1])
					};
			
			// wave shaping
			seq_gain <= gain[seq_d1];
			case(wave[seq_d1])
				3'b000: wv <= seq_phs[16:1];	// saw up
				3'b001: wv <= seq_phs[16] ? 16'hffff : 16'h0000; // square
				3'b010: wv <= seq_phs[16] ? ~seq_phs[15:0] : seq_phs[15:0]; // triangle
				3'b011: wv <= sine^16'h8000;	// offset-binary sine
				3'b100: wv <= noise[seq][19] ? 16'hffff : 16'h0000; // 1-bit noise
				3'b101: wv <= noise[seq][15:0]; // 16-bit noise
				default : wv <= ~seq_phs[16:1]; // saw down
			endcase
			
			// gain scaling
			wv_scl <= wv * seq_gain;
			
			// 1st-order sigma-delta
			sd_acc <= {1'b0,sd_acc[15:0]} + {1'b0,wv_scl[23:8]};
		end
		
	// sigma-delta output is carry output of accum
	assign snd_l = sd_acc[16];
	assign snd_r = sd_acc[16];
	assign snd_nmute = 1'b1;
endmodule
module rom_cg_2kB(
    input clk,
    input [10:0] addr,
    output reg [7:0] dout
);
    reg [7:0] memory [0:2047];

    initial
        $readmemh("../src/chargen_2k.hex",memory);
    
    // synchronous read - FPGA can't do it async
    always @(posedge clk)
        dout <= memory[addr];
        
endmodule
module led_pwm(
	input clk,				// system clock
	input rst,				// system reset
	input cs,				// chip select
	input we,				// write enable
	input [3:0] addr,		// register select
	input [7:0] din,		// data bus input
	output reg [7:0] dout,	// data bus output
	output rgb0,			// rgb0 pin
	output rgb1,			// rgb1 pin
	output rgb2				// rgb2 pin
);
	// local control regs
	reg [7:0] mycr;
	always @(posedge clk)
		if(rst)
			mycr <= 8'h00;
		else if(cs & we & (addr==4'hF))
			mycr <= din;
	
	// data output
	always @(posedge clk)
		if(cs & !we)
			if(addr == 4'hF)
				dout <= mycr;	// read back mycr
			else
				dout <= {7'h00,led_on};	// read back status

	// LED PWM IP core
	wire LED0, LED1, LED2;
	wire led_on;
	SB_LEDDA_IP PWMgen_inst (
		//.LEDDRST(rst),	// "doesn't really exist"
		.LEDDCS(cs),
		.LEDDCLK(clk),
		.LEDDDAT7(din[7]),
		.LEDDDAT6(din[6]),
		.LEDDDAT5(din[5]),
		.LEDDDAT4(din[4]),
		.LEDDDAT3(din[3]),
		.LEDDDAT2(din[2]),
		.LEDDDAT1(din[1]),
		.LEDDDAT0(din[0]),
		.LEDDADDR3(addr[3]),
		.LEDDADDR2(addr[2]),
		.LEDDADDR1(addr[1]),
		.LEDDADDR0(addr[0]),
		.LEDDDEN(we),
		.LEDDEXE(mycr[6]),
		.PWMOUT0(LED0),
		.PWMOUT1(LED1),
		.PWMOUT2(LED2),
		.LEDDON(led_on)
	);
	
	// RGB LED Driver IP core
	SB_RGBA_DRV #(
		.CURRENT_MODE("0b1"),
		.RGB0_CURRENT("0b000001"),
		.RGB1_CURRENT("0b000001"),
		.RGB2_CURRENT("0b000011")
	) RGBA_DRIVER (
		.CURREN(mycr[4]),
		.RGBLEDEN(mycr[5]),
		.RGB0PWM(mycr[7] ? LED0 : mycr[0]),
		.RGB1PWM(mycr[7] ? LED1 : mycr[1]),
		.RGB2PWM(mycr[7] ? LED2 : mycr[2]),
		.RGB0(rgb0),
		.RGB1(rgb1),
		.RGB2(rgb2)
	);
endmodule
module ps2_rx(
	input clk,
	input rst,
	input ps2_clk_in,
	input ps2_dat_in,
	input ps2_clk_ena,
	input ps2_dat_sync,
	output reg [7:0] rx_code,
	output reg rx_done,
	output reg rx_frmerr,
	output reg rx_parerr
);
	// rx state machine deserializes data
	localparam ST_WAIT = 4'h0;
	localparam ST_DAT0 = 4'hA;
	localparam ST_STOP = 4'h1;	
	reg [3:0] rx_state;
	reg [8:0] rx_sreg;
	always @(posedge clk)
		if(rst)
		begin
			rx_state <= ST_WAIT;
			rx_done <= 1'b0;
			rx_frmerr <= 1'b0;
			rx_parerr <= 1'b0;
		end
		else
		begin
			if(ps2_clk_ena)
			begin
				// Start or count or wait
				if(|rx_state)
					rx_state <= rx_state - 4'h1;
				else if(ps2_dat_sync == 1'b0)
					rx_state <= ST_DAT0;
				
				// shift in data lsb first
				if(|rx_state)
					rx_sreg <= {ps2_dat_sync,rx_sreg[8:1]};
				
				// final processing
				if(rx_state == ST_STOP)
				begin
					rx_done <= 1'b1;	// flag end of cycle
					if(ps2_dat_sync == 1'b0)
						rx_frmerr <= 1'b1;	// frame error if stop = 0
					if(^rx_sreg == 1'b0)
						rx_parerr <= 1'b1;	// parity error
					rx_code <= rx_sreg[7:0]; // grab data
				end
			end
			else
				rx_done <= 1'b0;	// rx_done only lasts one cycle
		end
endmodule
module our;
	initial begin
	    $display("Hello, world");
	    $finish;
	end
	endmodule
module delay_ff #(
    parameter DELAY = 1,
    parameter WIDTH = 1
) (
    input clk,

    input [WIDTH-1:0] in,
    output [WIDTH-1:0] out
);
    delay_ffr #(
        .DELAY(DELAY),
        .WIDTH(WIDTH)
    ) ffr (
        .clk(clk),
        .reset(0),

        .in(in),
        .out(out)
    );

endmodule
module delay_ffr #(
    parameter DELAY = 1,
    parameter WIDTH = 1
) (
    input clk,
    input reset,

    input [WIDTH-1:0] in,
    output [WIDTH-1:0] out
);

    reg [WIDTH-1:0] r [0:DELAY];

    assign out = r[DELAY-1];

    integer i;

    always @(posedge clk) begin
        if (reset) begin
            for (i = 0; i < DELAY; i = i + 1) begin
                r[i] <= 0;
            end
        end else begin
            r[0] <= in;

            if (DELAY > 1) begin
                for (i = 1; i < DELAY; i = i + 1) begin
                    r[i] <= r[i - 1];
                end
            end
        end
    end

endmodule
module reset_generator #(
    parameter integer DURATION_EXPONENT = 8
) (
    input clk_1x,
    input clk_2x,
    input pll_locked,

    // (TODO: an actual user reset input, presumably from a button or otherwise)

    output reg reset_1x = 1,
    output reg reset_2x = 1
);
    reg pll_locked_r;

    always @(negedge clk_2x) begin
        pll_locked_r <= pll_locked;
    end

    reg [DURATION_EXPONENT:0] counter = 0;
    
    reg reset = 1;

    always @(negedge clk_2x) begin
        if (!pll_locked_r) begin
            counter <= 0;
            reset <= 1;
        end else begin
            if (!counter[DURATION_EXPONENT]) begin
                counter <= counter + 1;
            end else if (!clk_1x) begin
                // ensure that both reset_1x and reset_2x occur on the same rising edge
                reset <= 0;
            end
        end
    end

    always @(posedge clk_1x) begin
        reset_1x <= reset;
    end

    always @(posedge clk_2x) begin
        reset_2x <= reset;
    end

endmodule
module flash_arbiter(
    input clk,
    input reset,

    input [23:0] read_address_a,
    input read_en_a,
    input size_a,
    output reg ready_a,
    
    input [23:0] read_address_b,
    input read_en_b,
    input size_b,
    output reg ready_b,

    output [31:0] read_data,

    // QSPI flash
    
    output flash_clk_en,
    output flash_csn,
    output [3:0] flash_in,
    output [3:0] flash_in_en,
    input [3:0] flash_out
);
    localparam [23:0] FLASH_USER_BASE = 24'h200000;

    // --- Arbitration between reader A/B ---

    localparam [0:0]
        READER_A = 1,
        READER_B = 0;

    reg reader_selected;
    reg read_active;

    reg read_en_a_r, read_en_b_r;
    reg read_en_a_edge, read_en_b_edge;

    always @(posedge clk) begin
        read_en_a_r <= read_en_a;
        read_en_b_r <= read_en_b;
        read_en_a_edge <= (read_en_a && !read_en_a_r) || read_en_a_edge;
        read_en_b_edge <= (read_en_b && !read_en_b_r) || read_en_b_edge;

        ready_a <= 0;
        ready_b <= 0;

        // Is either reader waiting?

        if (!read_active) begin
            // Prioritize B if there is a double read in same cycle
            if (read_en_b_edge) begin
                reader_selected <= READER_B;
                read_active <= 1;
                read_en_b_edge <= 0;
            end else if (read_en_a_edge) begin
                reader_selected <= READER_A;
                read_active <= 1;
                read_en_a_edge <= 0;
            end
        end

        // Is read done?

        if (flash_ready) begin
            if (reader_selected == READER_A) begin
                ready_a <= 1;
            end else begin
                ready_b <= 1;
            end

            read_active <= 0;
        end

        if (reset) begin
            read_active <= 0;
        end
    end

    // --- Register flash reader inputs ---

    reg [23:0] flash_read_address;
    reg flash_read_en;
    reg flash_read_size;

    always @(posedge clk) begin
        flash_read_address <= (reader_selected ? read_address_a : read_address_b) + FLASH_USER_BASE;
        flash_read_en <= (reader_selected ? read_en_a : read_en_b) && read_active;
        flash_read_size <= (reader_selected ? size_a : size_b);
    end

    // --- Flash memory (16Mbyte - 1Mbyte) ---

    wire flash_ready;

    flash_reader flash_reader(
        .clk(clk),
        .reset(reset),

        .valid(flash_read_en),
        .size(flash_read_size),
        .address(flash_read_address),

        .data(read_data),
        .ready(flash_ready),
        
        .flash_clk_en(flash_clk_en),
        .flash_csn(flash_csn),
        .flash_out(flash_out),
        .flash_in(flash_in),
        .flash_in_en(flash_in_en)
    );

endmodule
module cop_ram(
    input clk,

    input [10:0] write_address,
    input [15:0] write_data,
    input write_en,

    input [10:0] read_address,
    output reg [15:0] read_data,
    input read_en
);
    reg [15:0] ram [0:2047];

    always @(posedge clk) begin
        if (write_en) begin
            ram[write_address] <= write_data[15:0];
        end

        if (read_en) begin
            read_data <= ram[read_address];
        end
    end

    wire has_contention =  read_en && write_en && read_address == write_address;

    always @(posedge clk) begin
        if (has_contention) begin
            $display("COP RAM contention: %x", read_address);
        end
    end

endmodule