Author Topic: Reverse engineering Anlogic AL3_10 FPGA  (Read 13035 times)

0 Members and 1 Guest are viewing this topic.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #50 on: October 21, 2022, 12:10:55 pm »
Not that it made any difference, but I stumbled on some "Chinese" logic |O

For the logic slices there are setting bits to control the flip flop input multiplexer, and it looked liked that these bits did not exist for slice 0.

Listings I made from the database showed me this

Code: [Select]
MC1_DI0_S1 NONE A 1 PROPERTY(SLICE1.REG0_SD,F)
MC1_DI0_S2 NONE A 1 PROPERTY(SLICE2.REG0_SD,F)
MC1_DI0_S3 NONE A 1 PROPERTY(SLICE3.REG0_SD,F)
MC1_DI1_S1 NONE A 1 PROPERTY(SLICE1.REG1_SD,F)
MC1_DI1_S2 NONE A 1 PROPERTY(SLICE2.REG1_SD,F)
MC1_DI1_S3 NONE A 1 PROPERTY(SLICE3.REG1_SD,F)

MC1_FX0_S1 NONE A 1 PROPERTY(SLICE1.REG0_SD,FX)
MC1_FX0_S2 NONE A 1 PROPERTY(SLICE2.REG0_SD,FX)
MC1_FX0_S3 NONE A 1 PROPERTY(SLICE3.REG0_SD,FX)
MC1_FX1_S1 NONE A 1 PROPERTY(SLICE1.REG1_SD,FX)
MC1_FX1_S2 NONE A 1 PROPERTY(SLICE2.REG1_SD,FX)
MC1_FX1_S3 NONE A 1 PROPERTY(SLICE3.REG1_SD,FX)

Which made me believe there are no bits for slice 0 (_S0) and implemented the default use of the F output as input for the flip flop, because some scanning of the blocks and the connections showed this to be the case, at least for the ones I checked.

But today while doing more research on getting top level verilog generated for the design, I noticed that for some slice 0's it does use the mi input as the input for the flip flop so I wondered how the FPGA decided which to use. Modified the code to use the mi input when there is a connection to it, and that solved some of the errors I found. Unfortunately it did not lead to a working bit stream on the scope.

So I dove back into the list files of the settings bits I made and found that there are bits for slice 0, but they use a different name :palm:

Code: [Select]
TOP.XI390.NET104 NONE A 1 PROPERTY(SLICE0.REG0_SD,F)
TOP.XI390.NET97 NONE A 1 PROPERTY(SLICE0.REG1_SD,F)

TOP.XI389.NET104 NONE A 1 PROPERTY(SLICE0.REG0_SD,FX)
TOP.XI389.NET97 NONE A 1 PROPERTY(SLICE0.REG1_SD,FX)

So have to adapt the code to use these and see if this changes the outcome.

For the "top" level verilog I found that for the logic it should be doable to output "assign" statements for the LUT's and "always" statements for the flip flops. When the input of the flip flop is the output of the LUT it can be combined into a single "always" statement, as long as the output of the LUT is not used elsewhere.

The embedded memory is a bit trickier, but I will find some way to do it.

At least it is good exercise for the brain :)

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #51 on: October 24, 2022, 11:16:38 am »
Found another possible mistake made.

To make a multi bit adder a FPGA uses internal carry connections. These are implied and not specifically routed. So I wrote my code to handle these carry chains and assumed that the next possible block also being of type adder indicated it to be part of the chain. But working on trying to do it on a higher level in verilog I was checking on when the outputs are registered if the signal is also used from the not registered output, and found that a chain is also broken when the f_1 or q_1 output of a slice is not connected.

Stumbled on this because I noticed an open_net connection within a chain, and upon a closer look that the clocks between the two blocks differ, which does not make sense in a single addition chain.

So will have to tweak the code and see if it makes it work in the scope.

It is fortunate that it is not a very big design, but still has a lot of slices and connections to check, so another error might well be in there.

Another thing is that the IDE does not what I expected while testing the different flip flop options like given here: https://www.fpga4student.com/2017/02/verilog-code-for-d-flip-flop.html

With just a simple design like below:

Code: [Select]
module pin_test
(
  input  wire i_led_blue_control,
  input  wire i_led_red_control,
  output wire o_led_red, 
  output wire o_led_yellow,
  output wire o_led_blue
);

reg ireg_red_led = 0;

always@(posedge i_led_red_control)
  begin
    ireg_red_led <= i_led_blue_control;   
  end

assign o_led_red    = ireg_red_led | i_led_blue_control;
assign o_led_yellow = ireg_red_led & i_led_blue_control;
assign o_led_blue   = ireg_red_led ^ i_led_blue_control;

endmodule

The IDE creates a slice with a flip flop connected and some basic settings. What I wanted to see is what changed when I made it to work on the negative edge of the clock. I expected the CLK MUX to be set to inverted, but instead it just added an inverter in the clock line :palm:

So I tried to interpret the setting to the best of my knowledge and have to see if it matches what it should.

But even when it works with what I'm generating on the higher level, it will still take some interpreting the result before it is an actual usable bit of code.

Here is a sample of what it looks like.

Code: [Select]
//---------------------------------------------------------------------------
//Block 61, MSLICE 1

  assign sig_block_61_lut_0 = (~net_16 * ~net_527 * ((net_131 * net_141) + ~(~net_131 + net_141))) + (~net_16 * net_527) + (net_16 * ~net_527 * ((net_131 * net_141) + ~(net_131 + ~net_141))) + (net_16 * net_527);
  assign sig_block_61_lut_1 = (~(net_253 + net_22));
  assign net_32 = (~net_27 * sig_block_61_lut_0) + (net_27 * sig_block_61_lut_1);

//---------------------------------------------------------------------------
//Block 71, MSLICE 1

  assign net_53 = (~net_181 * ((net_315 * net_201) + ~(~net_315 + net_201))) + (net_181 * ((net_315 * net_201) + ~(net_315 + ~net_201)));
  assign net_50 = ~net_250;

  reg net_52;
  reg net_49;

  always @(posedge gclk_3)
  begin
    if(net_50 == 1'b1)
    begin
      if(net_261 == 1'b1)
      begin
        net_52 <= 1'b0;
        net_49 <= 1'b0;
      end
      else
      begin
        net_52 <= net_201;
        net_49 <= net_187;
      end
    end
  end

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #52 on: October 24, 2022, 04:02:28 pm »
What I stumbled on turns out not to be a mistake, for as far as I can tell.

I was misled by the fact that the f outputs are not used in the slices I stumbled on. The flip flops are used with the separate mi inputs and have no impact on the adder. For this set of slices only the last f output is used, which probably is the carry of the sum. It takes careful examination of all the settings and connections on a slice to turn it into proper output. So many possibilities.

I did find something else about not connected inputs on the adders. The IDE sets them as 1 in the gate level it generates for simulation, where I did not. Changed the code to handle this, but it does not make a difference.

It still refuses to set two of the MCU interface data pins as bidirectional.

Have to see what happens when the "high" level verilog is fully generated. Working on the add bit, which has some issues that need be figured out.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #53 on: October 26, 2022, 03:43:29 pm »
Did find something I missed in the adder handling. It can also be a subtract-er. I modified the code to handle this on the gate level output, but it did not make a difference on the scope. It still refuses to connect two of the MCU data lines as bidirectional.

But for the higher level verilog it is of importance to know if it is add or subtract, and I know have something working to handle the adders of the mslices. This is the simpler one but it still took some effort to generate output that leads to a similar bit stream.

Code: [Select]
module test
(
  wire [3:0] a_input,
  wire [3:0] b_input,
  wire [4:0] o_output
);

  assign o_output = a_input - b_input;

endmodule

yields what is shown below. (left out the module bit)

Code: [Select]
//---------------------------------------------------------------------------
//Adder blocks 53, 54, 55

  wire net_10, net_11, net_7, net_9, net_8;

  assign { net_10, net_11, net_7, net_9, net_8 } = { net_6, net_4, net_2, net_5 } - { net_12, net_13, net_3, net_14 };

To bundle these nets into a bus requires much more coding, because only after processing the adder it is known that it is a bus. I have tested the resulting code in the IDE and it handles it as intended, so that is no problem. Something for later processing when it is proven possible to reverse engineer the bit stream back in to working code.

Next up is handling the lsices. These can do a 4 bit add in a single slice and have different settings that need to be analyzed.

When that is done I can see if it all is correct and hopefully I can generate a working bit stream from it. So fingers crossed :)

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #54 on: October 28, 2022, 01:51:39 pm »
With a bit of manual tweaking I got a verilog file, and it compiles, but with lots of warnings about wires or registers being used before being declared, so it is going to need some buffering during generation of the output to hold a separate record of the wires, registers and the actual code to be able to output it in the correct order.

Furthermore I had a bit of a struggle with the embedded memory to get it right and that incorporated the manual patch, of which I know it is not correct. Have to do some more work in the code to get it right based on the settings bits. Or I have to do it like with the PLL and just output what I think it needs to be on the top level.

But generating the higher level verilog does have the benefit that things like address counters become clear. Have to think up a scheme to generate the signals in buses like

Code: [Select]
wire [11:0] sample_address;
instead of

Code: [Select]
wire net_46, net_42, net_44, net_43, net_45, net_36, net_38, net_37, net_39, net_33, net_35, net_34;
Also have to do this for the external connections and make it so that these external names are used in the verilog.


Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #55 on: October 29, 2022, 01:37:17 pm »
 |O |O |O

Why oh why is it always software crap messing things up.

I keep getting that for two of the MCU interface data bus pins the direction select is not connected. So I thought it is time to check what morris6 made when he played with making his own FPGA programming for the scope. It turns out that the same happens there too. The weird thing being that morris6 had something working on the scope. :-//

I have also made something with the AL3-10 connected to a Lichee Nano, but only used it to write data into the FPGA and not read from it.

So I decided to try an older version of the Tang Dynasty IDE and there all eight pins get their direction select connected when I run it on the gate level verilog. But still no dice in the scope. It does not even show the display after reset, unlike the output of the newer version of the IDE.

On the higher level verilog it throws errors, so there is something wrong in there too. But with the newer version it does compile but with some warnings I have to examine.

So the question is which version of the software to use. I have three versions, and maybe there is a new one. Have to check if Sipeed has an update.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #56 on: October 30, 2022, 10:26:17 am »
A small victory :-DD

I found that I had an error in the code making up the equations for the combinatorial logic assign statements causing an equation of a previous slice to be used instead of 1'b0 when one part of a mslice lut 5 setup has no bits set.

Fixed that and this resolved some warnings I got from the Tang Dynasty IDE. To make sure the MCU interface pins are connected as intended I switched back to version 4.6 of the IDE.

And even though way to few blocks are used I decided to test it on the scope. After loading the bit stream it just started up again without a reset and I could hear the screen brightness beep, and it is not frozen. Can change the volts per division settings with relay's clicking as a result. But the sampling bit is not working. The traces are flat and on maximum level.

Also adjusting the brightness does not work as in the original.

But it shows I'm onto something now.

Have to try the gate level output in the 4.6 version and see what it does.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #57 on: October 30, 2022, 12:18:08 pm »
I found the possible why behind the two direction select pins seemingly not getting connected. The IOB has some additional settings bits that control some multiplexer and my guess is that this multiplexer connects the two "ts" inputs of a possible differential pair together.

In the output of the version 5 software I can see these bits set for the pins in question where as they are not set in the original bit stream, or what is generated with version 4.6.

So that might explain why morris6 his test were working, and also that the bit stream generated based on the higher level verilog with version 5 of the IDE shows the same behavior on the scope.

Very frustrating this seemingly weird and also random behavior of the IDE. The other pin pairs used for the MCU interface do not show this and it also swaps on which pad it sets this bit. :palm:

Unfortunately still no success with the gate level output, but it might well be that it needs some things to be formatted differently. The whole experience is a bit like searching for a needle in a thousand haystacks. :o

But it is that damned curiosity of me that keeps nagging  :-DD

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #58 on: October 31, 2022, 02:15:08 pm »
Based on the small success I started to analyze the generated verilog and in the process name signals. Modified the code to do this based on a table I extend with more net names that I find the meaning for.

Already found some enable signals that allow writing the settings for the AC/DC relays and have to trace it back to how these signals are made. Here is a sample of what I found for command 0x37.

Code: [Select]
//---------------------------------------------------------------------------
//Block 289, MSLICE 1

  assign cmd37_enable = (net_170 * (net_745 * net_197));
  assign net_467 = (net_170 * (net_452 * net_197));

  always @(posedge i_mcu_clk)
  begin
    if(cmd37_enable == 1'b1)
    begin
      ac_dc_2 <= io_mcu_d_0;
    end
  end

Here they used a flip flop with an enable signal, but I have also found some other form of loading a register with data from the MCU

Code: [Select]
//---------------------------------------------------------------------------
//Block 832, LSLICE 3

  assign sig_832_lut_0 = (~net_1643 * net_1341 * ~i_mcu_dcs * ((io_mcu_d_0 * net_431) + ~(io_mcu_d_0 + ~net_431))) + (net_1643 * ~net_1341 * ~i_mcu_dcs) + (net_1643 * ~net_1341 * i_mcu_dcs * ((io_mcu_d_0 * net_431) + ~(~io_mcu_d_0 + net_431))) + (net_1643 * net_1341 * ~i_mcu_dcs * (io_mcu_d_0 + net_431)) + (net_1643 * net_1341 * i_mcu_dcs * ((io_mcu_d_0 * net_431) + ~(~io_mcu_d_0 + net_431)));
  assign net_1644 = (~net_1503 * ~net_1645 * ~net_1590 * (~(net_1642 * net_1643)));

  always @(posedge i_mcu_clk)
  begin
    net_1643 <= sig_832_lut_0;
  end

It uses a feedback of the q output of the flip flop back into the LUT to keep the previous value when needed. It uses the MCU data/command select line and a data line combined with other signals, and I wonder how this was originally written up to make this construct.

Parts of the code are certainly made up by the IDE, because for the reading of the samples, multiplexers are needed to get the data from the different blocks of embedded memory, and I'm quite certain that the original design just uses a single 32 bit wide 4K memory setup.

I hope that doing this analyzing will also show where the errors of my ways are. This simply because of the fact that the latest test showed some parts working and a lot of other things not, there have to be errors.

But it will be a fair bit of work and without the earlier work done on the scope software itself it would be very difficult to get an understanding of the design. I know what to look for so to speak.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #59 on: November 02, 2022, 12:50:48 pm »
Identified 215 of the 1673 nets and I'm starting to see how things are done. In the process I found that I swapped two inputs in the equations and this is what made it somewhat work, :palm: because now that I fixed that, the result is that the scope does the same as with the gate level verilog output. It shows the screen and hangs.

But getting to the bottom of what is causing this is not easy. I either missed some settings that make some necessary connections or got some levels wrong on reset states or made some other wrong interpretation. Due to the fact that a lot of signals I found so far make sense, I'm going to try to do the rest of the reverse engineering manually, by identifying more signals and then write up code for it.

I, for instance, found the display brightness bits, that are written after command 0x38, and the state machine part that is used to write the sequence of the bytes. This also lead to the counter that is used to make the PWM signal to control the brightness.

To me this means that a lot of the work done so far is correct, and that it is possible to get back to some original code. But it certainly needs a lot of manual labor to get it done. I don't see a solution where you just press the run button and out comes a clear cut verilog of the design. I think it would require a well trained artificial intelligence to actually get it done.

To get some "universal" reverse engineering system for the Anlogic FPGA's means a lot of work to be done still. It would need a module to process the setting bits into a net and block list, where all the primitives are handled and not just the ones I did now. A separate module would then be needed to process the net and block list into verilog. This module would need adaptation for the specific bit stream, to allow naming of the signals and other needed interpretation.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #60 on: November 03, 2022, 12:58:23 pm »
Done over a quarter of the nets, mostly with the MCU interface related. Lots of straight forward select logic and registers holding the data. Found many of the commands used in the scope software so was also able to use some meaningful names for the signals.

But there are also some weird looking "anti" select constructions that need further investigation as to their meaning.

Like this one, which is not super bad and if not mistaken, is true for commands 13, 17, 1B, 1F and 6F.

Edit: I was mistaken. Did not check the parentheses correctly. It is just 1F and 6F. Have to brush up my boolean algebra.

Code: [Select]
net_473 = (cmd_b3 * ~cmd6x_select * cmd_b2 * ((cmdxxxxxx11_select * cmd1x_select))) + (cmd_b3 * cmd6x_select * cmd_b2 * ((cmdxxxxxx11_select * ~cmd1x_select) + (cmdxxxxxx11_select * cmd1x_select)));

Where this one seems to make not much sense. True for lots of commands except some?

Code: [Select]
net_562 = (~cmd_b3 * ~cmd6C_select * ~cmd_b2 * ((~cmd6x_select * ~cmd2x_select) + (cmd6x_select * ~cmd2x_select))) + (~cmd_b3 * ~cmd6C_select * cmd_b2 * ((~cmd6x_select * ~cmd2x_select) + (cmd6x_select * ~cmd2x_select))) + (cmd_b3 * ~cmd6C_select * ~cmd_b2 * ((~cmd6x_select * ~cmd2x_select) + (~cmd6x_select * cmd2x_select))) + (cmd_b3 * ~cmd6C_select * cmd_b2);

Still no clue as to why the scope is frozen with this bit stream, but with what I have identified so far I should be able to deduce something. Need to look into how the reading of the data back to the MCU is done and find what is happening for either command 0x05 or 0x0A, because these are checks that can hold the scope frozen.

Here is what I have so far for the curious among us :)
« Last Edit: November 03, 2022, 01:46:01 pm by pcprogrammer »
 

Online Kean

  • Supporter
  • ****
  • Posts: 2094
  • Country: au
  • Embedded systems & IT consultant
    • Kean Electronics
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #61 on: November 03, 2022, 02:20:42 pm »
@pcprogrammer I must say your persistence (& skill) is impressive
 
The following users thanked this post: pcprogrammer

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #62 on: November 03, 2022, 04:49:29 pm »
@pcprogrammer I must say your persistence (& skill) is impressive

Thanks Kean, persistence and skill are certainly needed for this task.

Here is a sample of what I have to wade through to get the reading of the data by the MCU figured out. Some registered setup is used with lots of combinatory logic to select the different data sources. The one that I'm looking for is for command 0x05, because that is where the scope firmware can hang on.

Code: [Select]
net_354 = (net_784 * net_692 * net_355 * ((~net_425 * ~net_345)));
net_784 = (~net_534 * ~cmd69_select) + (~net_534 * cmd69_select * ((~net_690 * ~i_i2c_cmd69_b0) + (net_690 * ~i_i2c_cmd69_b0))) + (net_534 * ~cmd69_select * ((~net_690 * ~i_i2c_cmd69_b0) + (~net_690 * i_i2c_cmd69_b0))) + (net_534 * cmd69_select * ((~net_690 * ~i_i2c_cmd69_b0)));
net_692 =(net_990 * (~i_adc1A_d_0 * ~cmd24_select * ((~cmd21_select * ~net_767) + (~cmd21_select * net_767) + (cmd21_select * net_767))) + (~i_adc1A_d_0 * cmd24_select * ((~cmd21_select * ~net_767) + (~cmd21_select * net_767) + (cmd21_select * net_767))) + (i_adc1A_d_0 * ~cmd24_select * ((~cmd21_select * ~net_767) + (~cmd21_select * net_767) + (cmd21_select * net_767))));
net_355 = (~net_295 * ~net_195 * ~cmd41_select) + (~net_295 * ~net_195 * cmd41_select * ((byte_state_0 * ~cmd3C_b0))) + (~net_295 * net_195 * ~cmd41_select) + (~net_295 * net_195 * cmd41_select);
net_425 = (cmd_b1 * net_232 * ((cmd001000xx_select * ~cmd_b0)));
net_345 = ((cmd23_select * ~net_30));
net_534 = (~cmd_b0 * ((cmd001000xx_select * ~cmd_b1)));
net_690 = (~net_691 * ~read_addr_l10 * ~read_addr_l11 * ((o_adc1A_d0_0 * ~o_adc1A_d1_0) + (o_adc1A_d0_0 * o_adc1A_d1_0))) + (~net_691 * ~read_addr_l10 * read_addr_l11) + (~net_691 * read_addr_l10 * ~read_addr_l11 * ((~o_adc1A_d0_0 * o_adc1A_d1_0) + (o_adc1A_d0_0 * o_adc1A_d1_0))) + (~net_691 * read_addr_l10 * read_addr_l11);
net_990 = (~cmd6B_select * ~i_adc1B_d_0) + (~cmd6B_select * i_adc1B_d_0 * ((~i_i2c_cmd6B_b0 * ~cmd25_select) + (i_i2c_cmd6B_b0 * ~cmd25_select))) + (cmd6B_select * ~i_adc1B_d_0 * ((~i_i2c_cmd6B_b0 * ~cmd25_select) + (~i_i2c_cmd6B_b0 * cmd25_select))) + (cmd6B_select * i_adc1B_d_0 * ((~i_i2c_cmd6B_b0 * ~cmd25_select)));
net_767 = (~net_688 * (~read_addr_l10 * ~read_addr_l11) + (~read_addr_l10 * read_addr_l11 * ((~o_adc1B_d2_0 * ~o_adc1B_d3_0) + (~o_adc1B_d2_0 * o_adc1B_d3_0))) + (read_addr_l10 * ~read_addr_l11) + (read_addr_l10 * read_addr_l11 * ((~o_adc1B_d2_0 * ~o_adc1B_d3_0) + (o_adc1B_d2_0 * ~o_adc1B_d3_0))));
net_295 = (~net_292 * ~net_175 * ((cmd14_select * ~byte_state_0))) + (net_292 * ~net_175 * ((cmd14_select * ~byte_state_0) + (cmd14_select * byte_state_0)));
net_195 = (~byte_state_1 * ~byte_state_0 * ((~o_mcu_d_0 * ~cmd3C_b8) + (~o_mcu_d_0 * cmd3C_b8))) + (byte_state_1 * ~byte_state_0 * ((~o_mcu_d_0 * ~cmd3C_b8) + (o_mcu_d_0 * ~cmd3C_b8)));
net_232 = (~net_149 * (~read_addr_l10 * ~read_addr_l11 * ((o_adc2A_d0_0 * ~o_adc2A_d1_0) + (o_adc2A_d0_0 * o_adc2A_d1_0))) + (~read_addr_l10 * read_addr_l11) + (read_addr_l10 * ~read_addr_l11 * ((~o_adc2A_d0_0 * o_adc2A_d1_0) + (o_adc2A_d0_0 * o_adc2A_d1_0))) + (read_addr_l10 * read_addr_l11))
net_30  = (~net_31 * ~read_addr_l10 * ~read_addr_l11) + (~net_31 * ~read_addr_l10 * read_addr_l11 * ((~o_adc2B_d2_0 * ~o_adc2B_d3_0) + (~o_adc2B_d2_0 * o_adc2B_d3_0))) + (~net_31 * read_addr_l10 * ~read_addr_l11) + (~net_31 * read_addr_l10 * read_addr_l11 * ((~o_adc2B_d2_0 * ~o_adc2B_d3_0) + (o_adc2B_d2_0 * ~o_adc2B_d3_0)));
net_691 = (~o_adc1A_d2_0 * ~o_adc1A_d3_0 * ((read_addr_l11 * ~read_addr_l10) + (read_addr_l11 * read_addr_l10))) + (~o_adc1A_d2_0 * o_adc1A_d3_0 * ((read_addr_l11 * ~read_addr_l10))) + (o_adc1A_d2_0 * ~o_adc1A_d3_0 * ((read_addr_l11 * read_addr_l10)));
net_688 = (~o_adc1B_d1_0 * ~read_addr_l11 * ((~read_addr_l10 * o_adc1B_d0_0))) + (o_adc1B_d1_0 * ~read_addr_l11 * ((read_addr_l10 + o_adc1B_d0_0)));
net_175 = (~o_mcu_d_0 * ~byte_state_1 * ((~byte_state_0 * ~net_49) + (~byte_state_0 * net_49))) + (~o_mcu_d_0 * byte_state_1 * ((~byte_state_0 * ~net_49))) + (o_mcu_d_0 * byte_state_1 * ((~byte_state_0 * ~net_49)));
net_149 = (~o_adc2A_d3_0 * read_addr_l11 * ((~o_adc2A_d2_0 * ~read_addr_l10) + (~o_adc2A_d2_0 * read_addr_l10) + (o_adc2A_d2_0 * read_addr_l10))) + (o_adc2A_d3_0 * read_addr_l11 * ((~o_adc2A_d2_0 * ~read_addr_l10)));
net_31  = (~o_adc2B_d1_0 * o_adc2B_d0_0 * ((~read_addr_l11 * ~read_addr_l10))) + (o_adc2B_d1_0 * ~o_adc2B_d0_0 * ((~read_addr_l11 * read_addr_l10))) + (o_adc2B_d1_0 * o_adc2B_d0_0 * ((~read_addr_l11 * ~read_addr_l10) + (~read_addr_l11 * read_addr_l10)));

net_292 <= net_200;
net_49 <= net_187


net_789  = (net_788 * net_793 * net_1297 * (~(net_725 * net_549)));
net_788  = (net_272 * (~i_adc2A_d_0 * ~cmd26_select * (~(i_adc2B_d_0 * cmd27_select))) + (~i_adc2A_d_0 * cmd26_select * (~(i_adc2B_d_0 * cmd27_select))) + (i_adc2A_d_0 * ~cmd26_select * (~(i_adc2B_d_0 * cmd27_select))));
net_793  = (net_961 * ~cmd68_select * ~i_i2c_cmd68_b0 * (~(i_i2c_cmd6C_b0 * cmd6C_select))) + (net_961 * ~cmd68_select * i_i2c_cmd68_b0 * (~(i_i2c_cmd6C_b0 * cmd6C_select))) + (net_961 * cmd68_select * ~i_i2c_cmd68_b0 * (~(i_i2c_cmd6C_b0 * cmd6C_select)));
net_1297 = (~net_1606 * ~net_467 * (~(i_i2c_cmd6E_b0 * cmd6E_select))) + (~net_1606 * net_467 * (~(i_i2c_cmd6E_b0 * cmd6E_select))) + (net_1606 * ~net_467 * (~(i_i2c_cmd6E_b0 * cmd6E_select)));
net_272  = (~cmd1x_select * ~cmd6A_select) + (~cmd1x_select * cmd6A_select * ((~net_273 * ~i_i2c_cmd6A_b0) + (net_273 * ~i_i2c_cmd6A_b0))) + (cmd1x_select * ~cmd6A_select * ((~net_273 * ~i_i2c_cmd6A_b0) + (~net_273 * i_i2c_cmd6A_b0))) + (cmd1x_select * cmd6A_select * ((~net_273 * ~i_i2c_cmd6A_b0)));
net_961  = (~cmd0A_select * ~sample_write_enable * (~(i_i2c_cmd6D_b0 * cmd6D_select))) + (~cmd0A_select * sample_write_enable * (~(i_i2c_cmd6D_b0 * cmd6D_select))) + (cmd0A_select * sample_write_enable * (~(i_i2c_cmd6D_b0 * cmd6D_select)));
net_273 = (net_250 * cmd_b3 * ~cmd_b2 * ((~cmd_b1 * ~cmd_b0)));

net_725 <= sig_391_lut_0;
net_1606 <= sig_815_ff0_d;
net_250 <= sig_183_lut_1;


This means a lot of gathering of these lines of logic and then scanning through them to find how it is working, and thinking of how this was originally written in verilog. Which is also new for me so lots of learning here.

On every find of something that can be named, I add a line to a search table, like this sample below.

Code: [Select]
NETRENAME net_renaming_table[] =
{
  { "net_46",          "sample_addr_11"       },
  { "net_42",          "sample_addr_10"       },
  { "net_44",          "sample_addr_9"        },
  { "net_43",          "sample_addr_8"        },
  { "net_45",          "sample_addr_7"        },
  { "net_168",         "sample_write_enable"  },
  { "net_730",         "sample_write_clock"   },
  { "net_18",          "sample_read_clock"    },
  { "net_181",         "sample_read_enable"   },
  { "net_886",         "o_adc2B_d_7"          },
  { "net_885",         "o_adc2B_d_6"          },
  { "net_884",         "o_adc2B_d_5"          },
  { "net_182",         "trigger_mode"         },
  { "net_427",         "trigger_channel"      },
  { "net_457",         "trigger_edge"         },
  { "net_167",         "sampling_enable"      },
  { "net_261",         "sampling_reset"       },
  { "net_276",         "cmd3C_enable0"        },
  { "net_282",         "cmd3C_enable1"        },
  { 0,                 0                      }
};

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #63 on: November 04, 2022, 09:30:55 am »
While doing all this investigation within the generated verilog I forgot I wrote a simple test application for morris6 to make it easy to test the MCU - FPGA interface :palm:

I gave it a try this morning and found parts working and also confirmed my suspicion that command 0x05 is where the scope software hangs on. There is a reset command (0x01) that enables the reset and then the software waits for the result of command 0x05 to become one. This is what I see with the original bit stream. With the new one the result of command 0x05 stays zero after the reset command has been given, but when I release the reset it goes one. So some inversion somewhere.

But there is more that is not correct. The display brightness command works, but where the original has no beeping sound on the max setting this one does. Yet another handle to hold during the investigation of the code. (This means that the PWM signal never goes to full DC and thus 100%)

The relay control part seems to work as intended. I can hear the relays click for every of the 5 possible settings. Did not measure if the same relays are on or off compared to the original, but maybe I should. It would confirm if the logic equations are properly interpreted for at least that bit.

Another option could be simulation but earlier attempts to do simulations with Anlogic IP like the PLL and the memory did not work and I would have to figure that out first to take that route.

And so the story again continues with more plowing through the data 8)

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #64 on: November 04, 2022, 05:06:29 pm »
Solved some issues after I did do some simulation. After the tests of this morning I decided to look into the display brightness not working the same as on the original, and I found that the code derives a clock from the master 200MHz clock. I see a 16 bit counter and 16 registers and a reset signal made up from all the register bits. I thought that with the 16 bits it would divide the clock by 65535, but that would lead to ~3KHz, of which it is hard to derive a PWM with a carrier of ~800Hz and 1% steps.

So I copied the clock divide part to a separate file and loaded it into modelsim. Here I found that it likes the registers preloaded to make it work, and I saw that it just divides by 2. Also noticed that I used the wrong operators in the equations (* instead of & and + instead of |), but that did not change the outcome.

Why the bit stream shows this wide register setup for this baffles me. The fact that many things seem to work makes me believe to be on the right track, but then finding these kind of unnecessary things also makes me doubt the correctness.

I modified my verilog generator and ran the new output through the Tang IDE and tested it again in the scope. The display brightness issue has been resolved. No beep at maximum setting and full brightness on the screen, but the command 0x05 problem is still there :palm:

Also verified the relay states based on the setting and they match with the original, so that part works as intended.

Having used the simulator on a part of the code steers me to doing more of it this way. It is a bit of work to extract the bits to test, but it shows what is going on and makes things more clear.

Attached is the clock divider bit I simulated.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #65 on: November 05, 2022, 05:56:53 pm »
Verified the display brightness signal with modelsim and it confirms the 833Hz it is running on.

To get to the bottom of the sample reset part not working as intended I'm renaming more and more nets to get some picture of what is being done. Named about 35% of the nets, and found the PWM circuits for the channel offset voltages, and also what command 0x1F is doing. It sets a 12 bit address offset as a starting point for reading back the samples.

Named a lot of the special interface IC commands, but still have to follow a lot of the nets here too. Is a fair bit of code.

But it is still a mystery as to why that reset part is not working. I'm going to look into a setup where I can simulate this part, but it is a lot of code that is used in this part.

Hopefully I will get something setup tomorrow.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #66 on: November 06, 2022, 12:35:31 pm »
Created a version without the PLL and embedded memory for simulation. Wrote a test bench to write the display brightness command and checked if the PWM output signal showed the intended result, which it did.

So I can now start with the hunt for the sampling reset not doing what it should. Have to modify the test bench to write the commands and data as needed and switch to reading the data bus to see the status of the flag. Then inspect the used signals and try to find what is wrong.

Even though it is a lot of work it at least brings a lot of insight in what is going on.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #67 on: November 06, 2022, 01:51:04 pm »
For some reason the simulator can't determine the state of the internal mcu databus output :palm:

I do see the signal that shows the sampling reset state change state when the reset has been lifted, and this is also what I saw in the scope. Enable the reset and it returned a 0, disable the reset and it returned a 1. Still have to find why this is inverted while the rest of it seems to work as intended. It is the last signal in the simulation screen attached.

The signals that go red are the mcu databus signals, both the internal ones that are typed as register and the ones from the test bench which are typed wire. It goes red when the direction is set for read and the mcu clock goes high.

More research required 8)

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #68 on: November 06, 2022, 05:35:26 pm »
So much to learn :o

The red signals were caused by not specified input signals. I found commands with which it is possible to directly read the ADC data, and for these the ADC data lines needed to be inputted from the test bench. So with that fixed I now see the data returned for command 0x05, and it is indeed wrong, but why is still the question.

Have to check the sampling reset part a bit further to see if the state signal is actually correct and the problem lies in the read logic, or in the sampling reset part.

But that is for tomorrow.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #69 on: November 07, 2022, 02:45:47 pm »
Been simulating and looking through the code for several hours and I just don't see where things are wrong. The sampling reset part is a bit strange in the sense that the state set by the MCU is used to reset all the counters and what more is used in the sampling part, including the flag that is read by the MCU with command 0x05. When the reset state is reset (lifted) by the MCU a counter starts to count to 7 and then sets the flag that is read with command 0x05.

This flag is only used when command 0x05 is read, and does nothing in the reset part, and neither are the four counter signals. The code looks good, just like the rest of it. But the signal is inverted in the original. Set to one when the reset is enabled and reset to zero when reset is disabled.

Tried a hack with inverting this signal and tested it in the scope. The screen is no longer frozen, but it reads some random signals which do not change when the input sensitivity is changed. So something is not correct, but what, that is the big question.  :-//

I did a simulation with the channel offset signals, and this part also works just as intended. A ~25KHz PWM output on both outputs and the pulse widths are adjustable with the two settings.

And the more I check the more things look like to be valid code.

If the simulation of the "special IC" interface bit shows it is also working as intended, then I'm convinced that the reversal of the logic parts is correct. I base this on the fact that here almost all the elements of the logic are used. Within the always blocks the enable is used in combination with the reset. And it is these bits I might have misinterpreted the levels.

When the above is the case it basically leaves the embedded memory part that might be wrong. I can do simulations on the reading parts with the code as is, but for the writing I have to make some modifications.

All in all very frustrating, but that is what you get when venturing into the unknown :-DD


Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #70 on: November 08, 2022, 05:11:37 pm »
Unfortunately the I2C part seems to be wrong too. The simulation tries did not show any change in the SCL line, but it is made up of so many signals that I can't tell what is wrong.

I'm seeing some weird setup with a kind of reset signal on lots of the flip flops used in this bit, but the flip flop reset scheme is also used for the channel offset PWM signals, and these work without problems.

So I'm back to naming the nets and are a bit over half way. But the easy signals are basically done, so it is getting harder to identify the meaning of a signal. Lots of them are part of the big multiplexer for reading the data back to the MCU.

For the I2C there are 7 x 8 signals for the bytes received from the "special ic" that can only be identified by tracing them down to the MCU data lines or by finding the logic in the enabling sequence for clocking these bits in from the SDA signal.

One thing I probably interpreted wrong was that the clock enable of the flip flop also enabled the reset function, but changing it did not lead to a working I2C part. After reading up on this on the internet I believe that the reset overrides the clock enable even when synchronous reset is used.

To get my finger behind the problem, I have to bite the bullet and write up some verilog code to do the I2C bit or sampling bit in a similar way and have it working in the simulator. Then generate a bit stream for it. Modify my net list tracer code to also handle the global clocks, and then create verilog for the bit stream. Then analyze and simulate that to see if it works and when not try to find the why.

Ain't hobby fun :-DD

But I'm learning quite a bit from this.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #71 on: November 09, 2022, 09:44:34 am »
Finally I found something that is wrong and was easily fixed in the simulation.

There was another big counter with the nets still unnamed, so I looked into that one, expecting it to be for the 1KHz calibration signal. It indeed traced back to this signal, so I renamed the nets accordingly and loaded it into the simulator.

There I found that the first count up to the reset signal was working as expected, but after it going high for the reset it stayed high. I looked at the signals in the registers for the counter and found two of them to not being reset to 0 and therefore keeping the reset line high.

Changed the two offending code bits and now the 1KHz is generated as expected.

This means I have to go back to the analyzing of the bits to see why the incorrect settings are made for these slices. I also suspect that it is this what is causing the sampling and the I2C parts to not be working.

It is these kind of exceptions that are hard to find with the simple design tests I did to find the meaning of the bits. You need a large and intricate design to test for these. And the FNIRSI-1013D design is big enough for this. :-DD

But not there yet. Still have to find the error in my analyzing code. |O

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #72 on: November 09, 2022, 10:15:31 am »
Wow, that was disappointing :palm:

The problem was another of my copy, paste and not modify errors. For the second flip flop the flag of the first was used to set the reset value. Easy fix, but not for the sampling reset nor the I2C parts. They still don't work as needed.

Ah well, at least fixed a bug.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #73 on: November 09, 2022, 08:28:48 pm »
Dug deeper into the I2C part and found some weird behavior in the simulation. There is a 16 bit counter used as some state machine to send or receive the bits of the 7 variables in one go, but the first bits were always kept low due to the reset line on them. I modified the state of the reset line and it started counting, but never beyond 7. Looking at the code revealed that some of the slices that register the bits of this counter are reset on the signal being 1 and others on 0, which makes no sense to me, because the state counts used to send the bits go over 234, because that is a number I found for sending one of the bits in the before last register.

So this needs some careful checking of the bits set for these blocks and try to figure out what is behind this.

Still have to rename about a third of the nets, which is tricky for some of them where negative logic is used. Like a signal that is not state a and not state b, and thus any state but a or b. With names like i2c_state_xxxxxxxx1100xxxx and i2c_state_xxxxxxxx0000xxxx it is hard to come up with a not to long name that makes sense.

I also wonder how this has been written in the original verilog. Something that will take its time too, to get it written up in an easier to understand form.

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 3709
  • Country: nl
Re: Reverse engineering Anlogic AL3_10 FPGA
« Reply #74 on: November 10, 2022, 09:44:04 am »
First part of the mission is accomplished 8)

This morning I did a test with the I2C part by setting all the checks on the reset signal to the same low level and ran it in the simulator. Lo and behold it worked. The SCL line showed the clock pulses as needed. So based on that I looked at the slices used for the counters and buffers and checked them against the setting bits.

Found that I checked on the SRMUX bit for MSLICE1 and LSLICE3 but not for MSLICE0 and LSLICE2. These bits where named differently and I missed that. Added them to the check code and compiled the resulting verilog in the Tang Dynasty IDE and loaded it in the scope. And yes, it showed proper signs of life.

There might be some problems with timing though, because the 1KHz calibration signal is not perfect, at least on the scope it self. Have to check with another scope and signal generator to see which part is flawed.

What is left is finish the renaming of the nets and try to convert it to more readable verilog. Also have to modify and finish the reverse engineering code to at least incorporate the global clock routing.


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf