This is pretty much useless [...] If your mew target uses a different lut architecture it won't even synthesize.
This is just plain wrong.
In the video I used the following code for initial synthesis:
module top (
input clk,
output LED1,
output LED2,
output LED3,
output LED4,
output LED5
);
localparam BITS = 5;
localparam LOG2DELAY = 22;
function [BITS-1:0] bin2gray(input [BITS-1:0] in);
integer i;
reg [BITS:0] temp;
begin
temp = in;
for (i=0; i<BITS; i=i+1)
bin2gray[i] = ^temp[i +: 2];
end
endfunction
reg [BITS+LOG2DELAY-1:0] counter = 0;
always@(posedge clk)
counter <= counter + 1;
assign {LED1, LED2, LED3, LED4, LED5} = bin2gray(counter >> LOG2DELAY);
endmodule
And this was the output of icebox_vlog:
module chip (output LED1, output LED3, output LED4, output LED5, output LED2, input clk);
wire n1;
reg LED1, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21, n22, n23, n24, n25, n26, n27, n28;
wire n29, n30, n31, n32, n33, n34, n35, n36, n37, n38, n39, n40, n41, n42, n43, n44, n45, LED3, LED4, LED5, n49, n50, n51, n52, n53, n54, n55, n56, n57, n58, LED2;
assign n1 = clk, n29 = 1;
wire n60, n61, n62, n63, n64, n65, n66, n67, n68, n69, n70, n71, n72, n73, n74, n75, n76, n77, n78, n79, n80, n81, n82, n83, n84, n85, n86;
assign n60 = /* LUT 8 9 0 */ n29 ? !n4 : n4;
assign LED5 = /* LUT 9 11 3 */ n26 ? !n27 : n27;
assign n61 = /* LUT 8 9 1 */ n30 ? !n5 : n5;
assign LED4 = /* LUT 9 11 2 */ n28 ? !n27 : n27;
assign n62 = /* LUT 8 9 2 */ n31 ? !n6 : n6;
assign LED3 = /* LUT 9 11 1 */ n3 ? !n28 : n28;
assign n63 = /* LUT 8 9 3 */ n32 ? !n7 : n7;
assign n64 = /* LUT 8 9 4 */ n33 ? !n8 : n8;
assign n65 = /* LUT 8 10 1 */ n38 ? !n13 : n13;
assign n66 = /* LUT 8 9 5 */ n34 ? !n9 : n9;
assign n67 = /* LUT 8 10 0 */ n37 ? !n12 : n12;
assign n68 = /* LUT 8 9 6 */ n35 ? !n10 : n10;
assign n69 = /* LUT 8 10 3 */ n40 ? !n15 : n15;
assign n70 = /* LUT 8 9 7 */ n36 ? !n11 : n11;
assign n71 = /* LUT 8 10 2 */ n39 ? !n14 : n14;
assign n72 = /* LUT 8 10 5 */ n42 ? !n17 : n17;
assign n73 = /* LUT 8 11 2 */ n50 ? !n22 : n22;
assign n74 = /* LUT 8 10 4 */ n41 ? !n16 : n16;
assign n75 = /* LUT 8 11 3 */ n51 ? !n23 : n23;
assign n76 = /* LUT 8 10 7 */ n44 ? !n19 : n19;
assign n77 = /* LUT 8 11 0 */ n45 ? !n20 : n20;
assign n78 = /* LUT 8 10 6 */ n43 ? !n18 : n18;
assign n79 = /* LUT 8 11 1 */ n49 ? !n21 : n21;
assign n80 = /* LUT 8 11 6 */ n54 ? !n26 : n26;
assign n81 = /* LUT 8 11 7 */ n55 ? !n27 : n27;
assign n82 = /* LUT 8 12 2 */ n58 ? !LED1 : LED1;
assign n83 = /* LUT 8 11 4 */ n52 ? !n24 : n24;
assign n84 = /* LUT 8 12 1 */ n57 ? !n3 : n3;
assign LED2 = /* LUT 12 12 7 */ n3 ? !LED1 : LED1;
assign n85 = /* LUT 8 11 5 */ n53 ? !n25 : n25;
assign n86 = /* LUT 8 12 0 */ n56 ? !n28 : n28;
assign n30 = /* CARRY 8 9 0 */ (0 & n4) | ((0 | n4) & n29);
assign n31 = /* CARRY 8 9 1 */ (0 & n5) | ((0 | n5) & n30);
assign n32 = /* CARRY 8 9 2 */ (0 & n6) | ((0 | n6) & n31);
assign n33 = /* CARRY 8 9 3 */ (0 & n7) | ((0 | n7) & n32);
assign n34 = /* CARRY 8 9 4 */ (0 & n8) | ((0 | n8) & n33);
assign n39 = /* CARRY 8 10 1 */ (0 & n13) | ((0 | n13) & n38);
assign n35 = /* CARRY 8 9 5 */ (0 & n9) | ((0 | n9) & n34);
assign n38 = /* CARRY 8 10 0 */ (0 & n12) | ((0 | n12) & n37);
assign n36 = /* CARRY 8 9 6 */ (0 & n10) | ((0 | n10) & n35);
assign n41 = /* CARRY 8 10 3 */ (0 & n15) | ((0 | n15) & n40);
assign n37 = /* CARRY 8 9 7 */ (0 & n11) | ((0 | n11) & n36);
assign n40 = /* CARRY 8 10 2 */ (0 & n14) | ((0 | n14) & n39);
assign n43 = /* CARRY 8 10 5 */ (0 & n17) | ((0 | n17) & n42);
assign n51 = /* CARRY 8 11 2 */ (0 & n22) | ((0 | n22) & n50);
assign n42 = /* CARRY 8 10 4 */ (0 & n16) | ((0 | n16) & n41);
assign n52 = /* CARRY 8 11 3 */ (0 & n23) | ((0 | n23) & n51);
assign n45 = /* CARRY 8 10 7 */ (0 & n19) | ((0 | n19) & n44);
assign n49 = /* CARRY 8 11 0 */ (0 & n20) | ((0 | n20) & n45);
assign n44 = /* CARRY 8 10 6 */ (0 & n18) | ((0 | n18) & n43);
assign n50 = /* CARRY 8 11 1 */ (0 & n21) | ((0 | n21) & n49);
assign n55 = /* CARRY 8 11 6 */ (0 & n26) | ((0 | n26) & n54);
assign n56 = /* CARRY 8 11 7 */ (0 & n27) | ((0 | n27) & n55);
assign n53 = /* CARRY 8 11 4 */ (0 & n24) | ((0 | n24) & n52);
assign n58 = /* CARRY 8 12 1 */ (0 & n3) | ((0 | n3) & n57);
assign n54 = /* CARRY 8 11 5 */ (0 & n25) | ((0 | n25) & n53);
assign n57 = /* CARRY 8 12 0 */ (0 & n28) | ((0 | n28) & n56);
/* FF 8 9 0 */ always @(posedge n1) if (1) n4 <= 0 ? 0 : n60;
/* FF 8 9 1 */ always @(posedge n1) if (1) n5 <= 0 ? 0 : n61;
/* FF 8 9 2 */ always @(posedge n1) if (1) n6 <= 0 ? 0 : n62;
/* FF 8 9 3 */ always @(posedge n1) if (1) n7 <= 0 ? 0 : n63;
/* FF 8 9 4 */ always @(posedge n1) if (1) n8 <= 0 ? 0 : n64;
/* FF 8 10 1 */ always @(posedge n1) if (1) n13 <= 0 ? 0 : n65;
/* FF 8 9 5 */ always @(posedge n1) if (1) n9 <= 0 ? 0 : n66;
/* FF 8 10 0 */ always @(posedge n1) if (1) n12 <= 0 ? 0 : n67;
/* FF 8 9 6 */ always @(posedge n1) if (1) n10 <= 0 ? 0 : n68;
/* FF 8 10 3 */ always @(posedge n1) if (1) n15 <= 0 ? 0 : n69;
/* FF 8 9 7 */ always @(posedge n1) if (1) n11 <= 0 ? 0 : n70;
/* FF 8 10 2 */ always @(posedge n1) if (1) n14 <= 0 ? 0 : n71;
/* FF 8 10 5 */ always @(posedge n1) if (1) n17 <= 0 ? 0 : n72;
/* FF 8 11 2 */ always @(posedge n1) if (1) n22 <= 0 ? 0 : n73;
/* FF 8 10 4 */ always @(posedge n1) if (1) n16 <= 0 ? 0 : n74;
/* FF 8 11 3 */ always @(posedge n1) if (1) n23 <= 0 ? 0 : n75;
/* FF 8 10 7 */ always @(posedge n1) if (1) n19 <= 0 ? 0 : n76;
/* FF 8 11 0 */ always @(posedge n1) if (1) n20 <= 0 ? 0 : n77;
/* FF 8 10 6 */ always @(posedge n1) if (1) n18 <= 0 ? 0 : n78;
/* FF 8 11 1 */ always @(posedge n1) if (1) n21 <= 0 ? 0 : n79;
/* FF 8 11 6 */ always @(posedge n1) if (1) n26 <= 0 ? 0 : n80;
/* FF 8 11 7 */ always @(posedge n1) if (1) n27 <= 0 ? 0 : n81;
/* FF 8 12 2 */ always @(posedge n1) if (1) LED1 <= 0 ? 0 : n82;
/* FF 8 11 4 */ always @(posedge n1) if (1) n24 <= 0 ? 0 : n83;
/* FF 8 12 1 */ always @(posedge n1) if (1) n3 <= 0 ? 0 : n84;
/* FF 8 11 5 */ always @(posedge n1) if (1) n25 <= 0 ? 0 : n85;
/* FF 8 12 0 */ always @(posedge n1) if (1) n28 <= 0 ? 0 : n86;
endmodule
Now please point to the construct in that verilog code that will not synthesize on some targets!
Note : do no confuse LUT. LUT in this context = logic unit , not 'look-up-table). Some families hav a LUT that is 2 fliplfops with a combinatorial cloud before it with 10 inputs. , others have 4 flipflops with a larger cloud. every manufacturer and family has its own mix of such LUT blocks.
take any fpga where the LUT is constructed differently from the Lattice LUT used for this specific family.
If i understand it correctly what you do is pull a reverse netlist and wire it into the LUT inputs and outputs. And then you unmap the lut matrix into NOt AND and OR operations and multiplexers and assign those to wires. you know what the LUT of this particular device looks like so you can resolve down to the flipflop inputs and outputs. correct ?
Assume one architecture where 1 lut consists of an 8 input and/or matrix feeding 2 flipflops.
Assume a different architecture where 1 lut is a 20 input and/or matrix feeding 4 flipflops
The lut architecture is different between families of the same manufacturers. Compare a lut from Lattice against an altera or a Xilinx one. They are different. Even though you have a logic cloud of and/not/or and multiplexers ( the ? operand in verilog ) feeding flipflops , that will not map correctly on an architecture with a different lut structure. You may end up with such large differences that the recompiled entity does not run as timing is completely off.
It gets more complex once code starts using specialistic macros.
How will you trans-map the bitstream if it uses embedded memory blocks , embedded adders / multipliers or other hard-macros that don't exist in other families or manufacturers ?
It s great you found a way to decompile the bit stream, but its output is a massive logic cloud of and/or/not that is pretty much unreadable. Yes you can recompile it , providing you don't switch architecture or families, if you are lucky it may work on some other families.
So what you have is a bitstream to logic equation resolver ( you could take your output one step further and get rid of the intermediate wires and write out the boolean equations driving the fliplfop control lines. You can compare your output to opening the final , minimized logic netlist in the schematic viewer of the FPGA tools.
that's not really decompiling in my book.
Anyway, cool you figured out how the bitstream works , but i don't see a practical use.
Let's say i have a board with a xilinx fpga that has, amongst other functionality, some logic function in it i really want. i want to 'decompile the bitstream' , steal that interesting block and slap it in an altera.
The system works for simple devices but is not really portable ( mainly due to architectural differences between manufacturers and their use of hard-macro's that do not exist in other families.
As for 'free' compilers for FPGA : you can synthesize down to a point but then you really need the manufacturer tools. Only the manufacturer tools have access to those hard macro's.
The tools are optimized to recognize certain functions and map those onto available hardware in the particular device. you may code a simple counter . The compiler detects this and knows it has a certain number of LUTS that have optimized interconnects to implement counters.
Every FPGA manufacturer has their secret sauce of 'accelerators'. Only they know how to translate the source to an optimized output.
With old, simple CPLD's and fpga's that only held simple gates and simple flipflops it doesn't matter.
Fact is that devices produced in the last 10 years have 'accelerators'. your code is not flattened to it shortest form logic equation like they did 20 years ago. Instead it is smartly mapped on those accelerators. every vendor has their own 'secret mix'.
most devices these days have special functionality to even accelerate relatively simple things like counters. unless you know those exist, and how they work ( for example the carry propagation logic may exist as a hard , optimized block that is much faster than its synthesized equivalent ) you don't stand a chance reversing that , nor porting it.
While this is a cool experiment , it doesn't really have a practical application. The output is pretty much unreadable and it will only work for simple devices.