dakies/OSS_Verilog huggingface dataset:
module AOI21_HPNW4 (Y, A0, A1, B0);
	output Y;
	input A0, A1, B0;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		(A0 => Y) = 0;
		(A1 => Y) = 0;
		if ((A0 & ~A1))
			(B0 => Y) = 0;
		if ((~A0 & A1))
			(B0 => Y) = 0;
		if ((~A0 & ~A1))
			(B0 => Y) = 0;
		ifnone (B0 => Y) = 0;
	endspecify
endmodule
module DFFNQ1_HPNW4 (Q, D, CKN);
	output Q;
	input D, CKN;
	reg notifier;
	wire delayed_D, delayed_CKN;
	// Missing function for pin Q
	// Timing
	specify
		(negedge CKN => (Q:CKN)) = 0;
		$setuphold (negedge CKN, posedge D, 0, 0, notifier,,, delayed_CKN, delayed_D);
		$setuphold (negedge CKN, negedge D, 0, 0, notifier,,, delayed_CKN, delayed_D);
		$width (posedge CKN, 0, 0, notifier);
		$width (negedge CKN, 0, 0, notifier);
	endspecify
endmodule
module DFFQ1_HPNW4 (Q, D, CK);
	output Q;
	input D, CK;
	reg notifier;
	wire delayed_D, delayed_CK;
	// Missing function for pin Q
	// Timing
	specify
		(posedge CK => (Q:CK)) = 0;
		$setuphold (posedge CK, posedge D, 0, 0, notifier,,, delayed_CK, delayed_D);
		$setuphold (posedge CK, negedge D, 0, 0, notifier,,, delayed_CK, delayed_D);
		$width (posedge CK, 0, 0, notifier);
		$width (negedge CK, 0, 0, notifier);
	endspecify
endmodule
module DFFQN1_HPNW4 (QN, D, CK);
	output QN;
	input D, CK;
	reg notifier;
	wire delayed_D, delayed_CK;
	// Missing function for pin QN
	// Timing
	specify
		(posedge CK => (QN:CK)) = 0;
		$setuphold (posedge CK, posedge D, 0, 0, notifier,,, delayed_CK, delayed_D);
		$setuphold (posedge CK, negedge D, 0, 0, notifier,,, delayed_CK, delayed_D);
		$width (posedge CK, 0, 0, notifier);
		$width (negedge CK, 0, 0, notifier);
	endspecify
endmodule
module INV1_HPNW4 (Y, A);
	output Y;
	input A;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		if (A)
			(posedge A => (Y-:1'b0)) = 0;
		if (~A)
			(negedge A => (Y+:1'b1)) = 0;
		ifnone (A => Y) = 0;
	endspecify
endmodule
module MUX2_HPNW4 (Y, A, B, S0);
	output Y;
	input A, B, S0;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		if (B)
			(A => Y) = 0;
		if (~B)
			(A => Y) = 0;
		ifnone (A => Y) = 0;
		if (A)
			(B => Y) = 0;
		if (~A)
			(B => Y) = 0;
		ifnone (B => Y) = 0;
		(posedge S0 => (Y:S0)) = 0;
		(negedge S0 => (Y:S0)) = 0;
	endspecify
endmodule
module MUXI2_HPNW4 (Y, A, B, S0);
	output Y;
	input A, B, S0;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		if (B)
			(A => Y) = 0;
		if (~B)
			(A => Y) = 0;
		ifnone (A => Y) = 0;
		if (A)
			(B => Y) = 0;
		if (~A)
			(B => Y) = 0;
		ifnone (B => Y) = 0;
		(posedge S0 => (Y:S0)) = 0;
		(negedge S0 => (Y:S0)) = 0;
	endspecify
endmodule
module NAND2_HPNW4 (Y, A, B);
	output Y;
	input A, B;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		(A => Y) = 0;
		(B => Y) = 0;
	endspecify
endmodule
module NOR2_HPNW4 (Y, A, B);
	output Y;
	input A, B;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		(A => Y) = 0;
		(B => Y) = 0;
	endspecify
endmodule
module OAI21_HPNW4 (Y, A0, A1, B0);
	output Y;
	input A0, A1, B0;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		(A0 => Y) = 0;
		(A1 => Y) = 0;
		if ((A0 & A1))
			(B0 => Y) = 0;
		if ((A0 & ~A1))
			(B0 => Y) = 0;
		if ((~A0 & A1))
			(B0 => Y) = 0;
		ifnone (B0 => Y) = 0;
	endspecify
endmodule
module OR2_HPNW4 (Y, A, B);
	output Y;
	input A, B;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		(A => Y) = 0;
		(B => Y) = 0;
	endspecify
endmodule
module XNOR2_HPNW4 (Y, A, B);
	output Y;
	input A, B;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		(posedge A => (Y:A)) = 0;
		(negedge A => (Y:A)) = 0;
		(posedge B => (Y:B)) = 0;
		(negedge B => (Y:B)) = 0;
	endspecify
endmodule
module XNOR3_HPNW4 (Y, A, B, C);
	output Y;
	input A, B, C;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		if ((B & ~C))
			(A => Y) = 0;
		if ((~B & C))
			(A => Y) = 0;
		ifnone (A => Y) = 0;
		if ((B & C))
			(A => Y) = 0;
		if ((~B & ~C))
			(A => Y) = 0;
		if ((A & ~C))
			(B => Y) = 0;
		if ((~A & C))
			(B => Y) = 0;
		ifnone (B => Y) = 0;
		if ((A & C))
			(B => Y) = 0;
		if ((~A & ~C))
			(B => Y) = 0;
		if ((A & ~B))
			(C => Y) = 0;
		if ((~A & B))
			(C => Y) = 0;
		ifnone (C => Y) = 0;
		if ((A & B))
			(C => Y) = 0;
		if ((~A & ~B))
			(C => Y) = 0;
	endspecify
endmodule
module XOR2_HPNW4 (Y, A, B);
	output Y;
	input A, B;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		(posedge A => (Y:A)) = 0;
		(negedge A => (Y:A)) = 0;
		(posedge B => (Y:B)) = 0;
		(negedge B => (Y:B)) = 0;
	endspecify
endmodule
module XOR3_HPNW4 (Y, A, B, C);
	output Y;
	input A, B, C;

	// Function
	buf (Y, 1'b0);

	// Timing
	specify
		if ((B & C))
			(A => Y) = 0;
		if ((~B & ~C))
			(A => Y) = 0;
		ifnone (A => Y) = 0;
		if ((B & ~C))
			(A => Y) = 0;
		if ((~B & C))
			(A => Y) = 0;
		if ((A & C))
			(B => Y) = 0;
		if ((~A & ~C))
			(B => Y) = 0;
		ifnone (B => Y) = 0;
		if ((A & ~C))
			(B => Y) = 0;
		if ((~A & C))
			(B => Y) = 0;
		if ((A & B))
			(C => Y) = 0;
		if ((~A & ~B))
			(C => Y) = 0;
		ifnone (C => Y) = 0;
		if ((A & ~B))
			(C => Y) = 0;
		if ((~A & B))
			(C => Y) = 0;
	endspecify
endmodule
module mapped_register(D, Q, CLK);
input D, CLK;
output Q;
wire B;
sky130_fd_sc_hd__dfxtp_1 fflop (.CLK(CLK), .D(D), .Q(B));
sky130_fd_sc_hd__buf_8 buffer (.A(B), .X(Q));
endmodule
module mapped_inverter(A, Y);
input A; output Y;
sky130_fd_sc_hd__inv_1 i(.A(A), .Y(Y));
endmodule
module GPIO (
  input clk,
  input rst,

  input  [31:0] io_addr,
  input         io_op,
  input  [3:0]  io_mask,
  input  [31:0] io_wdata,
  output [31:0] io_rdata,
  
  output [1:0] io_gpio
);

  reg [1:0] out_val;

  assign io_gpio = out_val;

  assign rdata = {30'h0, out_val};

  always @(posedge clk) begin
    if (rst) begin
      out_val <= 2'h0;
    end
    else begin
      if (io_op) begin
        out_val <= io_wdata[1:0];
      end
    end
  end

endmodule
module ALU (
  input  [`ALU_SEL_WIDTH-1:0] io_sel,
  input  [31:0] io_in_a, 
  input  [31:0] io_in_b,
  output [31:0] io_out
);
  
  wire [31:0] out_add, out_and, out_or, out_sll, out_slt, 
              out_sltu, out_sra, out_srl, out_sub, out_xor;

  wire signed [31:0] a_signed, b_signed;

  assign a_signed = io_in_a;
  assign b_signed = io_in_b;

  assign out_add  = io_in_a + io_in_b;
  assign out_sub  = io_in_a - io_in_b;
  assign out_sll  = io_in_a << io_in_b[4:0];
  assign out_slt  = (a_signed < b_signed) ? 'h01 : 'h00;
  assign out_sltu = (io_in_a < io_in_b) ? 'h01 : 'h00;
  assign out_xor  = io_in_a ^ io_in_b;
  assign out_srl  = io_in_a >> io_in_b[4:0];
  assign out_sra  = a_signed >>> io_in_b[4:0];
  assign out_or   = io_in_a | io_in_b;
  assign out_and  = io_in_a & io_in_b;

  assign io_out = (
    (io_sel == `ALU_SEL_ADD)  ? out_add  :
    (io_sel == `ALU_SEL_SUB)  ? out_sub  :
    (io_sel == `ALU_SEL_SLL)  ? out_sll  :
    (io_sel == `ALU_SEL_SRL)  ? out_srl  :
    (io_sel == `ALU_SEL_SRA)  ? out_sra  :
    (io_sel == `ALU_SEL_AND)  ? out_and  :
    (io_sel == `ALU_SEL_OR)   ? out_or   :
    (io_sel == `ALU_SEL_XOR)  ? out_xor  :
    (io_sel == `ALU_SEL_SLT)  ? out_slt  :
    (io_sel == `ALU_SEL_SLTU) ? out_sltu :
    (io_sel == `ALU_SEL_COPYB) ? io_in_b :
    'h0);
  
endmodule
module Tile (
  input clk,
  input rst,

  output [3:0] led
);

  wire clk;
  wire rst;

  wire         io_interrupt;

  wire  [3:0]  io_hart_id;
  wire  [31:0] io_reset_vector;

  parameter DMEM_BASE = 32'h08000000;
  parameter GPIO_BASE = 32'h10010000;

  wire [31:0] imem_addr;
  wire [31:0] imem_rdata;

  wire [31:0] dmem_addr;
  wire        dmem_op;
  wire [3:0]  dmem_mask;
  wire [31:0] dmem_wdata;
  wire [31:0] dmem_rdata;

  wire        dmem_mem_op;
  wire        dmem_gpio_op;

  wire [31:0] dmem_mem_addr;
  wire [31:0] dmem_mem_rdata;
  wire [31:0] dmem_gpio_addr;
  wire [31:0] dmem_gpio_rdata;

  wire gpio_selected = (dmem_addr >= GPIO_BASE) && (dmem_addr < GPIO_BASE + 'h1000);
  wire dmem_selected = (dmem_addr >= DMEM_BASE) && (dmem_addr < DMEM_BASE + 'h1000);

  assign dmem_rdata = gpio_selected ? dmem_gpio_rdata : dmem_mem_rdata;
  assign dmem_mem_op = dmem_selected ? dmem_op : 1'b0;
  assign dmem_gpio_op = gpio_selected ? dmem_op : 1'b0;

  assign dmem_mem_addr = dmem_addr - DMEM_BASE;
  assign dmem_gpio_addr = dmem_addr - GPIO_BASE;
  

  Core core (
    .clk(clk),
    .rst(rst),

    .io_interrupt(io_interrupt),
    .io_hart_id(io_hart_id),
    .io_reset_vector(io_reset_vector),

    .io_imem_addr(imem_addr),
    .io_imem_rdata(imem_rdata),
    .io_dmem_addr(dmem_addr),
    .io_dmem_op(dmem_op),
    .io_dmem_mask(dmem_mask),
    .io_dmem_wdata(dmem_wdata),
    .io_dmem_rdata(dmem_rdata)
  );

  ROM imem (
    .clk(clk),
    .addr(imem_addr[15:2]),
    .dout(imem_rdata)
  );

  RAM_Simple dmem (
    .clk(clk),
    .addr(dmem_mem_addr[15:2]),
    .op(dmem_mem_op),
    .mask(dmem_mask),
    .wdata(dmem_wdata),
    .rdata(dmem_mem_rdata)
  );

  GPIO gpio (
    .clk(clk),
    .rst(rst),

    .io_addr(dmem_gpio_addr),
    .io_op(dmem_gpio_op),
    .io_mask(dmem_mask),
    .io_wdata(dmem_wdata),
    .io_rdata(dmem_gpio_rdata),
    
    .io_gpio(led[1:0])
  );

  assign led[2] = 1'b1;
  assign led[3] = 1'b0;


endmodule
module Core (
  input clk,
  input rst,

  input         io_interrupt,
  input  [3:0]  io_hart_id,
  input  [31:0] io_reset_vector,

  output [31:0]               io_imem_addr,
  input  [31:0]               io_imem_rdata,
  output [31:0]               io_dmem_addr,
  output [`MEM_OP_WIDTH-1:0]  io_dmem_op,
  output [3:0]                io_dmem_mask,
  output [31:0]               io_dmem_wdata,
  input  [31:0]               io_dmem_rdata
);

wire [1:0]                  dmem_addr_offset;

wire                        ctl_stall;
wire [`PC_SEL_WIDTH-1:0]    ctl_pc_sel;
wire [`IMM_SEL_WIDTH-1:0]   ctl_imm_sel;
wire                        ctl_op1_sel;
wire                        ctl_op2_sel;
wire [`ALU_SEL_WIDTH-1:0]   ctl_alu_sel;
wire                        ctl_mem_signed;
wire [`WB_SEL_WIDTH-1:0]    ctl_wb_sel;
wire                        ctl_rf_wen;

wire [31:0] dat_inst;
wire        dat_br_eq;
wire        dat_br_lt;
wire        dat_br_ltu;

assign dmem_addr_offset = io_dmem_addr[1:0];


ControlPath ctrlpath (
  .clk(clk),
  .rst(rst),

  .io_dmem_addr_offset(dmem_addr_offset),
  .io_dmem_op(io_dmem_op),
  .io_dmem_mask(io_dmem_mask),

  .io_ctl_stall(ctl_stall),
  .io_ctl_pc_sel(ctl_pc_sel),
  .io_ctl_imm_sel(ctl_imm_sel),
  .io_ctl_op1_sel(ctl_op1_sel),
  .io_ctl_op2_sel(ctl_op2_sel),
  .io_ctl_alu_sel(ctl_alu_sel),
  .io_ctl_mem_signed(ctl_mem_signed),
  .io_ctl_wb_sel(ctl_wb_sel),
  .io_ctl_rf_wen(ctl_rf_wen),

  .io_dat_inst(dat_inst),
  .io_dat_br_eq(dat_br_eq),
  .io_dat_br_lt(dat_br_lt),
  .io_dat_br_ltu(dat_br_ltu)
);

DataPath datapath (
  .clk(clk),
  .rst(rst),
  
  .io_interrupt(io_interrupt),
  .io_hart_id(io_hart_id),
  .io_reset_vector(io_reset_vector),

  .io_imem_addr(io_imem_addr),
  .io_imem_rdata(io_imem_rdata),
  .io_dmem_addr(io_dmem_addr),
  .io_dmem_mask(io_dmem_mask),
  .io_dmem_wdata(io_dmem_wdata),
  .io_dmem_rdata(io_dmem_rdata),

  .io_ctl_stall(ctl_stall),
  .io_ctl_pc_sel(ctl_pc_sel),
  .io_ctl_imm_sel(ctl_imm_sel),
  .io_ctl_op1_sel(ctl_op1_sel),
  .io_ctl_op2_sel(ctl_op2_sel),
  .io_ctl_alu_sel(ctl_alu_sel),
  .io_ctl_mem_signed(ctl_mem_signed),
  .io_ctl_wb_sel(ctl_wb_sel),
  .io_ctl_rf_wen(ctl_rf_wen),

  .io_dat_inst(dat_inst),
  .io_dat_br_eq(dat_br_eq),
  .io_dat_br_lt(dat_br_lt),
  .io_dat_br_ltu(dat_br_ltu)
);

endmodule
module RegFile (
  input         clk,
  input  [4:0]  io_rd_addr,
  input         io_rd_wen,
  input  [31:0] io_rd_data,
  
  input  [4:0]  io_rs1_addr,
  output [31:0] io_rs1_data,
  input  [4:0]  io_rs2_addr,
  output [31:0] io_rs2_data
);

  (* ram_style = "distributed" *) reg [31:0] mem[31-1:0];
  
  always @(posedge clk) begin
    if (io_rd_wen && (io_rd_addr !== 'h0)) begin
      mem[io_rd_addr-1] <= io_rd_data;
    end
  end

  assign io_rs1_data = io_rs1_addr !== 'h0 ? mem[io_rs1_addr-1] : 'h0;
  assign io_rs2_data = io_rs2_addr !== 'h0 ? mem[io_rs2_addr-1] : 'h0;

endmodule
module Top (
  input CLK100MHZ,
  input ck_rst,

  output [3:0] led
);

  wire clk;
  wire rst;

  assign rst = ~ck_rst;
  
  clk_wiz_0 clk_wiz_0 (
    .clk_out1(clk),
    .reset(rst),
    .clk_in1(CLK100MHZ)
 );

  Tile tile (
    .clk(clk),
    .rst(rst),

    // .io_interrupt(io_interrupt),
    // .io_hart_id(io_hart_id),
    // .io_reset_vector(io_reset_vector),

    .led(led)
  );


endmodule
module Register (q, d, clk);
  parameter N = 1;
  input            clk;
  output reg [N-1:0] q;
  input      [N-1:0] d;
  initial q = {N{1'b0}};
  always @(posedge clk)
    q <= d;
endmodule // REGISTER
module Register_CE (q, d, ce, clk);
  parameter N = 1;
  input            clk;
  output reg [N-1:0] q;
  input      [N-1:0] d;
  input 	          ce;
  initial q = {N{1'b0}};
  always @(posedge clk)
    if (ce) q <= d;
endmodule // REGISTER_CE
module Register_R (q, d, rst, clk);
  parameter N = 1;
  parameter INIT = {N{1'b0}};
  input            clk;
  input            rst;
  output reg [N-1:0] q;
  input      [N-1:0] d;
  initial q = INIT;
  always @(posedge clk)
    if (rst) q <= INIT;
    else q <= d;
endmodule // REGISTER_R
module Register_R_CE (q, d, rst, ce, clk);
  parameter N = 1;
  parameter INIT = {N{1'b0}};
  input            clk;
  input            rst;
  output reg [N-1:0] q;
  input      [N-1:0] d;
  input 	          ce;
  initial q = INIT;
  always @(posedge clk)
    if (rst) q <= INIT;
    else if (ce) q <= d;
endmodule // REGISTER_R_CE
module ROM #(
  parameter DEPTH = 16384
)(
    input         clk,
    input  [11:0] addr,
    output [31:0] dout
);
  
  reg [31:0] mem [DEPTH-1:0];

  assign dout = mem[addr];

  initial begin
    $readmemh("/scratch/vivado_projects/BAD-RISCV-CPU/BA20X-Verilog/software/firmware.mem", mem);
  end

endmodule
module RAM_Simple #(
  parameter DEPTH = 16384
)(
   input clk,

   input  [13:0]  addr,
   input          op,
   input  [3:0]   mask,
   input  [31:0]  wdata,
   output [31:0]  rdata
);
  // See page 133 of the Vivado Synthesis Guide for the template
  // https://www.xilinx.com/support/documentation/sw_manuals/xilinx2016_4/ug901-vivado-synthesis.pdf

  reg [31:0] mem [DEPTH-1:0];

  assign rdata = mem[addr];

  always @(posedge clk) begin  
    if (op == 'b1) begin
      mem[addr] <= (
        (mask == 'b1111) ? wdata :
        (mask == 'b0011) ? {mem[addr][31:16], wdata[15:0]} :
        (mask == 'b1100) ? {wdata[31:16], mem[addr][15:0]} :
        (mask == 'b0001) ? {mem[addr][31:8], wdata[7:0]} :
        (mask == 'b0010) ? {mem[addr][31:16], wdata[15:8], mem[addr][7:0]} :
        (mask == 'b0100) ? {mem[addr][31:24], wdata[23:16], mem[addr][15:0]} :
        (mask == 'b1000) ? {wdata[31:24], mem[addr][23:0]} :
        mem[addr]
      );
    end
  end
endmodule
module ram_true_dual #(parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 5, parameter DISTR = 0) (clka,clkb,ena,enb,wea,web,addra,addrb,dia,dib,doa,dob);

   parameter DEPTH = 2**ADDR_WIDTH;

   input clka,clkb,ena,enb,wea,web;
   input [ADDR_WIDTH-1:0] addra,addrb;
   input [DATA_WIDTH-1:0] dia,dib;
   output [DATA_WIDTH-1:0] doa,dob;
   reg [DATA_WIDTH-1:0] doa,dob;


   generate
     if (DISTR) begin : distributed_ram
       (* ram_style = "distributed" *)reg [DATA_WIDTH-1:0] ram [DEPTH-1:0];
       integer i;
       initial for (i=0; i<DEPTH; i=i+1) ram[i] = 0;

       always @(posedge clka)
       begin
         if (ena)
           begin
             if (wea)
               ram[addra] <= dia;
             doa <= ram[addra];
           end 
       end

       always @(posedge clkb)
       begin
         if (enb)
           begin
             if (web)
               ram[addrb] <= dib;
             dob <= ram[addrb];
           end
       end
     end

     else begin : block_ram
       integer i;
       reg [DATA_WIDTH-1:0] ram [DEPTH-1:0];
       initial for (i=0; i<DEPTH; i=i+1) ram[i] = 0;

       always @(posedge clka)
       begin
         if (ena)
           begin
             if (wea)
               ram[addra] <= dia;
             doa <= ram[addra];
           end 
       end

       always @(posedge clkb)
       begin
         if (enb)
           begin
             if (web)
               ram[addrb] <= dib;
             dob <= ram[addrb];
           end
       end
     end
   endgenerate


endmodule
module brdg_axi_slave_cmd_fifo (
          clk,
         rst_n,

         axi_id,
         axi_addr,
         axi_len,
         axi_size,
         axi_burst,
         axi_user,
         cf_id,
         cf_addr,
         cf_len,
         cf_size,
         cf_burst,
         cf_user,

         cf_wr_en,
         cf_almost_full,
         cf_full,
         cf_empty,
         cf_rd_en
);

input                     clk;
input                     rst_n;

input      [`IDW-1:0]      axi_id;
input      [63:0]         axi_addr;
input      [7:0]          axi_len;
input      [2:0]          axi_size;
input      [1:0]          axi_burst;
input      [`CTXW-1:0]     axi_user;

output     [`IDW-1:0]      cf_id;
output     [63:0]         cf_addr;
output     [7:0]          cf_len;
output     [2:0]          cf_size;
output     [1:0]          cf_burst;
output     [`CTXW-1:0]     cf_user;

input                     cf_wr_en; //There is a valid cmd

output                    cf_almost_full;
output                    cf_full;
output                    cf_empty;
input                     cf_rd_en;




wire [`IDW + 64 + 8 + 3 + 2 + `CTXW - 1:0] din;
wire [`IDW + 64 + 8 + 3 + 2 + `CTXW - 1:0] dout;

assign din = {axi_id, axi_len, axi_size, axi_burst, axi_user, axi_addr};
assign {cf_id, cf_len, cf_size, cf_burst, cf_user,  cf_addr} = dout; 

//`IDW=5, `CTXW=9
//5 + 64 + 8 + 3 + 2 + 9 = 91


        //axicf_sync_fifo_16_91i91o axicfifo(
        fifo_sync          # (.DATA_WIDTH (91),
                              .ADDR_WIDTH (4), 
                              .FWFT (1)
                              ) axicfifo 
                                     (
                                     .clk        (clk                      ),
                                     .rst_n      (rst_n                    ),
                                     .din        (din                      ),
                                     .wr_en      (cf_wr_en                 ),
                                     .rd_en      (cf_rd_en                 ),
                                     .dout       (dout                     ),
                                     .valid      (                         ),
                                     .full       (cf_full                  ),
                                     .almost_full(cf_almost_full           ),
                                     .almost_empty (                       ),
                                     .count      (                         ),
                                     .empty      (cf_empty                 )
                                     );


endmodule
module ram_simple_dual #(parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 5, parameter DISTR = 0) (clk,ena,enb,wea,addra,addrb,dia,dob);

   parameter DEPTH = 2**ADDR_WIDTH;

   input clk,ena,enb,wea;
   input [ADDR_WIDTH-1:0] addra,addrb;
   input [DATA_WIDTH-1:0] dia;
   output [DATA_WIDTH-1:0] dob;
   reg [DATA_WIDTH-1:0] ram [DEPTH-1:0];
   reg [DATA_WIDTH-1:0] dob;
  

   generate
     if (DISTR) begin : distributed_ram
       (* ram_style = "distributed" *)reg [DATA_WIDTH-1:0] ram [DEPTH-1:0];
       integer i;
       initial for (i=0; i<DEPTH; i=i+1) ram[i] = 0;

       always @(posedge clk) begin
        if (ena) begin
           if (wea)
               ram[addra] <= dia;
       end end

       always @(posedge clk) begin
         if (enb)
           dob <= ram[addrb];
       end
     end

     else begin : block_ram
       reg [DATA_WIDTH-1:0] ram [DEPTH-1:0];
       integer i;
       initial for (i=0; i<DEPTH; i=i+1) ram[i] = 0;

       always @(posedge clk) begin
        if (ena) begin
           if (wea)
               ram[addra] <= dia;
       end end

       always @(posedge clk) begin
         if (enb)
           dob <= ram[addrb];
       end
     end
   endgenerate


endmodule
module ram_single_port (clk, we, addr, data_in, data_out);

   parameter DATA_WIDTH = 8;
   parameter ADDR_WIDTH = 5;
   parameter DEPTH = 2**ADDR_WIDTH;

   input clk, we;
   input [ADDR_WIDTH-1:0] addr;
   input [DATA_WIDTH-1:0] data_in;
   output [DATA_WIDTH-1:0] data_out;

   reg [DATA_WIDTH-1:0] ram [DEPTH-1:0];
  
   reg [ADDR_WIDTH-1:0] addr_reg;
   integer i;
   initial for (i=0; i<DEPTH; i=i+1) ram[i] = 0;

   always @(posedge clk) begin
       addr_reg <= addr;
       if (we) 
           ram[addr] <= data_in;
   end

   assign data_out = ram[addr_reg];


/////  clk ___^^^___^^^___^^^___^^^___^^^___
//
//      we ___^^^^^^______^^^^^^^^^^^^______
//      di ___XXXXXX______YYYYYYZZZZZZ______
//    addr ___AAAAAA______BBBBBBCCCCCC______
//addr_reg _________AAAAAA______BBBBBBCCCCCC
//      do _________XXXXXX______YYYYYYZZZZZZ

endmodule
module top(
	input CLK,
	output LEDR_N,
	output LEDG_N,
	output LED1,
	output LED2,
	output LED3,
	output LED4,
	output LED5
);

// Create reset signal 16 clocks long
reg reset = 1'b1;
reg [3:0] reset_cnt = 0;
always @(posedge CLK)
begin
	reset <= (reset_cnt != 15);
	reset_cnt <= reset_cnt + (reset_cnt != 15);
end

// Map 7 LEDs that exists on icebreaker board
wire [31:0] leds;
assign { LEDR_N, LEDG_N, LED1, LED2, LED3, LED4, LED5 } = {~leds[6:5], leds[4:0]};

nervsoc soc (
	.clock(CLK),
	.reset(reset),
	.leds(leds)
);

endmodule
module riscv_rv32i_insn (
	input [31:0] insn,
	output reg valid
);
	always @* begin
		valid = 0;

		if (insn[6:0] == 7'b 01_101_11) valid = 1; // LUI
		if (insn[6:0] == 7'b 00_101_11) valid = 1; // AUIPC
		if (insn[6:0] == 7'b 11_011_11) valid = 1; // JAL

		if (insn[6:0] == 7'b 11_001_11) begin // JALR
			valid = insn[14:12] == 3'b 000;
		end

		if (insn[6:0] == 7'b 11_000_11) begin // BRANCH
			valid = (insn[14:12] != 3'b 010) && (insn[14:12] != 3'b 011);
		end

		if (insn[6:0] == 7'b 00_000_11) begin // LOAD
			valid = (insn[14:12] != 3'b 011) && (insn[14:12] != 3'b 110) && (insn[14:12] != 3'b 111);
		end

		if (insn[6:0] == 7'b 01_000_11) begin // STORE
			valid = (insn[14:12] == 3'b 000) || (insn[14:12] == 3'b 001) || (insn[14:12] == 3'b 010);
		end

		if (insn[6:0] == 7'b 00_100_11) begin // OP-IMM
			case (insn[14:12])
				3'b 001: begin // SLLI
					valid = insn[31:25] == 7'b 0000000;
				end
				3'b 101: begin // SRLI SRAI
					valid = (insn[31:25] == 7'b 0000000) || (insn[31:25] == 7'b 0100000);
				end
				default: begin
					valid = 1;
				end
			endcase
		end

		if (insn[6:0] == 7'b 01_100_11) begin // OP
			case (insn[14:12])
				3'b 000, 3'b 101: begin // ADD SUB SRL SRA
					valid = (insn[31:25] == 7'b 0000000) || (insn[31:25] == 7'b 0100000);
				end
				default: begin
					valid = insn[31:25] == 7'b 0000000;
				end
			endcase
		end
	end
endmodule
module riscv_rv64i_insn (
	input [31:0] insn,
	output reg valid
);
	always @* begin
		valid = 0;

		if (insn[6:0] == 7'b 01_101_11) valid = 1; // LUI
		if (insn[6:0] == 7'b 00_101_11) valid = 1; // AUIPC
		if (insn[6:0] == 7'b 11_011_11) valid = 1; // JAL

		if (insn[6:0] == 7'b 11_001_11) begin // JALR
			valid = insn[14:12] == 3'b 000;
		end

		if (insn[6:0] == 7'b 11_000_11) begin // BRANCH
			valid = (insn[14:12] != 3'b 010) && (insn[14:12] != 3'b 011);
		end

		if (insn[6:0] == 7'b 00_000_11) begin // LOAD
			valid = (insn[14:12] != 3'b 111);
		end

		if (insn[6:0] == 7'b 01_000_11) begin // STORE
			valid = (insn[14:12] == 3'b 000) || (insn[14:12] == 3'b 001) || (insn[14:12] == 3'b 010) || (insn[14:12] == 3'b 011);
		end

		if (insn[6:0] == 7'b 00_100_11) begin // OP-IMM
			case (insn[14:12])
				3'b 001: begin // SLLI
					valid = insn[31:26] == 6'b 000000;
				end
				3'b 101: begin // SRLI SRAI
					valid = (insn[31:26] == 6'b 000000) || (insn[31:26] == 6'b 010000);
				end
				default: begin
					valid = 1;
				end
			endcase
		end

		if (insn[6:0] == 7'b 01_100_11) begin // OP
			case (insn[14:12])
				3'b 000, 3'b 101: begin // ADD SUB SRL SRA
					valid = (insn[31:25] == 7'b 0000000) || (insn[31:25] == 7'b 0100000);
				end
				default: begin
					valid = insn[31:25] == 7'b 0000000;
				end
			endcase
		end

		if (insn[6:0] == 7'b 00_110_11) begin // OP-IMM-32
			case (insn[14:12])
				3'b 001: begin // SLLIW
					valid = insn[31:25] == 7'b 0000000;
				end
				3'b 101: begin // SRLIW SRAIW
					valid = (insn[31:25] == 7'b 0000000) || (insn[31:25] == 7'b 0100000);
				end
				3'b 000: begin // ADDIW
					valid = 1;
				end
			endcase
		end

		if (insn[6:0] == 7'b 01_110_11) begin // OP-32
			case (insn[14:12])
				3'b 000, 3'b 101: begin // ADDW SUBW SRLW SRAW
					valid = (insn[31:25] == 7'b 0000000) || (insn[31:25] == 7'b 0100000);
				end
				3'b 001: begin // SLLW
					valid = insn[31:25] == 7'b 0000000;
				end
			endcase
		end
	end
endmodule
module xyloni
(
  input BTN1,
  input BTN2_J2_7,
  input [14:0] GPIO_J1_IN,
  input [13:0] GPIO_J2_IN,
  input [8:0] GPIO_J3_IN,
  input RXD,
  input SD_DI,
  input SPI_MISO,
  input i_sysclk,
  input i_pll_locked,
  output [14:0] GPIO_J1_OUT,
  output [14:0] GPIO_J1_OE,
  output [13:0] GPIO_J2_OUT,
  output [13:0] GPIO_J2_OE,
  output [8:0] GPIO_J3_OUT,
  output [8:0] GPIO_J3_OE,
  output LED1,
  output LED2,
  output LED3_J2_6,
  output LED4_J2_5,
  output SD_CS,
  output SD_DO,
  output SD_SCLK,
  output SPI_MOSI,
  output SPI_SCLK,
  output SPI_SS,
  output TXD
);


endmodule
module rgb_to_cymk
#(
	parameter	COLOR_PRECISION	= 8
)
(
	input	i_arst,
	input	i_sysclk,
	
	input	[COLOR_PRECISION-1:0]i_R,
	input	[COLOR_PRECISION-1:0]i_G,
	input	[COLOR_PRECISION-1:0]i_B,
	
	output	[COLOR_PRECISION-1:0]o_C,
	output	[COLOR_PRECISION-1:0]o_M,
	output	[COLOR_PRECISION-1:0]o_Y,
	output	[COLOR_PRECISION-1:0]o_K
);

reg		[COLOR_PRECISION-1:0]r_R_1P, r_G_1P, r_B_1P, r_K_1P;
reg		[COLOR_PRECISION-1:0]r_R_2P, r_G_2P, r_B_2P, r_K_2P;
reg		[COLOR_PRECISION-1:0]r_C_3P, r_M_3P, r_Y_3P, r_K_3P;

always@(posedge i_arst or posedge i_sysclk)
begin
	if (i_arst)
	begin
	end
	else
	begin
		if (i_R > i_G)
			r_K_1P	<= i_R;
		else
			r_K_1P	<= i_G;
		
		if (r_B_1P > r_K_1P)
			r_K_2P	<= {COLOR_PRECISION{1'b1}} - r_B_1P;
		else
			r_K_2P	<= {COLOR_PRECISION{1'b1}} - r_K_1P;
		
		r_C_3P	<= r_R_2P - r_K_2P;
		r_M_3P	<= r_G_2P - r_K_2P;
		r_Y_3P	<= r_B_2P - r_K_2P;
	end
end

endmodule
module jfif_parser
#(
	parameter	SOS_CNT_W	= 4
)
(
	input	i_arst,
	input	i_sysclk,
`ifdef DBG_MODE
	output	[1:0]o_sos_status,
`endif
	
	input	i_byte_en,
	input	[7:0]i_byte,
	output	o_jfif_ready,
	output	o_jfif_eoi,
	
	input	i_sos_re,
	output	o_sos_start,
	output	[15:0]o_sos_width,
	output	[15:0]o_sos_height,
	output	o_sos_scan_en,
	output	o_sos_ecs_bit
);

sos_parser
#(
	.CNT_W		(SOS_CNT_W)
)
inst_sos_parser
(
	.i_arst		(i_arst),
	.i_sysclk	(i_sysclk),
`ifdef DBG_MODE
	.o_scan_status	(o_sos_status),
`endif
	
	.i_byte_en	(i_byte_en),
	.i_byte		(i_byte),
	.o_ready	(o_jfif_ready),
	.o_eoi		(o_jfif_eoi),
	
	.i_re		(i_sos_re),
	.o_start	(o_sos_start),
	.o_width	(o_sos_width),
	.o_height	(o_sos_height),
	.o_scan_en	(o_sos_scan_en),
	.o_ecs_bit	(o_sos_ecs_bit)
);

endmodule
module subsampling
#(
	parameter	XI_SUBSAMPLE	= 1,
	parameter	YI_SUBSAMPLE	= 1,
	parameter	XO_SUBSAMPLE	= 2,
	parameter	YO_SUBSAMPLE	= 2,
	parameter	MCU_WIDTH		= 8,
	parameter	MCU_HEIGHT		= 8,
	parameter	COLOR_PRECISION	= 8,
	parameter	REGISTER		= "YES"
)
(
	input	i_arst,
	input	i_sysclk,
	input	i_we,
	input	[COLOR_PRECISION-1:0]i_color,
	output	o_we,
	output	[COLOR_PRECISION-1:0]o_color
);

function integer log2;
	input	integer	val;
	integer	i;
	begin
		log2 = 0;
		for (i=0; 2**i<val; i=i+1)
			log2 = i+1;
	end
endfunction

wire	w_x_subsample;
wire	w_y_subsample;
wire	[log2(MCU_WIDTH)-1:0]w_mcu_width;
wire	[log2(MCU_HEIGHT)-1:0]w_mcu_height;

reg		r_x_1P;
reg		r_y_1P;
reg		[log2(MCU_WIDTH)-1:0]r_w_1P;
reg		[log2(MCU_HEIGHT)-1:0]r_h_1P;
reg		r_we_1P;
reg		[COLOR_PRECISION-1:0]r_color_1P;

wire	w_we_0P;
wire	[COLOR_PRECISION-1:0]w_color_0P;

assign	w_x_subsample	= XO_SUBSAMPLE/XI_SUBSAMPLE-1'b1;
assign	w_y_subsample	= YO_SUBSAMPLE/YI_SUBSAMPLE-1'b1;
assign	w_mcu_width		= MCU_WIDTH-1'b1;
assign	w_mcu_height	= MCU_HEIGHT-1'b1;

assign	w_we_0P		= (r_y_1P == 1'b0 && r_x_1P == 1'b0)?
						i_we:1'b0;
assign	w_color_0P	= i_color;

always@(posedge i_arst or posedge i_sysclk)
begin
	if (i_arst)
	begin
		r_x_1P		<= 1'b0;
		r_y_1P		<= 1'b0;
		r_w_1P		<= {log2(MCU_WIDTH){1'b0}};
		r_h_1P		<= {log2(MCU_HEIGHT){1'b0}};
		r_we_1P		<= 1'b0;
		r_color_1P	<= {COLOR_PRECISION{1'b0}};
	end
	else
	begin
		if (i_we)
		begin
			r_x_1P	<= r_x_1P+1'b1;
			r_w_1P	<= r_w_1P+1'b1;
			if (r_x_1P == w_x_subsample)
				r_x_1P	<= 1'b0;
			
			if (r_w_1P == w_mcu_width)
			begin
				r_w_1P	<= {log2(MCU_WIDTH){1'b0}};
				r_y_1P	<= r_y_1P+1'b1;
				r_h_1P	<= r_h_1P+1'b1;
				if (r_y_1P == w_y_subsample)
					r_y_1P	<= 1'b0;
				if (r_h_1P == w_mcu_height)
					r_h_1P	<= {log2(MCU_HEIGHT){1'b0}};
			end
		end
		
		r_we_1P		<= w_we_0P;
		r_color_1P	<= w_color_0P;
	end
end

generate
	if (REGISTER == "YES")
	begin
		assign	o_we	= r_we_1P;
		assign	o_color	= r_color_1P;
	end
	else
	begin
		assign	o_we	= w_we_0P;
		assign	o_color	= w_color_0P;
	end
endgenerate

endmodule
module accumulator
#(
	parameter	A_IN_PRECISION	= 16,
	parameter	B_IN_PRECISION	= 10,
	parameter	O_OUT_PRECISION	= 8,
	parameter	MULT_LATENCY	= 0
)
(
	input	i_arst,
	input	i_sysclk,
	input	i_en,
	input	i_load,
	input	[A_IN_PRECISION-1:0]i_a,
	input	[B_IN_PRECISION-1:0]i_b,
	output	o_en,
	output	[O_OUT_PRECISION:0]o_O
);

wire	[A_IN_PRECISION+B_IN_PRECISION-1:0]w_mult_out;
reg		r_en_1P;
reg		[A_IN_PRECISION+B_IN_PRECISION-8-1:0]r_adder_1P;

mult_a_signed_b_signed
#(
	.A_WIDTH(A_IN_PRECISION),
	.B_WIDTH(B_IN_PRECISION),
	.LATENCY(MULT_LATENCY)
)
inst_mult
(
	.arst	(i_arst),
	.clk	(i_sysclk),
	.a		(i_a),
	.b		(i_b),
	.o		(w_mult_out)
);

always@(posedge i_arst or posedge i_sysclk)
begin
	if (i_arst)
	begin
		r_en_1P		<= 1'b0;
		r_adder_1P	<= {A_IN_PRECISION+B_IN_PRECISION-8{1'b0}};
	end
	else
	begin
		r_en_1P	<= i_en;
		if (i_en)
		begin
			if (i_load)
				r_adder_1P	<= w_mult_out[A_IN_PRECISION+B_IN_PRECISION-1:8];
			else
				r_adder_1P	<= r_adder_1P+w_mult_out[A_IN_PRECISION+B_IN_PRECISION-1:8];
		end
	end
end

assign	o_en	= r_en_1P;
assign	o_O		= r_adder_1P[O_OUT_PRECISION+2:2];

endmodule
module dct
(
	input	[2:0]i_Gxy,
	input	[2:0]i_Buv,
	output	[8:0]o_dct
);

wire	[8:0]w_dct[0:63];

wire	[8:0]w_p9807, w_p9238, w_p8314, w_p7071, w_p5555, w_p3826, w_p1950;
wire	[8:0]w_n9807, w_n9238, w_n8314, w_n7071, w_n5555, w_n3826, w_n1950;

assign	w_p9807	= 9'd251;
assign	w_p9238	= 9'd237;
assign	w_p8314	= 9'd213;
assign	w_p7071	= 9'd181;
assign	w_p5555	= 9'd142;
assign	w_p3826	= 9'd98;
assign	w_p1950	= 9'd50;

assign	w_n9807	= ~w_p9807+1'b1;
assign	w_n9238	= ~w_p9238+1'b1;
assign	w_n8314	= ~w_p8314+1'b1;
assign	w_n7071	= ~w_p7071+1'b1;
assign	w_n5555	= ~w_p5555+1'b1;
assign	w_n3826	= ~w_p3826+1'b1;
assign	w_n1950	= ~w_p1950+1'b1;

assign	w_dct[0]	= w_p7071;
assign	w_dct[1]	= w_p9807;
assign	w_dct[2]	= w_p9238;
assign	w_dct[3]	= w_p8314;
assign	w_dct[4]	= w_p7071;
assign	w_dct[5]	= w_p5555;
assign	w_dct[6]	= w_p3826;
assign	w_dct[7]	= w_p1950;

assign	w_dct[8]	= w_p7071;
assign	w_dct[9]	= w_p8314;
assign	w_dct[10]	= w_p3826;
assign	w_dct[11]	= w_n1950;
assign	w_dct[12]	= w_n7071;
assign	w_dct[13]	= w_n9807;
assign	w_dct[14]	= w_n9238;
assign	w_dct[15]	= w_n5555;

assign	w_dct[16]	= w_p7071;
assign	w_dct[17]	= w_p5555;
assign	w_dct[18]	= w_n3826;
assign	w_dct[19]	= w_n9807;
assign	w_dct[20]	= w_n7071;
assign	w_dct[21]	= w_p1950;
assign	w_dct[22]	= w_p9238;
assign	w_dct[23]	= w_p8314;

assign	w_dct[24]	= w_p7071;
assign	w_dct[25]	= w_p1950;
assign	w_dct[26]	= w_n9238;
assign	w_dct[27]	= w_n5555;
assign	w_dct[28]	= w_p7071;
assign	w_dct[29]	= w_p8314;
assign	w_dct[30]	= w_n3826;
assign	w_dct[31]	= w_n9807;

assign	w_dct[32]	= w_p7071;
assign	w_dct[33]	= w_n1950;
assign	w_dct[34]	= w_n9238;
assign	w_dct[35]	= w_p5555;
assign	w_dct[36]	= w_p7071;
assign	w_dct[37]	= w_n8314;
assign	w_dct[38]	= w_n3826;
assign	w_dct[39]	= w_p9807;

assign	w_dct[40]	= w_p7071;
assign	w_dct[41]	= w_n5555;
assign	w_dct[42]	= w_n3826;
assign	w_dct[43]	= w_p9807;
assign	w_dct[44]	= w_n7071;
assign	w_dct[45]	= w_n1950;
assign	w_dct[46]	= w_p9238;
assign	w_dct[47]	= w_n8314;

assign	w_dct[48]	= w_p7071;
assign	w_dct[49]	= w_n8314;
assign	w_dct[50]	= w_p3826;
assign	w_dct[51]	= w_p1950;
assign	w_dct[52]	= w_n7071;
assign	w_dct[53]	= w_p9807;
assign	w_dct[54]	= w_n9238;
assign	w_dct[55]	= w_p5555;

assign	w_dct[56]	= w_p7071;
assign	w_dct[57]	= w_n9807;
assign	w_dct[58]	= w_p9238;
assign	w_dct[59]	= w_n8314;
assign	w_dct[60]	= w_p7071;
assign	w_dct[61]	= w_n5555;
assign	w_dct[62]	= w_p3826;
assign	w_dct[63]	= w_n1950;

assign	o_dct	= w_dct[{i_Gxy, i_Buv}];

endmodule
module yuv_to_rgb_tb();

localparam	Y_PRECISION	= 8;
localparam	U_PRECISION	= 8;
localparam	V_PRECISION	= 8;
localparam	R_PRECISION	= 8;
localparam	G_PRECISION	= 8;
localparam	B_PRECISION	= 8;

reg		r_arst;
reg		r_sysclk;

reg		[Y_PRECISION-1:0]r_Y;
reg		[U_PRECISION-1:0]r_U;
reg		[V_PRECISION-1:0]r_V;

wire	[R_PRECISION-1:0]w_R;
wire	[G_PRECISION-1:0]w_G;
wire	[B_PRECISION-1:0]w_B;

/*
Y		U		V		c		d		e		m00		m01		m02		m10		m11		m12		m20		m21		m22		R		G		B
0		0		0		-16		-128	-128	-4768	0		-52352	-4768	12800	26624	-4768	-66048	0		-56992	34784	-70688
																														-222.6	90.8	-276.1
255		255		255		239		127		127		71222	0		51943	71222	-12700	-26416	71222	65532	0		123293	32234	136882
																														481.6	125.9	534.6
*/

initial
begin
	r_arst	<= 1'b1;
	
	r_Y		<= 8'd0;
	r_U		<= 8'd0;
	r_V		<= 8'd0;
	// 0 135 0
	
	#10	r_arst	<= 1'b0;
	#10	r_Y		<= 8'd255;
		r_U		<= 8'd255;
		r_V		<= 8'd255;
		// 255 120 255
	#10	r_Y		<= 8'd76;
		r_U		<= 8'd84;
		r_V		<= 8'd255;
		// 255 0 0
	#10	r_Y		<= 8'd149;
		r_U		<= 8'd43;
		r_V		<= 8'd21;
		// 0 255 0
	#10	r_Y		<= 8'd29;
		r_U		<= 8'd255;
		r_V		<= 8'd107;
		// 0 0 255	
	#10	r_Y		<= 8'd178;
		r_U		<= 8'd171;
		r_V		<= 8'd0;
		// 0 255 255
	#10	r_Y		<= 8'd225;
		r_U		<= 8'd0;
		r_V		<= 8'd148;
		// 255 255 0
end

initial
begin
	r_sysclk	<= 1'b0;
	forever
		#5	r_sysclk	<= ~r_sysclk;
end

yuv_to_rgb
#(
	.Y_PRECISION(Y_PRECISION),
	.U_PRECISION(U_PRECISION),
	.V_PRECISION(V_PRECISION),
	.R_PRECISION(R_PRECISION),
	.G_PRECISION(G_PRECISION),
	.B_PRECISION(B_PRECISION)
)
inst_yuv_to_rgb
(
	.i_arst		(r_arst),
	.i_sysclk	(r_sysclk),
	.i_Y		(r_Y),
	.i_U		(r_U),
	.i_V		(r_V),
	.o_R		(w_R),
	.o_G		(w_G),
	.o_B		(w_B)
);

endmodule
module sos_parser_tb();

localparam	CNT_W	= 4;

integer	jpeg_file;
integer	temp;

reg		r_arst;
reg		r_sysclk;
reg		r_byte_en;
reg		[7:0]r_byte[0:1023];
reg		[15:0]r_ptr;
wire	[7:0]w_byte;
wire	w_ready;
reg		r_re;
wire	w_start;
wire	w_scan_en;
wire	w_ecs_bit;

assign	w_byte	= r_byte[r_ptr];

sos_parser
#(
	.CNT_W(CNT_W)
)
inst_sos_parser
(
	.i_arst		(r_arst),
	.i_sysclk	(r_sysclk),
	.i_byte_en	(r_byte_en),
	.i_byte		(w_byte),
	.o_ready	(w_ready),
	.i_re		(r_re),
	.o_start	(w_start),
	.o_scan_en	(w_scan_en),
	.o_ecs_bit	(w_ecs_bit)
);

initial
begin
	jpeg_file	= $fopen("test_pattern_01.jpg", "rb");
	temp		= $fread(r_byte, jpeg_file, 0, 1023);
	$fclose(jpeg_file);
end

initial
begin
	r_arst	<= 1'b1;
	#10	r_arst	<= 1'b0;
end

initial
begin
	r_sysclk	<= 1'b1;
	forever
		#2.5	r_sysclk	<= ~r_sysclk;
end

always@(posedge r_arst or posedge r_sysclk)
begin
	if (r_arst)
	begin
		r_byte_en	<= 1'b0;
		r_ptr		<= 'h0;
		r_re		<= 1'b0;
	end
	else
	begin
		r_byte_en	<= 1'b1;
		if (w_ready)
			r_ptr		<= r_ptr+1'b1;
		r_re		<= 1'b1;
	end
end

endmodule
module yuv_to_rgb_tb();

localparam	COLOR_PRECISION	= 8;

reg		r_arst;
reg		r_sysclk;

reg		[COLOR_PRECISION-1:0]r_R;
reg		[COLOR_PRECISION-1:0]r_G;
reg		[COLOR_PRECISION-1:0]r_B;

wire	[COLOR_PRECISION-1:0]w_C;
wire	[COLOR_PRECISION-1:0]w_M;
wire	[COLOR_PRECISION-1:0]w_Y;
wire	[COLOR_PRECISION-1:0]w_K;

initial
begin
	r_arst	<= 1'b1;
	
	r_R		<= 8'd0;
	r_G		<= 8'd0;
	r_B		<= 8'd0;
	
	#10	r_arst	<= 1'b0;
	#5	r_R		<= 8'd255;
		r_G		<= 8'd255;
		r_B		<= 8'd255;
		//
	#5	r_R		<= 8'd255;
		r_G		<= 8'd0;
		r_B		<= 8'd0;
		//
	#5	r_R		<= 8'd0;
		r_G		<= 8'd255;
		r_B		<= 8'd0;
		//
	#5	r_R		<= 8'd0;
		r_G		<= 8'd0;
		r_B		<= 8'd255;
end

initial
begin
	r_sysclk	<= 1'b1;
	forever
		#2.5	r_sysclk	<= ~r_sysclk;
end

rgb_to_cmyk
#(
	.COLOR_PRECISION(COLOR_PRECISION)
)
inst_rgb_to_cmyk
(
	.i_arst		(r_arst),
	.i_sysclk	(r_sysclk),
	.i_R		(r_R),
	.i_G		(r_G),
	.i_B		(r_B),
	.o_C		(w_C),
	.o_M		(w_M),
	.o_Y		(w_Y),
	.o_K		(w_K)
);

endmodule
module spi_controller_tb();

localparam	SCLK_FREQ		= 6'd1;
localparam	ADDR_WIDTH		= 24;
localparam	NUM_OF_JPG		= 16;
localparam	START_ADDR		= 'h00000;
localparam	ADDR_OFFSET		= 'h00200;

reg		r_arst;
reg		r_sysclk;

reg		r_next;
reg		r_back;
reg		r_interrupt;
reg		r_flush;

wire	w_WPn;
wire	w_HOLDn;
wire	w_miso;
wire	w_DIO;
wire	w_nss;
wire	w_sclk;
wire	w_mosi;
wire	w_mosi_oe;

wire	w_ready;
wire	w_byte_en;
wire	[7:0]w_byte;

assign	w_WPn	= 1'b1;
assign	w_HOLDn	= 1'b1;
assign	w_ready	= 1'b1;

spi_controller
#(
	.SCLK_FREQ		(SCLK_FREQ),
	.ADDR_WIDTH		(ADDR_WIDTH),
	.NUM_OF_JPG		(NUM_OF_JPG),
	.START_ADDR		(START_ADDR),
	.ADDR_OFFSET	(ADDR_OFFSET)
)
inst_spi_controller
(
	.i_arst		(r_arst),
	.i_sysclk	(r_sysclk),
	.i_next		(r_next),
	.i_back		(r_back),
	.i_interrupt(r_interrupt),
	.i_flush	(r_flush),
	
	.i_miso		(w_miso),
	.i_miso_1	(w_DIO),
	.o_nss		(w_nss),
	.o_sclk		(w_sclk),
	.o_mosi		(w_mosi),
	.o_mosi_oe	(w_mosi_oe),
	
	.i_ready	(w_ready),
	.o_byte_en	(w_byte_en),
	.o_byte		(w_byte)
);

W25Q32JV
inst_w25q32jv
(
	.DIO	(w_DIO),
	.WPn	(w_WPn),
	.HOLDn	(w_HOLDn),
	.DO		(w_miso),
	.CSn	(w_nss),
	.CLK	(w_sclk)
);

pullup(w_DIO);
pullup(w_miso);
assign	w_DIO	= (w_mosi_oe)?
					w_mosi:1'bz;

initial
begin
	r_arst	<= 1'b1;
	#10	r_arst	<= 1'b0;
end

initial
begin
	r_sysclk	<= 1'b1;
	forever
		#2.5	r_sysclk	<= ~r_sysclk;
end

always@(posedge r_arst or posedge r_sysclk)
begin
	if (r_arst)
	begin
		r_next		<= 1'b0;
		r_back		<= 1'b0;
		r_interrupt	<= 1'b0;
		r_flush		<= 1'b0;
	end
	else
	begin
		r_next		<= 1'b0;
		r_back		<= 1'b0;
		r_interrupt	<= 1'b0;
		r_flush		<= 1'b0;
	end
end

endmodule
module runlength_shifter_tb();

localparam	AMPLITUDE_PRECISION	= 16;

reg		r_arst;
reg		r_sysclk;
reg		r_we;
wire	[19:0]w_eob;
wire	[4:0]w_runlength[0:19];
wire	[AMPLITUDE_PRECISION-1:0]w_B[0:19];
reg		[4:0]r_ptr;
wire	w_ready;
reg		r_ready;
wire	w_de;
wire	[AMPLITUDE_PRECISION-1:0]o_B;

reg		r_test_state_1P;

localparam	s_test_0	= 1'b0;
localparam	s_test_1	= 1'b1;

wire	i_eob;
wire	[4:0]i_runlength;
wire	[AMPLITUDE_PRECISION-1:0]i_B;

assign	i_eob		= w_eob[r_ptr];
assign	i_runlength	= w_runlength[r_ptr];
assign	i_B			= w_B[r_ptr];

assign	w_runlength[0]	= 5'd0;	assign	w_eob[0]	= 1'b0;	assign	w_B[0]	= 16'h1;
assign	w_runlength[1]	= 5'd1;	assign	w_eob[1]	= 1'b0;	assign	w_B[1]	= 16'h2;
assign	w_runlength[2]	= 5'd0;	assign	w_eob[2]	= 1'b0;	assign	w_B[2]	= 16'h3;
assign	w_runlength[3]	= 5'd0;	assign	w_eob[3]	= 1'b0;	assign	w_B[3]	= 16'h4;
assign	w_runlength[4]	= 5'd0;	assign	w_eob[4]	= 1'b0;	assign	w_B[4]	= 16'h5;
assign	w_runlength[5]	= 5'd0;	assign	w_eob[5]	= 1'b0;	assign	w_B[5]	= 16'h6;
assign	w_runlength[6]	= 5'd0;	assign	w_eob[6]	= 1'b0;	assign	w_B[6]	= 16'h7;
assign	w_runlength[7]	= 5'd0;	assign	w_eob[7]	= 1'b0;	assign	w_B[7]	= 16'h8;
assign	w_runlength[8]	= 5'd0;	assign	w_eob[8]	= 1'b0;	assign	w_B[8]	= 16'h9;
assign	w_runlength[9]	= 5'd0;	assign	w_eob[9]	= 1'b0;	assign	w_B[9]	= 16'hA;
assign	w_runlength[10]	= 5'd0;	assign	w_eob[10]	= 1'b0;	assign	w_B[10]	= 16'hB;
assign	w_runlength[11]	= 5'd0;	assign	w_eob[11]	= 1'b0;	assign	w_B[11]	= 16'hC;
assign	w_runlength[12]	= 5'd0;	assign	w_eob[12]	= 1'b0;	assign	w_B[12]	= 16'hD;
assign	w_runlength[13]	= 5'd0;	assign	w_eob[13]	= 1'b0;	assign	w_B[13]	= 16'hE;
assign	w_runlength[14]	= 5'd0;	assign	w_eob[14]	= 1'b0;	assign	w_B[14]	= 16'hF;
assign	w_runlength[15]	= 5'd0;	assign	w_eob[15]	= 1'b0;	assign	w_B[15]	= 16'h10;
assign	w_runlength[16]	= 5'd0;	assign	w_eob[16]	= 1'b0;	assign	w_B[16]	= 16'h11;
assign	w_runlength[17]	= 5'd5;	assign	w_eob[17]	= 1'b0;	assign	w_B[17]	= 16'h12;
assign	w_runlength[18]	= 5'd0;	assign	w_eob[18]	= 1'b0;	assign	w_B[18]	= 16'h13;
assign	w_runlength[19]	= 5'd0;	assign	w_eob[19]	= 1'b1;	assign	w_B[19]	= 16'h14;

runlength_shifter
#(
	.AMPLITUDE_PRECISION(AMPLITUDE_PRECISION)
)
inst_runlength_shifter
(
	.i_arst		(r_arst),
	.i_sysclk	(r_sysclk),
	.i_we		(r_we),
	.i_eob		(i_eob),
	.i_runlength(i_runlength),
	.i_B		(i_B),
	.o_ready	(w_ready),
	.i_ready	(r_ready),
	.o_de		(w_de),
	.o_B		(o_B)
);

initial
begin
	r_arst	<= 1'b1;
	#10	r_arst	<= 1'b0;
end

initial
begin
	r_sysclk	<= 1'b1;
	forever
		#2.5	r_sysclk	<= ~r_sysclk;
end

always@(posedge r_arst or posedge r_sysclk)
begin
	if (r_arst)
	begin
		r_test_state_1P	<= s_test_0;
		r_ptr			<= {5{1'b0}};
		r_we			<= 1'b1;
		r_ready			<= 1'b1;
	end
	else
	begin
		case (r_test_state_1P)
			s_test_0:
			begin
				if (w_ready)
				begin
					r_ptr	<= r_ptr+1'b1;
					if (r_ptr == 5'd19)
					begin
						r_test_state_1P	<= s_test_1;
						r_ptr			<= {5{1'b0}};
					end
				end
			end
			
			s_test_1:
			begin
				r_ready	<= 1'b1;
				if (w_ready)
				begin
					r_ready	<= 1'b0;
					r_ptr	<= r_ptr+1'b1;
					if (r_ptr == 5'd19)
					begin
						r_ptr	<= r_ptr;
					end
				end
			end
		endcase
	end
end

endmodule
module multi_n1_ext2
#(
	parameter	D_WIDTH	= 8
)
(
	input	i_arst,
	input	i_clk,
	
	input	[D_WIDTH-1:0]i_d,
	output	[D_WIDTH+2-1:0]o_q
);

reg		[D_WIDTH+2-1:0]r_q_1P;

wire	[D_WIDTH+2-1:0]w_d_0P;

assign	w_d_0P	= {2'b00, i_d};

always@(posedge i_arst or posedge i_clk)
begin
	if (i_arst)
		r_q_1P	<= {D_WIDTH+2{1'b0}};
	else
		r_q_1P	<= ~w_d_0P+1'b1;
end

assign	o_q	= r_q_1P;

endmodule
module multi_p1_ext2
#(
	parameter	D_WIDTH	= 8
)
(
	input	i_arst,
	input	i_clk,
	
	input	[D_WIDTH-1:0]i_d,
	output	[D_WIDTH+2-1:0]o_q
);

reg		[D_WIDTH+2-1:0]r_q_1P;

wire	[D_WIDTH+2-1:0]w_d_0P;

assign	w_d_0P	= {2'b00, i_d};

always@(posedge i_arst or posedge i_clk)
begin
	if (i_arst)
		r_q_1P	<= {D_WIDTH+2{1'b0}};
	else
		r_q_1P	<= w_d_0P;
end

assign	o_q	= r_q_1P;

endmodule
module multi_p8_ext5
#(
	parameter	D_WIDTH	= 8
)
(
	input	i_arst,
	input	i_clk,
	
	input	[D_WIDTH-1:0]i_d,
	output	[D_WIDTH+5-1:0]o_q
);

reg		[D_WIDTH+5-1:0]r_q_1P;

wire	[D_WIDTH+5-1:0]w_d_0P;

assign	w_d_0P	= {2'b0, i_d, 3'b000};

always@(posedge i_arst or posedge i_clk)
begin
	if (i_arst)
		r_q_1P	<= {D_WIDTH+5{1'b0}};
	else
		r_q_1P	<= w_d_0P;
end

assign	o_q	= r_q_1P;

endmodule
module vga_controller
#(
	parameter	VESA_STD	= "VESA_1280X720_60FPS",
	parameter	R_DEPTH		= 6,
	parameter	G_DEPTH		= 6,
	parameter	B_DEPTH		= 6
)
(
	input	i_arst,
	input	i_pclk,
	
	input	i_vs,
	input	i_hs,
	input	i_de,
	input	[R_DEPTH-1:0]i_r,
	input	[G_DEPTH-1:0]i_g,
	input	[B_DEPTH-1:0]i_b,
	
	output	o_vga_vs,
	output	o_vga_hs,
	output	o_vga_de,
	output	[R_DEPTH-1:0]o_vga_r,
	output	[G_DEPTH-1:0]o_vga_g,
	output	[B_DEPTH-1:0]o_vga_b
);

localparam	HOR_SYNC_POLARITY	= `HOR_SYNC_POLARITY;
localparam	VER_SYNC_POLARITY	= `VER_SYNC_POLARITY;
wire	c_act_vs_por;
wire	c_ina_vs_por;
wire	c_act_hs_por;
wire	c_ina_hs_por;
wire	c_act_de_por;
wire	c_ina_de_por;

reg		r_vs_1P;
reg		r_hs_1P;
reg		r_de_r_1P;
reg		r_de_g_1P;
reg		r_de_b_1P;
reg		[R_DEPTH-1:0]r_r_1P;
reg		[G_DEPTH-1:0]r_g_1P;
reg		[B_DEPTH-1:0]r_b_1P;

reg		r_vs_2P;
reg		r_hs_2P;
reg		r_de_2P;
reg		[R_DEPTH-1:0]r_r_2P;
reg		[G_DEPTH-1:0]r_g_2P;
reg		[B_DEPTH-1:0]r_b_2P;

generate
	if (HOR_SYNC_POLARITY == "NEGATIVE")
	begin
		assign	c_act_hs_por	= 1'b0;
		assign	c_ina_hs_por	= 1'b1;
	end
	else
	begin
		assign	c_act_hs_por	= 1'b1;
		assign	c_ina_hs_por	= 1'b0;
	end
	
	if (VER_SYNC_POLARITY == "NEGATIVE")
	begin
		assign	c_act_vs_por	= 1'b0;
		assign	c_ina_vs_por	= 1'b1;
	end
	else
	begin
		assign	c_act_vs_por	= 1'b1;
		assign	c_ina_vs_por	= 1'b0;
	end
endgenerate

assign	c_act_de_por	= 1'b1;
assign	c_ina_de_por	= 1'b0;

always@(posedge i_arst or posedge i_pclk)
begin
	if (i_arst)
	begin
		r_vs_1P		<= c_ina_vs_por;
		r_hs_1P		<= c_ina_hs_por;
		r_de_r_1P	<= c_ina_de_por;
		r_de_g_1P	<= c_ina_de_por;
		r_de_b_1P	<= c_ina_de_por;
		r_r_1P		<= {R_DEPTH{1'b0}};
		r_g_1P		<= {G_DEPTH{1'b0}};
		r_b_1P		<= {B_DEPTH{1'b0}};
		
		r_vs_2P		<= c_ina_vs_por;
		r_hs_2P		<= c_ina_hs_por;
		r_de_2P		<= c_ina_de_por;
		r_r_2P		<= {R_DEPTH{1'b0}};
		r_g_2P		<= {G_DEPTH{1'b0}};
		r_b_2P		<= {B_DEPTH{1'b0}};
	end
	else
	begin
		r_vs_1P		<= i_vs;
		r_hs_1P		<= i_hs;
		r_de_r_1P	<= i_de;
		r_de_g_1P	<= i_de;
		r_de_b_1P	<= i_de;
		r_r_1P		<= i_r;
		r_g_1P		<= i_g;
		r_b_1P		<= i_b;
		
		r_vs_2P		<= r_vs_1P;
		r_hs_2P		<= r_hs_1P;
		r_de_2P		<= r_de_r_1P;
		if (r_de_r_1P)
			r_r_2P		<= r_r_1P;
		else
			r_r_2P		<= {R_DEPTH{1'b0}};
		if (r_de_g_1P)
			r_g_2P		<= r_g_1P;
		else
			r_g_2P		<= {G_DEPTH{1'b0}};
		if (r_de_b_1P)
			r_b_2P		<= r_b_1P;
		else
			r_b_2P		<= {B_DEPTH{1'b0}};
	end
end

assign	o_vga_vs	= r_vs_2P;
assign	o_vga_hs	= r_hs_2P;
assign	o_vga_de	= r_de_2P;
assign	o_vga_r		= r_r_2P;
assign	o_vga_g		= r_g_2P;
assign	o_vga_b		= r_b_2P;

endmodule
module multi_n2_ext5
#(
	parameter	D_WIDTH	= 8
)
(
	input	i_arst,
	input	i_clk,
	
	input	[D_WIDTH-1:0]i_d,
	output	[D_WIDTH+5-1:0]o_q
);

reg		[D_WIDTH+5-1:0]r_q_1P;

wire	[D_WIDTH+5-1:0]w_d_0P;

assign	w_d_0P	= {4'b0000, i_d, 1'b0};

always@(posedge i_arst or posedge i_clk)
begin
	if (i_arst)
		r_q_1P	<= {D_WIDTH+5{1'b0}};
	else
		r_q_1P	<= ~w_d_0P+1'b1;
end

assign	o_q	= r_q_1P;

endmodule
module multi_n8_ext5
#(
	parameter	D_WIDTH	= 8
)
(
	input	i_arst,
	input	i_clk,
	
	input	[D_WIDTH-1:0]i_d,
	output	[D_WIDTH+5-1:0]o_q
);

reg		[D_WIDTH+5-1:0]r_q_1P;

wire	[D_WIDTH+5-1:0]w_d_0P;

assign	w_d_0P	= {2'b00, i_d, 3'b000};

always@(posedge i_arst or posedge i_clk)
begin
	if (i_arst)
		r_q_1P	<= {D_WIDTH+5{1'b0}};
	else
		r_q_1P	<= ~w_d_0P+1'b1;
end

assign	o_q	= r_q_1P;

endmodule
module ov5640_config
(
	input	i_arst,
	input	i_sysclk,
	input	i_pll_locked,
	output	o_confdone,
	
	input	i_sda,
	output	o_sda_oe,
	input	i_scl,
	output	o_scl_oe
);

localparam	DEVICE_ADDRESS	= 8'h00;
localparam	ADDRESSING		= 7;
localparam	SYSCLK_FREQ		= 25;
localparam	MODE			= "FAST";
localparam	SLAVE_ENABLE	= "FALSE";

localparam	s_IDLE		= 2'b01;
localparam	s_CONFIG	= 2'b10;
localparam	s_DONE		= 2'b00;

reg		r_m_en_1P;
reg		r_m_wr_1P;
wire	[7:0]w_ov5640_reg;
reg		r_last_1P;
wire	w_ack;
wire	w_last;
wire	[7:0]w_data;

reg		[1:0]r_i2c_config_state_1P;
reg		[9:0]r_addr_1P;
reg		[1:0]r_byte_cnt_1P;
reg		[8:0]r_reg_cnt_1P;
reg		r_confdone_1P;

i2c_wrapper
#(
	.DEVICE_ADDRESS	(DEVICE_ADDRESS),
	.ADDRESSING		(ADDRESSING),
	.SYSCLK_FREQ	(SYSCLK_FREQ),
	.MODE			(MODE),
	.SLAVE_ENABLE	(SLAVE_ENABLE)
)
inst_i2c
(
	.i_arst		(i_arst),
	.i_sysclk	(i_sysclk),
	.i_m_en		(r_m_en_1P),
	.i_m_wr		(r_m_wr_1P),
	.i_last		(r_last_1P),
	.i_addr		(7'h3C),
	.i_data		(w_ov5640_reg),
//	.o_s_en		(w_s_en),
//	.o_s_wr		(w_s_wr),
	.o_ack		(w_ack),
	.o_last		(w_last),
	.o_data		(w_data),
	.i_sda		(i_sda),
	.o_sda_oe	(o_sda_oe),
	.i_scl		(i_scl),
	.o_scl_oe	(o_scl_oe)
);


ov5640_reg
inst_ov5640_reg
(
	.i_addr(r_addr_1P),
	.o_data(w_ov5640_reg)
);

always@(posedge i_arst or posedge i_sysclk)
begin
	if (i_arst)
	begin
		r_i2c_config_state_1P	<= s_IDLE;
		r_addr_1P				<= {10{1'b0}};
		r_m_en_1P				<= 1'b0;
		r_m_wr_1P				<= 1'b0;
		r_last_1P				<= 1'b0;
		
		r_byte_cnt_1P			<= {2{1'b0}};
		r_reg_cnt_1P			<= {9{1'b0}};
		
		r_confdone_1P			<= 1'b0;
	end
	else
	begin
		case (r_i2c_config_state_1P)
			s_IDLE:
			begin
				if (i_pll_locked)
				begin
					r_i2c_config_state_1P	<= s_CONFIG;
					r_addr_1P				<= {10{1'b0}};
					r_m_en_1P				<= 1'b1;
					r_m_wr_1P				<= 1'b0;
					r_last_1P				<= 1'b0;
					
					r_byte_cnt_1P			<= {2{1'b0}};
					r_reg_cnt_1P			<= {9{1'b0}};
				end
			end
			
			s_CONFIG:
			begin
				r_m_en_1P		<= 1'b1;
				r_last_1P		<= 1'b0;
				if (w_ack)
				begin
					if (r_reg_cnt_1P != 9'd305)
//					if (r_reg_cnt_1P != 9'd001)
					begin
						r_addr_1P		<= r_addr_1P+1'b1;
						r_byte_cnt_1P	<= r_byte_cnt_1P+1'b1;
						if (r_byte_cnt_1P == 2'b10)
						begin
							r_m_en_1P		<= 1'b0;
							r_last_1P		<= 1'b1;
							r_byte_cnt_1P	<= {2{1'b0}};
							r_reg_cnt_1P	<= r_reg_cnt_1P+1'b1;
						end
					end
					else
					begin
						r_i2c_config_state_1P	<= s_DONE;
						r_m_en_1P				<= 1'b0;
						r_confdone_1P			<= 1'b1;
					end
				end
			end
			
			s_DONE:
			begin
			end
			
			default:
			begin
				r_i2c_config_state_1P	<= s_IDLE;
				r_addr_1P				<= {10{1'b0}};
				r_m_en_1P				<= 1'b0;
				r_m_wr_1P				<= 1'b0;
				
				r_byte_cnt_1P			<= {2{1'b0}};
				r_reg_cnt_1P			<= {9{1'b0}};
			end
		endcase
	end
end

assign	o_confdone	= r_confdone_1P;

endmodule