| /* |
| * yosys -- Yosys Open SYnthesis Suite |
| * |
| * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| * |
| */ |
| |
| // ============================================================================ |
| // LCU |
| |
| (* techmap_celltype = "$lcu" *) |
| module _80_xilinx_lcu (P, G, CI, CO); |
| parameter WIDTH = 2; |
| |
| input [WIDTH-1:0] P, G; |
| input CI; |
| |
| output [WIDTH-1:0] CO; |
| |
| wire _TECHMAP_FAIL_ = WIDTH <= 2; |
| |
| genvar i; |
| |
| `ifdef _CLB_CARRY |
| |
| localparam CARRY4_COUNT = (WIDTH + 3) / 4; |
| localparam MAX_WIDTH = CARRY4_COUNT * 4; |
| localparam PAD_WIDTH = MAX_WIDTH - WIDTH; |
| |
| wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G}; |
| wire [MAX_WIDTH-1:0] C = CO; |
| |
| generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice |
| |
| // Partially occupied CARRY4 |
| if ((i+1)*4 > WIDTH) begin |
| |
| // First one |
| if (i == 0) begin |
| CARRY4 carry4_1st_part |
| ( |
| .CYINIT(CI), |
| .CI (1'd0), |
| .DI (G [(Y_WIDTH - 1):i*4]), |
| .S (S [(Y_WIDTH - 1):i*4]), |
| .CO (CO[(Y_WIDTH - 1):i*4]), |
| ); |
| // Another one |
| end else begin |
| CARRY4 carry4_part |
| ( |
| .CYINIT(1'd0), |
| .CI (C [i*4 - 1]), |
| .DI (G [(Y_WIDTH - 1):i*4]), |
| .S (S [(Y_WIDTH - 1):i*4]), |
| .CO (CO[(Y_WIDTH - 1):i*4]), |
| ); |
| end |
| |
| // Fully occupied CARRY4 |
| end else begin |
| |
| // First one |
| if (i == 0) begin |
| CARRY4 carry4_1st_full |
| ( |
| .CYINIT(CI), |
| .CI (1'd0), |
| .DI (G [((i+1)*4 - 1):i*4]), |
| .S (S [((i+1)*4 - 1):i*4]), |
| .CO (CO[((i+1)*4 - 1):i*4]), |
| ); |
| // Another one |
| end else begin |
| CARRY4 carry4_full |
| ( |
| .CYINIT(1'd0), |
| .CI (C [i*4 - 1]), |
| .DI (G [((i+1)*4 - 1):i*4]), |
| .S (S [((i+1)*4 - 1):i*4]), |
| .CO (CO[((i+1)*4 - 1):i*4]), |
| ); |
| end |
| |
| end |
| |
| end endgenerate |
| |
| `elsif _EXPLICIT_CARRY |
| |
| wire [WIDTH-1:0] C = {CO, CI}; |
| wire [WIDTH-1:0] S = P & ~G; |
| |
| generate for (i = 0; i < WIDTH; i = i + 1) begin:slice |
| MUXCY muxcy ( |
| .CI(C[i]), |
| .DI(G[i]), |
| .S(S[i]), |
| .O(CO[i]) |
| ); |
| end endgenerate |
| |
| `else |
| |
| wire [WIDTH-1:0] C = {CO, CI}; |
| wire [WIDTH-1:0] S = P & ~G; |
| |
| generate for (i = 0; i < WIDTH; i = i + 1) begin:slice |
| MUXCY muxcy ( |
| .CI(C[i]), |
| .DI(G[i]), |
| .S(S[i]), |
| .O(CO[i]) |
| ); |
| end endgenerate |
| `endif |
| |
| endmodule |
| |
| |
| // ============================================================================ |
| // ALU |
| |
| (* techmap_celltype = "$alu" *) |
| module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 1; |
| parameter B_WIDTH = 1; |
| parameter Y_WIDTH = 1; |
| parameter _TECHMAP_CONSTVAL_CI_ = 0; |
| parameter _TECHMAP_CONSTMSK_CI_ = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] X, Y; |
| |
| input CI, BI; |
| output [Y_WIDTH-1:0] CO; |
| |
| wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; |
| |
| wire [Y_WIDTH-1:0] A_buf, B_buf; |
| \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); |
| \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); |
| |
| wire [Y_WIDTH-1:0] AA = A_buf; |
| wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; |
| |
| genvar i; |
| |
| `ifdef _CLB_CARRY |
| |
| localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4; |
| localparam MAX_WIDTH = CARRY4_COUNT * 4; |
| localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; |
| |
| wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; |
| wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB}; |
| |
| wire [MAX_WIDTH-1:0] C = CO; |
| |
| genvar i; |
| generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice |
| |
| // Partially occupied CARRY4 |
| if ((i+1)*4 > Y_WIDTH) begin |
| |
| // First one |
| if (i == 0) begin |
| CARRY4 carry4_1st_part |
| ( |
| .CYINIT(CI), |
| .CI (1'd0), |
| .DI (DI[(Y_WIDTH - 1):i*4]), |
| .S (S [(Y_WIDTH - 1):i*4]), |
| .O (Y [(Y_WIDTH - 1):i*4]), |
| .CO (CO[(Y_WIDTH - 1):i*4]) |
| ); |
| // Another one |
| end else begin |
| CARRY4 carry4_part |
| ( |
| .CYINIT(1'd0), |
| .CI (C [i*4 - 1]), |
| .DI (DI[(Y_WIDTH - 1):i*4]), |
| .S (S [(Y_WIDTH - 1):i*4]), |
| .O (Y [(Y_WIDTH - 1):i*4]), |
| .CO (CO[(Y_WIDTH - 1):i*4]) |
| ); |
| end |
| |
| // Fully occupied CARRY4 |
| end else begin |
| |
| // First one |
| if (i == 0) begin |
| CARRY4 carry4_1st_full |
| ( |
| .CYINIT(CI), |
| .CI (1'd0), |
| .DI (DI[((i+1)*4 - 1):i*4]), |
| .S (S [((i+1)*4 - 1):i*4]), |
| .O (Y [((i+1)*4 - 1):i*4]), |
| .CO (CO[((i+1)*4 - 1):i*4]) |
| ); |
| // Another one |
| end else begin |
| CARRY4 carry4_full |
| ( |
| .CYINIT(1'd0), |
| .CI (C [i*4 - 1]), |
| .DI (DI[((i+1)*4 - 1):i*4]), |
| .S (S [((i+1)*4 - 1):i*4]), |
| .O (Y [((i+1)*4 - 1):i*4]), |
| .CO (CO[((i+1)*4 - 1):i*4]) |
| ); |
| end |
| |
| end |
| |
| end endgenerate |
| |
| `elsif _EXPLICIT_CARRY |
| |
| wire [Y_WIDTH-1:0] S = AA ^ BB; |
| wire [Y_WIDTH-1:0] DI = AA & BB; |
| |
| wire CINIT; |
| // Carry chain. |
| // |
| // VPR requires that the carry chain never hit the fabric. The CO input |
| // to this techmap is the carry outputs for synthesis, e.g. might hit the |
| // fabric. |
| // |
| // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR, |
| // e.g. off fabric dedicated chain. CO is the carry outputs that are |
| // available to the fabric. |
| wire [Y_WIDTH-1:0] CO_CHAIN; |
| wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT}; |
| |
| // If carry chain is being initialized to a constant, techmap the constant |
| // source. Otherwise techmap the fabric source. |
| generate for (i = 0; i < 1; i = i + 1) begin:slice |
| CARRY0 #(.CYINIT_FABRIC(1)) carry( |
| .CI_INIT(CI), |
| .DI(DI[0]), |
| .S(S[0]), |
| .CO_CHAIN(CO_CHAIN[0]), |
| .CO_FABRIC(CO[0]), |
| .O(Y[0]) |
| ); |
| end endgenerate |
| |
| generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice |
| if(i % 4 == 0) begin |
| CARRY0 carry ( |
| .CI(C[i]), |
| .DI(DI[i]), |
| .S(S[i]), |
| .CO_CHAIN(CO_CHAIN[i]), |
| .CO_FABRIC(CO[i]), |
| .O(Y[i]) |
| ); |
| end |
| else |
| begin |
| CARRY carry ( |
| .CI(C[i]), |
| .DI(DI[i]), |
| .S(S[i]), |
| .CO_CHAIN(CO_CHAIN[i]), |
| .CO_FABRIC(CO[i]), |
| .O(Y[i]) |
| ); |
| end |
| end endgenerate |
| |
| generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice |
| if(i % 4 == 0) begin |
| CARRY0 top_of_carry ( |
| .CI(C[i]), |
| .DI(DI[i]), |
| .S(S[i]), |
| .CO_CHAIN(CO_CHAIN[i]), |
| .O(Y[i]) |
| ); |
| end |
| else |
| begin |
| CARRY top_of_carry ( |
| .CI(C[i]), |
| .DI(DI[i]), |
| .S(S[i]), |
| .CO_CHAIN(CO_CHAIN[i]), |
| .O(Y[i]) |
| ); |
| end |
| // Turns out CO_FABRIC and O both use [ABCD]MUX, so provide |
| // a non-congested path to output the top of the carry chain. |
| // Registering the output of the CARRY block would solve this, but not |
| // all designs do that. |
| if((i+1) % 4 == 0) begin |
| CARRY0 carry_output ( |
| .CI(CO_CHAIN[i]), |
| .DI(0), |
| .S(0), |
| .O(CO[i]) |
| ); |
| end |
| else |
| begin |
| CARRY carry_output ( |
| .CI(CO_CHAIN[i]), |
| .DI(0), |
| .S(0), |
| .O(CO[i]) |
| ); |
| end |
| end endgenerate |
| |
| `else |
| |
| wire [Y_WIDTH-1:0] S = AA ^ BB; |
| wire [Y_WIDTH-1:0] DI = AA & BB; |
| |
| wire [Y_WIDTH-1:0] C = {CO, CI}; |
| |
| generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice |
| MUXCY muxcy ( |
| .CI(C[i]), |
| .DI(DI[i]), |
| .S(S[i]), |
| .O(CO[i]) |
| ); |
| XORCY xorcy ( |
| .CI(C[i]), |
| .LI(S[i]), |
| .O(Y[i]) |
| ); |
| end endgenerate |
| |
| `endif |
| |
| assign X = S; |
| endmodule |
| |