Reverse engineering Anlogic AL3_10 FPGA - Page 1
Forum section: electronics / general

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 07, 2022, 06:11:03 pm
content: I'm trying to reverse engineer the bitstream of an Anlogic AL3_10 FPGA, but have trouble matching the configuration bits onto logical names.With the information from prjtang (https://github.com/mmicko/prjtang) I'm able to make a map of the used tiles, but mapping the actual bits fails. To check things, I made a simple design in the Tang Dynasty IDE and the bitstream generator tells me how many configuration bits are set one. This matches with output of my rudimentary tool mapping these bits to the tiles.The json database files for the bits show a x,y coordinate system, for which I tried several matching options, but the resulting bit names make no sense. For most of the tiles it is just two bits for making connections over the interconnect, and one would expect logical names with something like "mux" in them to pop up.To get a better understanding I'm also trying to decode the work files of the IDE, which is slowly coming together, but I'm not sure if that will provide the answer. The prjtang data is a big help in this quest but it lacks information about how the mapping of the bits is done.So if anyone has some in-depth knowledge of this, I would appreciate if it is shared here.When there is an interest in the code I'm making (written in either C or python) let me know. I have no problem with sharing it.

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 13, 2022, 01:02:44 pm
content: I'm new to modern FPGA's and certainly new to the internals of them. My quest to reverse engineer one is a learning one, so questions come up.Here is one I hope someone has an answer for. When in an IO tile that holds 4 pads, a single pad is enabled for either input or output, do the other pads need to be configured then too?I made a simple verilog project with just two wires connected to each other. P23 as input connected to P112 as output. When I list the configuration bits, it looks like the Tang IDE sets unused bits and bits for the other pads.Attached is the list file I made and a zip of a bitmap I made showing the tiles and the configuration bits.

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 17, 2022, 12:49:40 pm
content: It took a lot of thinking and looking through the data to figure out what was wrong. At first I gave up on the whole quest due to not getting the wanted results, but the brain kept on wondering.What I did wrong was to assume that the 4 pad bits each frame of the configuration data has were at the end.At some point in the process I thought, hang on, when I change the "pulltype" property on a pin certain bits have to change, and looking in the bits file for the io tile in question and the pin used, showed these to be the bits in column 3 (x) and rows 14 and 16 (y), but in my generated image the bits were on column 3 and rows 18 and 20. So an offset of 4, and then the quarter droppedI knew about the bit stream having 257 bytes per frame which is 2056 bits and the database only using 2052 of them. My programmers instinct naturally assumed the not used bits to be at the end. It turns out they are at the beginning.After testing with more io pins at all sides of the chip this was confirmed and I now have clear data on the configuration bits.It turns out that the Tang Dynasty software always sets the source and sink property bits for all the pads in a tile even when the pad is not used or connected to the actual pins. The other bits are only controlled when a pad is used.Still a lot to figure out to get from the bit listing to a net list and from that back to hdl.

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 26, 2022, 09:02:21 am
content: I'm revisiting this topic after new information came up.For the Gowin FPGA's more has been done on the front of the open source tools, and I was looking into that in regards to the Gowin FPGA used in the Hantek DSO2000 series. I learned from it about the naming convention in the routing. So to gain more experience on FPGA reverse engineering I decided to try the probably simpler design of the in the FNIRSI-1013D used Anlogic FPGA.Still a lot of discovery to be done, but think it is possible to trace the connections through the FPGA.The configuration bits are set based on a logic equation on input parameters. For the routing these are like "ARCVAL(S6BEG0,E1END0)" where this means a connection between a south going wire spanning 6 blocks and an east going wire spanning a single block. The first character is the direction letter, the second character is the span, being either 1,2 or 6. Then followed by a tap point being "BEG", "MID" or "END" and a last character being the wire index.For the single block span it looks like there are only 4 wires per route. For the multi block spans there seem to be 8 wires per route.I made a listing of all the separate ARCVAL entities to gain more insight.The screen shot shows a routing in the Tang IDE chip viewer.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 06, 2022, 07:46:34 am
content: I have a question about interconnect wires in a FPGA.Are they unidirectional?In the Anlogic AL3_10 FPGA I'm trying to reverse engineer a design from, I'm progressing slowly and gain more insight in the interconnect and wonder if I'm right in thinking that the interconnect wires are indeed unidirectional.The Tang Dynasty IDE has a chip viewer and I found some new features that allow highlighting of the RSB/PIB SWI lines. It has three types, namely 1 hop, 2 hop and 6 hop lines. When viewing these for a single block it shows only 4 lines per type originating from the block. See the attached pictures.This leads to the below and the total number of connections match up.Code:outgoing incoming4x 1 hop 4x 1 hop4x 2 hop 8x 2 hop (4 mid and 4 end)4x 6 hop 8x 6 hop (4 mid and 4 end)total connections12 + 20 = 32 (4 x 8)I made a listing of the arcval pairs found in the database and this seems to confirm my idea. The pairs have the following meaning (endpoint, startpoint). For instance (W6BEG5,Q0) signals a connection between a logic block output Q0 and a wire start W6BEG5. In the list it only shows connections to the BEG wires and not the MID or END wires. There are of course also connections to logic block inputs like A0, B0, etc.Another question is if this setup is proprietary to the Anlogic FPGA's or a rather common thing?

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 08, 2022, 05:38:41 pm
content: Making some progress.A simple test design yielded no problems and showed the nets correctly, but the bitstream of the FNIRSI 1013D FPGA failsNeeds more tinkering, but I'm getting output which I can trace through to see what the problem is. It at least shows that I'm on the right track.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 09, 2022, 07:35:37 pm
content: After a bit of tweaking and modding the code, it successfully created a full net list for the FNIRSI FPGA.It is a small step in the big process of reversing the bit stream to HDL, but I feel it is good progress.Next up is turning the list into an actual net list with just a start and an endpoint, because all the in between connection points are not of interest.Code:91ARCVAL(W6BEG1,Q1)x0y35pib035TOP.XI2.MC00NONE24500A+B+C+DAB+C+D+4ARCVAL(W6BEG1,F1)ARCVAL(W6BEG1,F5)ARCVAL(W6BEG1,Q1)ARCVAL(W6BEG1,W1END2)91ARCVAL(W6BEG1,Q1)x0y35pib035TOP.XI2.MC06NONE04500A+B+C+DAB+C+D+4ARCVAL(W6BEG1,FX5)ARCVAL(W6BEG1,N6MID1)ARCVAL(W6BEG1,Q1)ARCVAL(W6BEG1,S6END1)94ARCVAL(S6BEG1,E6MID1)x2y35plb235TOP.XI1.MC02NONE14300A+B+C+DAB+C+D+4ARCVAL(S6BEG1,E1END2)ARCVAL(S6BEG1,E6MID1)ARCVAL(S6BEG1,S2END1)ARCVAL(S6BEG1,W1END2)94ARCVAL(S6BEG1,E6MID1)x2y35plb235TOP.XI1.MC06NONE04400A+B+C+DAB+C+D+4ARCVAL(S6BEG1,E6MID1)ARCVAL(S6BEG1,FX5)ARCVAL(S6BEG1,Q1)ARCVAL(S6BEG1,W6END1)94ARCVAL(S6BEG3,S6END1)x2y29plb229TOP.XI33.MC03NONE23000A+B+C+DAB+C+D+4ARCVAL(S6BEG3,E6END3)ARCVAL(S6BEG3,S6END1)ARCVAL(S6BEG3,W6END3)ARCVAL(S6BEG3,W6MID3)94ARCVAL(S6BEG3,S6END1)x2y29plb229TOP.XI33.MC07NONE03100A+B+C+DAB+C+D+4ARCVAL(S6BEG3,S1END2)ARCVAL(S6BEG3,S2END3)ARCVAL(S6BEG3,S6END1)ARCVAL(S6BEG3,S6END3)94ARCVAL(S6BEG1,S6END3)x2y23plb223TOP.XI1.MC03NONE24200A+B+C+DAB+C+D+4ARCVAL(S6BEG1,E6END1)ARCVAL(S6BEG1,S6END3)ARCVAL(S6BEG1,W6END1)ARCVAL(S6BEG1,W6MID1)94ARCVAL(S6BEG1,S6END3)x2y23plb223TOP.XI1.MC07NONE04300A+B+C+DAB+C+D+4ARCVAL(S6BEG1,S1END2)ARCVAL(S6BEG1,S2END1)ARCVAL(S6BEG1,S6END1)ARCVAL(S6BEG1,S6END3)94ARCVAL(E6BEG1,S6END1)x2y17plb217TOP.XI2.MC13NONE34700A+B+C+DAB+C+D+4ARCVAL(E6BEG1,E6END3)ARCVAL(E6BEG1,N6END1)ARCVAL(E6BEG1,S6END1)ARCVAL(E6BEG1,S6MID1)94ARCVAL(E6BEG1,S6END1)x2y17plb217TOP.XI2.MC16NONE04700A+B+C+DAB+C+D+4ARCVAL(E6BEG1,FX5)ARCVAL(E6BEG1,N6MID1)ARCVAL(E6BEG1,Q1)ARCVAL(E6BEG1,S6END1)94ARCVAL(E2BEG1,E6END1)x8y17pib817TOP.XI21.MC12NONE174600A+B+C+D+EAB+C+D+E+5ARCVAL(E2BEG1,E2END1)ARCVAL(E2BEG1,E6END1)ARCVAL(E2BEG1,N2MID1)ARCVAL(E2BEG1,N6MID1)ARCVAL(E2BEG1,S6MID1)94ARCVAL(E2BEG1,E6END1)x8y17pib817TOP.XI21.MC14NONE124700A+B+C+DAB+C+D+4ARCVAL(E2BEG1,E6END1)ARCVAL(E2BEG1,F1)ARCVAL(E2BEG1,FX1)ARCVAL(E2BEG1,N2END1)92ARCVAL(B5,E2MID1)x9y17plb917TOP.XI371.MC12NONE254600A+B+C+D+E+F+G+HAB+C+D+E+F+G+H+8ARCVAL(B5,E2END1)ARCVAL(B5,E2MID1)ARCVAL(B5,N2END1)ARCVAL(B5,N2MID1)ARCVAL(B5,Q6)ARCVAL(B5,S2MID1)ARCVAL(B5,W2END1)ARCVAL(B5,W2MID1)92ARCVAL(B5,E2MID1)x9y17plb917TOP.XI371.MC14NONE204700A+B+C+DAB+C+D+4ARCVAL(B5,E1END0)ARCVAL(B5,E2END0)ARCVAL(B5,E2MID1)ARCVAL(B5,S2END1)Because the above list can be reduced to just a short entry where it shows that x0,y35 Q1 is connected to x9,y17 B5 where Q1 is an IO pin input signal onto the FPGA fabric and B5 is the input to a LUT on a logic block.With such a list the step to HDL is much closer. But it also needs the information about what is in a LUT.Still lots of work to be done.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 10, 2022, 08:12:58 am
content: Found an oversight in my route tracing which I had thought about and knew investigation was needed.My simple test was just an input pin connected to an output pin, but a FPGA can do so much more then that of course. But I was very happy that my fixes from last night ran through the original FNIRSI bitstream without obvious errorsSo this morning I made a new test where two input pins are connected through logic with three output pins. (And, Or and Xor). And running that through my code did deliver a net list, but only 56 of the 92 routing bits were actually used. It turns out that interconnects can be linked to multiple targets, which I did expect but had no idea how it was done.It is rather simple. An incoming connection on a RSB can be connected multiple times, which means that more bit pairs use the same start point. So I have to adapt the code to handle this too.

author: fabiodl
author_rank: Frequent Contributor
timestamp: August 10, 2022, 08:26:42 am
content: I am sorry I have nothing meaningful to add, but please keep up with this work!!

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 10, 2022, 07:00:16 pm
content: That I will.Decided to move to a new c project to rewrite the net list generation. The bitstream analyzer is ok for creating the bitmap and a list of the bits, but for the net list a new approach is needed.So I started the Anlogic_netlist_tracer project. It is a copy of the bitstream analyzer, but ripped out almost all the code and are writing new functions to get it done. First it reads in the bitstream and creates a tile array with all the route bits separated per tile. It then scans through all the tiles to find net start points and assign a net number to them. A single output from an IO or logic block can be connected to multiple interconnect routes and these are all assigned the same net number to create single nets for all the inputs connected to one output.The next bit of code has to trace down all the connections, which is where I left of for today.More to follow

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 11, 2022, 02:11:57 pm
content: Finished the new tracing code and it matches all the routes of my test design, but when I run it on the FNIRSI bitstream it still goes somewhat wrong. It does match 30644 bits to 4049 nets, but it leaves 7820 bits that are not connected to any of the nets. So I'm missing something and have to investigate some more.There is a possibility that it has to do with the clock nets. Most connections are made in pairs of bits, but I just spotted odd numbers of bits in some tiles, which means there can also be single bit connections. Experimenting is the only way to find out what is what and how it works, because documentation is non existentBut that is the challenge.Edit: Found two problems. The first one was an oversight due to which multiple connections in a tile were not found properly. The fix for this reduced the not connected bits by some 3000 bits. The second one was a wrong assumption about the connections. The multi hop wires can have connections on both the middle as well as on the end point, where I assumed it to be to only one of them. This fix reduced the number of unconnected bits to 468, of which a large part are single bit connections for clock signals. The net count has reduced to 2295 because before a fix the multiple connections to a single block output were counted separately.Conclusion is that I need to write some code to handle the clock routes in a different manner to solve these unconnected bits, but I also have to look into the remainder of the unconnected bit pairs.But that is for tomorrow.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 12, 2022, 11:26:46 am
content: Fixed most of the issues with the net list trace.The result is a left over of 422 single bits to connect the clock signals to the logic, for which I have to add some extra functionality.There is one more issue with the tracing and that has to do with CE and SR signals of the blocks. These are inputs to the logic, but can also connect to some other signals in a tile. I did not see this used in the FNIRSI FPGA bitstream so not an issue for now.To get a proper net list I now have to change the code to first trace down all the inputs connected to GND, and then trace all the global clock nets to make them into bigger single nets per global clock line. After this it is making sure all the actual clock connections based on the single routing bits are traced into the nets too.All in all a nice learning experience so far.Still lots of work to be done before some HDL rolls out of it.Edit: Finished the changes to make the separate GND and GCLK nets. All the routing bits are now accounted for. It yields 1673 nets for the FNIRSI 1013D and 1699 nets for the FNIRSI 1014D.Next up is to format the lists into a usable way. This means only one entry for a single output connected to one or more inputs, and identify the io pins and logic blocks the inputs and outputs belong to.Code:16991ARCVAL(S1BEG2,Q1)x34y29pib3429TOP.XI315.MC01NONE83700A+B+C+D+E+FAB+C+D+E+F+6ARCVAL(S1BEG2,F6)ARCVAL(S1BEG2,F7)ARCVAL(S1BEG2,Q0)ARCVAL(S1BEG2,Q1)ARCVAL(S1BEG2,Q2)ARCVAL(S1BEG2,Q3)16991ARCVAL(S1BEG2,Q1)x34y29pib3429TOP.XI315.MC07NONE63700A+B+C+DAB+C+D+4ARCVAL(S1BEG2,F3)ARCVAL(S1BEG2,FX5)ARCVAL(S1BEG2,Q1)ARCVAL(S1BEG2,Q7)16994ARCVAL(S1BEG3,Q1)x34y29pib3429TOP.XI313.MC01NONE8700A+B+C+D+E+FAB+C+D+E+F+6ARCVAL(S1BEG3,F6)ARCVAL(S1BEG3,F7)ARCVAL(S1BEG3,Q0)ARCVAL(S1BEG3,Q1)ARCVAL(S1BEG3,Q2)ARCVAL(S1BEG3,Q3)16994ARCVAL(S1BEG3,Q1)x34y29pib3429TOP.XI313.MC07NONE6700A+B+C+DAB+C+D+4ARCVAL(S1BEG3,F3)ARCVAL(S1BEG3,FX5)ARCVAL(S1BEG3,Q1)ARCVAL(S1BEG3,Q7)16994ARCVAL(W6BEG3,S1END2)x34y28pib3428TOP.XI32.MC05NONE13500A+B+C+DAB+C+D+4ARCVAL(W6BEG3,F7)ARCVAL(W6BEG3,FX3)ARCVAL(W6BEG3,S1END2)ARCVAL(W6BEG3,S6MID3)16994ARCVAL(W6BEG3,S1END2)x34y28pib3428TOP.XI32.MC02NONE13400A+B+C+DAB+C+D+4ARCVAL(W6BEG3,N1END2)ARCVAL(W6BEG3,N6MID3)ARCVAL(W6BEG3,S1END2)ARCVAL(W6BEG3,W2END3)16994ARCVAL(W6BEG7,S1END3)x34y28pib3428TOP.XI58.MC05NONE1500A+B+C+DAB+C+D+4ARCVAL(W6BEG7,F7)ARCVAL(W6BEG7,FX7)ARCVAL(W6BEG7,S1END3)ARCVAL(W6BEG7,S6MID7)16994ARCVAL(W6BEG7,S1END3)x34y28pib3428TOP.XI58.MC02NONE1400A+B+C+DAB+C+D+4ARCVAL(W6BEG7,N1END3)ARCVAL(W6BEG7,N6MID7)ARCVAL(W6BEG7,S1END3)ARCVAL(W6BEG7,W2END7)16994ARCVAL(W6BEG3,W6END3)x28y28plb2828TOP.XI32.MC01NONE23400A+B+C+DAB+C+D+4ARCVAL(W6BEG3,FX3)ARCVAL(W6BEG3,FX7)ARCVAL(W6BEG3,Q7)ARCVAL(W6BEG3,W6END3)16994ARCVAL(W6BEG3,W6END3)x28y28plb2828TOP.XI32.MC07NONE03400A+B+C+DAB+C+D+4ARCVAL(W6BEG3,W1END2)ARCVAL(W6BEG3,W2END3)ARCVAL(W6BEG3,W6END1)ARCVAL(W6BEG3,W6END3)16994ARCVAL(W6BEG7,W6END7)x28y28plb2828TOP.XI58.MC01NONE2400A+B+C+DAB+C+D+4ARCVAL(W6BEG7,FX3)ARCVAL(W6BEG7,FX7)ARCVAL(W6BEG7,Q7)ARCVAL(W6BEG7,W6END7)16994ARCVAL(W6BEG7,W6END7)x28y28plb2828TOP.XI58.MC07NONE0400A+B+C+DAB+C+D+4ARCVAL(W6BEG7,W1END3)ARCVAL(W6BEG7,W2END7)ARCVAL(W6BEG7,W6END5)ARCVAL(W6BEG7,W6END7)16994ARCVAL(S6BEG3,W6END3)x22y28plb2228TOP.XI33.MC03NONE23000A+B+C+DAB+C+D+4ARCVAL(S6BEG3,E6END3)ARCVAL(S6BEG3,S6END1)ARCVAL(S6BEG3,W6END3)ARCVAL(S6BEG3,W6MID3)16994ARCVAL(S6BEG3,W6END3)x22y28plb2228TOP.XI33.MC06NONE03200A+B+C+DAB+C+D+4ARCVAL(S6BEG3,E6MID3)ARCVAL(S6BEG3,FX7)ARCVAL(S6BEG3,Q3)ARCVAL(S6BEG3,W6END3)16994ARCVAL(S6BEG7,W6END7)x22y28plb2228TOP.XI59.MC03NONE2000A+B+C+DAB+C+D+4ARCVAL(S6BEG7,E6END7)ARCVAL(S6BEG7,S6END5)ARCVAL(S6BEG7,W6END7)ARCVAL(S6BEG7,W6MID7)16994ARCVAL(S6BEG7,W6END7)x22y28plb2228TOP.XI59.MC06NONE0200A+B+C+DAB+C+D+4ARCVAL(S6BEG7,E6MID7)ARCVAL(S6BEG7,FX3)ARCVAL(S6BEG7,Q3)ARCVAL(S6BEG7,W6END7)16994ARCVAL(S6BEG1,S6END3)x22y22plb2222TOP.XI1.MC03NONE24200A+B+C+DAB+C+D+4ARCVAL(S6BEG1,E6END1)ARCVAL(S6BEG1,S6END3)ARCVAL(S6BEG1,W6END1)ARCVAL(S6BEG1,W6MID1)16994ARCVAL(S6BEG1,S6END3)x22y22plb2222TOP.XI1.MC07NONE04300A+B+C+DAB+C+D+4ARCVAL(S6BEG1,S1END2)ARCVAL(S6BEG1,S2END1)ARCVAL(S6BEG1,S6END1)ARCVAL(S6BEG1,S6END3)16994ARCVAL(S6BEG5,S6END7)x22y22plb2222TOP.XI47.MC03NONE21200A+B+C+DAB+C+D+4ARCVAL(S6BEG5,E6END5)ARCVAL(S6BEG5,S6END7)ARCVAL(S6BEG5,W6END5)ARCVAL(S6BEG5,W6MID5)16994ARCVAL(S6BEG5,S6END7)x22y22plb2222TOP.XI47.MC07NONE01300A+B+C+DAB+C+D+4ARCVAL(S6BEG5,S1END3)ARCVAL(S6BEG5,S2END5)ARCVAL(S6BEG5,S6END5)ARCVAL(S6BEG5,S6END7)16994ARCVAL(W2BEG1,S6END1)x22y16plb2216TOP.XI21.MC01NONE144600A+B+C+D+EAB+C+D+E+5ARCVAL(W2BEG1,FX1)ARCVAL(W2BEG1,N6END1)ARCVAL(W2BEG1,S6END1)ARCVAL(W2BEG1,W1END2)ARCVAL(W2BEG1,W6END1)16994ARCVAL(W2BEG1,S6END1)x22y16plb2216TOP.XI21.MC05NONE124500A+B+C+DAB+C+D+4ARCVAL(W2BEG1,F5)ARCVAL(W2BEG1,N6MID1)ARCVAL(W2BEG1,S2MID1)ARCVAL(W2BEG1,S6END1)16994ARCVAL(W2BEG5,S6END5)x22y16plb2216TOP.XI25.MC01NONE141600A+B+C+D+EAB+C+D+E+5ARCVAL(W2BEG5,FX5)ARCVAL(W2BEG5,N6END5)ARCVAL(W2BEG5,S6END5)ARCVAL(W2BEG5,W1END3)ARCVAL(W2BEG5,W6END5)16994ARCVAL(W2BEG5,S6END5)x22y16plb2216TOP.XI25.MC05NONE121500A+B+C+DAB+C+D+4ARCVAL(W2BEG5,F5)ARCVAL(W2BEG5,N6MID5)ARCVAL(W2BEG5,S2MID5)ARCVAL(W2BEG5,S6END5)16992ARCVAL(B4,W2END1)x20y16plb2016TOP.XI371.MC07NONE194600A+B+C+DAB+C+D+4ARCVAL(B4,F1)ARCVAL(B4,N2MID0)ARCVAL(B4,S1END0)ARCVAL(B4,W2END1)16992ARCVAL(B4,W2END1)x20y16plb2016TOP.XI371.MC02NONE184600A+B+C+D+E+F+G+HAB+C+D+E+F+G+H+8ARCVAL(B4,E2END1)ARCVAL(B4,E2MID1)ARCVAL(B4,N2END1)ARCVAL(B4,N2MID1)ARCVAL(B4,Q6)ARCVAL(B4,S2MID1)ARCVAL(B4,W2END1)ARCVAL(B4,W2MID1)16992ARCVAL(MI4,W2END5)x20y16plb2016TOP.XI331.MC09NONE102100A+B+C+DAB+C+D+4ARCVAL(MI4,GND)ARCVAL(MI4,LOCAL6)ARCVAL(MI4,N2END4)ARCVAL(MI4,W2END5)16992ARCVAL(MI4,W2END5)x20y16plb2016TOP.XI331.MC01NONE82200A+B+C+D+E+FAB+C+D+E+F+6ARCVAL(MI4,E2END5)ARCVAL(MI4,E2MID5)ARCVAL(MI4,S2END4)ARCVAL(MI4,S2MID4)ARCVAL(MI4,W2END5)ARCVAL(MI4,W2MID5)Needs to become something likeCode:Q1 34,29 IO PIN xxB4 20,16 SLICE2 LB4 BMI4 20,16 SLICE2 LB4 MI

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 13, 2022, 04:42:50 pm
content: I hit a snag againNow that I have a net list with single outputs connected to multiple inputs, I wanted to couple the IO pins into the listing. I have mapped the IO pins with the control bits before but this is only for setting the type of the IO pin, like input or output and not for the connection with the fabric. There the mapping is not straight forwardIn the PIB tiles the same naming is used as in the PLB tiles, where A, B, C, D, E, MI, CE, SR, CLK_S, CLKN_S are inputs and F, FX, Q are outputs. I did find that for an input pin the Q is used to bring it onto the fabric, but which one in which tile is which pin is the big question.For the PLB it matches mostly with the picture I have of the slices, and I don't expect much problems there. Embedded memory and DSP slices are a different story again.So it is back to the drawing board and try to find this information in the original Anlogic database or try to find it with test designs when using different pins. I understood that the latter is called "fuzzing" so maybe I have to look into that.A well, I will see how it goes

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 14, 2022, 01:26:00 pm
content: Seems I don't have to use fuzzingI found a section in the database for the AL3-10 that gives information on which tile signal name matches onto which IO pad name.Code:6 40 10ce 0 10 ce0 0 -1clk 0 10 clk_s0 0 -1di 0 10 q0 0 -1eninr_dyn 0 10 d3 0 -1icomp 0 10 f1 0 -1itrue 0 10 f0 0 -1ocomp 0 10 b3 0 -1otrue 0 10 a3 0 -1rst 0 10 sr0 0 -1ts 0 10 c3 0 -11 10ce 0 10 ce1 0 -1clk 0 10 clk_s1 0 -1di 0 10 q1 0 -1eninr_dyn 0 10 d4 0 -1icomp 0 10 f2 0 -1itrue 0 10 f3 0 -1ocomp 0 10 b4 0 -1otrue 0 10 a4 0 -1rst 0 10 sr1 0 -1ts 0 10 c4 0 -12 10ce 0 10 ce1 0 -2clk 0 10 clk_s1 0 -2di 0 10 q1 0 -2eninr_dyn 0 10 d4 0 -2icomp 0 10 f2 0 -2itrue 0 10 f3 0 -2ocomp 0 10 b4 0 -2otrue 0 10 a4 0 -2rst 0 10 sr1 0 -2ts 0 10 c4 0 -23 10ce 0 10 ce0 0 -2clk 0 10 clk_s0 0 -2di 0 10 q0 0 -2eninr_dyn 0 10 d3 0 -2icomp 0 10 f1 0 -2itrue 0 10 f0 0 -2ocomp 0 10 b3 0 -2otrue 0 10 a3 0 -2rst 0 10 sr0 0 -2ts 0 10 c3 0 -2All I have to do now is figure out how it translates from what I have to what I need. It requires a bit of tinkering because it differs for left/right to top/bottom pads and there are also io pair pads that also use a different mapping.Have to code a bit of python first to convert the found data into something I can use in my C code and then modify my C code to make use of it.The found tables also provide information about the embedded memory, dsp, pll, and what more there is in the FPGA. So again a step in the right direction.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 16, 2022, 08:09:17 am
content: For me python sucks. I tried to write some code to convert the data I found into something I can use in my project, but failed on a stupid data copying bit I don't grasp and the IDE does not tell me what is wrong so I ended up just writing it in C. As ii was for just a single job one time conversion not the most elegant code but it did the trick.The python code kept failing on the assignment "sectionnames= items". I tried to just load it with a static but every time it just bailed out without any info. Was not in the mood to research it further. My python knowledge is very little and not high upon my list to learn more about it, but if it is obvious to someone why it fails, please enlighten me.Code:items = []sectionnames = []sectionids = []def main():global itemsglobal sectionnamesglobal sectionidsinputfile = open("al3_10_connection_setup", "rt")outputfile = open("al3_10_signal_mapping.h", "wt")strinp = inputfile.readline()nofsections = int(strinp)for i in range(nofsections):strinp = inputfile.readline()items = strinp.split()sectionnames = itemssectionids = itemsstrinp = inputfile.readline()if __name__ == "__main__":main()In my C code I added a couple of if statements for breakpoints to detect if parts of the data did something unexpected and at some point it did. A counter was 2 instead of 1 so had to deal with that. Also the length of the names were bigger then expected.Code:#include <stdio.h> // standard input / output functions#include <stdlib.h>#include <string.h>void listdatasection(FILE *fin, FILE *fout, char *sectionname, int count){int datatid;int datacount;char hdl_name;char signal_name;int cnt0;int cnt1;int signalid;int xoff;int yoff;int len;char line;char *sptr;char *dptr;while(count--){fgets(line, 128, fin);sptr = line;datatid = atoi(sptr);while(*sptr++ != ' ');datacount = atoi(sptr);fprintf(fout, "//----------------------------------------------------------------------------------------------------------------------------------\n\n");fprintf(fout, "SIGNAL_NAME_MAP %s_%d[] =\n{\n", sectionname, datatid);while(datacount--){fgets(line, 128, fin);dptr = hdl_name;sptr = line;while(*sptr != ' '){*dptr++ = *sptr++;}*dptr = 0;sptr++;cnt0 = atoi(sptr);while(*sptr++ != ' ');cnt1 = atoi(sptr);if((cnt0 != 0) || ((cnt1 != 1) && (cnt1 != 2))){dptr = 0;}//This next bit needs to be done cnt1 times????//Not entirely. The multiple data is on the same line and is repeated as such indicating a signal can have entries in to tilesfgets(line, 128, fin);sptr = line;signalid = atoi(sptr);if(signalid != 0){dptr = 0;}while(*sptr++ != ' ');dptr = signal_name;while(*sptr != ' '){*dptr++ = *sptr++;}*dptr = 0;sptr++;xoff = atoi(sptr);while(*sptr++ != ' ');yoff = atoi(sptr);fprintf(fout, " { \"%s\",", hdl_name);len = 21 - strlen(hdl_name);if(len < 0){dptr = 0;}while(len--){fwrite(" ", 1, 1, fout);}fprintf(fout, "\"%s\",", signal_name);len = 13 - strlen(signal_name);if(len < 0){dptr = 0;}while(len--){fwrite(" ", 1, 1, fout);}if(xoff >= 0){fwrite(" ", 1, 1, fout);}fprintf(fout, "%d, ", xoff);if(yoff >= 0){fwrite(" ", 1, 1, fout);}fprintf(fout, "%d },\n", yoff);if(cnt1 == 2){while(*sptr++ != ' ');signalid = atoi(sptr);if(signalid != 0){dptr = 0;}while(*sptr++ != ' ');dptr = signal_name;while(*sptr != ' '){*dptr++ = *sptr++;}*dptr = 0;sptr++;xoff = atoi(sptr);while(*sptr++ != ' ');yoff = atoi(sptr);fprintf(fout, " { \"%s\",", hdl_name);len = 21 - strlen(hdl_name);if(len < 0){dptr = 0;}while(len--){fwrite(" ", 1, 1, fout);}fprintf(fout, "\"%s\",", signal_name);len = 13 - strlen(signal_name);if(len < 0){dptr = 0;}while(len--){fwrite(" ", 1, 1, fout);}if(xoff >= 0){fwrite(" ", 1, 1, fout);}fprintf(fout, "%d, ", xoff);if(yoff >= 0){fwrite(" ", 1, 1, fout);}fprintf(fout, "%d },\n", yoff);}}fprintf(fout, "};\n\n" );}}int main(int argc, char** argv){FILE *fin = fopen("al3_10_connection_setup", "r");FILE *fout = fopen("al3_10_connection_setup.h", "w");char line;int nofsections;int i,j;char *sptr;char *dptr;char sectionnames;char sectionids;int id;int count;if(fin && fout){fgets(line, 128, fin);nofsections = atoi(line);for(i=0;i<nofsections;i++){fgets(line, 128, fin);dptr = sectionnames;sptr = line;while(*sptr != ' '){*dptr++ = *sptr++;}*dptr = 0;sptr++;sectionids = atoi(sptr);}while(fgets(line, 128, fin)){//Next bit has an id number and a countsptr = line;id = atoi(sptr);while(*sptr++ != ' ');count = atoi(sptr);//Match the id to one of the section ids and use the belonging name to make an entry in the h filefor(i=0;i<nofsections;i++){if(id == sectionids){id = i;break;}}//Make a function to read the lines from the file and write them to the h filelistdatasection(fin, fout, sectionnames, count);}fprintf(fout, "//----------------------------------------------------------------------------------------------------------------------------------\n\n");fclose(fin);fclose(fout);}}It yielded information like belowCode://----------------------------------------------------------------------------------------------------------------------------------SIGNAL_NAME_MAP iol_tb_0[] ={{ "ce", "ce0", 0, 0 },{ "clk", "clk_s0", 0, 0 },{ "di", "q0", 0, 0 },{ "eninr_dyn", "d3", 0, 0 },{ "icomp", "f1", 0, 0 },{ "itrue", "f0", 0, 0 },{ "ocomp", "b3", 0, 0 },{ "otrue", "a3", 0, 0 },{ "rst", "sr0", 0, 0 },{ "ts", "c3", 0, 0 },};//----------------------------------------------------------------------------------------------------------------------------------SIGNAL_NAME_MAP iol_tb_1[] ={{ "ce", "ce1", 0, 0 },{ "clk", "clk_s1", 0, 0 },{ "di", "q1", 0, 0 },{ "eninr_dyn", "d4", 0, 0 },{ "icomp", "f2", 0, 0 },{ "itrue", "f3", 0, 0 },{ "ocomp", "b4", 0, 0 },{ "otrue", "a4", 0, 0 },{ "rst", "sr1", 0, 0 },{ "ts", "c4", 0, 0 },};//----------------------------------------------------------------------------------------------------------------------------------SIGNAL_NAME_MAP iol_tb_2[] ={{ "ce", "ce1", 1, 0 },{ "clk", "clk_s1", 1, 0 },{ "di", "q1", 1, 0 },{ "eninr_dyn", "d4", 1, 0 },{ "icomp", "f2", 1, 0 },{ "itrue", "f3", 1, 0 },{ "ocomp", "b4", 1, 0 },{ "otrue", "a4", 1, 0 },{ "rst", "sr1", 1, 0 },{ "ts", "c4", 1, 0 },};//----------------------------------------------------------------------------------------------------------------------------------SIGNAL_NAME_MAP iol_tb_3[] ={{ "ce", "ce0", 1, 0 },{ "clk", "clk_s0", 1, 0 },{ "di", "q0", 1, 0 },{ "eninr_dyn", "d3", 1, 0 },{ "icomp", "f1", 1, 0 },{ "itrue", "f0", 1, 0 },{ "ocomp", "b3", 1, 0 },{ "otrue", "a3", 1, 0 },{ "rst", "sr0", 1, 0 },{ "ts", "c3", 1, 0 },};//----------------------------------------------------------------------------------------------------------------------------------Now that I have this data I have to make an array with information per tile on which of the tables need to be searched to translate the tile signal name to the hdl signal name.

author: Kean
author_rank: Unknown
timestamp: August 17, 2022, 03:21:28 am
content: Your Python arrays are zero length, so you can't just index into them.You should probably use something like this.Code:sectionnames.append(items)sectionids.append(items)Alternatively, you could pre-fill the arrays just before the for-loop and leave the assignments as-isCode:sectionnames =  * nofsectionssectionids =  * nofsections

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 17, 2022, 01:59:50 pm
content: @Kean: Thanks, that must be it. I expected a high level language to do it for me without special "functions". Thought it was supposed to make things easyTook a bit of thinking and fiddling but now I made a reverse table setup via which it is possible to find the HDL name for a signal. Modified the code to test it for the IO pins and it seems to work on my test bitstream. The pins are correctly identified.Have to turn it in a more general function that returns a HDL name for every signal and use these names in the net list. There is still some ambiguity around embedded memory I need to look into. Because it can be regular, dual port or fifo memory. Guess there will be settings bits for it that will show the type and with that a guide to which translation table needs to be used.It all requires a lot of thinking to get from the bits back to something useful where the design data is setup for doing it the other way roundBut if it was easy everybody would be doing itStill a long way to go.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 17, 2022, 05:17:02 pm
content: I now have a net list with names that show the kind of block the signal is coming from or going to, like mslice0 or emb2 or pad1.The first item in a net is always an output and the rest are always inputs. For this gnd is also seen as an output. The hard part is now to translate this into verilog somehow.Next up is to process the other bits to figure out the configuration of the logic. Already did this for the IO pins, and I should be able to distill a .adc file from it. This is a file with the pin mapping for the Tang Dynasty IDE. Maybe also a top level verilog file to match it.The fight continues

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 20, 2022, 01:07:41 pm
content: After studying the setup bits I found out a bit more about the logic blocks. For a basic lookup table to create for instance a two input AND gate it fills the complete table (16 entries) with the needed bits. In the data, for a mslice, it looks like below.Code:LUT0_S0_12 MEMORY(SLICE0,LUT0,12)LUT0_S0_13 MEMORY(SLICE0,LUT0,13)LUT0_S0_14 MEMORY(SLICE0,LUT0,14)LUT0_S0_15 MEMORY(SLICE0,LUT0,15)This turns on the top 4 bits and the routing is done on the C and D input. The F output is where the signal comes out.For lsices it uses names like "LUTF0_S2_0" and "LUTG0_S2_0" to fill two tables with 16 entries. Combined they make up a 5 input lookup table.Also found that for the embedded memory there are settings to enable it as a FIFO, dual port or single port memory.Converting all this information into actually usable verilog will not be easy and might require a lot of manual labor. At the moment the best way forward seems to be to draw a "gate" level schematic, but instead of actual gates it will be the different blocks that can be found in a FPGA. This will take a bit of time.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 23, 2022, 02:02:35 pm
content: Still plowing on the data. There is a lot to analyze on the settings part.I'm working on making a block list that gives insight in the used parts of the FPGA.Had to fix an oversight first in the mapping of the signal names though. Had to track back to the original tile for specific types of logic to be able to properly name the signals. This is the case with, for instance, embedded memory blocks, where they spread across several tiles, but also for io blocks. The mapping of some signals in the 1013D FPGA onto the memory make more sense now. I saw ADC data bits go into address lines firstWith proper mapping it now shows data lines.Knowing the settings of the blocks makes up for how the verilog should be written. But there are a lot of different settings to consider. Still fun though.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 26, 2022, 04:51:59 pm
content: Was a bit of a struggle to match the items on the net list to the blocks, but it looks good now. Only implemented what is used in the FNIRSI 1013D FPGA, so it is not a generic tool.In the Tang Dynasty IDE there is a schematic viewer that gives a wired block diagram and this gives some idea on what the block should look like. For this I will first make a drawing tool with some table setup for the different blocks and then I will see if I can make a viewer, because an image says more then a 1000 netsThere are 891 items in the block list and 1673 in the net list.A lot of work to be done until there is a verilog file.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 03, 2022, 11:03:58 am
content: Back on the job after a couple of days of being preoccupied or to tired.Still working on making a block schematic and to make it possible had to add code to see if there are connections to the found blocks. It turns out that there are hidden clock routes, which can only be tracked through property bits instead of topology bits. SO these do not show up in the net list.How this works for the clock input pin is something I have to figure out, because how it sits now it looks like pin 23, which is the 50MHz clock input, is not connected to the logic.Furthermore the global clock spine is also something that needs to be investigated. I believe it uses the global clock multiplexers but how the connections are made requires looking at all the specific settings on these tile elements.The amount of data to process is becoming quite big, so more filtering needs to be programmed to bring out the important stuff. More on this story later. Sit back and enjoy

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 04, 2022, 12:35:28 pm
content: Decided to simplify things a bit and will just make a named block schematic instead of a wired one. I will start with just a single block per image and leave some room for adding property information like the logic table for lut's.I hope this will give a better insight then all the lists I have been making. Although very helpful, I feel is will be easier to see relations with the block schematics.At first I made the blocks with a bus based drawing and naming style (e.g. dia[8:0]), but to connect them to other signals would need a fan out, so switched to just drawing all the single pins. Attached is the set of blocks I need.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 05, 2022, 08:15:53 am
content: First block I draw the schematic for shows an embedded memory block and by the looks of it they used dual port memory to separate between the writing into and reading out of, but what I don't get is why it does not use the lower 3 address bits?Guess I have to study the properties to see if there is some mode to switch between 1, 2, 4 or 8 (9) bits mode for the memory block at hand. Would make some sense then.But at least making the block schematics does reveal things like thisHave to look into the naming of the nets and blocks to see if more information can be given there.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 07, 2022, 02:10:22 pm
content: I analyzed the embedded block memory settings and connections and I think I have the matching IP generated for it. A 32 bit wide 4096 word block of simple dual port memory.Have to connect signals to it and make a test design to see if it matches the settings I found, but the IP generator estimates it as 15 BRAM(s), which is matching what I found.It will be a lot of work to analyze the blocks and settings and make verilog based on the findings, but see this as a good study for and test of my verilog knowledge, which is still on beginners level.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 10, 2022, 10:02:53 am
content: Looked at the clock system and it is still a mystery. Did manage to get the used PLL settings. Had to manually tweak the ICP_CURRENT setting to get the setting bits to match. No idea what this does though.The PLL is set to just generate a single 200MHz clock. I now have to figure out what is connected to this clock. It is a step by step process of just creating a verilog design and compare the result with the original bit stream. This is also needed to get a better understanding of the global clock routing.I guess it should be possible to generate gate level verilog from what I have found so far, but that would still need to be translated into a more readable design anyway. So back to generating some more lists to get some insight in how the blocks are connected together.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 10, 2022, 03:14:47 pm
content: The mystery surrounding the global clock is slowly disappearing. The manual has a section on it and by looking at the specific configuration bits there is some light at the end of the tunnel.Since in this design PLL0 only outputs one clock which is routed via the left premux it is possible to trace it onto one of the 8 lines going to the center distribution hub. From there on it is still a bit of a puzzle to figure out how the connections are made based on the signal names used in the configuration bit data.It is also through the premux blocks that internally derived clocks are routed into the global clock network. I have seen two signals being routed this way, and can start to trace those too.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 11, 2022, 06:29:13 pm
content: Well I somewhat figured it out. The central global clock multiplexer has some very complicated setup for selecting which signal from the pre-multiplexers is put into the global clock spines.There are two sets of 6 bits per multiplexer to make the selection. It then depends on the active signal pair on which bits are set.Code:MC1_S_0(A)*~(B+C+D+E+F+G+H+I+J+K+L+M)13WIRE(VPSPX0)ARCVAL(VPSPX0,HTK0)ARCVAL(VPSPX0,HTK6)ARCVAL(VPSPX0,HTK12)ARCVAL(VPSPX0,HTK18)ARCVAL(VPSPX0,HTK24)ARCVAL(VPSPX0,HTK30)ARCVAL(VPSPX0,HTK0)ARCVAL(VPSPX0,HTK6)ARCVAL(VPSPX0,HTK12)ARCVAL(VPSPX0,HTK18)ARCVAL(VPSPX0,HTK24)ARCVAL(VPSPX0,HTK30)MC1_S_1A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK1)ARCVAL(VPSPX0,HTK7)ARCVAL(VPSPX0,HTK13)ARCVAL(VPSPX0,HTK19)ARCVAL(VPSPX0,HTK25)ARCVAL(VPSPX0,HTK31)ARCVAL(VPSPX0,HTK1)ARCVAL(VPSPX0,HTK7)ARCVAL(VPSPX0,HTK13)ARCVAL(VPSPX0,HTK19)ARCVAL(VPSPX0,HTK25)ARCVAL(VPSPX0,HTK31)MC1_S_2A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK2)ARCVAL(VPSPX0,HTK8)ARCVAL(VPSPX0,HTK14)ARCVAL(VPSPX0,HTK20)ARCVAL(VPSPX0,HTK26)ARCVAL(VPSPX0,HTK32)ARCVAL(VPSPX0,HTK2)ARCVAL(VPSPX0,HTK8)ARCVAL(VPSPX0,HTK14)ARCVAL(VPSPX0,HTK20)ARCVAL(VPSPX0,HTK26)ARCVAL(VPSPX0,HTK32)MC1_S_3A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK3)ARCVAL(VPSPX0,HTK9)ARCVAL(VPSPX0,HTK15)ARCVAL(VPSPX0,HTK21)ARCVAL(VPSPX0,HTK27)ARCVAL(VPSPX0,HTK33)ARCVAL(VPSPX0,HTK3)ARCVAL(VPSPX0,HTK9)ARCVAL(VPSPX0,HTK15)ARCVAL(VPSPX0,HTK21)ARCVAL(VPSPX0,HTK27)ARCVAL(VPSPX0,HTK33)MC1_S_4A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK4)ARCVAL(VPSPX0,HTK10)ARCVAL(VPSPX0,HTK16)ARCVAL(VPSPX0,HTK22)ARCVAL(VPSPX0,HTK28)ARCVAL(VPSPX0,PIBCLKB0)ARCVAL(VPSPX0,HTK4)ARCVAL(VPSPX0,HTK10)ARCVAL(VPSPX0,HTK16)ARCVAL(VPSPX0,HTK22)ARCVAL(VPSPX0,HTK28)ARCVAL(VPSPX0,PIBCLKB0)MC1_S_5A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK5)ARCVAL(VPSPX0,HTK11)ARCVAL(VPSPX0,HTK17)ARCVAL(VPSPX0,HTK23)ARCVAL(VPSPX0,HTK29)ARCVAL(VPSPX0,PIBCLKB1)ARCVAL(VPSPX0,HTK5)ARCVAL(VPSPX0,HTK11)ARCVAL(VPSPX0,HTK17)ARCVAL(VPSPX0,HTK23)ARCVAL(VPSPX0,HTK29)ARCVAL(VPSPX0,PIBCLKB1)MC1_Z_0(A)*~(B+C+D+E+F+G+H+I+J+K+L+M)13WIRE(VPSPX0)ARCVAL(VPSPX0,HTK5)ARCVAL(VPSPX0,HTK4)ARCVAL(VPSPX0,HTK3)ARCVAL(VPSPX0,HTK2)ARCVAL(VPSPX0,HTK1)ARCVAL(VPSPX0,HTK0)ARCVAL(VPSPX0,HTK5)ARCVAL(VPSPX0,HTK4)ARCVAL(VPSPX0,HTK3)ARCVAL(VPSPX0,HTK2)ARCVAL(VPSPX0,HTK1)ARCVAL(VPSPX0,HTK0)MC1_Z_1A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK11)ARCVAL(VPSPX0,HTK10)ARCVAL(VPSPX0,HTK9)ARCVAL(VPSPX0,HTK8)ARCVAL(VPSPX0,HTK7)ARCVAL(VPSPX0,HTK6)ARCVAL(VPSPX0,HTK11)ARCVAL(VPSPX0,HTK10)ARCVAL(VPSPX0,HTK9)ARCVAL(VPSPX0,HTK8)ARCVAL(VPSPX0,HTK7)ARCVAL(VPSPX0,HTK6)MC1_Z_2A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK17)ARCVAL(VPSPX0,HTK16)ARCVAL(VPSPX0,HTK15)ARCVAL(VPSPX0,HTK14)ARCVAL(VPSPX0,HTK13)ARCVAL(VPSPX0,HTK12)ARCVAL(VPSPX0,HTK17)ARCVAL(VPSPX0,HTK16)ARCVAL(VPSPX0,HTK15)ARCVAL(VPSPX0,HTK14)ARCVAL(VPSPX0,HTK13)ARCVAL(VPSPX0,HTK12)MC1_Z_3A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK23)ARCVAL(VPSPX0,HTK22)ARCVAL(VPSPX0,HTK21)ARCVAL(VPSPX0,HTK20)ARCVAL(VPSPX0,HTK19)ARCVAL(VPSPX0,HTK18)ARCVAL(VPSPX0,HTK23)ARCVAL(VPSPX0,HTK22)ARCVAL(VPSPX0,HTK21)ARCVAL(VPSPX0,HTK20)ARCVAL(VPSPX0,HTK19)ARCVAL(VPSPX0,HTK18)MC1_Z_4A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,HTK29)ARCVAL(VPSPX0,HTK28)ARCVAL(VPSPX0,HTK27)ARCVAL(VPSPX0,HTK26)ARCVAL(VPSPX0,HTK25)ARCVAL(VPSPX0,HTK24)ARCVAL(VPSPX0,HTK29)ARCVAL(VPSPX0,HTK28)ARCVAL(VPSPX0,HTK27)ARCVAL(VPSPX0,HTK26)ARCVAL(VPSPX0,HTK25)ARCVAL(VPSPX0,HTK24)MC1_Z_5A+B+C+D+E+F+G+H+I+J+K+L12ARCVAL(VPSPX0,PIBCLKB1)ARCVAL(VPSPX0,PIBCLKB0)ARCVAL(VPSPX0,HTK33)ARCVAL(VPSPX0,HTK32)ARCVAL(VPSPX0,HTK31)ARCVAL(VPSPX0,HTK30)ARCVAL(VPSPX0,PIBCLKB1)ARCVAL(VPSPX0,PIBCLKB0)ARCVAL(VPSPX0,HTK33)ARCVAL(VPSPX0,HTK32)ARCVAL(VPSPX0,HTK31)ARCVAL(VPSPX0,HTK30)The above shows the sets for the wire VPSPX0. Only one pair of ARCVAL signals can be active. A bit of a thing is that in each line the first six ARCVAL pairs are repeated in the next six. This might have to do with FPGA's with a bigger density having more global clock lines, but I'm not sure on that.I now have to write some code to do a reverse lookup from the bits set to find which HTK or PIBCLKB signal is active.Another thing I have to modify in the code I made is that the global clocks are not FPGA global, but half FPGA global. For instance GCLK_0 can be a different signal in either half. Despite the fact that the block diagram of the clock systems shows quadrants and there are four central clock multiplexers, the first set of 8 vertical lines is multiplexed by the lower central multiplexer and the next 8 vertical lines are multiplexed by the upper central multiplexer.Lots of puzzles still to be solved.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 14, 2022, 08:43:46 am
content: The next hurdle is going to take a lot of experiments. Figuring out the configuration of the logic slices. The lookup table it self is simple, but the flip flop part is the more tricky bit. Also a lslice has more functionality in the sense that it can do two 4 luts or one 5 lut, which is controlled by settings bits, but then the question is how the outputs of the luts are routed onto which output of the lslice.Another thing to figure out is how the connections of the carry bits are done. The slices have a dedicated connection bus between them, that does not show in the global topology routing through the switch boxes.For the global clocks there still is the question about what the premux default connection is. In the design I found that the top and bottom premux have signals on the input, but no setting bits for the multiplexer nor enable bits for the wires, but within the ctmux there are connections for these signals.Again the story continues.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 17, 2022, 01:37:41 pm
content: Did a fair bit of experimenting with the Tang Dynasty IDE to get more insight in the logic blocks and decided to generate gate level verilog first. The IDE can make gate level verilog for simulation and together with a file containing their own macros I'm able to match the used setting bits to the parameters of the macros.Found out that I can't do this for the pins without loosing the assignment to the actual pins, so have to use the pin constraints file and some higher level verilog to make it work.The reason for taking this path is that I can then generate a new bit stream based on the generated gate level verilog and see if it comes out the same, and when not, tweak things to get it right. Had to do this for one of the experiments I did, which showed me that the pin out gets lost, but also that some default parameters lead to unwanted bits in the configuration.The code I'm writing will not be an universal tool for reverse engineering and AL3-10 design. It is custom written to fit the bill for the FNIRSI 1013D and maybe 1014D designs. Things like DSP blocks or special pin configurations like LVDS are not handled by the code.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 18, 2022, 06:50:24 pm
content: Today I managed to generate the pin constraint file and the main module with the external signal names.The code recognizes the bits for slew rate and pull type and can determine if a pin is set for input or output when not connected to any visible routes. This is the case for the clock input pin. It connects directly to the pll, but I can't tell which bits are set to make this work.For now I will manually configure the global clock connections because I already examined what these connections are.Next up is generating code for the logic slices. I will have to test with several scenarios if the correct code is generated.I do feel things are on the right track, but still have a lot to do before proper top level verilog is obtained, because gate level verilog is not very useful, other then giving the ability to re generate the bit stream. Making modifications to the design on that level is not really doable.It does help with interpreting the setting bits though.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 19, 2022, 12:04:29 pm
content: Hmm, hit a bit of a snafuSimply translating the logic blocks in either AL_PHY_MSLICE or AL_PHY_LSLICE macro does not lead to the same bit stream when run through the IDE again. There are quite a bit of different functions a slice can have and to get the exact same bit stream the logic has to be mapped to the correct functional macro.For instance when a simple two input AND gate is intended, an AL_MAP_LUT2 is needed and the logic equation needs to be given like (B*A). This means that the lookup table has to be examined together with the used inputs to find the correct equation. Not to hard for a two input function, but more so when it is a 5 or even 6 input one.Getting the bits set in the lookup table is easy and already implemented. Now I have to write a lot of code to determine the type of macro to use for the slice or part of the slice, and then, when needed, make up the correct equation for it.A well, it is all part of the adventure I embarked on

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 23, 2022, 12:02:31 pm
content: There is still lot of work to be done, but I'm getting some output.I made a simple design in verilog to see what the different types of logic would do in the setting bits. With the IDE it is possible to make gate level verilog for simulation, which gives a good insight in to what I need to produce.The verilog used to make the bit stream.Code:module pin_test(input wire i_led_red_control,input wire i_led_blue_control,input wire i_led_yellow_control,output wire o_led_red,output wire o_led_blue,output wire o_led_green,output wire o_led_yellow);reg ireg_red_led = 0;always@(posedge i_led_red_control)beginireg_red_led <= ~(i_led_blue_control | i_led_yellow_control);endassign o_led_yellow = (~i_led_yellow_control & (i_led_red_control & i_led_blue_control)) | (i_led_yellow_control & (i_led_red_control ^ i_led_blue_control));assign o_led_red = i_led_red_control | i_led_blue_control;assign o_led_blue = i_led_red_control ^ i_led_blue_control;assign o_led_green = ireg_red_led;endmoduleThe gate level output from the IDECode:// Verilog netlist created by TD v5.0.28716// Thu Sep 22 20:04:13 2022`timescale 1ns / 1psmodule pin_test // pin_test.v(1)(i_led_blue_control,i_led_red_control,i_led_yellow_control,o_led_blue,o_led_green,o_led_red,o_led_yellow);input i_led_blue_control; // pin_test.v(4)input i_led_red_control; // pin_test.v(3)input i_led_yellow_control; // pin_test.v(5)output o_led_blue; // pin_test.v(7)output o_led_green; // pin_test.v(8)output o_led_red; // pin_test.v(6)output o_led_yellow; // pin_test.v(9)wire i_led_blue_control_pad; // pin_test.v(4)wire i_led_red_control_pad; // pin_test.v(3)wire i_led_yellow_control_pad; // pin_test.v(5)wire n1;wire o_led_blue_pad; // pin_test.v(7)wire o_led_green_pad; // pin_test.v(8)wire o_led_red_pad; // pin_test.v(6)wire o_led_yellow_pad; // pin_test.v(9)AL_PHY_PAD #(//.LOCATION("P88"),//.PCICLAMP("OFF"),//.PULLMODE("NONE"),.IOTYPE("LVCMOS33"),.MODE("IN"),.TSMUX("1"))_al_u0 (.ipad(i_led_blue_control),.di(i_led_blue_control_pad)); // pin_test.v(4)AL_PHY_PAD #(//.LOCATION("P28"),//.PCICLAMP("OFF"),//.PULLMODE("NONE"),.IOTYPE("LVCMOS33"),.MODE("IN"),.TSMUX("1"))_al_u1 (.ipad(i_led_red_control),.di(i_led_red_control_pad)); // pin_test.v(3)AL_MAP_LUT2 #(.EQN("(~B*~A)"),.INIT(4'h1))_al_u10 (.a(i_led_blue_control_pad),.b(i_led_yellow_control_pad),.o(n1));AL_PHY_PAD #(//.LOCATION("P31"),//.PCICLAMP("OFF"),//.PULLMODE("NONE"),.IOTYPE("LVCMOS33"),.MODE("IN"),.TSMUX("1"))_al_u2 (.ipad(i_led_yellow_control),.di(i_led_yellow_control_pad)); // pin_test.v(5)AL_PHY_PAD #(//.LOCATION("P49"),//.PCICLAMP("OFF"),//.PULLMODE("PULLDOWN"),//.SLEWRATE("MED"),.DRIVE("8"),.IOTYPE("LVCMOS33"),.MODE("OUT"),.TSMUX("0"))_al_u3 (.otrue(o_led_blue_pad),.opad(o_led_blue)); // pin_test.v(7)AL_PHY_PAD #(//.LOCATION("P39"),//.PCICLAMP("OFF"),//.PULLMODE("NONE"),//.SLEWRATE("SLOW"),.DRIVE("8"),.IOTYPE("LVCMOS33"),.MODE("OUT"),.TSMUX("0"))_al_u4 (.otrue(o_led_green_pad),.opad(o_led_green)); // pin_test.v(8)AL_PHY_PAD #(//.LOCATION("P112"),//.PCICLAMP("OFF"),//.PULLMODE("KEEPER"),//.SLEWRATE("FAST"),.DRIVE("8"),.IOTYPE("LVCMOS33"),.MODE("OUT"),.TSMUX("0"))_al_u5 (.otrue(o_led_red_pad),.opad(o_led_red)); // pin_test.v(6)AL_PHY_PAD #(//.LOCATION("P34"),//.PCICLAMP("OFF"),//.PULLMODE("NONE"),//.SLEWRATE("SLOW"),.DRIVE("8"),.IOTYPE("LVCMOS33"),.MODE("OUT"),.TSMUX("0"))_al_u6 (.otrue(o_led_yellow_pad),.opad(o_led_yellow)); // pin_test.v(9)AL_MAP_LUT2 #(.EQN("~(~B*~A)"),.INIT(4'he))_al_u7 (.a(i_led_blue_control_pad),.b(i_led_red_control_pad),.o(o_led_red_pad));AL_MAP_LUT2 #(.EQN("(B@A)"),.INIT(4'h6))_al_u8 (.a(i_led_blue_control_pad),.b(i_led_red_control_pad),.o(o_led_blue_pad));AL_MAP_LUT3 #(.EQN("(A*B*~(C)+A*~(B)*C+~(A)*B*C)"),.INIT(8'h68))_al_u9 (.a(i_led_blue_control_pad),.b(i_led_red_control_pad),.c(i_led_yellow_control_pad),.o(o_led_yellow_pad));AL_MAP_SEQ #(.CEMUX("1"),.CLKMUX("CLK"),.DFFMODE("FF"),.REGSET("RESET"),.SRMODE("ASYNC"),.SRMUX("0"))ireg_red_led_reg (.clk(i_led_red_control_pad),.d(n1),.q(o_led_green_pad)); // pin_test.v(14)endmoduleWhat comes back from my code so far.Code:module pin_test(output wire o_led_yellow,input wire i_led_yellow_control,input wire i_led_red_control,output wire o_led_green,output wire o_led_blue,output wire o_led_red,input wire i_led_blue_control);AL_MAP_LUT2 #(.EQN("B@A"))_al_block_18_lut_0(.a(x0y10_pin_28_di_net_3),.b(x34y16_pin_88_di_net_8),.o(x10y5_mslice1_f_0_net_6));AL_MAP_LUT2 #(.EQN("B+A"))_al_block_23_lut_0(.a(x0y10_pin_28_di_net_3),.b(x34y16_pin_88_di_net_8),.o(x15y13_mslice1_f_0_net_7));endmoduleThe pin constraint file is fully generated, so the AL_PHY_PAD macros are not needed and would give problems with the pin assignment as written before. But I do need to list the wires and output assigns to connect the internally used wires to the external wires.The target for now is to get these "simple" logic parts generated and check if it produces the same bit stream as the original.For the equations I'm using a lookup table for two inputs and for more inputs I will make combinations based on NOT, AND and OR logic.The fact that there are two LUT's and flip flops per slice makes it more complex to derive all the needed verilog marcos from the settings, but with a step by step approach I will get there. But it involves a lot of probing a black box, due to the lack of documentation. But that is something the FPGA manufactures don't want out in the world. In depth information about their products

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 25, 2022, 11:51:02 am
content: A first test showed some success. The two files generated so far (gate level verilog and pin constraint) allow me to generate a new bit stream, but for some reason the router swaps some of the logic between the two available parts in a slice.It uses the same tiles and slices, but instead of using the flip flop connected to LUT0 it uses the one connected to LUT1 to make up the register from the original code. It sets the same number of bits to on and when I run the bit stream through my code again it looks the same, except for the swap of the two LUT's and flip flop.I now have to see if this is also going to be the case with the actual FNIRSI-1013D bit stream, but before I can run that I need to implement a lot more code, and run lots of other tests.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 25, 2022, 02:10:53 pm
content: Managed to solve the LUT and flipflop swapping. Had to do with the naming of the AL_MAP_SEQ macroThe AL_MAP_LUT macros use names like _al_ and the AL_MAP_SEQ macro uses the name of the register given in the original design. This name is of course unknown, but when I name it starting with reg_ instead of _al_ it fixes the swapping problem.It was after this that I noticed another problem. The routing through the fabric was different and a better look at the generated verilog showed that signals where swapped on LUT inputs.This is caused by the way I mapped the signals onto the AL_MAP_LUT macros, which seems to be the wrong way round. I assumed that the first input starting from the fabric input "a" would be the "a" input of the macro, but the output of my code shows that it is then swapped against to what the IDE generates for the gate level simulation. This means that the highest input either "mi", "e", or "d" depending on the slice and LUT configuration is the "a" input of the AL_MAP_LUT macro.So some modification of the code is needed.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 06, 2022, 12:20:18 pm
content: After a holiday break back on the project. By the looks of it getting a gate level verilog that will yield the exact same bit stream seems to be hard to accomplish. Had to make more tweaks after implementing the LUT3 macro and was able to get the exact same output from the original verilog and the generated gate level verilog.But then after implementing the LUT4 macro it failed again. Found that it had to do with the naming of the macros and was able to get it back on track, but now after implementing the LUT5 macro it is of againSo will not try to get it to match, but will continue implementing the logic for generating the gate level verilog. Even if it does not yield the exact same bit stream it is still possible to verify the result by running the new bit stream through the reversal code and check the outcome against the first run.As long as it is just routing that changes and not the logic equations the functionality should be the same.The mapping of the inputs on the lookup tables is different to what I wrote before. For 1, 2 and 3 input LUT's it uses dedicated mappings, but for the 4 and 5 input LUT's there is a 1 to 1 relation between the signals.At least it is all taking shape and even though still a lot to do, it is leading to a satisfactory result.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 10, 2022, 10:04:22 am
content: It involves a lot of research through all the data to get to the bottom of what the different settings for the logic blocks do. Some are also hard to verify due to the fact that the IDE has a will of its own. For instance it won't create a LUT6 using one slice even when I specifically provide the LUT6 macro. It just splits it up in two or more separate LUT's spread over different slices.Another one that is hard to verify is a LUT5 made within a single mslice. The bit stream of the original 1013D FPGA seems to have these in it, and another design I have in actual verilog source of, does use it to, and it took some thinking and looking at the data to get an understanding of it. The easiest way to deal with it in my code is to create 3 LUT macros though.The two LUT4's of the mslice get the same signals on their inputs, but not always in the same order, as can be seen in the attached pictures. This is why I now create two LUT4 macros and a LUT3 macro to select between the signals of the other two based on the "mi_0" input.Then there is the fact that slice 0 of every logic tile differs from slice 1, because there are some settings bit missing for this slice. Where slice 1 seems to route the "mi" input to the flip flop input by default, slice 0 has the "f" output routed to the flip flop and only switches to the "fx" output when the FX MUX is turned on.If someone is ever going to make the open source place and route software for these devices they have a lot of stuff to figure out

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 12, 2022, 10:22:18 am
content: I think I have the MSLICE handling down. Did some random checks on what is in the generated gate level verilog and the listed settings in the block list and it looks like it is matching up.A full test by running it via the Tang Dynasty IDE is not possible due to the clock part not being done yet, and most likely a lot of signals are not connected since the rest of the logic is not yet generated. Did some tests with a simple 4 bit adder and registers to iron out the kinks though.The LSLICE has more abilities so will be a bit more work, but with the increased knowledge gathered from doing the MSLICE it should go faster.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 13, 2022, 11:12:23 am
content: The LSLICE was less work then I thought. Just implemented what is used in the 1013D bit stream, so not suitable for full reverse engineering of every bit stream out there.For the PLL I already did some exploring and have the verilog IP for it, which I will manually copy into the gate level verilog file I'm generating, so what is left is the block ram. This means looking through the settings bits to generate the proper settings for the parameters of the block ram macro, and connect all the signals to the blocks.A fair bit of coding but not to complex.And when that is done the big question is, if what I generate compiles into a bit stream that does what the original bit stream does.If so it will then need translation to more readable verilog, which will not be that simple, but will cross that bridge when I get to it

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 15, 2022, 12:14:05 pm
content: Well I managed to get output that can be compiled with the IDE, but if it is correct needs to be verified.Due to the fact that I manually did the clock signals I can't just run my reverse engineering program on the newly generated bit stream and expect it to be able to compile again. When the clock generation blocks are moved to different tiles the names I have fixed in the code will not be the correct onesBut a quick inspection showed me that the newly generated bit stream uses about 3000 bits less, and I'm not sure if this is just due to a different placement and routing.One way to test of course is to load it into the actual scope and see what it does. So fingers crossed and hope it does not blow upI will do a bit more checking of what is generated though.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 15, 2022, 01:21:43 pm
content: A quick look at the settings bits and the block connections showed me that the global clocks are not used for some reason. That certainly explains the missing 3000 settings bitsSo more testing of the gate level verilog generation is needed to see if I can solve this. No need to test the bit stream I have now in the actual scope, because without clocks it will not work.Edit: It was a case of caseI used "GCLK" in my manually assigned names and the rest used "gclk". The bit count went up with >2000, so still a bit of a difference and also the net list is longer. More work to be doneEdit2: Tried the generated bit stream on the scope but somewhat expected, it did not work. When I upload the original the scope stops working during upload and needs a reset to come back up again, but it does work. With the new bit stream it does not come back after the reset. Definitely more work to be done. But I do have some ideas based on new knowledge gained.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 16, 2022, 02:26:08 pm
content: "What a mistaka to maka"I found out today that I forgot to cater for the bidirectional pins. I'm handling input and output pins but am not making the needed connections for the bidirectional pins, and these are needed for the interface with the MCUAs another experiment I changed the code to just use the SLICE macros because these can represent all the logic made with one block and is easier then creating the LUT macros, and the resulting output did compile in the IDE, but still no dice on the scope. It was also ~2500 setting bits less then the original. So I started looking at the net list, block list and setup list again and noticed that the bidirectional pins had changed into output pins.So another change of the code is needed and hopefully it will then bring success.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 16, 2022, 03:52:25 pm
content: Aaaaaaaargh so close, but still no dice on the scope.The net list of the newly generated bit stream now has one net more then the original, and the same goes for the block list. It has one extra blockDue to different routing and placing it still has less bits set, but not sure if that can cause it to not work. Routing makes up for a fair number of the used bits. But maybe some timing constraints that are not met makes it fail?Or I made an error in the clock connections. The design uses 6 global clocks and it is still not completely clear how these clocks are connected to the global routes.Ah well, more digging to be done.

author: cedric!
author_rank: Contributor
timestamp: October 16, 2022, 06:58:23 pm
content: I have no knowledge of Anlogic FPGA's, but there are other projects  that are reverse engineering FPGA bitstreams. They have projects for Lattice iCE40, Lattice ECP5, Xilinx 7, Xilinx Ultrascale, Ultrascale+ and UltraScale MPSoC The selling point of those projects is that they have documented the process of reverse engineering. Maybe you can (ask to) create a reverse engineering project for Anlogic FPGA's?https://f4pga.org/https://github.com/F4PGA/icestormhttps://github.com/F4PGA/prjtrellishttps://github.com/F4PGA/prjxrayhttps://github.com/f4pga/prjuray

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 16, 2022, 07:16:27 pm
content: Hi cediric!, thanks for the input, but I'm aware of these kind of projects, which are targeted to reverse engineering of the process of generating a bit stream with open source place and route software.There is a project for the Anlogic FPGA's based on prjtrellis. (See my first post at the start of this topic) I have used that to get the listings of what a setting bit means and it was certainly helpful, but I still had to figure out a hell of a lot myself. The same applies to Gowin. It was actually the Gowin project that provided some needed information to be able to continue with my project.A bit of a problem with these somewhat experimental projects is that they are never finished, like only fit for a single type of the manufacturers FPGA line, or not supporting specific IP like embedded ram, etc. The same is true for what I'm doing. It is just targeted at the FNIRSI 1013D FPGA bit stream.What I'm trying to do is to reverse engineer an existing bit stream to verilog, which is a whole other ballgame. As you can read in this thread, all the data I found from the mentioned open source project for the Anlogic FPGA's is for going from verilog to a bit stream and not the other way round.I'm actually quite close to a working result now.

author: cedric!
author_rank: Contributor
timestamp: October 16, 2022, 07:20:35 pm
content: Quote from: pcprogrammer on October 16, 2022, 07:16:27 pmSorry, I missed that.

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 16, 2022, 07:45:17 pm
content: Does that imply that Anlogic FPGAs have an architecture very close to that of Lattice ones?Isn't that more or less the case for Gowin FPGAs too?

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 17, 2022, 05:15:43 am
content: I'm not familiar with the Lattice devices, but if they are similar to the Gowin devices then probably yes.The work done on the Gowin devices by Pepijn de Vos (https://github.com/YosysHQ/apicula) showed me how the routing through the chip is done. If the rest of the setup is the same I don't know yet.But the principles for reverse engineering a bit stream back to verilog will be the same. Get to know the meaning of the bits, derive a net list from them, create a list with the logic settings, like if a slice is an adder or an embedded memory block is a fifo and turn that into gate level verilog.The step of turning it into usable verilog is one I still have to take. The gate level stuff is ok to figure out bits about the working of the design, but not usable for making changes.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 17, 2022, 08:47:22 am
content: I have tried playing with the settings of the IDE and the two possible modes of doing tri state on the MCU interface pins, but for some reason it just fails to do what I want.I tried loading all the generated bit streams to the scope.Code:assign io_mcu_d_0 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x11y20_lslice3_q_0_net_365;assign io_mcu_d_1 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x11y18_lslice3_q_0_net_357;assign io_mcu_d_2 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x13y18_lslice2_q_0_net_551;assign io_mcu_d_3 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x11y15_lslice3_q_0_net_344;assign io_mcu_d_4 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x13y19_mslice1_q_0_net_557;assign io_mcu_d_5 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x11y18_mslice1_q_0_net_358;assign io_mcu_d_6 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x11y20_mslice1_q_0_net_362;assign io_mcu_d_7 = x12y23_lslice3_f_0_net_481 ? 1'bZ : x12y16_mslice1_q_0_net_438;With the above the scope stays black on the screen after a reset.With the below the scope comes back to live after a reset, but is then frozen. This might well be due to the fact that bit 0 is used to detect if the FPGA is finished with acquisitionCode:assign io_mcu_d_0 = x12y23_lslice3_f_0_net_481 ? x11y20_lslice3_q_0_net_365 : 1'bZ;assign io_mcu_d_1 = x12y23_lslice3_f_0_net_481 ? x11y18_lslice3_q_0_net_357 : 1'bZ;assign io_mcu_d_2 = x12y23_lslice3_f_0_net_481 ? x13y18_lslice2_q_0_net_551 : 1'bZ;assign io_mcu_d_3 = x12y23_lslice3_f_0_net_481 ? x11y15_lslice3_q_0_net_344 : 1'bZ;assign io_mcu_d_4 = x12y23_lslice3_f_0_net_481 ? x13y19_mslice1_q_0_net_557 : 1'bZ;assign io_mcu_d_5 = x12y23_lslice3_f_0_net_481 ? x11y18_mslice1_q_0_net_358 : 1'bZ;assign io_mcu_d_6 = x12y23_lslice3_f_0_net_481 ? x11y20_mslice1_q_0_net_362 : 1'bZ;assign io_mcu_d_7 = x12y23_lslice3_f_0_net_481 ? x12y16_mslice1_q_0_net_438 : 1'bZ;Research on the latter shows that the IDE just removes the select signal on io_mcu_d_0 and io_mcu_d_7, but connects it for the remaining 6 signals. The question is of course why the IDE does this.All the testing I did shows that it is possible to generate gate level code that compiles into the exact same bit stream, but it has to adhere to some weird rules that don't apply all the time. Like the naming of the macros mattered in getting it right, but then failed again in a next experiment.But I gained a lot of knowledge about it all, and I need to take another step to get it done. Work it back to some proper verilog. This means analyzing the generated gate level verilog in some way. One idea I started with earlier needs a revisit. Making a tree list of the blocks by tracing io signals. Since I know the external connections it is possible to identify different sections of the code based on this idea, and use it to write up the needed proper verilog.Already identified the PLL and embedded memory parts and have the IP for it.It would have been nice if the gate level code resulted in a working bit stream, because that would have proofed the premise.And so the story continues

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 19, 2022, 09:17:08 am
content: For some reason the IDE just does not handle the gate level code that well.I have tried a bit more things, but it constantly refuses to connect a couple of the enable pins on the tri state data bus. For the latest version it was d1 and d6. Showed the same result on the scope. It sits just frozen on a normal scope screen.Therefore I moved on to do a manual conversion to the top level verilog. It is a bit like going back from assembler to C, but more difficult since it is a lot of parallel "code" to interpret.I searched the net a bit, but did not find anything useful for it.Guess it is good exercise in getting more knowledge of verilog. Maybe gain some insights in how it could be automated.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 21, 2022, 12:10:55 pm
content: Not that it made any difference, but I stumbled on some "Chinese" logicFor 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 thisCode:MC1_DI0_S1NONEA1PROPERTY(SLICE1.REG0_SD,F)MC1_DI0_S2NONEA1PROPERTY(SLICE2.REG0_SD,F)MC1_DI0_S3NONEA1PROPERTY(SLICE3.REG0_SD,F)MC1_DI1_S1NONEA1PROPERTY(SLICE1.REG1_SD,F)MC1_DI1_S2NONEA1PROPERTY(SLICE2.REG1_SD,F)MC1_DI1_S3NONEA1PROPERTY(SLICE3.REG1_SD,F)MC1_FX0_S1NONEA1PROPERTY(SLICE1.REG0_SD,FX)MC1_FX0_S2NONEA1PROPERTY(SLICE2.REG0_SD,FX)MC1_FX0_S3NONEA1PROPERTY(SLICE3.REG0_SD,FX)MC1_FX1_S1NONEA1PROPERTY(SLICE1.REG1_SD,FX)MC1_FX1_S2NONEA1PROPERTY(SLICE2.REG1_SD,FX)MC1_FX1_S3NONEA1PROPERTY(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 nameCode:TOP.XI390.NET104NONEA1PROPERTY(SLICE0.REG0_SD,F)TOP.XI390.NET97NONEA1PROPERTY(SLICE0.REG1_SD,F)TOP.XI389.NET104NONEA1PROPERTY(SLICE0.REG0_SD,FX)TOP.XI389.NET97NONEA1PROPERTY(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

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 24, 2022, 11:16:38 am
content: 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.htmlWith just a simple design like below:Code: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)beginireg_red_led <= i_led_blue_control;endassign 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;endmoduleThe 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 lineSo 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://---------------------------------------------------------------------------//Block 61, MSLICE 1assign 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 1assign 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)beginif(net_50 == 1'b1)beginif(net_261 == 1'b1)beginnet_52 <= 1'b0;net_49 <= 1'b0;endelsebeginnet_52 <= net_201;net_49 <= net_187;endendend

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 24, 2022, 04:02:28 pm
content: 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 26, 2022, 03:43:29 pm
content: 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:module test(wire [3:0] a_input,wire [3:0] b_input,wire [4:0] o_output);assign o_output = a_input - b_input;endmoduleyields what is shown below. (left out the module bit)Code://---------------------------------------------------------------------------//Adder blocks 53, 54, 55wire 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

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 28, 2022, 01:51:39 pm
content: 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 likeCode:wire [11:0] sample_address;instead ofCode: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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 29, 2022, 01:37:17 pm
content: 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 30, 2022, 10:26:17 am
content: A small victoryI 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 30, 2022, 12:18:08 pm
content: 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.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.But it is that damned curiosity of me that keeps nagging

author: pcprogrammer
author_rank: Super Contributor
timestamp: October 31, 2022, 02:15:08 pm
content: 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://---------------------------------------------------------------------------//Block 289, MSLICE 1assign cmd37_enable = (net_170 * (net_745 * net_197));assign net_467 = (net_170 * (net_452 * net_197));always @(posedge i_mcu_clk)beginif(cmd37_enable == 1'b1)beginac_dc_2 <= io_mcu_d_0;endendHere 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 MCUCode://---------------------------------------------------------------------------//Block 832, LSLICE 3assign 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)beginnet_1643 <= sig_832_lut_0;endIt 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 02, 2022, 12:50:48 pm
content: 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,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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 03, 2022, 12:58:23 pm
content: 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 commands13, 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: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: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

author: Kean
author_rank: Unknown
timestamp: November 03, 2022, 02:20:42 pm
content: @pcprogrammer I must say your persistence (& skill) is impressive

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 03, 2022, 04:49:29 pm
content: Quote from: Kean on November 03, 2022, 02:20:42 pmThanks 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: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_187net_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: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 }};

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 04, 2022, 09:30:55 am
content: 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 interfaceI 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

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 04, 2022, 05:06:29 pm
content: 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 thereAlso 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 05, 2022, 05:56:53 pm
content: 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 06, 2022, 12:35:31 pm
content: 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 06, 2022, 01:51:04 pm
content: For some reason the simulator can't determine the state of the internal mcu databus outputI 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

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 06, 2022, 05:35:26 pm
content: So much to learnThe 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 07, 2022, 02:45:47 pm
content: 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

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 08, 2022, 05:11:37 pm
content: 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 funBut I'm learning quite a bit from this.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 09, 2022, 09:44:34 am
content: 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.But not there yet. Still have to find the error in my analyzing code.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 09, 2022, 10:15:31 am
content: Wow, that was disappointingThe 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 09, 2022, 08:28:48 pm
content: 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 10, 2022, 09:44:04 am
content: First part of the mission is accomplishedThis 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.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 10, 2022, 12:37:35 pm
content: Having it working in the simulator makes the naming job easierI added all the enable signals I found in the code to the waveform display and sorted them on their place in time. Saved the list and formatted it into my renaming table et voila another 56 nets done.A lot easier then tracing them in the code and figuring out which state they belong to. Naming the belonging bits that are stored on these enables is now just looking through the code and pick the nets that are loaded on these enables.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 12, 2022, 09:12:04 am
content: Hmmm, I found something weird. While simulating the sampling part of the design I found that the clock signals for the ADC's are 50MHz instead of 100MHz when the highest sample rate is selected. So to verify this I got my big scope on the bench and started measuring the signals both for the original and the reverse engineered version.It turns out that the sampling clocks are indeed to slow compared to the original, while the 1KHz probe calibration signal is ~1KHz for both versions. So I must have missed something in the clock setup.But the big question is what.It can't be the PLL setting, because doubling it would mean a 2KHz output on the probe calibration signal.One more puzzle to be solved

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 12, 2022, 10:46:38 am
content: I gave the gate level verilog a try to see what the frequency of the sampling clock is then, and it comes out as 100MHz, but the sampling it self appears to be not working.This means that my translation to higher level verilog is not correct where it comes to this bit of the design. Why the sampling fails for the gate level verilog is yet another question. Might well be that the interpretation of the embedded memory block macro settings is wrong.More simulation of what I have now is needed to provide some insight in the sampling setup, to allow me to translate it to better readable code. I already started with some simple bits like the main clock divider and the 1KHz probe calibration signal. The latter I tweaked to be actually for 1KHz. The original is of by a count of one 50MHz cycle.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 12, 2022, 12:51:54 pm
content: The problem with the frequency has been found. It turns out that I did not pay attention to a carry in on add or subtract chains. For the dividing of the ADC clock the carry output of a subtract is used. The inputs are the set divider value and subtracted from that is the output of a counter. It is here that there is an input carry that needs to be subtracted too.It now simulates the 100MHz for setting 0 and 50MHz for setting 1, etc.Getting the sampling bit working in the simulator is not going that well unfortunately. I need to work on my test bench skills for this or something in the verilog to simulate the memory is not set up right. I can see the setup do its work, where the sampling is reset, and then started, leading to buffers being filled, but when I try to read the data it is not showing any output.In the test bench I have to make some setup with modules if possible to make sending commands and reading data more clear and robust. Have to do some reading up on the subjectStill in the learning phase of the art of simulation

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 13, 2022, 01:36:34 pm
content: Decided not to be bothered to much by the simulation not showing output and started converting the code to more readable and concise code.Started with a simple parameterizable counter module to be used in the clock division parts. Based the 50MHz and 1KHz clock on it and that tested fine. Reduced the sizes of the counters to what is needed. So slight deviation from the original.Did the code for the command loading and the multiple byte writing and reading. Started with just a few write commands like the sampling rate divider and the channel DC offset setting. Also improved on the test bench with tasks to simply write a command or the different sizes of data. Makes the test bench more clear.Now I have to run some tests in the simulator to check if the correct bytes are set and then implement the PWM parts for the channel DC offsets. Step by step I'm going to write the code for all the bits found in the original, and test each bit along the way.When it all checks out I will run it on the scope to see if it works as intended.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 14, 2022, 02:38:26 pm
content: More and more parts are added to the better readable verilog design.Just did the sample write clock which is variable and can be changed with command 0x0D. Tested it in the simulator and is works just like the original.Here is the code with a test bench I made so far. It is an attempt to recreate it like the original code with just minor improvements. I believe there can be improved on a lot of the original design, but that is not the goal.A funny thing that I found is that the scope firmware writes to a couple of commands at startup, but these commands are not implemented in the FPGAAnother thing I found is that I did not understood the meaning of command 0x3C when reverse engineering the firmware. I thought it did something with the battery level, but it turns out that what is written to the FPGA with command 0x3C is read with command 0x41. In the original firmware the data from command 0x41 is used as an address to read from the touch panel. Some weird and unnecessary stuff they did in this scope.Next up is the trickier part of dissecting the sampling and trigger code together with the read back of the samples.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 14, 2022, 07:42:03 pm
content: Found an oversightwhile testing the sampling system reset functionality based around command 0x01 and 0x05. Forgot to filter the writing of the registers on data and write state, so on every MCU clock signal the last selected register was written leading to unexpected results.Forgot the same in the read part, where it should only be on data and read state.Easily fixed by adding a "if" statement in the related always blocks.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 16, 2022, 11:02:39 am
content: Getting to the bottom of the sampling bit is a lot of searching through the generated code and determining which signal is used for what.I did figure out what the data set with the command 0x0E does. It makes up a delay before the system decides the sampling is done. This is only used in auto trigger mode. When no trigger is found the sampling runs until it has done the set amount of samples.For instance for the highest sample clock (100MHz) the setting is 411100, and this means that as long as no trigger is seen it takes 411100 samples before it signals the MCU it can read the samples from memory. And this is where it is a bit weird, it only has memory for 4096 samplesSo to speed up the process it can be reduced without real consequences. But for the lowest sample rates the original firmware used 800, and this explains why it only read 750 samples for that setting, because it stops after 800 samples in auto mode.Still have to figure out how the trigger part is done. It uses the samples from memory, which means a mixing of the write and the read clock is done. For the logic in rising and falling edge together with the set trigger level I have to go through a bunch of still unnamed nets.But the end is nearing

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 17, 2022, 10:27:56 am
content: The way the trigger system is implemented is definitely not how I would have done it. Still working through the signals and converting it all to more readable code and it ain't simple.After the sampling system reset has been lifted by the MCU the sampling starts, and 1600 samples are taken, then it starts the trigger process, where it starts reading the samples from address 800, and as soon as it finds a trigger point in the data it stops the write process and this is signaled by the MCU with command 0x0A.When no trigger is found it just keeps on writing until the time base timeout signal is set. This is after the number of samples, set with command 0x0E, have been taken. In this case it would be possible to read 8K of samples per channel from the buffer (4K for each of the two ADC's for each of the channels) In the case of a trigger this is limited to 1600 plus the number of samples it took to find the trigger.When the trigger is found the address in memory where the trigger has been found is captured and can be read with the MCU by command 0x14. This provides some insight in what is done in the software to determine the starting point for reading the data.How the trigger is found, I still have to investigate further. I believe it keeps a previously read sample and then compares it with the next, but the implementation is not to clear, so needs simulation to find the logic.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 17, 2022, 12:01:26 pm
content: Here is what I see in the simulation for the input signal, what it reads back for finding the trigger and the previous data is uses for it too.The trigger is found under the yellow cursor line. The weird spikes are caused by the registering of the top two address bits, which select the data from the different memory blocks. The other deformations are probably caused by the signals used to determine the trigger. After sampling stops writing the counters keep running, and the checking keeps on going too.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 18, 2022, 12:25:25 pm
content: Getting the trigger signals right is a bit of a pain in the bum.By the looks of it I have the rising edge part working as intended, but the falling edge is wrong. As written before the way it is done is not how I would do it, and that makes it more difficult to grasp the logic behind it.It involves quite a bit of signals that are combined together making up detects and enables for the rising and the falling edge, and with the aid of simulation I was able to determine that it uses "less then or equal to" against the set level for both the current and the previous sample, and based on the trigger edge setting it uses one of the signals to decide on being triggered.So a bit more investigating is needed to find why the falling edge is not working as expected.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 18, 2022, 02:52:40 pm
content: Not exactly like the original but in simulation it looks like it works for both the rising and the falling edge.Next up is the part to read the samples with the MCU, and then run a test on the actual scope.Not sure if I'm going to tackle the I2C part in the making it more readable. The journey was to see if it was possible to reverse engineer a FPGA and that has been confirmed.

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 18, 2022, 06:46:00 pm
content: Bit of a downerI finished of the translation and compiled it with the Tang Dynasty IDE. Had to fix a small issue with loading a register from two sources, but that was easy to solve. Without the I2C part in it the number of used bits is about 55% of the originalBut dammit it did not work on the scope.Tried using timing constraints and it failed to reach the 200MHz timingThe crude reverse engineered code did though, so a bit of a mystery as to why this one fails.Will play a bit more with the simulator to see if it reacts as expected and if so try to improve the code a bit.I did find another missing thing. The software writes to command 0x28 to select between sampling via memory or direct reading the samples, but there is nothing in the FPGA for supporting command 0x28

author: pcprogrammer
author_rank: Super Contributor
timestamp: November 19, 2022, 12:08:06 pm
content: Decided it is time to move on to other projects.The more readable version I distilled from the crude version compiles with timing problems and does not work on the scope, but in simulation the response seems to be correct. Since it is a crap design I don't feel the urge to continue on it.With the crude version of the design, generated with the tool I wrote for it, it is proven that it is possible to get a somewhat working design from a given bit stream. Renamed most of the nets, and the ones left are for reading the data with the MCU and for the I2C part of the design.Granted it is not perfect, and there are still issues when compiling it back into a bit stream due to compiler version, timing constraints and differences in place and route.Conclusion is that it requires a lot of patience, skill and persistence to get a thing like this done. It was fun and I learned a lot from it about the working of FPGA's and simulation.I uploaded the latest results to the repositoryhttps://github.com/pecostm32/Anlogic_AL3-10_Analyzing

author: tv84
author_rank: Super Contributor
timestamp: December 11, 2022, 11:39:30 am
content: Quote from: pcprogrammer on November 19, 2022, 12:08:06 pmFirst of all:my deepest RESPECT for what you accomplished here.It's mind-blowing the level of knowlege, wit and resilience you showed! Doing all this quest alone is quite a feat.I had surfed your MCU software investigations but I had never seen this FPGA reversing thread, until today. Just to be able to follow your descriptions requires a unique ammount of knowledge (that I unfortunately only have a small part) but, nonetheless, provides a perfect sense of a reverse process goes along and how a reverser's mind work.Love the iteration, bug catching, optimization, head banging, adaptation, accomplishment satisfaction, return to start...Very well done. This is pure reversing and looks amazing in one's curriculum!I hope to see (one day) you finish the work with the official HYPER-CRAP design and tools... (I know, from experience, that such an endeaveour is never finished, in one's mind, if we don't proper close it...)

author: pcprogrammer
author_rank: Super Contributor
timestamp: December 11, 2022, 03:32:32 pm
content: Thanks tv84,It was quite the quest indeed.To finish it it would mean a lot of trial and error to find the right version of the IDE, the proper optimization settings and maybe even the order in how the verilog is written. Not sure if my curiosity is big enough for it.Since you just now spotted this, you probably also missed the grandeur joke I made about it in the FNIRSI thread.Quote from: pcprogrammer on November 10, 2022, 09:27:20 amIt is the curse of the curious mind though, that I persisted and might dive into a new reversal adventure with the Hantek DSO2D15 FPGA. A bit more of a challenge and a lot harder due to almost no knowledge of the workings of it. But first some other projects like modernizing a FischerTechnik 27MHz remote control set.

author: Atlan
author_rank: Frequent Contributor
timestamp: January 23, 2025, 09:20:31 am
content: How did the project actually end?Are there 2 firmware versions for the fpga?The result is a file for flash spi or some other file that is uploaded to the fpga via jtag and a special anlogic programmer?Is it programmed directly from the TD environment? Is the fpga blocked from reading al3 or EF2.It is possible to load the fpga res. Flash spi firmware to make a backup of the original firmware (Al3 or EF2)Thank you

author: Atlan
author_rank: Frequent Contributor
timestamp: January 23, 2025, 11:27:52 am
content: Apparently the pins between AL3 and EF2 do not fit, so there are also changes in the wiring on the board if EF2 is used. Another thing is that EF2 has few cells"Design is emb num =15, exceeds the limit 12"So let's try AL3 first.

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 23, 2025, 12:48:51 pm
content: Hi Atlan,It ended with a somewhat reverse engineered FPGA. In simulation it is possible to see the working of the logic and get an understanding of how and what has been done, but I did not succeed in getting a fully functional version synthesized due to timing constraints not being met.I did not finish the "I2C" part of the design, but it is not to complex and not needed for the open source firmware, because the "special IC" is not used.Another part that is still a bit dark is the clock routing and I made some assumptions to what is what in the clocking part.There is the Altera Cyclone version used in the first release of the scope, but the working is the same, so basically the same design will be used, although not easy to verify since for the Altera FPGA's there is not much information about the meaning of the bits in the bit stream, so reverse engineering that one is a lot harder to do.The output generated by the TD IDE needs to be converted to binary to be loaded into the FLASH, but this can be done with the IDE. It is also possible to just load a configuration to the SRAM for testing, and when satisfied with the result it can be written to the FLASH with the IDE.The AL3 does not have protection features for as far as I know, but the EF2 is a different story. The FLASH is internal in that one and a read back can only be done via JTAG. You need the dedicated JTAG interface for it.I assume that the basic design is the same for the EF2. It does have less logic blocks, but the original design in the AL3 is rather small, so should easily fit in the EF2.I have no experience with the EF2 though, so no idea what the possibilities are with it.For the AL3 the FLASH has been read of course, and with new design it could even be done from the MCU, since the FLASH is connected to usable IO pins. For the EF2 you need the JTAG interface to try to read it back.The EF2 has different types of embedded memory if I recall correctly. In the AL3 design only the 9K blocks are used and that might not be possible in the EF2, so the design will use the 32K or even more K blocks for the sampling memory.Yep might be best to start with the AL3.

author: Atlan
author_rank: Frequent Contributor
timestamp: January 23, 2025, 03:45:51 pm
content: The output generated by the TD IDE needs to be converted to binary to be loaded into the FLASH, but this can be done with the IDE. It is also possible to just load a configuration to the SRAM for testing, and when satisfied with the result it can be written to the FLASH with the IDE.How is it possible to get the file for the ch341a programmer fpga-1013D-1-zb25vq80.bin from the file Original_1013D.bitDo I need a special programmer for this? I can order a basic programmer from China for Anlogic, but I want to avoid that at this stage.

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 23, 2025, 03:59:49 pm
content: You know you can use the quote button to highlight what I wrote.Quote from: Atlan on January 23, 2025, 03:45:51 pmUse the "Create Flash File" option on the Download window in the Tang Dynasty IDE. This opens another window where you can add bit files and set starting address in the FLASH. For a single file just start at 0x00000000. It will create a bin file you can write to FLASH with a ch341 programmer.Quote from: Atlan on January 23, 2025, 03:45:51 pmFor loading via JTAG you can convert a bluepill (STM32F103) board. You need some additional hardware. See:https://github.com/pecostm32/Lichee_Nano/tree/main/Hardware/Anlogic_JTAG_Programmer

author: Atlan
author_rank: Frequent Contributor
timestamp: January 23, 2025, 04:18:42 pm
content: not work

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 23, 2025, 04:20:46 pm
content: Target file is the binary output file. Use the add file button to add a .bit fileForget that. I have to try for myself. It has been long ago that I played with it.The "Create Flash File" functionality is to add additional data to an existing file. Try to find the TD user guide in English. It is to big to add to my post.To make a binary file from the source files you have to set the "bin" option to on in the properties configuration window and then rerun the synthesis.Menu option Process->Properties.See the attached image. For me the "bin" option is off.

author: Atlan
author_rank: Frequent Contributor
timestamp: January 24, 2025, 08:25:08 am
content: upload this bin. and scope is deathSince it won't boot, I can't reprogram the flash. I'll have to unsolder it. Will I avoid such problems if I use jtag?The relay clicks, but the backlight doesn't turn on, and neither does the oscilloscope.

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 24, 2025, 09:28:35 am
content: Yes, with the JTAG option, just loading to the FPGA SRAM the FLASH remains in tact and is it easy to test things.But you can still write to the FPGA FLASH with a CH341 programmer, no need to de-solder. Just wait for the FPGA to be finished and don't connect the programmers 3.3V to the target. Have the FLASH powered by the scope. That is what I did in the beginning before making the JTAG connections.The MCU most likely gets stuck on trying to identify the FPGA configuration on being valid.

author: Atlan
author_rank: Frequent Contributor
timestamp: January 24, 2025, 10:01:52 am
content: So I did it, turned on the oscilloscope, it went into FEL mode, and then it started programming the flash. But I guess something was compiled incorrectly. It's working now.Will the bluepill programmer work under WINdows?Isn't this a problem?TMR-5009 WARNING: No clock constraint on 4 clock net(s):clk_50MHzi_mcu_clk_pado_adc1_encB_padsample_read_clock

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 24, 2025, 10:29:49 am
content: Quote from: Atlan on January 24, 2025, 10:01:52 amI don't see a reason why it would not work, but I only do this kind of stuff on Linux. If the TD IDE works under Windows, I assume they provide for the programmer to work under Windows too.Unfortunately the source code for the programmer is no longer available, at least I could not find it. Just the binary to load into the STM32F103.Quote from: Atlan on January 24, 2025, 10:01:52 amNot necessarily. Without a clock constraint on it the routing can add delays that may cause it to not work, but my knowledge of setting these constraints fell short. If I remember correctly I tried all kinds of constraint settings on these signals and have it fail with errors.For me it is also a learning experience, to do these kind of projects.

author: Atlan
author_rank: Frequent Contributor
timestamp: January 24, 2025, 12:01:59 pm
content: I downloaded the flash content on my oscilloscope: it's the same as yours.I made a code correction, for AD converter timing.I've only read 3 scripts from college so far, so I don't have the knowledge yet. I'm attaching a BIN that can be loaded into SPI flash for FPGA, of course the part for I2C is missing so it only works with PECO firmware.The waveform looks good (at least for channel 1)What doesn't work is the trigger for rising or falling edge or the trigger level is wrong. To be precise, the trigger for falling edge doesn't work for rising edge and it's even swapped between them.You please could try it on your oscilloscope, fnirsi_1013d.bin v0.026b thank youadc1 means converter for channel 1 yellow, and the given converter has 2 parts encA and encB?

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 24, 2025, 01:19:17 pm
content: Quote from: Atlan on January 24, 2025, 12:01:59 pmIf you want me to take a look at it please provide me with the verilog files so I can synthesize things myself and load them directly in via JTAG. Is easier for me.Quote from: Atlan on January 24, 2025, 12:01:59 pmYes adc1 is for channel 1 and it uses two actual converters that are clocked with encA and encB. These clocks have a 180 degree phase shift between them.

author: Atlan
author_rank: Frequent Contributor
timestamp: January 24, 2025, 01:23:24 pm
content: ok, sending ALL

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 24, 2025, 05:33:37 pm
content: Hi Atlan,I looked at what you changed and the reduction of the clock divider widths should not make a difference in the working and only reduce the number of logic cells used.The other change, where you invert the adc1_encA and adc2_encA signals should also not make a difference to what the original code did.Keep in mind that in HDL actions are taken in parallel in this case. So with the code as it was the two encA registers are set to what the encB registers were before the clock pulse and the encB registers are inverted on the clock pulse. In simulation it works as intended.With your setup it inverts all four of the signals instead of copying. Internally it most likely is just a difference in the routing.I have not tested it on the scope as it will do just the same as what I tested 2 years ago.Also be aware that the original design is as crap as can be. There can be clock domain crossing and meta stability issues with it. If your intent is to improve things, my advice is to start over and make your own design.Some useful threads might be:https://www.eevblog.com/forum/fpga/beginner-questions/msg4646935/#msg4646935https://www.eevblog.com/forum/fpga/what-is-a-beter-write-enable/msg4074163/#msg4074163https://www.eevblog.com/forum/fpga/why-does-this-dds-code-fail/msg4066636/#msg4066636BrianHG is very good and helped me quite a bit.Or take a look at the projects on fpga4fun:https://www.fpga4fun.com/digitalscope.html

author: Atlan
author_rank: Frequent Contributor
timestamp: January 26, 2025, 05:30:44 pm
content: any reason why this doesn't work with FIFORAMCode:sample_memory samples(.di ({ i_adc2B_d, i_adc2A_d, i_adc1B_d, i_adc1A_d }),//.wrusedw (actual_write_address),.clkw (sample_write_clock),.we (sample_write_enable),.rst (sample_system_reset),.do ({ o_adc2B_d, o_adc2A_d, o_adc1B_d, o_adc1A_d }),//.addrb (sample_read_address),.clkr (sample_read_clock),.re (sample_read_enable)//.ceb (1'b1));

author: pcprogrammer
author_rank: Super Contributor
timestamp: January 26, 2025, 07:41:52 pm
content: Quote from: Atlan on January 26, 2025, 05:30:44 pmI have no idea. But a FIFO is not what you would need to make it work. A circular buffer is what is a far better approach, were the samples are continuously stored and when the trigger is seen, a count down starts to limit the number of samples after the trigger. Record the trigger point for read back by the MCU.The trigger part should always run at the maximum sample rate. For the writing in the circular buffer the sampling clock is lowered. This means you throw away a lot of samples, but the trigger is much more accurate.To get a better help on FPGA matters you best start a new thread with the specific questions about your problems with the design. There are others on the forum with much more knowledge on FPGA than I have.

author: Atlan
author_rank: Frequent Contributor
timestamp: January 26, 2025, 11:03:41 pm
content: I would use FIFoRAM to get a lot of sample memory. For periodic signals it doesn't matter, just take 800 samples and activate the trigger search. If found, the value at which the FIFO is located is written as the trigger address. The chance that the trigger will be found within 100 samples is very high. With the possibility of 32000 samples. The question is the duration of loading 32000 samples into the uP. But that could also be handled in the FPGA, since we know the trigger address.

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 12, 2025, 07:44:38 pm
content: If one is in need of a new license for the Anlogic IDE, I have attached the latest from the Anlogic site here. It is good until January 2026