dakies/OSS_Verilog huggingface dataset:
module hazard3_regfile_1w2r #(
	parameter RESET_REGS = 0,	// Unsupported for FAKE_DUALPORT
	parameter N_REGS = 16,
	parameter W_DATA = 32,
	parameter W_ADDR = $clog2(W_DATA)	// should be localparam. ISIM...
) (
	input wire clk,
	input wire rst_n,

	input wire [W_ADDR-1:0] raddr1,
	output reg [W_DATA-1:0] rdata1,

	input wire [W_ADDR-1:0] raddr2,
	output reg [W_DATA-1:0] rdata2,

	input wire [W_ADDR-1:0] waddr,
	input wire [W_DATA-1:0] wdata,
	input wire              wen
);

generate
if (RESET_REGS) begin: real_dualport_reset
	// This will presumably always be implemented with flops
	reg [W_DATA-1:0] mem [0:N_REGS-1];

	integer i;
	always @ (posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			for (i = 0; i < N_REGS; i = i + 1) begin
				mem[i] <= {W_DATA{1'b0}};
			end
			rdata1 <= {W_DATA{1'b0}};
			rdata2 <= {W_DATA{1'b0}};
		end else begin
			if (wen) begin
				mem[waddr] <= wdata;
			end
			rdata1 <= mem[raddr1];
			rdata2 <= mem[raddr2];
		end
	end
end else begin: real_dualport_noreset
	// This should be inference-compatible on FPGAs with dual-port BRAMs
	`ifdef YOSYS
	`ifdef FPGA_ICE40
	// We do not require write-to-read bypass logic on the BRAM
	(* no_rw_check *)
	`endif
	`endif
	reg [W_DATA-1:0] mem [0:N_REGS-1];

	always @ (posedge clk) begin
		if (wen) begin
			mem[waddr] <= wdata;
		end
		rdata1 <= mem[raddr1];
		rdata2 <= mem[raddr2];
	end
end
endgenerate

endmodule
module fpga_orangecrab_25f (
	input  wire       clk_osc,
	output wire [7:0] dbg,

	output wire       uart_tx,
	input  wire       uart_rx,

	output rgb_led0_r,
	output rgb_led0_g,
	output rgb_led0_b,

	output rst_n,
	input usr_btn
);

wire clk_sys = clk_osc;
wire rst_n_sys;
wire trst_n;

fpga_reset #(
	.SHIFT (3)
) rstgen (
	.clk         (clk_sys),
	.force_rst_n (1'b1),
	.rst_n       (rst_n_sys)
);

example_soc #(
	.DTM_TYPE           ("ECP5"),
	.SRAM_DEPTH         (1 << 14),
	.CLK_MHZ            (48),

	.EXTENSION_M         (1),
	.EXTENSION_A         (1),
	.EXTENSION_C         (0),
	.EXTENSION_ZBA       (0),
	.EXTENSION_ZBB       (0),
	.EXTENSION_ZBC       (0),
	.EXTENSION_ZBS       (0),
	.EXTENSION_ZBKB      (0),
	.EXTENSION_ZIFENCEI  (1),
	.EXTENSION_XH3BEXTM  (0),
	.EXTENSION_XH3PMPM   (0),
	.EXTENSION_XH3POWER  (0),
	.CSR_COUNTER         (1),
	.MUL_FAST            (1),
	.MUL_FASTER          (0),
	.MULH_FAST           (0),
	.MULDIV_UNROLL       (1),
	.FAST_BRANCHCMP      (1),
	.BRANCH_PREDICTOR    (1)
) soc_u (
	.clk     (clk_sys),
	.rst_n   (rst_n_sys),

	// JTAG connections provided internally by ECP5 JTAGG primitive
	.tck     (1'b0),
	.trst_n  (1'b0),
	.tms     (1'b0),
	.tdi     (1'b0),
	.tdo     (/* unused */),

	.uart_tx (uart_tx),
	.uart_rx (uart_rx)
);

	// Create a 27 bit register
	reg [26:0] counter = 0;

	// Every positive edge increment register by 1
	always @(posedge clk_sys) begin
		counter <= counter + 1;
	end

	// Output inverted values of counter onto LEDs
	assign rgb_led0_r = ~counter[24];
	assign rgb_led0_g = ~counter[25];
	assign rgb_led0_b = 0;

	assign dbg = 8'hff;

	// Reset logic on button press.
	// this will enter the bootloader
	reg reset_sr = 1'b1;
	always @(posedge clk_sys) begin
		reset_sr <= {usr_btn};
	end
	assign rst_n = reset_sr;


endmodule
module pll_25_50
(
    input clkin, // 25 MHz, 0 deg
    output clkout0, // 50 MHz, 0 deg
    output locked
);
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="50" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
        .PLLRST_ENA("DISABLED"),
        .INTFB_WAKE("DISABLED"),
        .STDBY_ENABLE("DISABLED"),
        .DPHASE_SOURCE("DISABLED"),
        .OUTDIVIDER_MUXA("DIVA"),
        .OUTDIVIDER_MUXB("DIVB"),
        .OUTDIVIDER_MUXC("DIVC"),
        .OUTDIVIDER_MUXD("DIVD"),
        .CLKI_DIV(1),
        .CLKOP_ENABLE("ENABLED"),
        .CLKOP_DIV(12),
        .CLKOP_CPHASE(5),
        .CLKOP_FPHASE(0),
        .FEEDBK_PATH("CLKOP"),
        .CLKFB_DIV(2)
    ) pll_i (
        .RST(1'b0),
        .STDBY(1'b0),
        .CLKI(clkin),
        .CLKOP(clkout0),
        .CLKFB(clkout0),
        .CLKINTFB(),
        .PHASESEL0(1'b0),
        .PHASESEL1(1'b0),
        .PHASEDIR(1'b1),
        .PHASESTEP(1'b1),
        .PHASELOADREG(1'b1),
        .PLLWAKESYNC(1'b0),
        .ENCLKOP(1'b0),
        .LOCK(locked)
	);
endmodule
module fpga_icebreaker (
	input wire        clk_osc,

	// No external trst_n as iCEBreaker can't easily drive it from FTDI, so we
	// generate a pulse internally from FPGA PoR.
	input  wire       tck,
	input  wire       tms,
	input  wire       tdi,
	output wire       tdo,

	output wire       led,

	output wire       mirror_tck,
	output wire       mirror_tms,
	output wire       mirror_tdi,
	output wire       mirror_tdo,

	output wire       uart_tx,
	input  wire       uart_rx
);

assign mirror_tck = tck;
assign mirror_tms = tms;
assign mirror_tdi = tdi;
assign mirror_tdo = tdo;

wire clk_sys = clk_osc;
wire rst_n_sys;
wire trst_n;

fpga_reset #(
	.SHIFT (3)
) rstgen (
	.clk         (clk_sys),
	.force_rst_n (1'b1),
	.rst_n       (rst_n_sys)
);

reset_sync trst_sync_u (
	.clk       (tck),
	.rst_n_in  (rst_n_sys),
	.rst_n_out (trst_n)
);

activity_led #(
	.WIDTH (1 << 8),
	.ACTIVE_LEVEL (1'b0)
) tck_led_u (
	.clk   (clk_sys),
	.rst_n (rst_n_sys),
	.i     (tck),
	.o     (led)
);

example_soc #(
	.CLK_MHZ             (12),
	.EXTENSION_A         (1),
	.EXTENSION_C         (0),
	.EXTENSION_M         (1),
	.EXTENSION_ZBA       (0),
	.EXTENSION_ZBB       (0),
	.EXTENSION_ZBC       (0),
	.EXTENSION_ZBS       (0),
	.EXTENSION_ZBKB      (0),
	.EXTENSION_ZIFENCEI  (0),
	.EXTENSION_XH3BEXTM  (0),
	.EXTENSION_XH3PMPM   (0),
	.EXTENSION_XH3POWER  (0),
	.CSR_COUNTER         (0),
	.U_MODE              (0),
	.PMP_REGIONS         (0),
	.BREAKPOINT_TRIGGERS (0),
	.IRQ_PRIORITY_BITS   (0),
	.REDUCED_BYPASS      (0),
	.MULDIV_UNROLL       (1),
	.MUL_FAST            (0),
	.MUL_FASTER          (0),
	.MULH_FAST           (0),
	.FAST_BRANCHCMP      (1),
	.BRANCH_PREDICTOR    (0)
) soc_u (
	.clk            (clk_sys),
	.rst_n          (rst_n_sys),

	.tck            (tck),
	.trst_n         (trst_n),
	.tms            (tms),
	.tdi            (tdi),
	.tdo            (tdo),

	.uart_tx        (uart_tx),
	.uart_rx        (uart_rx)
);

endmodule
module fpga_ulx3s (
	input  wire       clk_osc,
	output wire [7:0] dbg,

	output wire       uart_tx,
	input  wire       uart_rx
);

wire clk_sys;
wire pll_sys_locked;
wire rst_n_sys;

pll_25_50 pll_sys (
	.clkin   (clk_osc),
	.clkout0 (clk_sys),
	.locked  (pll_sys_locked)
);

fpga_reset #(
	.SHIFT (3)
) rstgen (
	.clk         (clk_sys),
	.force_rst_n (pll_sys_locked),
	.rst_n       (rst_n_sys)
);

example_soc #(
	.DTM_TYPE           ("ECP5"),
	.SRAM_DEPTH         (1 << 15),
	.CLK_MHZ            (50),

	.EXTENSION_M         (1),
	.EXTENSION_A         (1),
	.EXTENSION_C         (0),
	.EXTENSION_ZBA       (0),
	.EXTENSION_ZBB       (0),
	.EXTENSION_ZBC       (0),
	.EXTENSION_ZBS       (0),
	.EXTENSION_ZBKB      (0),
	.EXTENSION_ZIFENCEI  (1),
	.EXTENSION_XH3BEXTM  (0),
	.EXTENSION_XH3PMPM   (0),
	.EXTENSION_XH3POWER  (0),
	.CSR_COUNTER         (1),
	.MUL_FAST            (1),
	.MUL_FASTER          (0),
	.MULH_FAST           (0),
	.MULDIV_UNROLL       (1),
	.FAST_BRANCHCMP      (1),
	.BRANCH_PREDICTOR    (1)
) soc_u (
	.clk     (clk_sys),
	.rst_n   (rst_n_sys),

	// JTAG connections provided internally by ECP5 JTAGG primitive
	.tck     (1'b0),
	.trst_n  (1'b0),
	.tms     (1'b0),
	.tdi     (1'b0),
	.tdo     (/* unused */),

	.uart_tx (uart_tx),
	.uart_rx (uart_rx)
);

assign dbg = 8'h00;

endmodule
module pll_25_40
(
    input clkin, // 25 MHz, 0 deg
    output clkout0, // 40 MHz, 0 deg
    output locked
);
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="40" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
        .PLLRST_ENA("DISABLED"),
        .INTFB_WAKE("DISABLED"),
        .STDBY_ENABLE("DISABLED"),
        .DPHASE_SOURCE("DISABLED"),
        .OUTDIVIDER_MUXA("DIVA"),
        .OUTDIVIDER_MUXB("DIVB"),
        .OUTDIVIDER_MUXC("DIVC"),
        .OUTDIVIDER_MUXD("DIVD"),
        .CLKI_DIV(5),
        .CLKOP_ENABLE("ENABLED"),
        .CLKOP_DIV(15),
        .CLKOP_CPHASE(7),
        .CLKOP_FPHASE(0),
        .FEEDBK_PATH("CLKOP"),
        .CLKFB_DIV(8)
    ) pll_i (
        .RST(1'b0),
        .STDBY(1'b0),
        .CLKI(clkin),
        .CLKOP(clkout0),
        .CLKFB(clkout0),
        .CLKINTFB(),
        .PHASESEL0(1'b0),
        .PHASESEL1(1'b0),
        .PHASEDIR(1'b1),
        .PHASESTEP(1'b1),
        .PHASELOADREG(1'b1),
        .PLLWAKESYNC(1'b0),
        .ENCLKOP(1'b0),
        .LOCK(locked)
	);
endmodule
module hazard3_riscv_timer #(
	parameter TICK_IS_NRZ = 0
) (
	input  wire               clk,
	input  wire               rst_n,

	input  wire [15:0]        paddr,
	input  wire               psel,
	input  wire               penable,
	input  wire               pwrite,
	input  wire [31:0]        pwdata,
	output reg  [31:0]        prdata,
	output wire               pready,
	output wire               pslverr,

	input  wire               dbg_halt,
	input  wire               tick,

	output reg                timer_irq
);

localparam ADDR_CTRL      = 16'h0000;
localparam ADDR_MTIME     = 16'h0008;
localparam ADDR_MTIMEH    = 16'h000c;
localparam ADDR_MTIMECMP  = 16'h0010;
localparam ADDR_MTIMECMPH = 16'h0014;

// ----------------------------------------------------------------------------
// Timer tick logic

wire tick_event;

generate
if (TICK_IS_NRZ) begin: edge_detect

	wire tick_nrz_sync;

	hazard3_sync_1bit tick_sync_u (
		.clk    (clk),
		.rst_n  (rst_n),
		.i      (tick_nrz),
		.o      (tick_nrz_sync)
	);

	reg tick_nrz_prev;
	always @ (posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			tick_nrz_prev <= 1'b0;
		end else begin
			tick_nrz_prev <= tick_nrz_sync;
		end
	end

	assign tick_event = tick_nrz_sync ^ tick_nrz_sync_prev;

end else begin: no_edge_detect

	assign tick_event = tick;

end
endgenerate

reg ctrl_en;
wire tick_now = tick_event && ctrl_en && !dbg_halt;

// ----------------------------------------------------------------------------
// Counter registers

wire bus_write = pwrite && psel && penable;
wire bus_read = !pwrite && psel && penable;

always @ (posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		ctrl_en <= 1'b1;
	end else if (bus_write && paddr == ADDR_CTRL) begin
		ctrl_en <= pwdata[0];
	end
end

reg [63:0] mtime;

always @ (posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		mtime <= 64'h0;
	end else begin
		if (tick_now)
			mtime <= mtime + 1'b1;
		if (bus_write && paddr == ADDR_MTIME)
			mtime[31:0] <= pwdata;
		if (bus_write && paddr == ADDR_MTIMEH)
			mtime[63:32] <= pwdata;
	end
end

// mtimecmp is stored inverted for minor LUT savings on iCE40
reg  [63:0] mtimecmp;
wire [64:0] cmp_diff = {1'b0, mtime} + {1'b0, mtimecmp} + 65'd1;

always @ (posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		mtimecmp <= 64'h0;
		timer_irq <= 1'b0;
	end else begin
		if (bus_write && paddr == ADDR_MTIMECMP)
			mtimecmp[31:0] <= ~pwdata;
		if (bus_write && paddr == ADDR_MTIMECMPH)
			mtimecmp[63:32] <= ~pwdata;
		timer_irq <= cmp_diff[64];
	end
end

always @ (*) begin
	case (paddr)
	ADDR_CTRL:      prdata = {31'h0, ctrl_en};
	ADDR_MTIME:     prdata = mtime[31:0];
	ADDR_MTIMEH:    prdata = mtime[63:32];
	ADDR_MTIMECMP:  prdata = ~mtimecmp[31:0];
	ADDR_MTIMECMPH: prdata = ~mtimecmp[63:32];
	default:        prdata = 32'h0;
	endcase
end

assign pready = 1'b1;
assign pslverr = 1'b0;

endmodule
module hazard3_shift_barrel #(
`include "hazard3_config.vh"
,
`include "hazard3_width_const.vh"
) (
	input wire [W_DATA-1:0]  din,
	input wire [W_SHAMT-1:0] shamt,
	input wire               right_nleft,
	input wire               rotate,
	input wire               arith,
	output reg [W_DATA-1:0]  dout
);

reg [W_DATA-1:0] din_rev;
reg [W_DATA-1:0] shift_accum;
reg sext; // haha

always @ (*) begin: shift
	integer i;

	for (i = 0; i < W_DATA; i = i + 1)
		din_rev[i] = right_nleft ? din[W_DATA - 1 - i] : din[i];

	sext = arith && din_rev[0];

	shift_accum = din_rev;
	for (i = 0; i < W_SHAMT; i = i + 1) begin
		if (shamt[i]) begin
			shift_accum = (shift_accum << (1 << i)) |
				({W_DATA{sext}} & ~({W_DATA{1'b1}} << (1 << i))) |
				({W_DATA{rotate && |EXTENSION_ZBB}} & (shift_accum >> (W_DATA - (1 << i))));
		end
	end

	for (i = 0; i < W_DATA; i = i + 1)
		dout[i] = right_nleft ? shift_accum[W_DATA - 1 - i] : shift_accum[i];
end

`ifdef HAZARD3_ASSERTIONS
always @ (*) begin
	if (right_nleft && arith && !rotate) begin: asr
		assert($signed(dout) == $signed(din) >>> $signed(shamt));
	end else if (right_nleft && !arith && !rotate) begin
		assert(dout == din >> shamt);
	end else if (!right_nleft && !arith && !rotate) begin
		assert(dout == din << shamt);
	end
end
`endif

endmodule
module hazard3_onehot_priority_dynamic #(
	parameter W_REQ                 = 8,
	parameter N_PRIORITIES          = 2,
	parameter PRIORITY_HIGHEST_WINS = 1, // If 1, numerically highest level has greatest priority.
	                                     // Otherwise, numerically lowest wins.
	parameter TIEBREAK_HIGHEST_WINS = 0, // If 1, highest-numbered request at the highest priority
	                                     // level wins the tiebreak. Otherwise, lowest-numbered.
	// Do not modify:
	parameter W_PRIORITY            = $clog2(N_PRIORITIES)
) (
	input  wire [W_REQ*W_PRIORITY-1:0] pri,
	input  wire [W_REQ-1:0]            req,
	output wire [W_REQ-1:0]            gnt
);

// 1. Stratify requests according to their level
reg [W_REQ-1:0]        req_stratified [0:N_PRIORITIES-1];
reg [N_PRIORITIES-1:0] level_has_req;

always @ (*) begin: stratify
	reg signed [31:0] i, j;
	for (i = 0; i < N_PRIORITIES; i = i + 1) begin
		for (j = 0; j < W_REQ; j = j + 1) begin
			req_stratified[i][j] = req[j] &&
				pri[W_PRIORITY * j +: W_PRIORITY] == i[W_PRIORITY-1:0];
		end
		level_has_req[i] = |req_stratified[i];
	end
end

// 2. Select the highest level with active requests
wire [N_PRIORITIES-1:0] active_layer_sel;

hazard3_onehot_priority #(
	.W_REQ        (N_PRIORITIES),
	.HIGHEST_WINS (PRIORITY_HIGHEST_WINS)
) prisel_layer (
	.req (level_has_req),
	.gnt (active_layer_sel)
);

// 3. Mask only those requests at this level
reg [W_REQ-1:0] reqs_from_highest_layer;

always @ (*) begin: mux_reqs_by_layer
	integer i;
	reqs_from_highest_layer = {W_REQ{1'b0}};
	for (i = 0; i < N_PRIORITIES; i = i + 1)
		reqs_from_highest_layer = reqs_from_highest_layer |
			(req_stratified[i] & {W_REQ{active_layer_sel[i]}});
end

// 4. Do a standard priority select on those requests as a tie break
hazard3_onehot_priority #(
	.W_REQ        (W_REQ),
	.HIGHEST_WINS (TIEBREAK_HIGHEST_WINS)
) prisel_tiebreak (
	.req (reqs_from_highest_layer),
	.gnt (gnt)
);

endmodule
module hazard3_onehot_encode #(
	parameter W_REQ = 16,
	parameter W_GNT = $clog2(W_REQ) // do not modify
) (
	input  wire [W_REQ-1:0] req,
	output reg  [W_GNT-1:0] gnt
);

always @ (*) begin: encode
	reg [W_GNT:0] i;
	gnt = {W_GNT{1'b0}};
	for (i = 0; i < W_REQ; i = i + 1) begin
		gnt = gnt | ({W_GNT{req[i[W_GNT-1:0]]}} & i[W_GNT-1:0]);
	end
end

endmodule
module hazard3_onehot_priority #(
	parameter W_REQ        = 16,
	parameter HIGHEST_WINS = 0
) (
	input  wire [W_REQ-1:0] req,
	output reg  [W_REQ-1:0] gnt
);

always @ (*) begin: select
	integer i;
	for (i = 0; i < W_REQ; i = i + 1) begin
		gnt[i] = req[i] && ~|(req & (
			HIGHEST_WINS ? ~({W_REQ{1'b1}} >> (W_REQ - 1 - i)) : ~({W_REQ{1'b1}} << i)
		));
	end
end

endmodule
module hazard3_branchcmp #(
`include "hazard3_config.vh"
,
`include "hazard3_width_const.vh"
) (
	input  wire [W_ALUOP-1:0] aluop,
	input  wire [W_DATA-1:0]  op_a,
	input  wire [W_DATA-1:0]  op_b,
	output wire               cmp
);

`include "hazard3_ops.vh"

wire [W_DATA-1:0] diff = op_a - op_b;

wire cmp_is_unsigned = aluop[2]; // aluop == ALUOP_LTU;

wire lt = op_a[W_DATA-1] == op_b[W_DATA-1] ? diff[W_DATA-1] :
          cmp_is_unsigned                  ? op_b[W_DATA-1] :
                                             op_a[W_DATA-1] ;

// ALUOP_SUB is used for equality check by main ALU
assign cmp = aluop[0] ? op_a != op_b : lt;

endmodule
module hazard3_priority_encode #(
	parameter W_REQ        = 16,
	parameter HIGHEST_WINS = 0,
	parameter W_GNT        = $clog2(W_REQ) // do not modify
) (
	input  wire [W_REQ-1:0] req,
	output wire [W_GNT-1:0] gnt
);

wire [W_REQ-1:0] gnt_onehot;

hazard3_onehot_priority #(
	.W_REQ        (W_REQ),
	.HIGHEST_WINS (HIGHEST_WINS)
) priority_u (
	.req (req),
	.gnt (gnt_onehot)
);

hazard3_onehot_encode #(
	.W_REQ (W_REQ)
) encode_u (
	.req (gnt_onehot),
	.gnt (gnt)
);

endmodule
module hazard3_sbus_to_ahb #(
	parameter W_ADDR = 32,
	parameter W_DATA = 32
) (
	input wire               clk,
	input wire               rst_n,

	input  wire [W_ADDR-1:0] sbus_addr,
	input  wire              sbus_write,
	input  wire [1:0]        sbus_size,
	input  wire              sbus_vld,
	output wire              sbus_rdy,
	output wire              sbus_err,
	input  wire [W_DATA-1:0] sbus_wdata,
	output wire [W_DATA-1:0] sbus_rdata,

	output wire [W_ADDR-1:0] ahblm_haddr,
	output wire              ahblm_hwrite,
	output wire [1:0]        ahblm_htrans,
	output wire [2:0]        ahblm_hsize,
	output wire [2:0]        ahblm_hburst,
	output wire [3:0]        ahblm_hprot,
	output wire              ahblm_hmastlock,
	input  wire              ahblm_hready,
	input  wire              ahblm_hresp,
	output wire [W_DATA-1:0] ahblm_hwdata,
	input  wire [W_DATA-1:0] ahblm_hrdata
);

// Most signals are simple tie-throughs

assign ahblm_haddr     = sbus_addr;
assign ahblm_hwrite    = sbus_write;
assign ahblm_hsize     = {1'b0, sbus_size};
assign ahblm_hwdata    = sbus_wdata;

// HPROT = noncacheable nonbufferable privileged data access:
assign ahblm_hprot     = 4'b0011;
assign ahblm_hmastlock = 1'b0;
assign ahblm_hburst    = 3'h0;

assign sbus_err        = ahblm_hresp;
assign sbus_rdata      = ahblm_hrdata;

// Handshaking

reg dph_active;

always @ (posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		dph_active <= 1'b0;
	end else if (ahblm_hready) begin
		dph_active <= ahblm_htrans[1];
	end
end

assign ahblm_htrans = sbus_vld && !dph_active ? 2'b10 : 2'b00;

assign sbus_rdy = ahblm_hready && dph_active;

endmodule
module data_mem (
    clk,

    data,         //< io >
    addr,         //< i
    rd,           //< i
    wr,           //< i
    en            //< i

 );

    //IOs
    input            clk;

    inout [7:0]      data;
    input [11:0]     addr;
    input            rd;
    input            wr;
    input            en;


    //define the sram structure here
    reg [7:0]    mem [0:4095];

    wire [7:0]    r_data;

    always @(posedge clk) begin
        if(en & wr) begin
            mem[addr] <= data;
        end
    end

    assign r_data[7:0] = mem[addr];

    assign data[7:0] = (en & rd) ? r_data[7:0] : 8'bzzzz_zzzz;
 endmodule
module assert_never (clk, reset_, test);
    parameter msg = "assert_never_msg";
    input clk;
    input reset_;
    input test;
    always @(posedge clk) begin
        if(reset_ === 1) begin
            if(test) begin
                $display("%c[1;31m",27);
                $display("%s %m",msg);
                $display("%c[0m",27);
                $finish;
            end
        end
    end
endmodule
module assert_always (clk, reset_, test);
    parameter msg = "assert_always_msg";
    input clk;
    input reset_;
    input test;
    always @(posedge clk) begin
        if(reset_ === 1) begin
            if(!test) begin
                $display("%c[1;31m",27);
                $display("%s %m",msg);
                $display("%c[0m",27);
                $finish;
            end
        end
    end
endmodule
module assert_impl (clk, reset_, antedecent, consequent);
    parameter msg = "assert_impl_msg";
    input clk;
    input reset_;
    input antedecent;
    input consequent;
    always @(posedge clk) begin
        if(reset_ === 1) begin
            if(antedecent && !consequent) begin
                $display("%c[1;31m",27);
                $display("%s %m",msg);
                $display("%c[0m",27);
                $finish;
            end
        end
    end
endmodule
module assert_no_x (clk, reset_, test);
    parameter msg = "assert_no_x_msg";
    input clk;
    input reset_;
    input test;
    always @(posedge clk) begin
        if(reset_ === 1) begin
            if(!((test === 1'b1) || (test === 1'b0))) begin
                $display("%c[1;31m",27);
                $display("%s %m",msg);
                $display("%c[0m",27);
                $finish;
            end
        end
    end
endmodule
module ifetch(
    clk,        //< i
    reset_,     //< i
    branch,     //< i branch indication from ctrl unit
    ret_addr,   //<i    //return address
    ret_addr_en,//<i
    ifetch_en,  //< i ifetch_en indiaction from ctrl unit
    inst_i,     //< i instruction input from inst_mem
    tgt_addr,   //< i tgt branch addr
    inst_o,     //> o instruction output to decode unit
    idecode_en, //> o ifetch2idecode_en
    inst_addr,  //> o addr for instruction memory 
    next_addr   //>o next PC address
);
    //IOs
    input           clk;
    input           reset_;

    input           branch;
    input           ifetch_en;

    input [7:0]     inst_i;
    input [11:0]    tgt_addr;
    input [11:0]    ret_addr;
    input           ret_addr_en;

    output [7:0]    inst_o;
    output [11:0]   inst_addr;
    output [11:0]   next_addr;

    output          idecode_en;
    
    //regs
    reg [11:0]  PC;
    reg [7:0]   inst_reg;
    reg         idecode_en;

    //wires
    wire [11:0] pc_addr_next;
    wire [7:0] inst;

    //Program Counter implementation
    always @(posedge clk)   begin
        if(!reset_) begin
            PC[11:0]    <= 12'd0;
        end
        else begin
            PC[11:0]    <= pc_addr_next[11:0]; 
        end
    end

    wire [11:0] next_addr;
    assign next_addr = PC + 1'b1; 
    assign pc_addr_next = (ifetch_en) ? ((branch) ? (tgt_addr + 1'b1) : (ret_addr_en ? ret_addr : next_addr)) : PC;
    assign inst_addr = branch ? tgt_addr : PC;    //address for inst mem

    //registering instruction from instruction mem
    always @(posedge clk)   begin
        if(!reset_) begin
            inst_reg[7:0]   <= 8'd0;
            idecode_en      <= 1'b0;
        end
        else begin
            inst_reg[7:0]   <= inst;
            idecode_en      <= ifetch_en;
        end
    end

    assign inst[7:0] = (ifetch_en) ? inst_i[7:0] : inst_reg[7:0];

    assign inst_o[7:0] = inst_reg[7:0];
endmodule
module transmitter(input wire [7:0] din,
		   input wire wr_en,
		   input wire clk_50m,
		   input wire clken,
		   output reg tx,
		   output wire tx_busy);

initial begin
	 tx = 1'b1;
end

parameter STATE_IDLE	= 2'b00;
parameter STATE_START	= 2'b01;
parameter STATE_DATA	= 2'b10;
parameter STATE_STOP	= 2'b11;

reg [7:0] data = 8'h00;
reg [2:0] bitpos = 3'h0;
reg [1:0] state = STATE_IDLE;

always @(posedge clk_50m) begin
	case (state)
	STATE_IDLE: begin
		if (wr_en) begin
			state <= STATE_START;
			data <= din;
			bitpos <= 3'h0;
		end
	end
	STATE_START: begin
		if (clken) begin
			tx <= 1'b0;
			state <= STATE_DATA;
		end
	end
	STATE_DATA: begin
		if (clken) begin
			if (bitpos == 3'h7)
				state <= STATE_STOP;
			else
				bitpos <= bitpos + 3'h1;
			tx <= data[bitpos];
		end
	end
	STATE_STOP: begin
		if (clken) begin
			tx <= 1'b1;
			state <= STATE_IDLE;
		end
	end
	default: begin
		tx <= 1'b1;
		state <= STATE_IDLE;
	end
	endcase
end

assign tx_busy = (state != STATE_IDLE);

endmodule
module pll(
	input  clock_in,
	output clock_out,
	output locked
	);

SB_PLL40_CORE #(
		.FEEDBACK_PATH("SIMPLE"),
		.DIVR(4'b0000),		// DIVR =  0
		.DIVF(7'b1000010),	// DIVF = 66
		.DIVQ(3'b100),		// DIVQ =  4
		.FILTER_RANGE(3'b001)	// FILTER_RANGE = 1
	) uut (
		.LOCK(locked),
		.RESETB(1'b1),
		.BYPASS(1'b0),
		.REFERENCECLK(clock_in),
		.PLLOUTCORE(clock_out)
		);

endmodule
module baud_rate_gen(input wire clk_50m,
		     output wire rxclk_en,
		     output wire txclk_en);

parameter RX_ACC_MAX = 50250000 / (115200 * 16);
parameter TX_ACC_MAX = 50250000 / 115200;
parameter RX_ACC_WIDTH = $clog2(RX_ACC_MAX);
parameter TX_ACC_WIDTH = $clog2(TX_ACC_MAX);
reg [RX_ACC_WIDTH - 1:0] rx_acc = 0;
reg [TX_ACC_WIDTH - 1:0] tx_acc = 0;

assign rxclk_en = (rx_acc == 5'd0);
assign txclk_en = (tx_acc == 9'd0);

always @(posedge clk_50m) begin
	if (rx_acc == RX_ACC_MAX[RX_ACC_WIDTH - 1:0])
		rx_acc <= 0;
	else
		rx_acc <= rx_acc + 5'b1;
end

always @(posedge clk_50m) begin
	if (tx_acc == TX_ACC_MAX[TX_ACC_WIDTH - 1:0])
		tx_acc <= 0;
	else
		tx_acc <= tx_acc + 9'b1;
end

endmodule
module cmac_pad #
(
    // Width of AXI stream interfaces in bits
    parameter DATA_WIDTH = 512,
    // tkeep signal width (words per cycle)
    parameter KEEP_WIDTH = (DATA_WIDTH/8),
    // tuser signal width
    parameter USER_WIDTH = 1
)
(
    input  wire                   clk,
    input  wire                   rst,
    
    /*
     * AXI input
     */
    input  wire [DATA_WIDTH-1:0]  s_axis_tdata,
    input  wire [KEEP_WIDTH-1:0]  s_axis_tkeep,
    input  wire                   s_axis_tvalid,
    output wire                   s_axis_tready,
    input  wire                   s_axis_tlast,
    input  wire [USER_WIDTH-1:0]  s_axis_tuser,

    /*
     * AXI output
     */
    output wire [DATA_WIDTH-1:0]  m_axis_tdata,
    output wire [KEEP_WIDTH-1:0]  m_axis_tkeep,
    output wire                   m_axis_tvalid,
    input  wire                   m_axis_tready,
    output wire                   m_axis_tlast,
    output wire [USER_WIDTH-1:0]  m_axis_tuser
);

// check configuration
initial begin
    if (DATA_WIDTH != 512) begin
        $error("Error: AXI stream data width must be 512 (instance %m)");
        $finish;
    end

    if (KEEP_WIDTH * 8 != DATA_WIDTH) begin
        $error("Error: AXI stream interface requires byte (8-bit) granularity (instance %m)");
        $finish;
    end
end

reg frame_reg = 1'b0;

generate
    genvar k;

    for (k = 0; k < KEEP_WIDTH; k = k + 1) begin
        assign m_axis_tdata[k*8 +: 8] = s_axis_tkeep[k] ? s_axis_tdata[k*8 +: 8] : 8'd0;
    end
endgenerate

assign m_axis_tkeep = (frame_reg ? {KEEP_WIDTH{1'b0}} : {60{1'b1}}) | s_axis_tkeep;
assign m_axis_tvalid = s_axis_tvalid;
assign s_axis_tready = m_axis_tready;
assign m_axis_tlast = s_axis_tlast;
assign m_axis_tuser = s_axis_tuser;

always @(posedge clk) begin
    if (s_axis_tvalid && s_axis_tready) begin
        frame_reg <= !s_axis_tlast;
    end

    if (rst) begin
        frame_reg <= 1'b0;
    end
end

endmodule
module priority_encoder #
(
    parameter WIDTH = 4,
    // LSB priority: "LOW", "HIGH"
    parameter LSB_PRIORITY = "LOW"
)
(
    input  wire [WIDTH-1:0]         input_unencoded,
    output wire                     output_valid,
    output wire [$clog2(WIDTH)-1:0] output_encoded,
    output wire [WIDTH-1:0]         output_unencoded
);

// power-of-two width
parameter W1 = 2**$clog2(WIDTH);
parameter W2 = W1/2;

generate
    if (WIDTH == 1) begin
        // one input
        assign output_valid = input_unencoded;
        assign output_encoded = 0;
    end else if (WIDTH == 2) begin
        // two inputs - just an OR gate
        assign output_valid = |input_unencoded;
        if (LSB_PRIORITY == "LOW") begin
            assign output_encoded = input_unencoded[1];
        end else begin
            assign output_encoded = ~input_unencoded[0];
        end
    end else begin
        // more than two inputs - split into two parts and recurse
        // also pad input to correct power-of-two width
        wire [$clog2(W2)-1:0] out1, out2;
        wire valid1, valid2;
        priority_encoder #(
            .WIDTH(W2),
            .LSB_PRIORITY(LSB_PRIORITY)
        )
        priority_encoder_inst1 (
            .input_unencoded(input_unencoded[W2-1:0]),
            .output_valid(valid1),
            .output_encoded(out1)
        );
        priority_encoder #(
            .WIDTH(W2),
            .LSB_PRIORITY(LSB_PRIORITY)
        )
        priority_encoder_inst2 (
            .input_unencoded({{W1-WIDTH{1'b0}}, input_unencoded[WIDTH-1:W2]}),
            .output_valid(valid2),
            .output_encoded(out2)
        );
        // multiplexer to select part
        assign output_valid = valid1 | valid2;
        if (LSB_PRIORITY == "LOW") begin
            assign output_encoded = valid2 ? {1'b1, out2} : {1'b0, out1};
        end else begin
            assign output_encoded = valid1 ? {1'b0, out1} : {1'b1, out2};
        end
    end
endgenerate

// unencoded output
assign output_unencoded = 1 << output_encoded;

endmodule
module pulse_merge #
(
    parameter INPUT_WIDTH = 2,
    parameter COUNT_WIDTH = 4
)
(
    input  wire                   clk,
    input  wire                   rst,

    input  wire [INPUT_WIDTH-1:0] pulse_in,
    output wire [COUNT_WIDTH-1:0] count_out,
    output wire                   pulse_out
);

reg [COUNT_WIDTH-1:0] count_reg = {COUNT_WIDTH{1'b0}}, count_next;
reg pulse_reg = 1'b0, pulse_next;

assign count_out = count_reg;
assign pulse_out = pulse_reg;

integer i;

always @* begin
    count_next = count_reg;
    pulse_next = count_reg > 0;

    if (count_reg > 0) begin
        count_next = count_reg - 1;
    end

    for (i = 0; i < INPUT_WIDTH; i = i + 1) begin
        count_next = count_next + pulse_in[i];
    end
end

always @(posedge clk) begin
    if (rst) begin
        count_reg <= {COUNT_WIDTH{1'b0}};
        pulse_reg <= 1'b0;
    end else begin
        count_reg <= count_next;
        pulse_reg <= pulse_next;
    end
end

endmodule
module axis_eth_fcs
(
    input  wire        clk,
    input  wire        rst,
    
    /*
     * AXI input
     */
    input  wire [7:0]  s_axis_tdata,
    input  wire        s_axis_tvalid,
    output wire        s_axis_tready,
    input  wire        s_axis_tlast,
    input  wire        s_axis_tuser,
    
    /*
     * FCS output
     */
    output wire [31:0] output_fcs,
    output wire        output_fcs_valid
);

reg [31:0] crc_state = 32'hFFFFFFFF;
reg [31:0] fcs_reg = 32'h00000000;
reg fcs_valid_reg = 1'b0;

wire [31:0] crc_next;

assign s_axis_tready = 1;
assign output_fcs = fcs_reg;
assign output_fcs_valid = fcs_valid_reg;

lfsr #(
    .LFSR_WIDTH(32),
    .LFSR_POLY(32'h4c11db7),
    .LFSR_CONFIG("GALOIS"),
    .LFSR_FEED_FORWARD(0),
    .REVERSE(1),
    .DATA_WIDTH(8),
    .STYLE("AUTO")
)
eth_crc_8 (
    .data_in(s_axis_tdata),
    .state_in(crc_state),
    .data_out(),
    .state_out(crc_next)
);

always @(posedge clk) begin
    if (rst) begin
        crc_state <= 32'hFFFFFFFF;
        fcs_reg <= 32'h00000000;
        fcs_valid_reg <= 1'b0;
    end else begin
        fcs_valid_reg <= 1'b0;
        if (s_axis_tvalid) begin
            if (s_axis_tlast) begin
                crc_state <= 32'hFFFFFFFF;
                fcs_reg <= ~crc_next;
                fcs_valid_reg <= 1'b1;
            end else begin
                crc_state <= crc_next;
            end
        end
    end
end

endmodule
module eth_phy_10g_rx #
(
    parameter DATA_WIDTH = 64,
    parameter CTRL_WIDTH = (DATA_WIDTH/8),
    parameter HDR_WIDTH = 2,
    parameter BIT_REVERSE = 0,
    parameter SCRAMBLER_DISABLE = 0,
    parameter PRBS31_ENABLE = 0,
    parameter SERDES_PIPELINE = 0,
    parameter SLIP_COUNT_WIDTH = 3,
    parameter COUNT_125US = 125000/6.4
)
(
    input  wire                  clk,
    input  wire                  rst,

    /*
     * XGMII interface
     */
    output wire [DATA_WIDTH-1:0] xgmii_rxd,
    output wire [CTRL_WIDTH-1:0] xgmii_rxc,

    /*
     * SERDES interface
     */
    input  wire [DATA_WIDTH-1:0] serdes_rx_data,
    input  wire [HDR_WIDTH-1:0]  serdes_rx_hdr,
    output wire                  serdes_rx_bitslip,

    /*
     * Status
     */
    output wire [6:0]            rx_error_count,
    output wire                  rx_bad_block,
    output wire                  rx_block_lock,
    output wire                  rx_high_ber,

    /*
     * Configuration
     */
    input  wire                  rx_prbs31_enable
);

// bus width assertions
initial begin
    if (DATA_WIDTH != 64) begin
        $error("Error: Interface width must be 64");
        $finish;
    end

    if (CTRL_WIDTH * 8 != DATA_WIDTH) begin
        $error("Error: Interface requires byte (8-bit) granularity");
        $finish;
    end

    if (HDR_WIDTH != 2) begin
        $error("Error: HDR_WIDTH must be 2");
        $finish;
    end
end

wire [DATA_WIDTH-1:0] encoded_rx_data;
wire [HDR_WIDTH-1:0]  encoded_rx_hdr;

eth_phy_10g_rx_if #(
    .DATA_WIDTH(DATA_WIDTH),
    .HDR_WIDTH(HDR_WIDTH),
    .BIT_REVERSE(BIT_REVERSE),
    .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
    .PRBS31_ENABLE(PRBS31_ENABLE),
    .SERDES_PIPELINE(SERDES_PIPELINE),
    .SLIP_COUNT_WIDTH(SLIP_COUNT_WIDTH),
    .COUNT_125US(COUNT_125US)
)
eth_phy_10g_rx_if_inst (
    .clk(clk),
    .rst(rst),
    .encoded_rx_data(encoded_rx_data),
    .encoded_rx_hdr(encoded_rx_hdr),
    .serdes_rx_data(serdes_rx_data),
    .serdes_rx_hdr(serdes_rx_hdr),
    .serdes_rx_bitslip(serdes_rx_bitslip),
    .rx_error_count(rx_error_count),
    .rx_block_lock(rx_block_lock),
    .rx_high_ber(rx_high_ber),
    .rx_prbs31_enable(rx_prbs31_enable)
);

xgmii_baser_dec_64 #(
    .DATA_WIDTH(DATA_WIDTH),
    .CTRL_WIDTH(CTRL_WIDTH),
    .HDR_WIDTH(HDR_WIDTH)
)
xgmii_baser_dec_inst (
    .clk(clk),
    .rst(rst),
    .encoded_rx_data(encoded_rx_data),
    .encoded_rx_hdr(encoded_rx_hdr),
    .xgmii_rxd(xgmii_rxd),
    .xgmii_rxc(xgmii_rxc),
    .rx_bad_block(rx_bad_block)
);

endmodule
module eth_phy_10g #
(
    parameter DATA_WIDTH = 64,
    parameter CTRL_WIDTH = (DATA_WIDTH/8),
    parameter HDR_WIDTH = 2,
    parameter BIT_REVERSE = 0,
    parameter SCRAMBLER_DISABLE = 0,
    parameter PRBS31_ENABLE = 0,
    parameter TX_SERDES_PIPELINE = 0,
    parameter RX_SERDES_PIPELINE = 0,
    parameter SLIP_COUNT_WIDTH = 3,
    parameter COUNT_125US = 125000/6.4
)
(
    input  wire                  rx_clk,
    input  wire                  rx_rst,
    input  wire                  tx_clk,
    input  wire                  tx_rst,

    /*
     * XGMII interface
     */
    input  wire [DATA_WIDTH-1:0] xgmii_txd,
    input  wire [CTRL_WIDTH-1:0] xgmii_txc,
    output wire [DATA_WIDTH-1:0] xgmii_rxd,
    output wire [CTRL_WIDTH-1:0] xgmii_rxc,

    /*
     * SERDES interface
     */
    output wire [DATA_WIDTH-1:0] serdes_tx_data,
    output wire [HDR_WIDTH-1:0]  serdes_tx_hdr,
    input  wire [DATA_WIDTH-1:0] serdes_rx_data,
    input  wire [HDR_WIDTH-1:0]  serdes_rx_hdr,
    output wire                  serdes_rx_bitslip,

    /*
     * Status
     */
    output wire [6:0]            rx_error_count,
    output wire                  rx_bad_block,
    output wire                  rx_block_lock,
    output wire                  rx_high_ber,

    /*
     * Configuration
     */
    input  wire                  tx_prbs31_enable,
    input  wire                  rx_prbs31_enable
);

eth_phy_10g_rx #(
    .DATA_WIDTH(DATA_WIDTH),
    .CTRL_WIDTH(CTRL_WIDTH),
    .HDR_WIDTH(HDR_WIDTH),
    .BIT_REVERSE(BIT_REVERSE),
    .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
    .PRBS31_ENABLE(PRBS31_ENABLE),
    .SERDES_PIPELINE(RX_SERDES_PIPELINE),
    .SLIP_COUNT_WIDTH(SLIP_COUNT_WIDTH),
    .COUNT_125US(COUNT_125US)
)
eth_phy_10g_rx_inst (
    .clk(rx_clk),
    .rst(rx_rst),
    .xgmii_rxd(xgmii_rxd),
    .xgmii_rxc(xgmii_rxc),
    .serdes_rx_data(serdes_rx_data),
    .serdes_rx_hdr(serdes_rx_hdr),
    .serdes_rx_bitslip(serdes_rx_bitslip),
    .rx_error_count(rx_error_count),
    .rx_bad_block(rx_bad_block),
    .rx_block_lock(rx_block_lock),
    .rx_high_ber(rx_high_ber),
    .rx_prbs31_enable(rx_prbs31_enable)
);

eth_phy_10g_tx #(
    .DATA_WIDTH(DATA_WIDTH),
    .CTRL_WIDTH(CTRL_WIDTH),
    .HDR_WIDTH(HDR_WIDTH),
    .BIT_REVERSE(BIT_REVERSE),
    .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
    .PRBS31_ENABLE(PRBS31_ENABLE),
    .SERDES_PIPELINE(TX_SERDES_PIPELINE)
)
eth_phy_10g_tx_inst (
    .clk(tx_clk),
    .rst(tx_rst),
    .xgmii_txd(xgmii_txd),
    .xgmii_txc(xgmii_txc),
    .serdes_tx_data(serdes_tx_data),
    .serdes_tx_hdr(serdes_tx_hdr),
    .tx_prbs31_enable(tx_prbs31_enable)
);

endmodule
module eth_phy_10g_rx_frame_sync #
(
    parameter HDR_WIDTH = 2,
    parameter SLIP_COUNT_WIDTH = 3
)
(
    input  wire                  clk,
    input  wire                  rst,

    /*
     * SERDES interface
     */
    input  wire [HDR_WIDTH-1:0]  serdes_rx_hdr,
    output wire                  serdes_rx_bitslip,

    /*
     * Status
     */
    output wire                  rx_block_lock
);

// bus width assertions
initial begin
    if (HDR_WIDTH != 2) begin
        $error("Error: HDR_WIDTH must be 2");
        $finish;
    end
end

localparam [1:0]
    SYNC_DATA = 2'b10,
    SYNC_CTRL = 2'b01;

reg [5:0] sh_count_reg = 6'd0, sh_count_next;
reg [3:0] sh_invalid_count_reg = 4'd0, sh_invalid_count_next;
reg [SLIP_COUNT_WIDTH-1:0] slip_count_reg = 0, slip_count_next;

reg serdes_rx_bitslip_reg = 1'b0, serdes_rx_bitslip_next;

reg rx_block_lock_reg = 1'b0, rx_block_lock_next;

assign serdes_rx_bitslip = serdes_rx_bitslip_reg;
assign rx_block_lock = rx_block_lock_reg;

always @* begin
    sh_count_next = sh_count_reg;
    sh_invalid_count_next = sh_invalid_count_reg;
    slip_count_next = slip_count_reg;

    serdes_rx_bitslip_next = 1'b0;

    rx_block_lock_next = rx_block_lock_reg;

    if (slip_count_reg) begin
        slip_count_next = slip_count_reg-1;
    end else if (serdes_rx_hdr == SYNC_CTRL || serdes_rx_hdr == SYNC_DATA) begin
        // valid header
        sh_count_next = sh_count_reg + 1;
        if (&sh_count_reg) begin
            // valid count overflow, reset
            sh_count_next = 0;
            sh_invalid_count_next = 0;
            if (!sh_invalid_count_reg) begin
                rx_block_lock_next = 1'b1;
            end
        end
    end else begin
        // invalid header
        sh_count_next = sh_count_reg + 1;
        sh_invalid_count_next = sh_invalid_count_reg + 1;
        if (!rx_block_lock_reg || &sh_invalid_count_reg) begin
            // invalid count overflow, lost block lock
            sh_count_next = 0;
            sh_invalid_count_next = 0;
            rx_block_lock_next = 1'b0;
            serdes_rx_bitslip_next = 1'b1;
            slip_count_next = {SLIP_COUNT_WIDTH{1'b1}};
        end else if (&sh_count_reg) begin
            // valid count overflow, reset
            sh_count_next = 0;
            sh_invalid_count_next = 0;
        end
    end
end

always @(posedge clk) begin
    if (rst) begin
        sh_count_reg <= 6'd0;
        sh_invalid_count_reg <= 4'd0;
        slip_count_reg <= 0;
        rx_block_lock_reg <= 1'b0;
    end else begin
        sh_count_reg <= sh_count_next;
        sh_invalid_count_reg <= sh_invalid_count_next;
        slip_count_reg <= slip_count_next;
        rx_block_lock_reg <= rx_block_lock_next;
    end
    
    serdes_rx_bitslip_reg <= serdes_rx_bitslip_next;
end

endmodule
module parser_wait_segs #(
	parameter C_AXIS_DATA_WIDTH = 512,
	parameter C_AXIS_TUSER_WIDTH = 128,
	parameter C_NUM_SEGS = 2
)
(
	input											axis_clk,
	input											aresetn,
	
	//
	input [C_AXIS_DATA_WIDTH-1:0]					s_axis_tdata,
	input [C_AXIS_TUSER_WIDTH-1:0]					s_axis_tuser,
	input [C_AXIS_DATA_WIDTH/8-1:0]					s_axis_tkeep,
	input											s_axis_tvalid,
	input											s_axis_tlast,
	
	//
	output reg[C_NUM_SEGS*C_AXIS_DATA_WIDTH-1:0]	tdata_segs,
	output reg[C_AXIS_TUSER_WIDTH-1:0]				tuser_1st,
	output reg										segs_valid
);

localparam	WAIT_1ST_SEG=0,
			WAIT_2ND_SEG=1,
			WAIT_1CYCLE=2,
			OUTPUT_SEGS=3,
			WAIT_TILL_LAST=4;

reg [2:0]	state, state_next;
reg [C_NUM_SEGS*C_AXIS_DATA_WIDTH-1:0] tdata_segs_next;
reg [C_AXIS_TUSER_WIDTH-1:0] tuser_1st_next;
reg	segs_valid_next;

always @(*) begin

	state_next = state;

	tdata_segs_next = tdata_segs;
	tuser_1st_next = tuser_1st;
	segs_valid_next = 0;

	case (state)
		// at-most 2 segs
		WAIT_1ST_SEG: begin
			if (s_axis_tvalid) begin
				tdata_segs_next[0*C_AXIS_DATA_WIDTH+:C_AXIS_DATA_WIDTH] = s_axis_tdata;
				tuser_1st_next = s_axis_tuser;

				if (s_axis_tlast) begin
					state_next = WAIT_1CYCLE;
				end
				else begin
					state_next = WAIT_2ND_SEG;
				end
			end
		end
		WAIT_1CYCLE: begin
			segs_valid_next = 1;
			state_next = WAIT_1ST_SEG;
		end
		WAIT_2ND_SEG: begin
			if (s_axis_tvalid) begin
				tdata_segs_next[1*C_AXIS_DATA_WIDTH+:C_AXIS_DATA_WIDTH] = s_axis_tdata;

				segs_valid_next = 1;
				if (s_axis_tlast) begin
					state_next = WAIT_1ST_SEG;
				end
				else begin
					state_next = WAIT_TILL_LAST;
				end
			end
		end
		WAIT_TILL_LAST: begin
			if (s_axis_tvalid && s_axis_tlast) begin
				state_next = WAIT_1ST_SEG;
			end
		end
	endcase
end


always @(posedge axis_clk) begin
	if (~aresetn) begin

		state <= WAIT_1ST_SEG;

		tdata_segs <= {C_NUM_SEGS*C_AXIS_DATA_WIDTH{1'b0}};
		tuser_1st <= {C_AXIS_TUSER_WIDTH{1'b0}};
		segs_valid <= 0;
	end
	else begin
		state <= state_next;

		tdata_segs <= tdata_segs_next;
		tuser_1st <= tuser_1st_next;

		segs_valid <= segs_valid_next;
	end
end

endmodule
module sub_parser #(
	parameter PKTS_HDR_LEN = 1024,
	parameter PARSE_ACT_LEN = 16,
	parameter VAL_OUT_LEN = 48
)
(
	input				clk,
	input				aresetn,

	input						parse_act_valid,
	input [PARSE_ACT_LEN-1:0]	parse_act,

	input [PKTS_HDR_LEN-1:0]	pkts_hdr,

	output reg					val_out_valid,
	output reg [VAL_OUT_LEN-1:0]	val_out,
	output reg [1:0]			val_out_type,
	output reg [2:0]			val_out_seq
);


reg [VAL_OUT_LEN-1:0]		val_out_nxt;
reg							val_out_valid_nxt;
reg [1:0]					val_out_type_nxt;
reg [2:0]					val_out_seq_nxt;

always @(*) begin
	val_out_valid_nxt = 0;
	val_out_nxt = val_out;
	val_out_type_nxt = val_out_type;
	val_out_seq_nxt = val_out_seq;

	if (parse_act_valid) begin
		val_out_valid_nxt = 1;
		val_out_seq_nxt = parse_act[3:1];
		
		case({parse_act[5:4], parse_act[0]})
			// 2B
			3'b011: begin
				val_out_type_nxt = 2'b01;
				val_out_nxt[15:0] = pkts_hdr[(parse_act[12:6])*8 +: 16];
			end
			// 4B
			3'b101: begin
				val_out_type_nxt = 2'b10;
				val_out_nxt[31:0] = pkts_hdr[(parse_act[12:6])*8 +: 32];
			end
			// 6B
			3'b111: begin
				val_out_type_nxt = 2'b11;
				val_out_nxt[47:0] = pkts_hdr[(parse_act[12:6])*8 +: 48];
			end
			default: begin
				val_out_type_nxt = 0;
				val_out_nxt = 0;
			end
		endcase
	end
end

always @(posedge clk) begin
	if (~aresetn) begin
		val_out_valid <= 0;
		val_out <= 0;
		val_out_type <= 0;
		val_out_seq <= 0;
	end
	else begin
		val_out_valid <= val_out_valid_nxt;
		val_out <= val_out_nxt;
		val_out_type <= val_out_type_nxt;
		val_out_seq <= val_out_seq_nxt;
	end
end


endmodule
module sub_deparser #(
	parameter C_PKT_VEC_WIDTH = (6+4+2)*8*8+256,
	parameter C_PARSE_ACT_LEN = 6						// only 6 bits are used here
)
(
	input										clk,
	input										aresetn,

	input										parse_act_valid,
	input [C_PARSE_ACT_LEN-1:0]					parse_act,
	input [C_PKT_VEC_WIDTH-1:0]					phv_in,

	output reg									val_out_valid,
	output reg [47:0]							val_out,
	output reg [1:0]							val_out_type
);

localparam PHV_2B_START_POS = 0+256;
localparam PHV_4B_START_POS = 16*8+256;
localparam PHV_6B_START_POS = 16*8+32*8+256;


reg			val_out_valid_nxt;
reg [47:0]	val_out_nxt;
reg [1:0]	val_out_type_nxt;


always @(*) begin
	val_out_valid_nxt = 0;
	val_out_nxt = val_out;
	val_out_type_nxt = val_out_type;

	if (parse_act_valid) begin
		val_out_valid_nxt = 1;

		case({parse_act[5:4], parse_act[0]})
			// 2B
			3'b011: begin
				val_out_type_nxt = 2'b01;
				case(parse_act[3:1])
					3'd0: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*0 +: 16];
					3'd1: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*1 +: 16];
					3'd2: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*2 +: 16];
					3'd3: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*3 +: 16];
					3'd4: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*4 +: 16];
					3'd5: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*5 +: 16];
					3'd6: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*6 +: 16];
					3'd7: val_out_nxt[15:0] = phv_in[PHV_2B_START_POS+16*7 +: 16];
				endcase
			end
			// 4B
			3'b101: begin
				val_out_type_nxt = 2'b10;
				case(parse_act[3:1])
					3'd0: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*0 +: 32];
					3'd1: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*1 +: 32];
					3'd2: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*2 +: 32];
					3'd3: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*3 +: 32];
					3'd4: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*4 +: 32];
					3'd5: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*5 +: 32];
					3'd6: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*6 +: 32];
					3'd7: val_out_nxt[31:0] = phv_in[PHV_4B_START_POS+32*7 +: 32];
				endcase
			end
			// 6B
			3'b111: begin
				val_out_type_nxt = 2'b11;
				case(parse_act[3:1])
					3'd0: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*0 +: 48];
					3'd1: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*1 +: 48];
					3'd2: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*2 +: 48];
					3'd3: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*3 +: 48];
					3'd4: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*4 +: 48];
					3'd5: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*5 +: 48];
					3'd6: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*6 +: 48];
					3'd7: val_out_nxt[47:0] = phv_in[PHV_6B_START_POS+48*7 +: 48];
				endcase
			end
			default: begin
				val_out_type_nxt = 0;
				val_out_nxt = 0;
			end
		endcase
	end
end


always @(posedge clk) begin
	if (~aresetn) begin
		val_out_valid <= 0;
		val_out <= 0;
		val_out_type <= 0;
	end
	else begin
		val_out_valid <= val_out_valid_nxt;
		val_out <= val_out_nxt;
		val_out_type <= val_out_type_nxt;
	end
end

endmodule
module blk_mem_gen_2 #(
    parameter ADDR_BITS = 5,
    parameter DATA_BITS = 38
)
(
    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 cam_top #(
    parameter C_DEPTH = 16,
    parameter ADDR_BITS = 4,
    parameter C_WIDTH = 205,
    parameter C_MEM_INIT = 0
) (
    input CLK,
    input RST,
    input [(C_WIDTH-1):0] CMP_DIN,
    input CMP_DATA_MASK,
    output BUSY,
    output MATCH,
    output [(ADDR_BITS - 1):0] MATCH_ADDR,

    input WE,
    input [(ADDR_BITS - 1):0] WR_ADDR,
    input DATA_MASK,
    input [(C_WIDTH-1):0] DIN,
    input EN
);

    cam_simple #(
        .DATA_WIDTH(C_WIDTH),
        .ADDR_WIDTH(ADDR_BITS),
        .SLICE_WIDTH(9)
    ) cam (
        .clk(CLK),
        .rst(RST),

        .write_addr(WR_ADDR),
        .write_data(DIN),
        .write_delete(0),
        .write_enable(WE),
        .write_busy(BUSY),

        .compare_data(CMP_DIN),
        .match_many(),
        .match_single(),
        .match_addr(MATCH_ADDR),
        .match(MATCH)
    );
endmodule