| /* |
| * user_module_341174480471589458.v |
| */ |
| |
| `default_nettype none |
| |
| module user_module_341174480471589458 ( |
| input wire latch_in, |
| input wire [7:0] io_in, |
| output wire [7:0] io_out |
| ); |
| |
| // Signals |
| // ------- |
| |
| // IO extension |
| wire [31:0] eio_in; |
| wire [31:0] eio_out; |
| wire [7:0] eio_latch_n; |
| |
| wire clk_slow; |
| wire clk_fast; |
| |
| |
| // IO extension |
| // ------------ |
| |
| // Input 0 is slow clock, keep as-is |
| sky130_fd_sc_hd__dlxtp_1 in_clk_slow_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .D (io_in[0]), |
| .GATE (latch_in), |
| .Q (clk_slow) |
| ); |
| |
| // Input [3:1] is 'address' |
| // Group 0 |
| sky130_fd_sc_hd__or4b_1 in_dec_0_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (io_in[1]), |
| .B (io_in[2]), |
| .C (io_in[3]), |
| .D_N (latch_in), |
| .X (eio_latch_n[0]) |
| ); |
| |
| // Group 1 |
| sky130_fd_sc_hd__nand4bb_1 in_dec_1_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (io_in[3]), |
| .B_N (io_in[2]), |
| .C (io_in[1]), |
| .D (latch_in), |
| .Y (eio_latch_n[1]) |
| ); |
| |
| // Group 2 |
| sky130_fd_sc_hd__nand4bb_1 in_dec_2_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (io_in[3]), |
| .B_N (io_in[1]), |
| .C (io_in[2]), |
| .D (latch_in), |
| .Y (eio_latch_n[2]) |
| ); |
| |
| // Group 3 |
| sky130_fd_sc_hd__nand4b_1 in_dec_3_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (io_in[3]), |
| .B (io_in[2]), |
| .C (io_in[1]), |
| .D (latch_in), |
| .Y (eio_latch_n[3]) |
| ); |
| |
| // Group 4 |
| sky130_fd_sc_hd__nand4bb_1 in_dec_4_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (io_in[1]), |
| .B_N (io_in[2]), |
| .C (io_in[3]), |
| .D (latch_in), |
| .Y (eio_latch_n[4]) |
| ); |
| |
| // Group 5 |
| sky130_fd_sc_hd__nand4b_1 in_dec_5_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (io_in[2]), |
| .B (io_in[1]), |
| .C (io_in[3]), |
| .D (latch_in), |
| .Y (eio_latch_n[5]) |
| ); |
| |
| // Group 6 |
| sky130_fd_sc_hd__nand4b_1 in_dec_6_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (io_in[1]), |
| .B (io_in[2]), |
| .C (io_in[3]), |
| .D (latch_in), |
| .Y (eio_latch_n[6]) |
| ); |
| |
| // Group 7 |
| sky130_fd_sc_hd__nand4_1 in_dec_7_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (io_in[1]), |
| .B (io_in[2]), |
| .C (io_in[3]), |
| .D (latch_in), |
| .Y (eio_latch_n[7]) |
| ); |
| |
| // Input [7:4] is data |
| // For the first 7 groups, we have latches |
| // The last group is pulse gen and not handled here |
| genvar i; |
| generate |
| for (i=0; i<7; i=i+1) begin |
| sky130_fd_sc_hd__dlxtn_1 in_latch_I[3:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .D (io_in[7:4]), |
| .GATE_N (eio_latch_n[i]), |
| .Q (eio_in[i*4+:4]) |
| ); |
| end |
| endgenerate |
| |
| // Output mux |
| sky130_fd_sc_hd__mux4_1 out_mux_I[7:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A0 (eio_out[ 7: 0]), |
| .A1 (eio_out[15: 8]), |
| .A2 (eio_out[23:16]), |
| .A3 (eio_out[31:24]), |
| .X (io_out), |
| .S0 (eio_in[0]), |
| .S1 (eio_in[1]) |
| ); |
| |
| |
| // Ring oscillator |
| // --------------- |
| |
| // Signals |
| wire [1:0] osc_ctrl; |
| wire [17:0] osc_chain; |
| wire [16:0] osc_chain_dly; |
| wire osc_mux; |
| wire osc_out; |
| |
| // IOs |
| assign osc_ctrl = eio_in[5:4]; |
| |
| // Chain |
| // First |
| assign osc_chain[0] = osc_out; |
| |
| // Delay |
| sky130_fd_sc_hd__clkdlybuf4s50_1 osc_dly_I[16:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (osc_chain[16:0]), |
| .X (osc_chain_dly) |
| ); |
| |
| // Inverter |
| sky130_fd_sc_hd__clkinv_1 osc_inv_I[16:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (osc_chain_dly), |
| .Y (osc_chain[17:1]) |
| ); |
| |
| // Feedback mux |
| sky130_fd_sc_hd__mux4_1 osc_mux_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A0 (1'b0), |
| .A1 (osc_chain[17]), |
| .A2 (osc_chain[9]), |
| .A3 (osc_chain[5]), |
| .X (osc_mux), |
| .S0 (osc_ctrl[0]), |
| .S1 (osc_ctrl[1]) |
| ); |
| |
| // Output buffer |
| sky130_fd_sc_hd__clkbuf_2 osc_buf_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (osc_mux), |
| .X (osc_out) |
| ); |
| |
| |
| // Clock divider |
| // ------------- |
| // Should support 1:1 / 1:4 / 1:16 / 1:64 |
| |
| // Signals |
| wire [1:0] clk_div_ctrl; |
| wire [6:0] clk_div_chain; |
| wire [6:0] clk_div_chain_n; |
| wire clk_div_mux; |
| |
| // IOs |
| assign clk_div_ctrl = eio_in[7:6]; |
| |
| // Input |
| assign clk_div_chain[0] = osc_out; |
| |
| // 6 stages of divide-by-2 |
| generate |
| for (i=1; i<7; i=i+1) |
| begin |
| sky130_fd_sc_hd__inv_1 clk_div_inv_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (clk_div_chain[i]), |
| .Y (clk_div_chain_n[i]) |
| ); |
| |
| sky130_fd_sc_hd__dfxtp_1 clk_div_reg_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .D (clk_div_chain_n[i]), |
| .Q (clk_div_chain[i]), |
| .CLK (clk_div_chain[i-1]) |
| ); |
| end |
| endgenerate |
| |
| // Output select |
| sky130_fd_sc_hd__mux4_1 clk_div_mux_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A0 (clk_div_chain[0]), |
| .A1 (clk_div_chain[2]), |
| .A2 (clk_div_chain[4]), |
| .A3 (clk_div_chain[6]), |
| .X (clk_div_mux), |
| .S0 (clk_div_ctrl[0]), |
| .S1 (clk_div_ctrl[1]) |
| ); |
| |
| // Output buffer |
| sky130_fd_sc_hd__clkbuf_8 clk_div_buf_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (clk_div_mux), |
| .X (clk_fast) |
| ); |
| |
| |
| // 16 bits LFSR |
| // ------------ |
| |
| // Signals |
| wire [3:0] lfsr_ctrl; |
| |
| wire lfsr_clk_mux; |
| wire lfsr_clk_gate; |
| wire lfsr_clk_buf; |
| |
| wire [15:0] lfsr_in; |
| wire [15:0] lfsr_out; |
| wire [2:0] lfsr_xor; |
| wire lfsr_init; |
| |
| // I/O |
| assign lfsr_ctrl = eio_in[11:8]; |
| assign eio_out[31:16] = lfsr_out; |
| |
| // Clock mux & enable |
| sky130_fd_sc_hd__mux2_1 lfsr_clk_mux_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A0 (clk_slow), |
| .A1 (clk_fast), |
| .S (lfsr_ctrl[2]), |
| .X (lfsr_clk_mux) |
| ); |
| |
| sky130_fd_sc_hd__and2_1 lfsr_clk_gate_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (lfsr_ctrl[3]), |
| .B (lfsr_clk_mux), |
| .X (lfsr_clk_gate) |
| ); |
| |
| sky130_fd_sc_hd__clkbuf_8 lfsr_clk_buf_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (lfsr_clk_gate), |
| .X (lfsr_clk_buf) |
| ); |
| |
| // Input mapping |
| assign lfsr_in = { |
| lfsr_init, |
| lfsr_out[15], |
| lfsr_xor[2:1], |
| lfsr_out[12], |
| lfsr_xor[0], |
| lfsr_out[10:1] |
| }; |
| |
| // Registers |
| sky130_fd_sc_hd__dfxtp_1 lfsr_reg_I[15:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .D (lfsr_in), |
| .Q (lfsr_out), |
| .CLK (lfsr_clk_buf) |
| ); |
| |
| // XORs |
| sky130_fd_sc_hd__xor2_1 lfsr_xor_I[2:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A ({lfsr_out[14], lfsr_out[13], lfsr_out[11]}), |
| .B (lfsr_out[0]), |
| .X (lfsr_xor) |
| ); |
| |
| // Init |
| sky130_fd_sc_hd__mux2_1 lfsr_init_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A0 (lfsr_out[0]), |
| .A1 (lfsr_ctrl[0]), |
| .S (lfsr_ctrl[1]), |
| .X (lfsr_init) |
| ); |
| |
| |
| // Pulse generator |
| // --------------- |
| // Writes to the last group of input IO generate pulses in `clk` domain |
| // and not constant values |
| |
| // Signals |
| wire [1:0] pgen_latch_reg; |
| wire [3:0] pgen_match; |
| |
| // Double register the latch signal |
| sky130_fd_sc_hd__dfxtp_1 pgen_sync_I[1:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .D ({pgen_latch_reg[0], eio_latch_n[7]}), |
| .Q ({pgen_latch_reg[1], pgen_latch_reg[0]}), |
| .CLK (clk_fast) |
| ); |
| |
| // On rising edge of latch signal, generate pulses |
| sky130_fd_sc_hd__and3b_1 pgen_match_I[3:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (pgen_latch_reg[1]), |
| .B (pgen_latch_reg[0]), |
| .C (io_in[7:4]), |
| .X (pgen_match) |
| ); |
| |
| sky130_fd_sc_hd__dfxtp_4 pgen_reg_I[3:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .D (pgen_match), |
| .Q (eio_in[31:28]), |
| .CLK (clk_fast) |
| ); |
| |
| |
| // Accumulator |
| // ----------- |
| |
| // OP reset load add sub |
| // |
| // A Input: |
| // . zero X X |
| // . acc_reg X X |
| // |
| // B Input |
| // . zero X |
| // . eio_in[19:12] X X |
| // . ~eio_in[19:12] X |
| // |
| // C Input |
| // . zero X X X |
| // . one X |
| |
| // Signals |
| wire [3:0] acc_ctrl; |
| |
| wire [7:0] acc_a; |
| wire [7:0] acc_b; |
| wire [7:0] acc_binv; |
| wire [8:0] acc_carry; |
| wire [7:0] acc_sum; |
| wire [7:0] acc_reg; |
| |
| wire acc_ce; |
| wire acc_clk; |
| |
| // Control pulses |
| assign acc_ctrl = eio_in[31:28]; |
| |
| // Generate gated clock for clock enable |
| sky130_fd_sc_hd__or4_1 acc_ce_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (acc_ctrl[0]), |
| .B (acc_ctrl[1]), |
| .C (acc_ctrl[2]), |
| .D (acc_ctrl[3]), |
| .X (acc_ce) |
| ); |
| |
| sky130_fd_sc_hd__dlclkp_1 acc_clk_gate_I ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .CLK (clk_fast), |
| .GATE (acc_ce), |
| .GCLK (acc_clk) |
| ); |
| |
| // A-input |
| sky130_fd_sc_hd__o21a_1 acc_a_I[7:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A1 (acc_ctrl[2]), |
| .A2 (acc_ctrl[3]), |
| .B1 (acc_reg), |
| .X (acc_a) |
| ); |
| |
| // B-input |
| sky130_fd_sc_hd__xor2_1 acc_binv_I[7:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (acc_reg), |
| .B (acc_ctrl[3]), |
| .X (acc_binv) |
| ); |
| |
| sky130_fd_sc_hd__and2b_1 acc_b_I[7:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A_N (acc_ctrl[0]), |
| .B (acc_binv), |
| .X (acc_b) |
| ); |
| |
| // Carry-Input |
| assign acc_carry[0] = acc_ctrl[3]; |
| |
| // Full adder |
| sky130_fd_sc_hd__fa_2 acc_add_I[7:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .A (acc_a), |
| .B (acc_b), |
| .CIN (acc_carry[7:0]), |
| .SUM (acc_sum), |
| .COUT (acc_carry[8:1]) |
| ); |
| |
| // Registers |
| sky130_fd_sc_hd__dfxtp_1 acc_reg_I[7:0] ( |
| `ifdef WITH_POWER |
| .VPWR (1'b1), |
| .VGND (1'b0), |
| `endif |
| .D (acc_sum), |
| .Q (acc_reg), |
| .CLK (acc_clk) |
| ); |
| |
| // Output |
| assign eio_out[7:0] = acc_reg; |
| |
| |
| // Loopback |
| // -------- |
| |
| // Just link in/output |
| assign eio_out[15:8] = eio_in[27:20]; |
| |
| endmodule // user_module_341174480471589458 |