data/full_repos/permissive/169639758/ice40/regressions/issue0148/hdl/cpu16.sv
data/verilator_xmls/48da8489-c97d-453c-82b5-61ee795dd8f2.xml
module cpu16(
        input clk,
        output [15:0]ins_rd_addr,
        input [15:0]ins_rd_data,
	output ins_rd_req,
	input ins_rd_rdy,

	output [15:0]dat_rw_addr,
	output [15:0]dat_wr_data,
	input [15:0]dat_rd_data,
	output dat_rd_req,
	output dat_wr_req,
	input dat_rd_rdy,
	input dat_wr_rdy,

	input reset
        );

localparam INS_NOP = 16'h0001;


reg [15:0]pc_next;
reg [15:0]ir_next;
reg ir_valid_next;

reg [15:0]pc = 16'd0;
reg [15:0]ir = 16'd0;
reg ir_valid = 1'b0;

assign ins_rd_addr = pc_next;
assign ins_rd_req = 1'b1;

always_comb begin
	if (reset) begin
		pc_next = 16'h0000;
	end else if (ex_do_branch_imm) begin
		pc_next = ex_branch_tgt;
	end else if (ins_rd_rdy) begin
		pc_next = pc + 16'h0001;
	end else begin
		pc_next = pc;
	end
	ir_next = ins_rd_rdy ? ins_rd_data : INS_NOP;
	ir_valid_next = ins_rd_rdy;
end

always_ff @(posedge clk) begin
	pc <= pc_next;
	ir <= ir_next;
	ir_valid <= ir_valid_next;
end


reg [11:0]de_ext = 12'b0;
reg de_ext_rdy = 1'b0;








wire [15:0]ir_imm_s6_raw = { {11 {ir[15]}}, ir[14:10] };
wire [15:0]ir_imm_s7 = { {10 {ir[15]}}, ir[6], ir[14:10] };
wire [15:0]ir_imm_s9_raw = { {8 {ir[15]}}, ir[9:7], ir[14:10] };
wire [15:0]ir_imm_s11 = { {6 {ir[15]}}, ir[8:4], ir[14:10] };
wire [15:0]ir_imm_s12 = { {5 {ir[15]}}, ir[9:4], ir[14:10] };
wire [2:0]ir_csel = ir[6:4];
wire [2:0]ir_asel = ir[9:7];
wire [2:0]ir_bsel = ir[12:10];
wire [2:0]ir_alu_op = ir[3] ? ir[2:0] : ir[15:13];
wire [3:0]ir_opcode = ir[3:0];

reg [11:0]ir_ext_imm = 12'b0;
reg ir_ext_rdy = 1'b0;

wire [15:0]ir_imm_s6 = { (ir_ext_rdy ? ir_ext_imm : ir_imm_s6_raw[15:4]), ir_imm_s6_raw[3:0] };
wire [15:0]ir_imm_s9 = { (ir_ext_rdy ? ir_ext_imm : ir_imm_s9_raw[15:4]), ir_imm_s9_raw[3:0] };


reg do_wreg_alu;
reg do_wreg_mem;
reg do_adata_zero;
reg do_bdata_imm;
reg do_wr_link;
reg do_branch_imm;
reg do_branch_reg;
reg do_branch_cond;
reg do_branch_zero;
reg do_use_imm9_or_imm6;
reg do_mem_read;
reg do_mem_write;
reg do_set_ext;

always_comb begin
	do_wreg_alu = 1'b0;
	do_wreg_mem = 1'b0;
	do_adata_zero = 1'b0;
	do_bdata_imm = 1'b0;
	do_wr_link = 1'b0;
	do_branch_imm = 1'b0;
	do_branch_reg = 1'b0;
	do_branch_cond = 1'b0;
	do_branch_zero = 1'b0;
	do_use_imm9_or_imm6 = 1'b0;
	do_mem_read = 1'b0;
	do_mem_write = 1'b0;
	do_set_ext = 1'b0;

	casez (ir_opcode)
	4'b0000: begin
		do_wreg_alu = 1'b1;
	end
	4'b0001: begin
	end
	4'b0010: begin
		do_set_ext = 1'b1;
	end
	4'b0011: begin
		do_wreg_alu = 1'b1;
		do_adata_zero = 1'b1;
		do_bdata_imm = 1'b1;
		do_use_imm9_or_imm6 = 1'b1;
	end
	4'b0100: begin
		do_mem_read = 1'b1;
		do_use_imm9_or_imm6 = 1'b0;
	end
	4'b0101: begin
		do_mem_write = 1'b1;
		do_use_imm9_or_imm6 = 1'b0;
	end
	4'b0110: begin
		do_branch_imm = 1'b1;
		do_wr_link = ir[9];
	end
	4'b0111: begin
		if (ir[5]) begin
			do_branch_reg = 1'b1;
			do_wr_link = ir[4];
		end else begin
			do_branch_cond = 1'b1;
			do_branch_zero = ~ir[4];
		end
	end
	4'b1???: begin
		do_wreg_alu = 1'b1;
		do_bdata_imm = 1'b1;
		do_use_imm9_or_imm6 = 1'b0;
	end
	endcase
end

always_ff @(posedge clk) begin
	if (ir_valid)
		ir_ext_rdy <= do_set_ext;
	if (ir_valid & do_set_ext)
		ir_ext_imm <= ir_imm_s12[11:0];
end

wire [15:0]ex_adata;
wire [15:0]ex_bdata;
wire [15:0]ex_alu_rdata;

regs16 regs(
	.clk(clk),
	.asel(ir_asel),
	.bsel(do_mem_write ? ir_csel : ir_bsel),
	.wsel(ex_wsel),
	.wreg(ex_do_wreg_alu),
	.adata(ex_adata),
	.bdata(ex_bdata),
	.wdata(ex_alu_rdata)
	);



reg [15:0]ex_branch_tgt = 16'b0;
reg [2:0]ex_alu_op = 3'b0;
reg [2:0]ex_wsel = 3'b0;
reg ex_do_wreg_alu = 1'b0;
reg ex_do_wreg_mem = 1'b0;
reg ex_do_adata_zero = 1'b0;
reg ex_do_bdata_imm = 1'b0;
reg ex_do_wr_link = 1'b0;
reg ex_do_branch_imm = 1'b0;
reg ex_do_branch_reg = 1'b0;
reg ex_do_branch_cond = 1'b0;
reg ex_do_branch_zero = 1'b0;
reg ex_do_mem_read = 1'b0;
reg ex_do_mem_write = 1'b0;

reg [15:0]ex_imm = 16'b0;

always_ff @(posedge clk) begin

	ex_alu_op <= (do_adata_zero | do_mem_read | do_mem_write) ? 3'b0 : ir_alu_op;
	ex_wsel <= do_wr_link ? 3'd7 : ir_csel;
	ex_branch_tgt <= pc + (do_branch_imm ? ir_imm_s11 : ir_imm_s7);
	ex_do_wreg_alu <= do_wreg_alu;
	ex_do_wreg_mem <= do_wreg_mem;
	ex_do_adata_zero <= do_adata_zero;
	ex_do_bdata_imm <= do_bdata_imm;
	ex_do_wr_link <= do_wr_link;
	ex_do_branch_imm <= do_branch_imm;
	ex_do_branch_reg <= do_branch_reg;
	ex_do_branch_cond <= do_branch_cond;
	ex_do_branch_zero <= do_branch_zero;
	ex_do_mem_read = do_mem_read;
	ex_do_mem_write = do_mem_write;
	ex_imm <= (do_mem_read | do_mem_write) ? ir_imm_s7 : (do_use_imm9_or_imm6 ? ir_imm_s9 : ir_imm_s6);
end


alu16 alu(
	.op(ex_alu_op),
	.xdata(ex_do_adata_zero ? 16'b0 : ex_adata),
	.ydata((ex_do_mem_read | ex_do_mem_write | ex_do_bdata_imm) ? ex_imm : ex_bdata),
	.rdata(ex_alu_rdata)
	);

assign dat_rw_addr = ex_alu_rdata;
assign dat_wr_data = ex_bdata;
assign dat_rd_req = ex_do_mem_read;
assign dat_wr_req = ex_do_mem_write;



`ifdef verilator
reg [15:0]dbg_addr = 16'd0;
wire [47:0]ir_dbg_dis;
reg [47:0]ex_dbg_dis = 48'd0;

assign ir_dbg_dis = { ir, 3'b0, ir_ext_rdy, ir_ext_imm, dbg_addr };

always_ff @(posedge clk) begin
	dbg_addr <= pc;
	ex_dbg_dis <= ir_dbg_dis;
end
`endif

endmodule
module cpu16(
        input clk,
        output [15:0]ins_rd_addr,
        input [15:0]ins_rd_data,
	output ins_rd_req,
	input ins_rd_rdy,

	output [15:0]dat_rw_addr,
	output [15:0]dat_wr_data,
	input [15:0]dat_rd_data,
	output dat_rd_req,
	output dat_wr_req,
	input dat_rd_rdy,
	input dat_wr_rdy,

	input reset
        );


localparam INS_NOP = 16'h0001;


reg [15:0]pc_next;
reg [15:0]ir_next;
reg ir_valid_next;

reg [15:0]pc = 16'd0;
reg [15:0]ir = 16'd0;
reg ir_valid = 1'b0;

assign ins_rd_addr = pc_next;
assign ins_rd_req = 1'b1;

always_comb begin
	if (reset) begin
		pc_next = 16'h0000;
	end else if (ex_do_branch_imm) begin
		pc_next = ex_branch_tgt;
	end else if (ins_rd_rdy) begin
		pc_next = pc + 16'h0001;
	end else begin
		pc_next = pc;
	end
	ir_next = ins_rd_rdy ? ins_rd_data : INS_NOP;
	ir_valid_next = ins_rd_rdy;
end

always_ff @(posedge clk) begin
	pc <= pc_next;
	ir <= ir_next;
	ir_valid <= ir_valid_next;
end


reg [11:0]de_ext = 12'b0;
reg de_ext_rdy = 1'b0;








wire [15:0]ir_imm_s6_raw = { {11 {ir[15]}}, ir[14:10] };
wire [15:0]ir_imm_s7 = { {10 {ir[15]}}, ir[6], ir[14:10] };
wire [15:0]ir_imm_s9_raw = { {8 {ir[15]}}, ir[9:7], ir[14:10] };
wire [15:0]ir_imm_s11 = { {6 {ir[15]}}, ir[8:4], ir[14:10] };
wire [15:0]ir_imm_s12 = { {5 {ir[15]}}, ir[9:4], ir[14:10] };
wire [2:0]ir_csel = ir[6:4];
wire [2:0]ir_asel = ir[9:7];
wire [2:0]ir_bsel = ir[12:10];
wire [2:0]ir_alu_op = ir[3] ? ir[2:0] : ir[15:13];
wire [3:0]ir_opcode = ir[3:0];

reg [11:0]ir_ext_imm = 12'b0;
reg ir_ext_rdy = 1'b0;

wire [15:0]ir_imm_s6 = { (ir_ext_rdy ? ir_ext_imm : ir_imm_s6_raw[15:4]), ir_imm_s6_raw[3:0] };
wire [15:0]ir_imm_s9 = { (ir_ext_rdy ? ir_ext_imm : ir_imm_s9_raw[15:4]), ir_imm_s9_raw[3:0] };


reg do_wreg_alu;
reg do_wreg_mem;
reg do_adata_zero;
reg do_bdata_imm;
reg do_wr_link;
reg do_branch_imm;
reg do_branch_reg;
reg do_branch_cond;
reg do_branch_zero;
reg do_use_imm9_or_imm6;
reg do_mem_read;
reg do_mem_write;
reg do_set_ext;

always_comb begin
	do_wreg_alu = 1'b0;
	do_wreg_mem = 1'b0;
	do_adata_zero = 1'b0;
	do_bdata_imm = 1'b0;
	do_wr_link = 1'b0;
	do_branch_imm = 1'b0;
	do_branch_reg = 1'b0;
	do_branch_cond = 1'b0;
	do_branch_zero = 1'b0;
	do_use_imm9_or_imm6 = 1'b0;
	do_mem_read = 1'b0;
	do_mem_write = 1'b0;
	do_set_ext = 1'b0;

	casez (ir_opcode)
	4'b0000: begin
		do_wreg_alu = 1'b1;
	end
	4'b0001: begin
	end
	4'b0010: begin
		do_set_ext = 1'b1;
	end
	4'b0011: begin
		do_wreg_alu = 1'b1;
		do_adata_zero = 1'b1;
		do_bdata_imm = 1'b1;
		do_use_imm9_or_imm6 = 1'b1;
	end
	4'b0100: begin
		do_mem_read = 1'b1;
		do_use_imm9_or_imm6 = 1'b0;
	end
	4'b0101: begin
		do_mem_write = 1'b1;
		do_use_imm9_or_imm6 = 1'b0;
	end
	4'b0110: begin
		do_branch_imm = 1'b1;
		do_wr_link = ir[9];
	end
	4'b0111: begin
		if (ir[5]) begin
			do_branch_reg = 1'b1;
			do_wr_link = ir[4];
		end else begin
			do_branch_cond = 1'b1;
			do_branch_zero = ~ir[4];
		end
	end
	4'b1???: begin
		do_wreg_alu = 1'b1;
		do_bdata_imm = 1'b1;
		do_use_imm9_or_imm6 = 1'b0;
	end
	endcase
end

always_ff @(posedge clk) begin
	if (ir_valid)
		ir_ext_rdy <= do_set_ext;
	if (ir_valid & do_set_ext)
		ir_ext_imm <= ir_imm_s12[11:0];
end

wire [15:0]ex_adata;
wire [15:0]ex_bdata;
wire [15:0]ex_alu_rdata;

regs16 regs(
	.clk(clk),
	.asel(ir_asel),
	.bsel(do_mem_write ? ir_csel : ir_bsel),
	.wsel(ex_wsel),
	.wreg(ex_do_wreg_alu),
	.adata(ex_adata),
	.bdata(ex_bdata),
	.wdata(ex_alu_rdata)
	);



reg [15:0]ex_branch_tgt = 16'b0;
reg [2:0]ex_alu_op = 3'b0;
reg [2:0]ex_wsel = 3'b0;
reg ex_do_wreg_alu = 1'b0;
reg ex_do_wreg_mem = 1'b0;
reg ex_do_adata_zero = 1'b0;
reg ex_do_bdata_imm = 1'b0;
reg ex_do_wr_link = 1'b0;
reg ex_do_branch_imm = 1'b0;
reg ex_do_branch_reg = 1'b0;
reg ex_do_branch_cond = 1'b0;
reg ex_do_branch_zero = 1'b0;
reg ex_do_mem_read = 1'b0;
reg ex_do_mem_write = 1'b0;

reg [15:0]ex_imm = 16'b0;

always_ff @(posedge clk) begin

	ex_alu_op <= (do_adata_zero | do_mem_read | do_mem_write) ? 3'b0 : ir_alu_op;
	ex_wsel <= do_wr_link ? 3'd7 : ir_csel;
	ex_branch_tgt <= pc + (do_branch_imm ? ir_imm_s11 : ir_imm_s7);
	ex_do_wreg_alu <= do_wreg_alu;
	ex_do_wreg_mem <= do_wreg_mem;
	ex_do_adata_zero <= do_adata_zero;
	ex_do_bdata_imm <= do_bdata_imm;
	ex_do_wr_link <= do_wr_link;
	ex_do_branch_imm <= do_branch_imm;
	ex_do_branch_reg <= do_branch_reg;
	ex_do_branch_cond <= do_branch_cond;
	ex_do_branch_zero <= do_branch_zero;
	ex_do_mem_read = do_mem_read;
	ex_do_mem_write = do_mem_write;
	ex_imm <= (do_mem_read | do_mem_write) ? ir_imm_s7 : (do_use_imm9_or_imm6 ? ir_imm_s9 : ir_imm_s6);
end


alu16 alu(
	.op(ex_alu_op),
	.xdata(ex_do_adata_zero ? 16'b0 : ex_adata),
	.ydata((ex_do_mem_read | ex_do_mem_write | ex_do_bdata_imm) ? ex_imm : ex_bdata),
	.rdata(ex_alu_rdata)
	);

assign dat_rw_addr = ex_alu_rdata;
assign dat_wr_data = ex_bdata;
assign dat_rd_req = ex_do_mem_read;
assign dat_wr_req = ex_do_mem_write;



`ifdef verilator
reg [15:0]dbg_addr = 16'd0;
wire [47:0]ir_dbg_dis;
reg [47:0]ex_dbg_dis = 48'd0;

assign ir_dbg_dis = { ir, 3'b0, ir_ext_rdy, ir_ext_imm, dbg_addr };

always_ff @(posedge clk) begin
	dbg_addr <= pc;
	ex_dbg_dis <= ir_dbg_dis;
end
`endif

endmodule