mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	intel_alm: Documentation improvements
This commit is contained in:
		
							parent
							
								
									02f1c7b9af
								
							
						
					
					
						commit
						16a3048308
					
				
					 3 changed files with 127 additions and 14 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue