/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Claire Xenia Wolf * * 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, 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, 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, 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, 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, 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 (A_SIGNED) begin:BLOCK1 if (B_SIGNED) begin:BLOCK2 assign Y = $signed(B) < 0 ? $signed(A) << -B : $signed(A) >> B; end else begin:BLOCK3 assign Y = $signed(A) >> B; end end else begin:BLOCK4 if (B_SIGNED) begin:BLOCK5 assign Y = $signed(B) < 0 ? A << -B : A >> B; end else begin:BLOCK6 assign Y = A >> B; end 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 // -------------------------------------------------------- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $div (A, B, Y) //- //- Division with truncated result (rounded towards 0). //- 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 // -------------------------------------------------------- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $mod (A, B, Y) //- //- Modulo/remainder of division with truncated result (rounded towards 0). //- //- Invariant: $div(A, B) * B + $mod(A, B) == A //- 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 // -------------------------------------------------------- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $divfloor (A, B, Y) //- //- Division with floored result (rounded towards negative infinity). //- module \$divfloor (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 localparam WIDTH = A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; wire [WIDTH:0] A_buf, B_buf, N_buf; assign A_buf = $signed(A); assign B_buf = $signed(B); assign N_buf = (A[A_WIDTH-1] == B[B_WIDTH-1]) || A == 0 ? A_buf : $signed(A_buf - (B[B_WIDTH-1] ? B_buf+1 : B_buf-1)); assign Y = $signed(N_buf) / $signed(B_buf); end else begin:BLOCK2 assign Y = A / B; end endgenerate endmodule // -------------------------------------------------------- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $modfloor (A, B, Y) //- //- Modulo/remainder of division with floored result (rounded towards negative infinity). //- //- Invariant: $divfloor(A, B) * B + $modfloor(A, B) == A //- module \$modfloor (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 localparam WIDTH = B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; wire [WIDTH-1:0] B_buf, Y_trunc; assign B_buf = $signed(B); assign Y_trunc = $signed(A) % $signed(B); // flooring mod is the same as truncating mod for positive division results (A and B have // the same sign), as well as when there's no remainder. // For all other cases, they behave as `floor - trunc = B` assign Y = (A[A_WIDTH-1] == B[B_WIDTH-1]) || Y_trunc == 0 ? Y_trunc : $signed(B_buf) + $signed(Y_trunc); end else begin:BLOCK2 // no difference between truncating and flooring for unsigned 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 @* 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 // -------------------------------------------------------- module \$dffsre (CLK, SET, CLR, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; input CLK, EN; 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 if (EN == EN_POLARITY) 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 \$sdff (CLK, SRST, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter SRST_POLARITY = 1'b1; parameter SRST_VALUE = 0; input CLK, SRST; input [WIDTH-1:0] D; output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; wire pos_srst = SRST == SRST_POLARITY; always @(posedge pos_clk) begin if (pos_srst) Q <= SRST_VALUE; else Q <= D; end endmodule // -------------------------------------------------------- module \$adffe (CLK, ARST, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; parameter ARST_POLARITY = 1'b1; parameter ARST_VALUE = 0; input CLK, ARST, EN; 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 if (EN == EN_POLARITY) Q <= D; end endmodule // -------------------------------------------------------- module \$sdffe (CLK, SRST, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; parameter SRST_POLARITY = 1'b1; parameter SRST_VALUE = 0; input CLK, SRST, EN; input [WIDTH-1:0] D; output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; wire pos_srst = SRST == SRST_POLARITY; always @(posedge pos_clk) begin if (pos_srst) Q <= SRST_VALUE; else if (EN == EN_POLARITY) Q <= D; end endmodule // -------------------------------------------------------- module \$sdffce (CLK, SRST, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; parameter SRST_POLARITY = 1'b1; parameter SRST_VALUE = 0; input CLK, SRST, EN; input [WIDTH-1:0] D; output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; wire pos_srst = SRST == SRST_POLARITY; always @(posedge pos_clk) begin if (EN == EN_POLARITY) begin if (pos_srst) Q <= SRST_VALUE; else Q <= D; end 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 // -------------------------------------------------------- module \$adlatch (EN, ARST, D, Q); parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; parameter ARST_POLARITY = 1'b1; parameter ARST_VALUE = 0; input EN, ARST; input [WIDTH-1:0] D; output reg [WIDTH-1:0] Q; always @* begin if (ARST == ARST_POLARITY) Q = ARST_VALUE; else 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 // --------------------------------------------------------