| /* |
| * 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. |
| * |
| * --- |
| * |
| * The Simulation Library. |
| * |
| * This Verilog library contains simple simulation models for the internal |
| * cells ($not, ...) generated by the frontends and used in most passes. |
| * |
| * This library can be used to verify the internal netlists as generated |
| * by the different frontends and passes. |
| * |
| * Note that memory can only be simulated when all $memrd and $memwr cells |
| * have been merged to stand-alone $mem cells (this is what the "memory_collect" |
| * pass is doing). |
| * |
| */ |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $not (A, Y) |
| //- |
| //- A bit-wise inverter. This corresponds to the Verilog unary prefix '~' operator. |
| //- |
| module \$not (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = ~$signed(A); |
| end else begin:BLOCK2 |
| assign Y = ~A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $pos (A, Y) |
| //- |
| //- A buffer. This corresponds to the Verilog unary prefix '+' operator. |
| //- |
| module \$pos (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A); |
| end else begin:BLOCK2 |
| assign Y = A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $neg (A, Y) |
| //- |
| //- An arithmetic inverter. This corresponds to the Verilog unary prefix '-' operator. |
| //- |
| module \$neg (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = -$signed(A); |
| end else begin:BLOCK2 |
| assign Y = -A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $and (A, B, Y) |
| //- |
| //- A bit-wise AND. This corresponds to the Verilog '&' operator. |
| //- |
| module \$and (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) & $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A & B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $or (A, B, Y) |
| //- |
| //- A bit-wise OR. This corresponds to the Verilog '|' operator. |
| //- |
| module \$or (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) | $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A | B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $xor (A, B, Y) |
| //- |
| //- A bit-wise XOR. This corresponds to the Verilog '^' operator. |
| //- |
| module \$xor (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) ^ $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A ^ B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $xnor (A, B, Y) |
| //- |
| //- A bit-wise XNOR. This corresponds to the Verilog '~^' operator. |
| //- |
| module \$xnor (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) ~^ $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A ~^ B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $reduce_and (A, B, Y) |
| //- |
| //- An AND reduction. This corresponds to the Verilog unary prefix '&' operator. |
| //- |
| module \$reduce_and (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = &$signed(A); |
| end else begin:BLOCK2 |
| assign Y = &A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $reduce_or (A, B, Y) |
| //- |
| //- An OR reduction. This corresponds to the Verilog unary prefix '|' operator. |
| //- |
| module \$reduce_or (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = |$signed(A); |
| end else begin:BLOCK2 |
| assign Y = |A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $reduce_xor (A, B, Y) |
| //- |
| //- A XOR reduction. This corresponds to the Verilog unary prefix '^' operator. |
| //- |
| module \$reduce_xor (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = ^$signed(A); |
| end else begin:BLOCK2 |
| assign Y = ^A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $reduce_xnor (A, B, Y) |
| //- |
| //- A XNOR reduction. This corresponds to the Verilog unary prefix '~^' operator. |
| //- |
| module \$reduce_xnor (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = ~^$signed(A); |
| end else begin:BLOCK2 |
| assign Y = ~^A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $reduce_bool (A, B, Y) |
| //- |
| //- An OR reduction. This cell type is used instead of $reduce_or when a signal is |
| //- implicitly converted to a boolean signal, e.g. for operands of '&&' and '||'. |
| //- |
| module \$reduce_bool (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = !(!$signed(A)); |
| end else begin:BLOCK2 |
| assign Y = !(!A); |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$shl (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) << B; |
| end else begin:BLOCK2 |
| assign Y = A << B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$shr (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) >> B; |
| end else begin:BLOCK2 |
| assign Y = A >> B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$sshl (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) <<< B; |
| end else begin:BLOCK2 |
| assign Y = A <<< B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$sshr (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) >>> B; |
| end else begin:BLOCK2 |
| assign Y = A >>> B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$shift (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(B) < 0 ? A << -B : A >> B; |
| end else begin:BLOCK2 |
| assign Y = A >> B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$shiftx (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (Y_WIDTH > 0) |
| if (B_SIGNED) begin:BLOCK1 |
| assign Y = A[$signed(B) +: Y_WIDTH]; |
| end else begin:BLOCK2 |
| assign Y = A[B +: Y_WIDTH]; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$fa (A, B, C, X, Y); |
| |
| parameter WIDTH = 1; |
| |
| input [WIDTH-1:0] A, B, C; |
| output [WIDTH-1:0] X, Y; |
| |
| wire [WIDTH-1:0] t1, t2, t3; |
| |
| assign t1 = A ^ B, t2 = A & B, t3 = C & t1; |
| assign Y = t1 ^ C, X = (t2 | t3) ^ (Y ^ Y); |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $lcu (P, G, CI, CO) |
| //- |
| //- Lookahead carry unit |
| //- A building block dedicated to fast computation of carry-bits used in binary |
| //- arithmetic operations. By replacing the ripple carry structure used in full-adder |
| //- blocks, the more significant bits of the sum can be expected to be computed more |
| //- quickly. |
| //- Typically created during `techmap` of $alu cells (see the "_90_alu" rule in |
| //- +/techmap.v). |
| module \$lcu (P, G, CI, CO); |
| |
| parameter WIDTH = 1; |
| |
| input [WIDTH-1:0] P; // Propagate |
| input [WIDTH-1:0] G; // Generate |
| input CI; // Carry-in |
| |
| output reg [WIDTH-1:0] CO; // Carry-out |
| |
| integer i; |
| always @* begin |
| CO = 'bx; |
| if (^{P, G, CI} !== 1'bx) begin |
| CO[0] = G[0] || (P[0] && CI); |
| for (i = 1; i < WIDTH; i = i+1) |
| CO[i] = G[i] || (P[i] && CO[i-1]); |
| end |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| //- |
| //- $alu (A, B, CI, BI, X, Y, CO) |
| //- |
| //- Arithmetic logic unit. |
| //- A building block supporting both binary addition/subtraction operations, and |
| //- indirectly, comparison operations. |
| //- Typically created by the `alumacc` pass, which transforms: |
| //- $add, $sub, $lt, $le, $ge, $gt, $eq, $eqx, $ne, $nex |
| //- cells into this $alu cell. |
| //- |
| module \$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; |
| |
| input [A_WIDTH-1:0] A; // Input operand |
| input [B_WIDTH-1:0] B; // Input operand |
| output [Y_WIDTH-1:0] X; // A xor B (sign-extended, optional B inversion, |
| // used in combination with |
| // reduction-AND for $eq/$ne ops) |
| output [Y_WIDTH-1:0] Y; // Sum |
| |
| input CI; // Carry-in (set for $sub) |
| input BI; // Invert-B (set for $sub) |
| output [Y_WIDTH-1:0] CO; // Carry-out |
| |
| wire [Y_WIDTH-1:0] AA, BB; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign AA = $signed(A), BB = BI ? ~$signed(B) : $signed(B); |
| end else begin:BLOCK2 |
| assign AA = $unsigned(A), BB = BI ? ~$unsigned(B) : $unsigned(B); |
| end |
| endgenerate |
| |
| // this is 'x' if Y and CO should be all 'x', and '0' otherwise |
| wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI}; |
| |
| assign X = AA ^ BB; |
| // Full adder |
| assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}}; |
| |
| function get_carry; |
| input a, b, c; |
| get_carry = (a&b) | (a&c) | (b&c); |
| endfunction |
| |
| genvar i; |
| generate |
| assign CO[0] = get_carry(AA[0], BB[0], CI) ^ y_co_undef; |
| for (i = 1; i < Y_WIDTH; i = i+1) begin:BLOCK3 |
| assign CO[i] = get_carry(AA[i], BB[i], CO[i-1]) ^ y_co_undef; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$lt (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) < $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A < B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$le (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) <= $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A <= B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$eq (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) == $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A == B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$ne (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) != $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A != B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$eqx (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) === $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A === B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$nex (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) !== $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A !== B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$ge (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) >= $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A >= B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$gt (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) > $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A > B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$add (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) + $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A + B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$sub (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) - $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A - B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$mul (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) * $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A * B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$macc (A, B, Y); |
| |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| parameter CONFIG = 4'b0000; |
| parameter CONFIG_WIDTH = 4; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output reg [Y_WIDTH-1:0] Y; |
| |
| // Xilinx XSIM does not like $clog2() below.. |
| function integer my_clog2; |
| input integer v; |
| begin |
| if (v > 0) |
| v = v - 1; |
| my_clog2 = 0; |
| while (v) begin |
| v = v >> 1; |
| my_clog2 = my_clog2 + 1; |
| end |
| end |
| endfunction |
| |
| localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1; |
| localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits); |
| localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1; |
| |
| function [2*num_ports*num_abits-1:0] get_port_offsets; |
| input [CONFIG_WIDTH-1:0] cfg; |
| integer i, cursor; |
| begin |
| cursor = 0; |
| get_port_offsets = 0; |
| for (i = 0; i < num_ports; i = i+1) begin |
| get_port_offsets[(2*i + 0)*num_abits +: num_abits] = cursor; |
| cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 +: num_bits]; |
| get_port_offsets[(2*i + 1)*num_abits +: num_abits] = cursor; |
| cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits]; |
| end |
| end |
| endfunction |
| |
| localparam [2*num_ports*num_abits-1:0] port_offsets = get_port_offsets(CONFIG); |
| |
| `define PORT_IS_SIGNED (0 + CONFIG[4 + i*(2 + 2*num_bits)]) |
| `define PORT_DO_SUBTRACT (0 + CONFIG[4 + i*(2 + 2*num_bits) + 1]) |
| `define PORT_SIZE_A (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 +: num_bits]) |
| `define PORT_SIZE_B (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits]) |
| `define PORT_OFFSET_A (0 + port_offsets[2*i*num_abits +: num_abits]) |
| `define PORT_OFFSET_B (0 + port_offsets[2*i*num_abits + num_abits +: num_abits]) |
| |
| integer i, j; |
| reg [Y_WIDTH-1:0] tmp_a, tmp_b; |
| |
| always @* begin |
| Y = 0; |
| for (i = 0; i < num_ports; i = i+1) |
| begin |
| tmp_a = 0; |
| tmp_b = 0; |
| |
| for (j = 0; j < `PORT_SIZE_A; j = j+1) |
| tmp_a[j] = A[`PORT_OFFSET_A + j]; |
| |
| if (`PORT_IS_SIGNED && `PORT_SIZE_A > 0) |
| for (j = `PORT_SIZE_A; j < Y_WIDTH; j = j+1) |
| tmp_a[j] = tmp_a[`PORT_SIZE_A-1]; |
| |
| for (j = 0; j < `PORT_SIZE_B; j = j+1) |
| tmp_b[j] = A[`PORT_OFFSET_B + j]; |
| |
| if (`PORT_IS_SIGNED && `PORT_SIZE_B > 0) |
| for (j = `PORT_SIZE_B; j < Y_WIDTH; j = j+1) |
| tmp_b[j] = tmp_b[`PORT_SIZE_B-1]; |
| |
| if (`PORT_SIZE_B > 0) |
| tmp_a = tmp_a * tmp_b; |
| |
| if (`PORT_DO_SUBTRACT) |
| Y = Y - tmp_a; |
| else |
| Y = Y + tmp_a; |
| end |
| for (i = 0; i < B_WIDTH; i = i+1) begin |
| Y = Y + B[i]; |
| end |
| end |
| |
| `undef PORT_IS_SIGNED |
| `undef PORT_DO_SUBTRACT |
| `undef PORT_SIZE_A |
| `undef PORT_SIZE_B |
| `undef PORT_OFFSET_A |
| `undef PORT_OFFSET_B |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$div (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) / $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A / B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$mod (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) % $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A % B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| `ifndef SIMLIB_NOPOW |
| |
| module \$pow (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) ** $signed(B); |
| end else if (A_SIGNED) begin:BLOCK2 |
| assign Y = $signed(A) ** B; |
| end else if (B_SIGNED) begin:BLOCK3 |
| assign Y = A ** $signed(B); |
| end else begin:BLOCK4 |
| assign Y = A ** B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| `endif |
| // -------------------------------------------------------- |
| |
| module \$logic_not (A, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED) begin:BLOCK1 |
| assign Y = !$signed(A); |
| end else begin:BLOCK2 |
| assign Y = !A; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$logic_and (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) && $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A && B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$logic_or (A, B, Y); |
| |
| parameter A_SIGNED = 0; |
| parameter B_SIGNED = 0; |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [Y_WIDTH-1:0] Y; |
| |
| generate |
| if (A_SIGNED && B_SIGNED) begin:BLOCK1 |
| assign Y = $signed(A) || $signed(B); |
| end else begin:BLOCK2 |
| assign Y = A || B; |
| end |
| endgenerate |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$slice (A, Y); |
| |
| parameter OFFSET = 0; |
| parameter A_WIDTH = 0; |
| parameter Y_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| output [Y_WIDTH-1:0] Y; |
| |
| assign Y = A >> OFFSET; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$concat (A, B, Y); |
| |
| parameter A_WIDTH = 0; |
| parameter B_WIDTH = 0; |
| |
| input [A_WIDTH-1:0] A; |
| input [B_WIDTH-1:0] B; |
| output [A_WIDTH+B_WIDTH-1:0] Y; |
| |
| assign Y = {B, A}; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$mux (A, B, S, Y); |
| |
| parameter WIDTH = 0; |
| |
| input [WIDTH-1:0] A, B; |
| input S; |
| output reg [WIDTH-1:0] Y; |
| |
| always @* begin |
| if (S) |
| Y = B; |
| else |
| Y = A; |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$pmux (A, B, S, Y); |
| |
| parameter WIDTH = 0; |
| parameter S_WIDTH = 0; |
| |
| input [WIDTH-1:0] A; |
| input [WIDTH*S_WIDTH-1:0] B; |
| input [S_WIDTH-1:0] S; |
| output reg [WIDTH-1:0] Y; |
| |
| integer i; |
| reg found_active_sel_bit; |
| |
| always @* begin |
| Y = A; |
| found_active_sel_bit = 0; |
| for (i = 0; i < S_WIDTH; i = i+1) |
| if (S[i]) begin |
| Y = found_active_sel_bit ? 'bx : B >> (WIDTH*i); |
| found_active_sel_bit = 1; |
| end |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| `ifndef SIMLIB_NOLUT |
| |
| module \$lut (A, Y); |
| |
| parameter WIDTH = 0; |
| parameter LUT = 0; |
| |
| input [WIDTH-1:0] A; |
| output reg Y; |
| |
| wire lut0_out, lut1_out; |
| |
| generate |
| if (WIDTH <= 1) begin:simple |
| assign {lut1_out, lut0_out} = LUT; |
| end else begin:complex |
| \$lut #( .WIDTH(WIDTH-1), .LUT(LUT ) ) lut0 ( .A(A[WIDTH-2:0]), .Y(lut0_out) ); |
| \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .A(A[WIDTH-2:0]), .Y(lut1_out) ); |
| end |
| |
| if (WIDTH > 0) begin:lutlogic |
| always @* begin |
| casez ({A[WIDTH-1], lut0_out, lut1_out}) |
| 3'b?11: Y = 1'b1; |
| 3'b?00: Y = 1'b0; |
| 3'b0??: Y = lut0_out; |
| 3'b1??: Y = lut1_out; |
| default: Y = 1'bx; |
| endcase |
| end |
| end |
| endgenerate |
| |
| endmodule |
| |
| `endif |
| // -------------------------------------------------------- |
| |
| module \$sop (A, Y); |
| |
| parameter WIDTH = 0; |
| parameter DEPTH = 0; |
| parameter TABLE = 0; |
| |
| input [WIDTH-1:0] A; |
| output reg Y; |
| |
| integer i, j; |
| reg match; |
| |
| always @* begin |
| Y = 0; |
| for (i = 0; i < DEPTH; i=i+1) begin |
| match = 1; |
| for (j = 0; j < WIDTH; j=j+1) begin |
| if (TABLE[2*WIDTH*i + 2*j + 0] && A[j]) match = 0; |
| if (TABLE[2*WIDTH*i + 2*j + 1] && !A[j]) match = 0; |
| end |
| if (match) Y = 1; |
| end |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$tribuf (A, EN, Y); |
| |
| parameter WIDTH = 0; |
| |
| input [WIDTH-1:0] A; |
| input EN; |
| output [WIDTH-1:0] Y; |
| |
| assign Y = EN ? A : 'bz; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$specify2 (EN, SRC, DST); |
| |
| parameter FULL = 0; |
| parameter SRC_WIDTH = 1; |
| parameter DST_WIDTH = 1; |
| |
| parameter SRC_DST_PEN = 0; |
| parameter SRC_DST_POL = 0; |
| |
| parameter T_RISE_MIN = 0; |
| parameter T_RISE_TYP = 0; |
| parameter T_RISE_MAX = 0; |
| |
| parameter T_FALL_MIN = 0; |
| parameter T_FALL_TYP = 0; |
| parameter T_FALL_MAX = 0; |
| |
| input EN; |
| input [SRC_WIDTH-1:0] SRC; |
| input [DST_WIDTH-1:0] DST; |
| |
| localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; |
| |
| `ifdef SIMLIB_SPECIFY |
| specify |
| if (EN && SD==0 && !FULL) (SRC => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && SD==0 && FULL) (SRC *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && SD==1 && FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && SD==2 && FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| endspecify |
| `endif |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$specify3 (EN, SRC, DST, DAT); |
| |
| parameter FULL = 0; |
| parameter SRC_WIDTH = 1; |
| parameter DST_WIDTH = 1; |
| |
| parameter EDGE_EN = 0; |
| parameter EDGE_POL = 0; |
| |
| parameter SRC_DST_PEN = 0; |
| parameter SRC_DST_POL = 0; |
| |
| parameter DAT_DST_PEN = 0; |
| parameter DAT_DST_POL = 0; |
| |
| parameter T_RISE_MIN = 0; |
| parameter T_RISE_TYP = 0; |
| parameter T_RISE_MAX = 0; |
| |
| parameter T_FALL_MIN = 0; |
| parameter T_FALL_TYP = 0; |
| parameter T_FALL_MAX = 0; |
| |
| input EN; |
| input [SRC_WIDTH-1:0] SRC; |
| input [DST_WIDTH-1:0] DST, DAT; |
| |
| localparam ED = EDGE_EN ? (EDGE_POL ? 1 : 2) : 0; |
| localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; |
| localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0; |
| |
| `ifdef SIMLIB_SPECIFY |
| specify |
| // DD=0 |
| |
| if (EN && DD==0 && SD==0 && ED==0 && !FULL) ( SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==0 && ED==0 && FULL) ( SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| if (EN && DD==0 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==1 && ED==0 && FULL) ( SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| if (EN && DD==0 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==2 && ED==0 && FULL) ( SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==0 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| // DD=1 |
| |
| if (EN && DD==1 && SD==0 && ED==0 && !FULL) ( SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==0 && ED==0 && FULL) ( SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| if (EN && DD==1 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==1 && ED==0 && FULL) ( SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| if (EN && DD==1 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==2 && ED==0 && FULL) ( SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==1 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| // DD=2 |
| |
| if (EN && DD==2 && SD==0 && ED==0 && !FULL) ( SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==0 && ED==0 && FULL) ( SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| if (EN && DD==2 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==1 && ED==0 && FULL) ( SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| |
| if (EN && DD==2 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==2 && ED==0 && FULL) ( SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| if (EN && DD==2 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); |
| endspecify |
| `endif |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$specrule (EN_SRC, EN_DST, SRC, DST); |
| |
| parameter TYPE = ""; |
| parameter T_LIMIT = 0; |
| parameter T_LIMIT2 = 0; |
| |
| parameter SRC_WIDTH = 1; |
| parameter DST_WIDTH = 1; |
| |
| parameter SRC_PEN = 0; |
| parameter SRC_POL = 0; |
| |
| parameter DST_PEN = 0; |
| parameter DST_POL = 0; |
| |
| input EN_SRC, EN_DST; |
| input [SRC_WIDTH-1:0] SRC; |
| input [DST_WIDTH-1:0] DST; |
| |
| `ifdef SIMLIB_SPECIFY |
| specify |
| // TBD |
| endspecify |
| `endif |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$assert (A, EN); |
| |
| input A, EN; |
| |
| `ifndef SIMLIB_NOCHECKS |
| always @* begin |
| if (A !== 1'b1 && EN === 1'b1) begin |
| $display("Assertion %m failed!"); |
| $stop; |
| end |
| end |
| `endif |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$assume (A, EN); |
| |
| input A, EN; |
| |
| `ifndef SIMLIB_NOCHECKS |
| always @* begin |
| if (A !== 1'b1 && EN === 1'b1) begin |
| $display("Assumption %m failed!"); |
| $stop; |
| end |
| end |
| `endif |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$live (A, EN); |
| |
| input A, EN; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$fair (A, EN); |
| |
| input A, EN; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$cover (A, EN); |
| |
| input A, EN; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$initstate (Y); |
| |
| output reg Y = 1; |
| reg [3:0] cnt = 1; |
| reg trig = 0; |
| |
| initial trig <= 1; |
| |
| always @(cnt, trig) begin |
| Y <= |cnt; |
| cnt <= cnt + |cnt; |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$anyconst (Y); |
| |
| parameter WIDTH = 0; |
| |
| output [WIDTH-1:0] Y; |
| |
| assign Y = 'bx; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$anyseq (Y); |
| |
| parameter WIDTH = 0; |
| |
| output [WIDTH-1:0] Y; |
| |
| assign Y = 'bx; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$allconst (Y); |
| |
| parameter WIDTH = 0; |
| |
| output [WIDTH-1:0] Y; |
| |
| assign Y = 'bx; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$allseq (Y); |
| |
| parameter WIDTH = 0; |
| |
| output [WIDTH-1:0] Y; |
| |
| assign Y = 'bx; |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$equiv (A, B, Y); |
| |
| input A, B; |
| output Y; |
| |
| assign Y = (A !== 1'bx && A !== B) ? 1'bx : A; |
| |
| `ifndef SIMLIB_NOCHECKS |
| always @* begin |
| if (A !== 1'bx && A !== B) begin |
| $display("Equivalence failed!"); |
| $stop; |
| end |
| end |
| `endif |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| `ifndef SIMLIB_NOSR |
| |
| module \$sr (SET, CLR, Q); |
| |
| parameter WIDTH = 0; |
| parameter SET_POLARITY = 1'b1; |
| parameter CLR_POLARITY = 1'b1; |
| |
| input [WIDTH-1:0] SET, CLR; |
| output reg [WIDTH-1:0] Q; |
| |
| wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; |
| wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; |
| |
| genvar i; |
| generate |
| for (i = 0; i < WIDTH; i = i+1) begin:bitslices |
| always @(posedge pos_set[i], posedge pos_clr[i]) |
| if (pos_clr[i]) |
| Q[i] <= 0; |
| else if (pos_set[i]) |
| Q[i] <= 1; |
| end |
| endgenerate |
| |
| endmodule |
| |
| `endif |
| // -------------------------------------------------------- |
| `ifdef SIMLIB_FF |
| |
| module \$ff (D, Q); |
| |
| parameter WIDTH = 0; |
| |
| input [WIDTH-1:0] D; |
| output reg [WIDTH-1:0] Q; |
| |
| always @($global_clk) begin |
| Q <= D; |
| end |
| |
| endmodule |
| |
| `endif |
| // -------------------------------------------------------- |
| |
| module \$dff (CLK, D, Q); |
| |
| parameter WIDTH = 0; |
| parameter CLK_POLARITY = 1'b1; |
| |
| input CLK; |
| input [WIDTH-1:0] D; |
| output reg [WIDTH-1:0] Q; |
| wire pos_clk = CLK == CLK_POLARITY; |
| |
| always @(posedge pos_clk) begin |
| Q <= D; |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$dffe (CLK, EN, D, Q); |
| |
| parameter WIDTH = 0; |
| parameter CLK_POLARITY = 1'b1; |
| parameter EN_POLARITY = 1'b1; |
| |
| input CLK, EN; |
| input [WIDTH-1:0] D; |
| output reg [WIDTH-1:0] Q; |
| wire pos_clk = CLK == CLK_POLARITY; |
| |
| always @(posedge pos_clk) begin |
| if (EN == EN_POLARITY) Q <= D; |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| `ifndef SIMLIB_NOSR |
| |
| module \$dffsr (CLK, SET, CLR, D, Q); |
| |
| parameter WIDTH = 0; |
| parameter CLK_POLARITY = 1'b1; |
| parameter SET_POLARITY = 1'b1; |
| parameter CLR_POLARITY = 1'b1; |
| |
| input CLK; |
| input [WIDTH-1:0] SET, CLR, D; |
| output reg [WIDTH-1:0] Q; |
| |
| wire pos_clk = CLK == CLK_POLARITY; |
| wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; |
| wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; |
| |
| genvar i; |
| generate |
| for (i = 0; i < WIDTH; i = i+1) begin:bitslices |
| always @(posedge pos_set[i], posedge pos_clr[i], posedge pos_clk) |
| if (pos_clr[i]) |
| Q[i] <= 0; |
| else if (pos_set[i]) |
| Q[i] <= 1; |
| else |
| Q[i] <= D[i]; |
| end |
| endgenerate |
| |
| endmodule |
| |
| `endif |
| // -------------------------------------------------------- |
| |
| module \$adff (CLK, ARST, D, Q); |
| |
| parameter WIDTH = 0; |
| parameter CLK_POLARITY = 1'b1; |
| parameter ARST_POLARITY = 1'b1; |
| parameter ARST_VALUE = 0; |
| |
| input CLK, ARST; |
| input [WIDTH-1:0] D; |
| output reg [WIDTH-1:0] Q; |
| wire pos_clk = CLK == CLK_POLARITY; |
| wire pos_arst = ARST == ARST_POLARITY; |
| |
| always @(posedge pos_clk, posedge pos_arst) begin |
| if (pos_arst) |
| Q <= ARST_VALUE; |
| else |
| Q <= D; |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$dlatch (EN, D, Q); |
| |
| parameter WIDTH = 0; |
| parameter EN_POLARITY = 1'b1; |
| |
| input EN; |
| input [WIDTH-1:0] D; |
| output reg [WIDTH-1:0] Q; |
| |
| always @* begin |
| if (EN == EN_POLARITY) |
| Q = D; |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| `ifndef SIMLIB_NOSR |
| |
| module \$dlatchsr (EN, SET, CLR, D, Q); |
| |
| parameter WIDTH = 0; |
| parameter EN_POLARITY = 1'b1; |
| parameter SET_POLARITY = 1'b1; |
| parameter CLR_POLARITY = 1'b1; |
| |
| input EN; |
| input [WIDTH-1:0] SET, CLR, D; |
| output reg [WIDTH-1:0] Q; |
| |
| wire pos_en = EN == EN_POLARITY; |
| wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; |
| wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; |
| |
| genvar i; |
| generate |
| for (i = 0; i < WIDTH; i = i+1) begin:bitslices |
| always @* |
| if (pos_clr[i]) |
| Q[i] = 0; |
| else if (pos_set[i]) |
| Q[i] = 1; |
| else if (pos_en) |
| Q[i] = D[i]; |
| end |
| endgenerate |
| |
| endmodule |
| |
| `endif |
| // -------------------------------------------------------- |
| |
| module \$fsm (CLK, ARST, CTRL_IN, CTRL_OUT); |
| |
| parameter NAME = ""; |
| |
| parameter CLK_POLARITY = 1'b1; |
| parameter ARST_POLARITY = 1'b1; |
| |
| parameter CTRL_IN_WIDTH = 1; |
| parameter CTRL_OUT_WIDTH = 1; |
| |
| parameter STATE_BITS = 1; |
| parameter STATE_NUM = 1; |
| parameter STATE_NUM_LOG2 = 1; |
| parameter STATE_RST = 0; |
| parameter STATE_TABLE = 1'b0; |
| |
| parameter TRANS_NUM = 1; |
| parameter TRANS_TABLE = 4'b0x0x; |
| |
| input CLK, ARST; |
| input [CTRL_IN_WIDTH-1:0] CTRL_IN; |
| output reg [CTRL_OUT_WIDTH-1:0] CTRL_OUT; |
| |
| wire pos_clk = CLK == CLK_POLARITY; |
| wire pos_arst = ARST == ARST_POLARITY; |
| |
| reg [STATE_BITS-1:0] state; |
| reg [STATE_BITS-1:0] state_tmp; |
| reg [STATE_BITS-1:0] next_state; |
| |
| reg [STATE_BITS-1:0] tr_state_in; |
| reg [STATE_BITS-1:0] tr_state_out; |
| reg [CTRL_IN_WIDTH-1:0] tr_ctrl_in; |
| reg [CTRL_OUT_WIDTH-1:0] tr_ctrl_out; |
| |
| integer i; |
| |
| task tr_fetch; |
| input [31:0] tr_num; |
| reg [31:0] tr_pos; |
| reg [STATE_NUM_LOG2-1:0] state_num; |
| begin |
| tr_pos = (2*STATE_NUM_LOG2+CTRL_IN_WIDTH+CTRL_OUT_WIDTH)*tr_num; |
| tr_ctrl_out = TRANS_TABLE >> tr_pos; |
| tr_pos = tr_pos + CTRL_OUT_WIDTH; |
| state_num = TRANS_TABLE >> tr_pos; |
| tr_state_out = STATE_TABLE >> (STATE_BITS*state_num); |
| tr_pos = tr_pos + STATE_NUM_LOG2; |
| tr_ctrl_in = TRANS_TABLE >> tr_pos; |
| tr_pos = tr_pos + CTRL_IN_WIDTH; |
| state_num = TRANS_TABLE >> tr_pos; |
| tr_state_in = STATE_TABLE >> (STATE_BITS*state_num); |
| tr_pos = tr_pos + STATE_NUM_LOG2; |
| end |
| endtask |
| |
| always @(posedge pos_clk, posedge pos_arst) begin |
| if (pos_arst) begin |
| state_tmp = STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST]; |
| for (i = 0; i < STATE_BITS; i = i+1) |
| if (state_tmp[i] === 1'bz) |
| state_tmp[i] = 0; |
| state <= state_tmp; |
| end else begin |
| state_tmp = next_state; |
| for (i = 0; i < STATE_BITS; i = i+1) |
| if (state_tmp[i] === 1'bz) |
| state_tmp[i] = 0; |
| state <= state_tmp; |
| end |
| end |
| |
| always @(state, CTRL_IN) begin |
| next_state <= STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST]; |
| CTRL_OUT <= 'bx; |
| // $display("---"); |
| // $display("Q: %b %b", state, CTRL_IN); |
| for (i = 0; i < TRANS_NUM; i = i+1) begin |
| tr_fetch(i); |
| // $display("T: %b %b -> %b %b [%d]", tr_state_in, tr_ctrl_in, tr_state_out, tr_ctrl_out, i); |
| casez ({state, CTRL_IN}) |
| {tr_state_in, tr_ctrl_in}: begin |
| // $display("-> %b %b <- MATCH", state, CTRL_IN); |
| {next_state, CTRL_OUT} <= {tr_state_out, tr_ctrl_out}; |
| end |
| endcase |
| end |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| `ifndef SIMLIB_NOMEM |
| |
| module \$memrd (CLK, EN, ADDR, DATA); |
| |
| parameter MEMID = ""; |
| parameter ABITS = 8; |
| parameter WIDTH = 8; |
| |
| parameter CLK_ENABLE = 0; |
| parameter CLK_POLARITY = 0; |
| parameter TRANSPARENT = 0; |
| |
| input CLK, EN; |
| input [ABITS-1:0] ADDR; |
| output [WIDTH-1:0] DATA; |
| |
| initial begin |
| if (MEMID != "") begin |
| $display("ERROR: Found non-simulatable instance of $memrd!"); |
| $finish; |
| end |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$memwr (CLK, EN, ADDR, DATA); |
| |
| parameter MEMID = ""; |
| parameter ABITS = 8; |
| parameter WIDTH = 8; |
| |
| parameter CLK_ENABLE = 0; |
| parameter CLK_POLARITY = 0; |
| parameter PRIORITY = 0; |
| |
| input CLK; |
| input [WIDTH-1:0] EN; |
| input [ABITS-1:0] ADDR; |
| input [WIDTH-1:0] DATA; |
| |
| initial begin |
| if (MEMID != "") begin |
| $display("ERROR: Found non-simulatable instance of $memwr!"); |
| $finish; |
| end |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$meminit (ADDR, DATA); |
| |
| parameter MEMID = ""; |
| parameter ABITS = 8; |
| parameter WIDTH = 8; |
| parameter WORDS = 1; |
| |
| parameter PRIORITY = 0; |
| |
| input [ABITS-1:0] ADDR; |
| input [WORDS*WIDTH-1:0] DATA; |
| |
| initial begin |
| if (MEMID != "") begin |
| $display("ERROR: Found non-simulatable instance of $meminit!"); |
| $finish; |
| end |
| end |
| |
| endmodule |
| |
| // -------------------------------------------------------- |
| |
| module \$mem (RD_CLK, RD_EN, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA); |
| |
| parameter MEMID = ""; |
| parameter signed SIZE = 4; |
| parameter signed OFFSET = 0; |
| parameter signed ABITS = 2; |
| parameter signed WIDTH = 8; |
| parameter signed INIT = 1'bx; |
| |
| parameter signed RD_PORTS = 1; |
| parameter RD_CLK_ENABLE = 1'b1; |
| parameter RD_CLK_POLARITY = 1'b1; |
| parameter RD_TRANSPARENT = 1'b1; |
| |
| parameter signed WR_PORTS = 1; |
| parameter WR_CLK_ENABLE = 1'b1; |
| parameter WR_CLK_POLARITY = 1'b1; |
| |
| input [RD_PORTS-1:0] RD_CLK; |
| input [RD_PORTS-1:0] RD_EN; |
| input [RD_PORTS*ABITS-1:0] RD_ADDR; |
| output reg [RD_PORTS*WIDTH-1:0] RD_DATA; |
| |
| input [WR_PORTS-1:0] WR_CLK; |
| input [WR_PORTS*WIDTH-1:0] WR_EN; |
| input [WR_PORTS*ABITS-1:0] WR_ADDR; |
| input [WR_PORTS*WIDTH-1:0] WR_DATA; |
| |
| reg [WIDTH-1:0] memory [SIZE-1:0]; |
| |
| integer i, j; |
| reg [WR_PORTS-1:0] LAST_WR_CLK; |
| reg [RD_PORTS-1:0] LAST_RD_CLK; |
| |
| function port_active; |
| input clk_enable; |
| input clk_polarity; |
| input last_clk; |
| input this_clk; |
| begin |
| casez ({clk_enable, clk_polarity, last_clk, this_clk}) |
| 4'b0???: port_active = 1; |
| 4'b1101: port_active = 1; |
| 4'b1010: port_active = 1; |
| default: port_active = 0; |
| endcase |
| end |
| endfunction |
| |
| initial begin |
| for (i = 0; i < SIZE; i = i+1) |
| memory[i] = INIT >>> (i*WIDTH); |
| end |
| |
| always @(RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin |
| `ifdef SIMLIB_MEMDELAY |
| #`SIMLIB_MEMDELAY; |
| `endif |
| for (i = 0; i < RD_PORTS; i = i+1) begin |
| if (!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i] && RD_EN[i] && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin |
| // $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); |
| RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; |
| end |
| end |
| |
| for (i = 0; i < WR_PORTS; i = i+1) begin |
| if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i])) |
| for (j = 0; j < WIDTH; j = j+1) |
| if (WR_EN[i*WIDTH+j]) begin |
| // $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]); |
| memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j]; |
| end |
| end |
| |
| for (i = 0; i < RD_PORTS; i = i+1) begin |
| if ((RD_TRANSPARENT[i] || !RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin |
| // $display("Transparent read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); |
| RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; |
| end |
| end |
| |
| LAST_RD_CLK <= RD_CLK; |
| LAST_WR_CLK <= WR_CLK; |
| end |
| |
| endmodule |
| |
| `endif |
| |
| // -------------------------------------------------------- |