final gds & drc results
diff --git a/Makefile.master b/Makefile.master
index f6b5af4..baf8c26 100644
--- a/Makefile.master
+++ b/Makefile.master
@@ -47,8 +47,8 @@
 STD_CELL_LIBRARY ?= sky130_fd_sc_hd
 SPECIAL_VOLTAGE_LIBRARY ?= sky130_fd_sc_hvl
 IO_LIBRARY ?= sky130_fd_io
-SKYWATER_COMMIT ?= 3d7617a1acb92ea883539bcf22a632d6361a5de4
-OPEN_PDKS_COMMIT ?= 49fc7125db927de199d1f69e002beadc0a29881b
+SKYWATER_COMMIT ?= f6f76f3dc99526c6fc2cfede19b5b1227d4ebde7
+OPEN_PDKS_COMMIT ?= 95c92cc563e00b3ee3ed9863b352304943e8ff8f
 
 .DEFAULT_GOAL := ship
 # We need portable GDS_FILE pointers...
@@ -58,6 +58,7 @@
 	@echo "Generating Caravel GDS (sources are in the 'gds' directory)"
 	@sleep 1
 	@echo "\
+		random seed `scripts/set_user_id.py -report`; \
 		gds readonly true; \
 		gds rescale false; \
 		gds read ../gds/user_project_wrapper.gds; \
@@ -70,8 +71,6 @@
 	@mv -f ./gds/caravel.gds ./gds/caravel.old.gds
 	mv ./mag/caravel.gds ./gds
 
-
-
 .PHONY: clean
 clean:
 	cd ./verilog/dv/caravel/mgmt_soc/ && \
@@ -129,13 +128,39 @@
 	@echo "All files are uncompressed!"
 
 
+# verify that the wrapper was respected
+xor-wrapper:
+	# first erase the user's user_project_wrapper.gds
+	sh utils/erase_box.sh gds/user_project_wrapper.gds 0 0 2920 3520
+	# do the same for the empty wrapper
+	sh utils/erase_box.sh gds/user_project_wrapper_empty.gds 0 0 2920 3520
+	mkdir -p signoff/user_project_wrapper_xor
+	# XOR the two resulting layouts
+	sh utils/xor.sh \
+		gds/user_project_wrapper_empty_erased.gds gds/user_project_wrapper_erased.gds \
+		user_project_wrapper user_project_wrapper.xor.xml
+	sh utils/xor.sh \
+		gds/user_project_wrapper_empty_erased.gds gds/user_project_wrapper_erased.gds \
+		user_project_wrapper gds/user_project_wrapper.xor.gds > signoff/user_project_wrapper_xor/xor.log
+	rm gds/user_project_wrapper_empty_erased.gds gds/user_project_wrapper_erased.gds
+	mv gds/user_project_wrapper.xor.gds gds/user_project_wrapper.xor.xml signoff/user_project_wrapper_xor
+	python utils/parse_klayout_xor_log.py \
+		-l signoff/user_project_wrapper_xor/xor.log \
+		-o signoff/user_project_wrapper_xor/total.txt
+	# screenshot the result for convenience
+	sh utils/scrotLayout.sh \
+		$(PDK_ROOT)/sky130A/libs.tech/klayout/sky130A.lyt \
+		signoff/user_project_wrapper_xor/user_project_wrapper.xor.gds
+
 # LVS
 BLOCKS = $(shell cd openlane && find * -maxdepth 0 -type d)
 LVS_BLOCKS = $(foreach block, $(BLOCKS), lvs-$(block))
 $(LVS_BLOCKS): lvs-% : ./mag/%.mag ./verilog/gl/%.v
 	echo "Extracting $*"
 	mkdir -p ./mag/tmp
-	echo "load $* -dereference;\
+	echo "addpath hexdigits;\
+		addpath \$$PDKPATH/libs.ref/sky130_ml_xx_hd/mag;\
+		load $* -dereference;\
 		select top cell;\
 		foreach cell [cellname list children] {\
 			load \$$cell -dereference;\
@@ -151,7 +176,9 @@
 		ext2spice $*.ext;\
 		feedback save extract_$*.log;\
 		exit;" > ./mag/extract_$*.tcl
-	cd mag && export MAGTYPE=maglef; magic -rcfile ${PDK_ROOT}/sky130A/libs.tech/magic/current/sky130A.magicrc -noc -dnull extract_$*.tcl < /dev/null
+	cd mag && \
+		export MAGTYPE=maglef; \
+		magic -rcfile ${PDK_ROOT}/sky130A/libs.tech/magic/current/sky130A.magicrc -noc -dnull extract_$*.tcl < /dev/null
 	mv ./mag/$*.spice ./spi/lvs
 	rm ./mag/*.ext
 	mv -f ./mag/extract_$*.{tcl,log} ./mag/tmp
@@ -264,11 +291,13 @@
 		rm -rf $(PDK_ROOT)/sky130A) || \
 		true
 	cd $(PDK_ROOT)/open_pdks && \
-		./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \
+		./configure --enable-alpha-lib --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \
 		cd sky130 && \
+		sed -i 's/REPO_PATH = ~\/gits/REPO_PATH = \$$\(PDK_ROOT\)\/open_pdks\/libs/g' Makefile && \
 		$(MAKE) veryclean && \
 		$(MAKE) && \
-		$(MAKE) install-local
+		$(MAKE) install-local && \
+		$(MAKE) clean
 
 .RECIPE: manifest
 manifest: mag/ maglef/ verilog/rtl/ scripts/ Makefile
@@ -277,7 +306,7 @@
 	find maglef/*.mag -type f ! -name "user_project_wrapper.mag" -exec shasum {} \; >> manifest && \
 	shasum mag/caravel.mag mag/.magicrc >> manifest
 	shasum scripts/set_user_id.py scripts/generate_fill.py scripts/compositor.py >> manifest
-
+	shasum lef/user_project_wrapper_empty.lef >> manifest
 
 check-env:
 ifndef PDK_ROOT
diff --git a/signoff/user_project_wrapper_xor/total.txt b/signoff/user_project_wrapper_xor/total.txt
new file mode 100644
index 0000000..05b29a4
--- /dev/null
+++ b/signoff/user_project_wrapper_xor/total.txt
@@ -0,0 +1 @@
+Total XOR differences = 0
\ No newline at end of file
diff --git a/signoff/user_project_wrapper_xor/user_project_wrapper.xor.gds b/signoff/user_project_wrapper_xor/user_project_wrapper.xor.gds
new file mode 100644
index 0000000..42a5912
--- /dev/null
+++ b/signoff/user_project_wrapper_xor/user_project_wrapper.xor.gds
Binary files differ
diff --git a/signoff/user_project_wrapper_xor/user_project_wrapper.xor.gds.png b/signoff/user_project_wrapper_xor/user_project_wrapper.xor.gds.png
new file mode 100644
index 0000000..7e6cc85
--- /dev/null
+++ b/signoff/user_project_wrapper_xor/user_project_wrapper.xor.gds.png
Binary files differ
diff --git a/signoff/user_project_wrapper_xor/user_project_wrapper.xor.xml b/signoff/user_project_wrapper_xor/user_project_wrapper.xor.xml
new file mode 100644
index 0000000..2d3f47a
--- /dev/null
+++ b/signoff/user_project_wrapper_xor/user_project_wrapper.xor.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<report-database>
+ <description>XOR gds/user_project_wrapper_empty_erased.gds vs. gds/user_project_wrapper_erased.gds</description>
+ <original-file/>
+ <generator>drc: script='utils/xor.drc'</generator>
+ <top-cell>user_project_wrapper</top-cell>
+ <tags>
+ </tags>
+ <categories>
+  <category>
+   <name>235/4</name>
+   <description>XOR results for layer 235/4 </description>
+   <categories>
+   </categories>
+  </category>
+  <category>
+   <name>69/20</name>
+   <description>XOR results for layer 69/20 </description>
+   <categories>
+   </categories>
+  </category>
+  <category>
+   <name>70/20</name>
+   <description>XOR results for layer 70/20 </description>
+   <categories>
+   </categories>
+  </category>
+  <category>
+   <name>71/20</name>
+   <description>XOR results for layer 71/20 </description>
+   <categories>
+   </categories>
+  </category>
+  <category>
+   <name>71/44</name>
+   <description>XOR results for layer 71/44 </description>
+   <categories>
+   </categories>
+  </category>
+  <category>
+   <name>72/20</name>
+   <description>XOR results for layer 72/20 </description>
+   <categories>
+   </categories>
+  </category>
+  <category>
+   <name>81/14</name>
+   <description>XOR results for layer 81/14 </description>
+   <categories>
+   </categories>
+  </category>
+ </categories>
+ <cells>
+  <cell>
+   <name>user_project_wrapper</name>
+   <variant/>
+   <references>
+   </references>
+  </cell>
+ </cells>
+ <items>
+ </items>
+</report-database>
diff --git a/signoff/user_project_wrapper_xor/xor.log b/signoff/user_project_wrapper_xor/xor.log
new file mode 100644
index 0000000..53d8736
--- /dev/null
+++ b/signoff/user_project_wrapper_xor/xor.log
@@ -0,0 +1,78 @@
+First Layout: gds/user_project_wrapper_empty_erased.gds
+Second Layout: gds/user_project_wrapper_erased.gds
+Design Name: user_project_wrapper
+Output GDS will be: gds/user_project_wrapper.xor.gds
+Reading gds/user_project_wrapper_empty_erased.gds ..
+Reading gds/user_project_wrapper_erased.gds ..
+--- Running XOR for 235/4 ---
+"_input" in: xor.drc:38
+Elapsed: 0.010s
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"^" in: xor.drc:38
+Elapsed: 0.010s
+XOR differences: 0
+"_output" in: xor.drc:41
+Elapsed: 0.000s
+--- Running XOR for 69/20 ---
+"_input" in: xor.drc:38
+Elapsed: 0.010s
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"^" in: xor.drc:38
+Elapsed: 0.010s
+XOR differences: 0
+"_output" in: xor.drc:41
+Elapsed: 0.000s
+--- Running XOR for 70/20 ---
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"_input" in: xor.drc:38
+Elapsed: 0.010s
+"^" in: xor.drc:38
+Elapsed: 0.000s
+XOR differences: 0
+"_output" in: xor.drc:41
+Elapsed: 0.010s
+--- Running XOR for 71/20 ---
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"^" in: xor.drc:38
+Elapsed: 0.010s
+XOR differences: 0
+"_output" in: xor.drc:41
+Elapsed: 0.000s
+--- Running XOR for 71/44 ---
+"_input" in: xor.drc:38
+Elapsed: 0.010s
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"^" in: xor.drc:38
+Elapsed: 0.010s
+XOR differences: 0
+"_output" in: xor.drc:41
+Elapsed: 0.000s
+--- Running XOR for 72/20 ---
+"_input" in: xor.drc:38
+Elapsed: 0.010s
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"^" in: xor.drc:38
+Elapsed: 0.010s
+XOR differences: 0
+"_output" in: xor.drc:41
+Elapsed: 0.000s
+--- Running XOR for 81/14 ---
+"_input" in: xor.drc:38
+Elapsed: 0.010s
+"_input" in: xor.drc:38
+Elapsed: 0.000s
+"^" in: xor.drc:38
+Elapsed: 0.010s
+XOR differences: 0
+"_output" in: xor.drc:41
+Elapsed: 0.000s
+Writing layout file: gds/user_project_wrapper.xor.gds ..
+Total run time: 0.140s
diff --git a/utils/erase_box.sh b/utils/erase_box.sh
new file mode 100644
index 0000000..41ceb65
--- /dev/null
+++ b/utils/erase_box.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+: ${1?"Usage: $0 file.gds llx lly urx ury"}
+: ${2?"Usage: $0 file.gds llx lly urx ury"}
+: ${3?"Usage: $0 file.gds llx lly urx ury"}
+: ${4?"Usage: $0 file.gds llx lly urx ury"}
+: ${5?"Usage: $0 file.gds llx lly urx ury"}
+: ${PDK_ROOT?"You need to export PDK_ROOT"}
+
+
+export PDK=sky130A
+
+export MAGIC_MAGICRC=$PDK_ROOT/$PDK/libs.tech/magic/$PDK.magicrc
+
+MAGTYPE=mag magic -rcfile $MAGIC_MAGICRC -dnull -noconsole  <<EOF
+echo $MAGTYPE
+tech unlock *
+gds read $1
+box $2um $3um $4um $5um
+erase
+select area
+delete
+#### REVISE THIS:
+select top cell
+erase labels
+####
+gds write ${1%.*}_erased.gds
+EOF
+ls ${1%.*}_erased.gds
diff --git a/utils/parse_klayout_xor_log.py b/utils/parse_klayout_xor_log.py
new file mode 100644
index 0000000..842b484
--- /dev/null
+++ b/utils/parse_klayout_xor_log.py
@@ -0,0 +1,42 @@
+# Copyright 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import re
+
+parser = argparse.ArgumentParser(
+    description='extracts the total xor differnces from an xor log')
+
+parser.add_argument('--log_file', '-l',required=True,
+                    help='log file')
+
+parser.add_argument('--output', '-o', required=True,
+                    help='output file to store results')
+
+args = parser.parse_args()
+log_file_name = args.log_file
+out_file_name = args.output
+
+string = "XOR differences:"
+pattern = re.compile(r'\s*%s\s*([\d+]+)' % string)
+tot_cnt = 0
+with open(log_file_name, "r") as f:
+    for line in f:
+        m = pattern.match(line)
+        if m:
+            tot_cnt += int(m.group(1))
+
+outFileOpener = open(out_file_name, "w")
+outFileOpener.write("Total XOR differences = "+ str(tot_cnt))
+outFileOpener.close()
diff --git a/utils/scrotLayout.py b/utils/scrotLayout.py
new file mode 100644
index 0000000..5469d19
--- /dev/null
+++ b/utils/scrotLayout.py
@@ -0,0 +1,58 @@
+# Copyright 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pya
+import re
+import os
+
+WIDTH = 2048
+HEIGHT = 2048
+
+app = pya.Application.instance()
+win = app.main_window()
+
+# Load technology file
+print('[INFO] Reading tech file: ' + str(tech_file))
+tech = pya.Technology()
+tech.load(tech_file)
+
+layoutOptions = tech.load_layout_options
+
+# Load def file in the main window
+print('[INFO] Reading Layout file: ' + str(input_layout))
+cell_view = win.load_layout(input_layout, layoutOptions, 0)
+layout_view = cell_view.view()
+
+layout_view.load_layer_props(os.path.splitext(tech_file)[0]+'.lyp')
+
+layout_view.max_hier()
+# layout_view.clear_layers()
+
+# Hide layers with these purposes
+hidden_purposes = [0, 4, 5]
+
+li = layout_view.begin_layers()
+while not li.at_end():
+    lp = li.current()
+    if lp.source_datatype in hidden_purposes:
+        new_lp = lp.dup()
+        new_lp.visible = False
+        layout_view.set_layer_properties(li, new_lp)
+
+    li.next()
+
+print("[INFO] Writing out PNG screenshot '{0}'".format(input_layout+".png"))
+layout_view.save_image(input_layout+".png", WIDTH, HEIGHT)
+print("Done")
+app.exit(0)
diff --git a/utils/scrotLayout.sh b/utils/scrotLayout.sh
new file mode 100644
index 0000000..d833783
--- /dev/null
+++ b/utils/scrotLayout.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Copyright 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+: ${1?"Usage: $0 tech_file input"}
+: ${2?"Usage: $0 tech_file input"}
+
+echo "Using Techfile: $1"
+echo "Using layout file: $2"
+
+# The -a here is necessary to handle race conditions.
+# This limits the max number of possible jobs to 100.
+xvfb-run -a klayout -z \
+    -rd input_layout=$2 \
+    -rd tech_file=$1 \
+    -rm $(dirname $0)/scrotLayout.py
+
+exit 0
diff --git a/utils/xor.drc b/utils/xor.drc
new file mode 100644
index 0000000..6caee91
--- /dev/null
+++ b/utils/xor.drc
@@ -0,0 +1,42 @@
+# A general XOR script
+# (https://www.klayout.de/forum/discussion/100/xor-vs-diff-tool)
+# This script uses KLayout's DRC language to implement a generic
+# XOR between two layouts. The name of the layouts is given
+# in $a and $b.
+
+# For layout-to-layout XOR with multiple cores, run this script with
+#   ./klayout -r xor.drc -rd thr=NUM_CORES -rd top_cell=TOP_CELL_NAME -rd a=a.gds -rd b=b.gds -rd ol=xor.gds -zz
+# (replace NUM_CORES by the desired number of cores to utilize
+
+# enable timing output
+verbose
+
+# set up input a
+a = source($a, $top_cell)
+
+# set up input b
+b = source($b, $top_cell)
+
+$o && $ext != "gds" && report("XOR #{$a} vs. #{$b}", $o)
+$ol && $ext == "gds" && target($ol, $co || "XOR")
+
+$thr && threads($thr) || threads(2)
+
+# collect all common layers
+layers = {}
+[ a.layout, b.layout ].each do |ly|
+  ly.layer_indices.each do |li|
+    i = ly.get_info(li)
+    layers[i.to_s] = i
+  end
+end
+
+# perform the XOR's
+layers.keys.sort.each do |l|
+  i = layers[l]
+  info("--- Running XOR for #{l} ---")
+  x = a.input(l) ^ b.input(l)
+  info("XOR differences: #{x.data.size}")
+  $o && $ext != "gds" && x.output(l, "XOR results for layer #{l} #{i.name}")
+  $ol && $ext == "gds" && x.output(i.layer, i.datatype, i.name)
+end
diff --git a/utils/xor.sh b/utils/xor.sh
new file mode 100644
index 0000000..3ea5176
--- /dev/null
+++ b/utils/xor.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Copyright 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+: ${1?"Usage: $0 file1.gds file2.gds <top_level_module_name> output.gds|markers.xml"}
+: ${2?"Usage: $0 file1.gds file2.gds <top_level_module_name> output.gds|markers.xml"}
+: ${3?"Usage: $0 file1.gds file2.gds <top_level_module_name> output.gds|markers.xml"}
+: ${4?"Usage: $0 file1.gds file2.gds <top_level_module_name> output.gds|markers.xml"}
+
+
+echo "First Layout: $1"
+echo "Second Layout: $2"
+echo "Design Name: $3"
+echo "Output GDS will be: $4"
+
+xvfb-run -a klayout -r $(dirname $0)/xor.drc \
+    -rd top_cell=$3 \
+    -rd a=$1 \
+    -rd b=$2 \
+    -rd thr=$(nproc) \
+    -rd ol=$4 \
+    -rd o=$4 \
+    -rd ext=${4##*.} \
+    -zz