blob: 2fb7e915101fbbcd0911dca8cc57c745b89769c0 [file] [log] [blame]
`default_nettype none
`default_nettype none
// Top level io for this module should stay the same to fit into the scan_wrapper.
// The pin connections within the user_module are up to you,
// although (if one is present) it is recommended to place a clock on io_in[0].
// This allows use of the internal clock divider if you wish.
module gatecat_fpga_top(
input [7:0] io_in,
output [7:0] io_out
);
wire cfg_mode, cfg_frameinc, cfg_framestrb, cfg_dataclk;
wire [3:0] cfg_sel;
sky130_fd_sc_hd__clkbuf_2 mode_clkbuf(.A(io_in[3]), .X(cfg_mode));
sky130_fd_sc_hd__clkbuf_2 frameinc_clkbuf(.A(io_in[1]), .X(cfg_frameinc));
sky130_fd_sc_hd__clkbuf_2 framestrb_clkbuf(.A(io_in[2]), .X(cfg_framestrb));
assign cfg_dataclk = io_in[0];
wire cfg_datain;
sky130_fd_sc_hd__buf_2 din_buf (.A(io_in[4]), .X(cfg_datain));
localparam W = 5;
localparam H = 6;
localparam FW = W * 4;
localparam FH = H * 2;
reg [$clog2(FH)-1:0] frame_ctr;
reg [FW-1:0] frame_sr;
always @(posedge cfg_frameinc, negedge cfg_mode)
if (~cfg_mode)
frame_ctr <= 0;
else
frame_ctr <= frame_ctr + 1'b1;
// avoid a shift register for the frame data because that's the highest hold risk
always @(posedge cfg_dataclk)
frame_sr <= {cfg_datain, frame_sr[FW-1:1]};
wire [FH-1:0] frame_strb;
wire gated_strobe = cfg_mode & cfg_framestrb;
generate;
genvar ii;
for (ii = 0; ii < FH; ii = ii + 1'b1) begin
//make sure this is glitch free
sky130_fd_sc_hd__nand2_2 cfg_nand (.A(gated_strobe), .B(frame_ctr == ii), .Y(frame_strb[ii]));
end
endgenerate
wire fab_clk = io_in[0];
wire [6:0] fab_din;
sky130_fd_sc_hd__buf_1 din_buf[6:0] (.A(io_in[7:1]), .X(fab_din));
wire [0:W-1] cell_q[0:H-1];
generate
genvar xx;
genvar yy;
for (yy = 0; yy < H; yy = yy + 1'b1) begin: y_c
for (xx = 0; xx < W; xx = xx + 1'b1) begin: x_c
wire ti, bi, li, ri;
if (yy > 0) assign ti = cell_q[yy-1][xx]; else assign ti = fab_din[xx];
if (yy < H-1) assign bi = cell_q[yy+1][xx]; else assign bi = cell_q[yy][xx];
if (xx > 0) assign li = cell_q[yy][xx-1]; else assign li = fab_din[yy + 1];
if (xx < W-1) assign ri = cell_q[yy][xx+1]; else assign ri = cell_q[yy][xx];
gatecat_logic_cell #(.has_ff(1'b1)) lc_i (
.CLK(fab_clk),
.cfg_mode(cfg_mode),
.cfg_strb(frame_strb[yy * 2 +: 2]),
.cfg_data(frame_sr[xx * 4 +: 4]),
.T(ti), .B(bi), .L(li),. R(ri),
.Q(cell_q[yy][xx])
);
end
end
endgenerate
assign io_out = {cell_q[5][W-1], cell_q[4][W-1], cell_q[3][W-1], cell_q[H-1]};
endmodule
module gatecat_logic_cell (
input CLK,
input cfg_mode,
input [1:0] cfg_strb,
input [3:0] cfg_data,
input T, L, R, B,
output Q
);
parameter has_ff = 1'b0;
// config storage
wire [7:0] cfg;
generate
genvar ii, jj;
for (ii = 0; ii < 2; ii = ii + 1'b1)
for (jj = 0; jj < 4; jj = jj + 1'b1)
sky130_fd_sc_hd__dlxtn_1 cfg_lat_i (
.D(cfg_data[jj]),
.GATE_N(cfg_strb[ii]),
.Q(cfg[ii*4 + jj])
);
endgenerate
wire i0, i1;
// I input muxes
wire i0a, i0b;
sky130_fd_sc_hd__nand2_1 i0muxa0 (
.A(T), .B(cfg[0]),
.Y(i0a)
);
sky130_fd_sc_hd__mux2i_1 i0muxa1 (
.A0(R), .A1(L), .S(cfg[0]),
.Y(i0b)
);
sky130_fd_sc_hd__mux2i_1 i0muxb (
.A0(i0a), .A1(i0b), .S(cfg[1]),
.Y(i0)
);
wire i1a, i1b;
sky130_fd_sc_hd__and2_1 i1muxa0 (
.A(cfg[2]), .B(L),
.X(i1a)
);
sky130_fd_sc_hd__mux2i_1 i1muxa1 (
.A0(B), .A1(R), .S(cfg[2]),
.Y(i1b)
);
sky130_fd_sc_hd__mux2i_1 i1muxb (
.A0(i1a), .A1(i1b), .S(cfg[3]),
.Y(i1)
);
// S input mux
wire s0s, s0, s0a, s0b;
sky130_fd_sc_hd__nand2_1 s0muxa0 (
.A(T), .B(cfg[4]),
.Y(s0a)
);
sky130_fd_sc_hd__mux2i_1 s0muxa1 (
.A0(R), .A1(L), .S(cfg[4]),
.Y(s0b)
);
sky130_fd_sc_hd__mux2i_1 s0muxb (
.A0(s0a), .A1(s0b), .S(cfg[5]),
.Y(s0s)
);
// S invert
sky130_fd_sc_hd__xnor2_1 sinv (
.A(s0s), .B(cfg[6]), .Y(s0)
);
// The logic element
wire muxo_n;
sky130_fd_sc_hd__mux2i_1 lmux (
.A0(i0), .A1(i1), .S(s0), .Y(muxo_n)
);
// The DFF
generate if (has_ff) begin: dff
wire dffo_n;
sky130_fd_sc_hd__dfsbp_1 dff(
.D(muxo_n),
.SET_B(~cfg_mode),
.CLK(CLK),
.Q(dffo_n)
);
// The final output mux
sky130_fd_sc_hd__mux2i_1 ffsel (
.A0(muxo_n), .A1(dffo_n), .S(cfg[7]), .Y(Q)
);
end else begin
sky130_fd_sc_hd__inv_1 linv (
.A(muxo_n), .Y(Q)
);
end
endgenerate
endmodule