YosysHQ / apicula

Project Apicula 🐝: bitstream documentation for Gowin FPGAs
MIT License
462 stars 66 forks source link

GW1NR-9 vs GW1N-9 bit-stream #206

Open chili-chips-ba opened 10 months ago

chili-chips-ba commented 10 months ago

The only difference between these two devices is in the package add-ons. FPGA die is the same for both. While N package includes only FPGA die, the NR is a SIP with SDRAM, PSRAM, or double PSRAM packaging options along with FPGA die.

Since those are essentially "external components", by supporting the N, Apicula is also supporting the NR. So far, all is nice and dandy.

But, the problem is that current Apicula doesn't allow specifying NR for --family. Without it, the NR bit-stream is built with N ID. When we then try to download Apicula-generated bit-stream using Gowin programmer, it complains about incorrect target. It does not seem it would take much to allow building the NR bitstream with the proper NR ID, thus opening the path for mixing and matching Apicula with Gowin proprietary tools.

NR-vs-N

yrabbit commented 10 months ago

What quickly came to my mind without having to duplicate databases with and without R or store multiple ids in the database (which would require adding multiple IDE runs to get different ids at the fuzzing stage) was to add the --device-id parameter to gowin_pack. This parameter will need to be specified very precisely and accurately, as expected by the vendor bootloader. The solution is not brilliant and any other patches are welcome, especially in light of the fact that I do not have the opportunity to run vendor things that work directly with hardware.

chili-chips-ba commented 10 months ago

The new --device-id option would indeed be a lightweight approach for developers, yet a flexible one for users.

However, we must note that your current classification is misaligned with Gowin's (https://www.gowinsemi.com/en/product/detail/46), hence confusing. It'd be more straightforward if you allowed specifying --family GW1NR-9C.

Such family could be virtual, essentially an alias to GW1N-9C in everything by the --device-id.

In that way, if the (ordinary) user does not explicitly specify the device-id, you can internally look it up based on --family and --device.

Should the (power) user specify device-id, you take it as-is, without trying to derive from the other passed options.

gowin-littlebee
jeremyherbert commented 9 months ago

I wrote this small script:

import json
import os
import subprocess
from collections import defaultdict

def build_family_aliases():
    db_hashes = defaultdict(list)

    md5_exec = subprocess.run("md5sum /usr/src/gowin/IDE/share/device/*/*.fse",
                              shell=True, check=True, capture_output=True,
                              encoding='utf-8')

    for line in md5_exec.stdout.splitlines():
        computed_hash, path = line.split("  ")
        family = os.path.split(path)[-1].replace(".fse", "")
        db_hashes[computed_hash].append(family)

    family_aliases = {}
    for computed_hash, families in db_hashes.items():
        # arbitrarily use the shortest family as the "true" family
        families.sort(key=lambda x: (len(x), x))
        family_aliases[families[0]] = families

    return family_aliases

if __name__ == "__main__":
    family_aliases = build_family_aliases()
    with open("family_alias.json", "w") as f:
        f.write(json.dumps(dict(family_aliases)))

and it outputs (when run in the docker container used in the CI):

{"GW1N-1": ["GW1N-1", "GW1NR-1"], "GW1N-2": ["GW1N-2", "GW1N-2B", "GW1NR-2", "GW1N-1P5", "GW1NR-2B", "GW1NZR-2", "GW1N-1P5B"], "GW1N-1S": ["GW1N-1S"], "GW1N-4": ["GW1N-4", "GW1N-4B", "GW1N-4D", "GW1NR-4", "GW1NR-4B", "GW1NR-4D", "GW1NRF-4B"], "GW1N-9": ["GW1N-9", "GW1NR-9"], "GW1N-9C": ["GW1N-9C", "GW1NR-9C"], "GW1NS-2": ["GW1NS-2", "GW1NS-2C", "GW1NSR-2", "GW1NSE-2C", "GW1NSR-2C"], "GW1NS-4": ["GW1NS-4", "GW1NS-4C", "GW1NSR-4", "GW1NSR-4C", "GW1NSER-4C"], "GW1NZ-1": ["GW1NZ-1", "GW1NZ-1C"], "GW2A-18": ["GW2A-18", "GW2AR-18"], "GW2A-18C": ["GW2A-18C", "GW2AR-18C", "GW2ANR-18C"], "GW2A-55": ["GW2A-55", "GW2A-55C", "GW2AN-55C"], "GW2AN-4X": ["GW2AN-4X", "GW2AN-9X", "GW2AN-18X"]}

So this should allow mapping any family back to the "true" family for nextpnr. However, I'm not quite sure where the bitstream ID gets set yet.

Also, it appears that nextpnr itself might need to have some changes, as it has some bits hardcoded: https://github.com/YosysHQ/nextpnr/blob/5bfe0dd1b137e43d8ed85485552e126a6b7ee978/gowin/main.cc#L80

yrabbit commented 9 months ago

I can assume that since the image is formed in gowun_pack, then from there you can start searching, which may end in some fuzzer, where the vendor IDE is launched to obtain a “clean” image.

chili-chips-ba commented 9 months ago

Would @bl0x be the right developer to pull in for this?

jeremyherbert commented 9 months ago

(I will PR once I get this working, just adding the info here as a work log)

An updated script to also extract IDCODEs for families is below, I also inverted the dictionary format which is written to the JSON file: https://gist.github.com/jeremyherbert/d8863a6893f54f000af78024c8c7e0db

I just need to work on the bitstream IDCODE override now.

jeremyherbert commented 9 months ago

Also just for a bit of fun, the IDCODEs in this document have some which are wrong: https://cdn.gowinsemi.com.cn/TN653E.pdf ;)

chili-chips-ba commented 9 months ago

Which ones are incorrect? How about bringing it to Gowin's attention? Have you followed up with them?

jeremyherbert commented 9 months ago

Well at least GW1NR-9 and 9C are swapped relative to what the IDE has in the programmer file, as confirmed by reading the IDCODE with JTAG/openFPGAloader out of a tang 9k. After I saw that just took the whole table as untrustworthy and moved on. Have a look in the gist at the IDCODEs and see how they are different for those two parts.

I don’t have any contacts at Gowin and I assume like most other semiconductor companies they don’t care about anyone not buying high volume. So I haven’t contacted them, but feel free to do so if you have a contact point.

jeremyherbert commented 9 months ago

@chili-chips-ba I know it's a lot to build, but you should be able to get this working now - please give it a go if you have time. I tested on both the tang nano 20k and tang nano 9k and they both worked fine with openFPGALoader (which rejects the flash if the IDCODE is wrong).

chili-chips-ba commented 9 months ago

Thank you! @Juninho99 from our team shall provide feedback. We have also contacted support@gowinsemi.com about the issue you found in their documentation. They are looking into it.

chili-chips commented 8 months ago

Gowin tech support has responded to our enquiry. Here is what they said:

This link is for an old out-of-date UG290 programming document, TN653-1.07E (https://cdn.gowinsemi.com.cn/TN653E.pdf). The latest UG290-2.7.3E is correct. The English version can be found here https://www.gowinsemi.com/en/support/database/?support_search=UG290 https://www.gowinsemi.com/upload/database_doc/1779/document/658e82dfb3d4e.pdf

image