From 16453de8b1a97c093992bed43366c0acfcac5997 Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 28 Jan 2022 17:35:15 +0800
Subject: [PATCH] initial support for GW1N-9C (#77)

* initial support for GW1N-9C

Its bitstream structure seems to be the same with GW1N-9, according to
openFPGALoader code.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

* examples: add blinky for Tang Nano 9K

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

* ci: add chipdb build for GW1N-9C

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

* Update chipdb.yml

Co-authored-by: Pepijn de Vos <pepijndevos@gmail.com>
---
 .github/workflows/chipdb.yml | 25 ++++++++++++++++++++++++-
 Makefile                     |  2 +-
 apycula/bslib.py             |  2 ++
 apycula/chipdb.py            | 15 ++++++++++++++-
 apycula/codegen.py           |  2 +-
 apycula/tiled_fuzzer.py      |  6 ++++++
 examples/Makefile            | 14 +++++++++++++-
 examples/tangnano9k.cst      | 11 +++++++++++
 8 files changed, 72 insertions(+), 5 deletions(-)
 create mode 100644 examples/tangnano9k.cst

diff --git a/.github/workflows/chipdb.yml b/.github/workflows/chipdb.yml
index 00afaba8..193b86b7 100644
--- a/.github/workflows/chipdb.yml
+++ b/.github/workflows/chipdb.yml
@@ -47,6 +47,24 @@ jobs:
       with:
           name: gw1n-9-stage
           path: GW1N-9*
+  gw1n9c:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - name: Build gw1n-9c chipdb
+      run: |
+        docker pull pepijndevos/apicula:1.9.8
+        docker run -v $(pwd):/usr/src/apicula pepijndevos/apicula:1.9.8 make apycula/GW1N-9C.pickle
+    - name: Archive artifact
+      uses: actions/upload-artifact@v2
+      with:
+          name: gw1n-9c-chipdb
+          path: apycula/GW1N-9C.pickle
+    - name: Archive stage artifact
+      uses: actions/upload-artifact@v2
+      with:
+          name: gw1n-9c-stage
+          path: GW1N-9C*
   gw1n4:
     runs-on: ubuntu-latest
     steps:
@@ -103,7 +121,7 @@ jobs:
           path: GW1NS-4*
   pypi:
     runs-on: ubuntu-latest
-    needs: [gw1n1, gw1n9, gw1n4, gw1ns2, gw1ns4]
+    needs: [gw1n1, gw1n9, gw1n9c, gw1n4, gw1ns2, gw1ns4]
     steps:
     - uses: actions/checkout@v2
     - name: Download gw1n-1 chipdb
@@ -121,6 +139,11 @@ jobs:
       with:
         name: gw1n-9-chipdb
         path: apycula
+    - name: Download gw1n-9c chipdb
+      uses: actions/download-artifact@v2
+      with:
+        name: gw1n-9c-chipdb
+        path: apycula
     - name: Download gw1ns-2 chipdb
       uses: actions/download-artifact@v2
       with:
diff --git a/Makefile b/Makefile
index 6d570988..36edec70 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ endif
 .SECONDARY:
 .PHONY: all clean
 all: apycula/GW1N-1.pickle apycula/GW1N-9.pickle apycula/GW1N-4.pickle \
-	 apycula/GW1NS-2.pickle apycula/GW1NS-4.pickle
+	 apycula/GW1NS-2.pickle apycula/GW1NS-4.pickle apycula/GW1N-9C.pickle
 
 %.json: apycula/dat19_h4x.py
 	python3 -m apycula.dat19_h4x $*
diff --git a/apycula/bslib.py b/apycula/bslib.py
index bb7925db..cb1660c0 100644
--- a/apycula/bslib.py
+++ b/apycula/bslib.py
@@ -45,6 +45,8 @@ def read_bitstream(fname):
                 if not preamble and ba[0] == 0x06: # device ID
                     if ba == b'\x06\x00\x00\x00\x11\x00\x58\x1b':
                         padding = 4
+                    elif ba == b'\x06\x00\x00\x00\x11\x00H\x1b':
+                        padding = 4
                     elif ba == b'\x06\x00\x00\x00\x09\x00\x28\x1b':
                         padding = 0
                     elif ba == b'\x06\x00\x00\x00\x01\x008\x1b':
diff --git a/apycula/chipdb.py b/apycula/chipdb.py
index e2b69736..69cc9380 100644
--- a/apycula/chipdb.py
+++ b/apycula/chipdb.py
@@ -238,7 +238,7 @@ def from_fse(fse):
     return dev
 
 def get_pins(device):
-    if device not in {"GW1N-1", "GW1N-4", "GW1N-9", "GW1NR-9", "GW1NS-2", "GW1NS-2C", "GW1NS-4", "GW1NSR-4C"}:
+    if device not in {"GW1N-1", "GW1N-4", "GW1N-9", "GW1NR-9", "GW1N-9C", "GW1NR-9C", "GW1NS-2", "GW1NS-2C", "GW1NS-4", "GW1NSR-4C"}:
         raise Exception(f"unsupported device {device}")
     pkgs = pindef.all_packages(device)
     res = {}
@@ -289,6 +289,19 @@ def json_pinout(device):
             "GW1N-9": pins,
             "GW1NR-9": pins_r
         }, res_bank_pins)
+    elif device == "GW1N-9C":
+        pkgs, pins, bank_pins = get_pins("GW1N-9C")
+        pkgs_r, pins_r, bank_pins_r = get_pins("GW1NR-9C")
+        res = {}
+        res.update(pkgs)
+        res.update(pkgs_r)
+        res_bank_pins = {}
+        res_bank_pins.update(bank_pins)
+        res_bank_pins.update(bank_pins_r)
+        return (res, {
+            "GW1N-9C": pins,
+            "GW1NR-9C": pins_r
+        }, res_bank_pins)
     elif device == "GW1NS-2":
         pkgs, pins, bank_pins = get_pins("GW1NS-2")
         pkgs_c, pins_c, bank_pins_c = get_pins("GW1NS-2C")
diff --git a/apycula/codegen.py b/apycula/codegen.py
index d7943974..27f055f4 100644
--- a/apycula/codegen.py
+++ b/apycula/codegen.py
@@ -133,7 +133,7 @@ def write(self, f):
             """
 
         device_desc = self.partnumber
-        if self.device in ['GW1N-9', 'GW1N-4']:
+        if self.device in ['GW1N-9', 'GW1N-4', 'GW1N-9C']:
             device_desc = f'-name {self.device} {device_desc}'
 
         f.write(template.format(
diff --git a/apycula/tiled_fuzzer.py b/apycula/tiled_fuzzer.py
index 1cd32564..e523be6e 100644
--- a/apycula/tiled_fuzzer.py
+++ b/apycula/tiled_fuzzer.py
@@ -89,6 +89,12 @@ def recode_idx_gw1n4(idx):
         "partnumber": "GW1N-LV9PG256C6/I5",
         "recode_idx": recode_idx_gw1n9,
     },
+    "GW1N-9C": {
+        "package": "UBGA332",
+        "device": "GW1N-9C-UBGA332-6",
+        "partnumber": "GW1N-LV9UG332C6/I5",
+        "recode_idx": recode_idx_gw1n9, # TODO: recheck
+    },
     "GW1N-4": {
         "package": "PBGA256",
         "device": "GW1N-4-PBGA256-6",
diff --git a/examples/Makefile b/examples/Makefile
index ec819271..f9815bb8 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -4,7 +4,7 @@ NEXTPNR ?= nextpnr-gowin
 all: attosoc-tec0117.fs nanolcd-tangnano.fs blinky-tec0117.fs blinky-runber.fs \
 	blinky-tangnano.fs blinky-honeycomb.fs shift-tec0117.fs shift-runber.fs \
 	shift-tangnano.fs shift-honeycomb.fs iob-tangnano.fs iob-default-flags-tangnano.fs \
-	tonegen-tec0117.fs
+	tonegen-tec0117.fs blinky-tangnano9k.fs
 
 unpacked: attosoc-tec0117-unpacked.v nanolcd-tangnano-unpacked.v blinky-tec0117-unpacked.v blinky-runber-unpacked.v \
 	blinky-tangnano-unpacked.v blinky-honeycomb-unpacked.v shift-tec0117-unpacked.v shift-runber-unpacked.v \
@@ -44,6 +44,12 @@ clean:
 %-tangnano4k.json: %-tangnano4k-synth.json tangnano4k.cst
 	$(NEXTPNR) --json $< --write $@ --device GW1NSR-LV4CQN48PC7/I6 --cst tangnano4k.cst
 
+%-tangnano9k.fs: %-tangnano9k.json
+	gowin_pack -d GW1N-9C -o $@ $^
+
+%-tangnano9k.json: %-tangnano9k-synth.json tangnano9k.cst
+	$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1N-9C --cst tangnano9k.cst
+
 %-honeycomb.fs: %-honeycomb.json
 	gowin_pack -d GW1NS-2 -o $@ $<
 
@@ -71,6 +77,9 @@ nanolcd-tangnano-synth.json: nanolcd/TOP.v nanolcd/VGAMod.v
 %-tangnano4k-synth.json: %.v
 	$(YOSYS) -D LEDS_NR=8 -p "read_verilog $^; synth_gowin -json $@"
 
+%-tangnano9k-synth.json: %.v
+	$(YOSYS) -D LEDS_NR=6 -p "read_verilog $^; synth_gowin -json $@"
+
 %-honeycomb-synth.json: %.v
 	$(YOSYS) -D LEDS_NR=3 -p "read_verilog $^; synth_gowin -json $@"
 
@@ -95,6 +104,9 @@ nanolcd-tangnano-synth.json: nanolcd/TOP.v nanolcd/VGAMod.v
 %-tangnano4k-unpacked.v: %-tangnano4k.fs
 	gowin_unpack -d GW1NS-4 -o $@ $^
 
+%-tangnano9k-unpacked.v: %-tangnano9k.fs
+	gowin_unpack -d GW1N-9C -o $@ $^
+
 %-runber-unpacked.v: %-runber.fs
 	gowin_unpack -d GW1N-4 -o $@ $^
 
diff --git a/examples/tangnano9k.cst b/examples/tangnano9k.cst
new file mode 100644
index 00000000..b10c8943
--- /dev/null
+++ b/examples/tangnano9k.cst
@@ -0,0 +1,11 @@
+//Part Number: GW1NR-LV9QN88PC6/I5
+
+IO_LOC "clk" 52;
+IO_LOC "led[0]" 10;
+IO_LOC "led[1]" 11;
+IO_LOC "led[2]" 13;
+IO_LOC "led[3]" 14;
+IO_LOC "led[4]" 15;
+IO_LOC "led[5]" 16;
+IO_LOC "key" 3;
+IO_LOC "rst" 4;