mirror of https://github.com/YosysHQ/yosys.git
intel_alm: Documentation improvements
This commit is contained in:
parent
02f1c7b9af
commit
16a3048308
|
@ -1,3 +1,72 @@
|
|||
// The core logic primitive of the Cyclone V/10GX is the Adaptive Logic Module
|
||||
// (ALM). Each ALM is made up of an 8-input, 2-output look-up table, covered
|
||||
// in this file, connected to combinational outputs, a carry chain, and four
|
||||
// D flip-flops (which are covered as MISTRAL_FF in dff_sim.v).
|
||||
//
|
||||
// The ALM is vertically symmetric, so I find it helps to think in terms of
|
||||
// half-ALMs, as that's predominantly the unit that synth_intel_alm uses.
|
||||
//
|
||||
// ALMs are quite flexible, having multiple modes.
|
||||
//
|
||||
// Normal (combinational) mode
|
||||
// ---------------------------
|
||||
// The ALM can implement:
|
||||
// - a single 6-input function (with the other inputs usable for flip-flop access)
|
||||
// - two 5-input functions that share two inputs
|
||||
// - a 5-input and a 4-input function that share one input
|
||||
// - a 5-input and a 3-or-less-input function that share no inputs
|
||||
// - two 4-or-less-input functions that share no inputs
|
||||
//
|
||||
// Normal-mode functions are represented as MISTRAL_ALUTN cells with N inputs.
|
||||
// It would be possible to represent a normal mode function as a single cell -
|
||||
// the vendor cyclone{v,10gx}_lcell_comb cell does exactly that - but I felt
|
||||
// it was more user-friendly to print out the specific function sizes
|
||||
// separately.
|
||||
//
|
||||
// With the exception of MISTRAL_ALUT6, you can think of two normal-mode cells
|
||||
// fitting inside a single ALM.
|
||||
//
|
||||
// Extended (7-input) mode
|
||||
// -----------------------
|
||||
// The ALM can also fit a 7-input function made of two 5-input functions that
|
||||
// share four inputs, multiplexed by another input.
|
||||
//
|
||||
// Because this can't accept arbitrary 7-input functions, Yosys can't handle
|
||||
// it, so it doesn't have a cell, but I would likely call it MISTRAL_ALUT7(E?)
|
||||
// if it did, and it would take up a full ALM.
|
||||
//
|
||||
// It might be possible to add an extraction pass to examine all ALUT5 cells
|
||||
// that feed into ALUT3 cells to see if they can be combined into an extended
|
||||
// ALM, but I don't think it will be worth it.
|
||||
//
|
||||
// Arithmetic mode
|
||||
// ---------------
|
||||
// In arithmetic mode, each half-ALM uses its carry chain to perform fast addition
|
||||
// of two four-input functions that share three inputs. Oddly, the result of
|
||||
// one of the functions is inverted before being added (you can see this as
|
||||
// the dot on a full-adder input of Figure 1-8 in the Handbook).
|
||||
//
|
||||
// The cell for an arithmetic-mode half-ALM is MISTRAL_ALM_ARITH. One idea
|
||||
// I've had (or rather was suggested by mwk) is that functions that feed into
|
||||
// arithmetic-mode cells could be packed directly into the arithmetic-mode
|
||||
// cell as a function, which reduces the number of ALMs needed.
|
||||
//
|
||||
// Shared arithmetic mode
|
||||
// ----------------------
|
||||
// Shared arithmetic mode looks a lot like arithmetic mode, but here the
|
||||
// output of every other four-input function goes to the input of the adder
|
||||
// the next bit along. What this means is that adding three bits together can
|
||||
// be done in an ALM, because functions can be used to implement addition that
|
||||
// then feeds into the carry chain. This means that three bits can be added per
|
||||
// ALM, as opposed to two in the arithmetic mode.
|
||||
//
|
||||
// Shared arithmetic mode doesn't currently have a cell, but I intend to add
|
||||
// it as MISTRAL_ALM_SHARED, and have it occupy a full ALM. Because it adds
|
||||
// three bits per cell, it makes addition shorter and use less ALMs, but
|
||||
// I don't know enough to tell whether it's more efficient to use shared
|
||||
// arithmetic mode to shorten the carry chain, or plain arithmetic mode with
|
||||
// the functions packed in.
|
||||
|
||||
`default_nettype none
|
||||
|
||||
(* abc9_lut=2, lib_whitebox *)
|
||||
|
|
|
@ -6,7 +6,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFF_P_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop that initialises to one");
|
||||
endmodule
|
||||
|
||||
module \$_DFF_N_ (input D, C, output Q);
|
||||
|
@ -14,7 +14,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFF_N_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop that initialises to one");
|
||||
endmodule
|
||||
|
||||
// D flip-flops with reset
|
||||
|
@ -23,7 +23,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFF_PP0_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with reset that initialises to one");
|
||||
endmodule
|
||||
|
||||
module \$_DFF_PN0_ (input D, C, R, output Q);
|
||||
|
@ -31,7 +31,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFF_PN0_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with reset that initialises to one");
|
||||
endmodule
|
||||
|
||||
module \$_DFF_NP0_ (input D, C, R, output Q);
|
||||
|
@ -39,7 +39,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFF_NP0_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with reset that initialises to one");
|
||||
endmodule
|
||||
|
||||
module \$_DFF_NN0_ (input D, C, R, output Q);
|
||||
|
@ -47,7 +47,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFF_NN0_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with reset that initialises to one");
|
||||
endmodule
|
||||
|
||||
// D flip-flops with set
|
||||
|
@ -58,7 +58,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
|
|||
wire Q_tmp;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
|
||||
assign Q = ~Q_tmp;
|
||||
end else $error("Unsupported flop: $_DFF_PP1_ with INIT=0");
|
||||
end else $error("Cannot implement a flip-flop with set that initialises to zero");
|
||||
endmodule
|
||||
|
||||
module \$_DFF_PN1_ (input D, C, R, output Q);
|
||||
|
@ -67,7 +67,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
|
|||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
wire Q_tmp;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
|
||||
end else $error("Unsupported flop: $_DFF_PN1_ with INIT=0");
|
||||
end else $error("Cannot implement a flip-flop with set that initialises to zero");
|
||||
endmodule
|
||||
|
||||
module \$_DFF_NP1_ (input D, C, R, output Q);
|
||||
|
@ -77,7 +77,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
|
|||
wire Q_tmp;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
|
||||
assign Q = ~Q_tmp;
|
||||
end else $error("Unsupported flop: $_DFF_NP1_ with INIT=0");
|
||||
end else $error("Cannot implement a flip-flop with set that initialises to zero");
|
||||
endmodule
|
||||
|
||||
module \$_DFF_NN1_ (input D, C, R, output Q);
|
||||
|
@ -87,7 +87,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
|
|||
wire Q_tmp;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
|
||||
assign Q = ~Q_tmp;
|
||||
end else $error("Unsupported flop: $_DFF_NN1_ with INIT=0");
|
||||
end else $error("Cannot implement a flip-flop with set that initialises to zero");
|
||||
endmodule
|
||||
|
||||
// D flip-flops with clock enable
|
||||
|
@ -96,7 +96,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFFE_PP_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with enable that initialises to one");
|
||||
endmodule
|
||||
|
||||
module \$_DFFE_PN_ (input D, C, E, output Q);
|
||||
|
@ -104,7 +104,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFFE_PN_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with enable that initialises to one");
|
||||
endmodule
|
||||
|
||||
module \$_DFFE_NP_ (input D, C, E, output Q);
|
||||
|
@ -112,7 +112,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFFE_NP_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with enable that initialises to one");
|
||||
endmodule
|
||||
|
||||
module \$_DFFE_NN_ (input D, C, E, output Q);
|
||||
|
@ -120,5 +120,5 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
|
|||
if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
|
||||
wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
|
||||
MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
|
||||
end else $error("Unsupported flop: $_DFFE_NN_ with INIT=1");
|
||||
end else $error("Cannot implement a flip-flop with enable that initialises to one");
|
||||
endmodule
|
||||
|
|
|
@ -1,3 +1,47 @@
|
|||
// The four D flip-flops (DFFs) in a Cyclone V/10GX Adaptive Logic Module (ALM)
|
||||
// act as one-bit memory cells that can be placed very flexibly (wherever there's
|
||||
// an ALM); each flop is represented by a MISTRAL_FF cell.
|
||||
//
|
||||
// The flops in these chips are rather flexible in some ways, but in practice
|
||||
// quite crippled by FPGA standards.
|
||||
//
|
||||
// What the flops can do
|
||||
// ---------------------
|
||||
// The core flop acts as a single-bit memory that initialises to zero at chip
|
||||
// reset. It takes in data on the rising edge of CLK if ENA is high,
|
||||
// and outputs it to Q. The ENA (clock enable) pin can therefore be used to
|
||||
// capture the input only if a condition is true.
|
||||
//
|
||||
// The data itself is zero if SCLR (synchronous clear) is high, else it comes
|
||||
// from SDATA (synchronous data) if SLOAD (synchronous load) is high, or DATAIN
|
||||
// if SLOAD is low.
|
||||
//
|
||||
// If ACLR (asynchronous clear) is low then Q is forced to zero, regardless of
|
||||
// the synchronous inputs or CLK edge. This is most often used for an FPGA-wide
|
||||
// power-on reset.
|
||||
//
|
||||
// An asynchronous set that sets Q to one can be emulated by inverting the input
|
||||
// and output of the flop, resulting in ACLR forcing Q to zero, which then gets
|
||||
// inverted to produce one. Likewise, logic can operate on the falling edge of
|
||||
// CLK if CLK is inverted before being passed as an input.
|
||||
//
|
||||
// What the flops *can't* do
|
||||
// -------------------------
|
||||
// The trickiest part of the above capabilities is the lack of configurable
|
||||
// initialisation state. For example, it isn't possible to implement a flop with
|
||||
// asynchronous clear that initialises to one, because the hardware initialises
|
||||
// to zero. Likewise, you can't emulate a flop with asynchronous set that
|
||||
// initialises to zero, because the inverters mean the flop initialises to one.
|
||||
//
|
||||
// If the input design requires one of these cells (which appears to be rare
|
||||
// in practice) then synth_intel_alm will fail to synthesize the design where
|
||||
// other Yosys synthesis scripts might succeed.
|
||||
//
|
||||
// This stands in notable contrast to e.g. Xilinx flip-flops, which have
|
||||
// configurable initialisation state and native synchronous/asynchronous
|
||||
// set/clear (although not at the same time), which means they can generally
|
||||
// implement a much wider variety of logic.
|
||||
|
||||
// DATAIN: synchronous data input
|
||||
// CLK: clock input (positive edge)
|
||||
// ACLR: asynchronous clear (negative-true)
|
||||
|
|
Loading…
Reference in New Issue