Merge branch 'develop' of github.com:efabless/caravel into develop

Merging recent work.
diff --git a/mag/.magicrc b/mag/.magicrc
index 0573be5..e785ae2 100644
--- a/mag/.magicrc
+++ b/mag/.magicrc
@@ -71,6 +71,7 @@
     addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_ls
     addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_ms
     addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_osu_sc
+    addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_ml_xx_hd
 } else {
     addpath ${PDKPATH}/libs.ref/sky130_fd_pr/${MAGTYPE}
     addpath ${PDKPATH}/libs.ref/sky130_fd_io/${MAGTYPE}
@@ -82,8 +83,11 @@
     addpath ${PDKPATH}/libs.ref/sky130_fd_sc_ls/${MAGTYPE}
     addpath ${PDKPATH}/libs.ref/sky130_fd_sc_ms/${MAGTYPE}
     addpath ${PDKPATH}/libs.ref/sky130_osu_sc/${MAGTYPE}
+    addpath ${PDKPATH}/libs.ref/sky130_ml_xx_hd/${MAGTYPE}
 }
 
+addpath hexdigits
+
 # add path to GDS cells
 
 # add path to IP from catalog.  This procedure defined in the PDK script.
diff --git a/mag/caravel.mag b/mag/caravel.mag
index b8bd0da..610ddf8 100644
--- a/mag/caravel.mag
+++ b/mag/caravel.mag
@@ -1,7 +1,7 @@
 magic
 tech sky130A
 magscale 1 2
-timestamp 1608238675
+timestamp 1608325192
 << metal1 >>
 rect 452176 1008113 452182 1008165
 rect 452234 1008153 452240 1008165
@@ -77792,188 +77792,200 @@
 rect 371542 265283 408362 265519
 rect 408598 265283 408640 265519
 rect 371264 265241 408640 265283
-use user_id_programming  user_id_value
-timestamp 1608238675
-transform 1 0 656624 0 1 80926
-box 0 0 7109 7077
+use open_source  open_source_0 hexdigits
+timestamp 1608325192
+transform 1 0 152038 0 1 2276
+box 752 5164 29030 16242
 use storage  storage
-timestamp 1608238675
+timestamp 1606855431
 transform 1 0 52032 0 1 53156
 box 38 0 88934 189234
-use mgmt_core  soc
-timestamp 1608238675
-transform 1 0 210434 0 1 53602
-box 0 0 430000 180000
 use sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped  rstb_level
-timestamp 1608238675
+timestamp 1607712712
 transform -1 0 137896 0 -1 51956
 box 0 -51 4992 5000
+use user_id_textblock  user_id_textblock_0
+timestamp 1608324878
+transform 1 0 42832 0 1 7182
+box -656 1508 33720 10344
+use copyright_block  copyright_block_0
+timestamp 1608325192
+transform 1 0 95314 0 1 15788
+box -262 -9464 35048 2764
+use user_id_programming  user_id_value
+timestamp 1607107372
+transform 1 0 656624 0 1 80926
+box 0 0 7109 7077
 use simple_por  por
-timestamp 1608238675
+timestamp 1606790297
 transform 1 0 654146 0 -1 112882
 box 25 11 11344 8291
-use gpio_control_block  gpio_control_bidir\[1\]
-timestamp 1608238675
-transform -1 0 708603 0 1 166200
-box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_bidir\[0\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 121000
 box -1620 -364 34000 13964
+use gpio_control_block  gpio_control_bidir\[1\]
+timestamp 1608227261
+transform -1 0 708603 0 1 166200
+box -1620 -364 34000 13964
+use mgmt_core  soc
+timestamp 1607549443
+transform 1 0 210434 0 1 53602
+box 0 0 430000 180000
 use gpio_control_block  gpio_control_in\[36\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 245800
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[37\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 202600
 box -1620 -364 34000 13964
 use mgmt_protect  mgmt_buffers
-timestamp 1608238675
+timestamp 1608143558
 transform 1 0 212180 0 1 246836
 box -2762 -2778 202678 20730
 use gpio_control_block  gpio_control_in\[2\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 211200
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[3\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 256400
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[33\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 375400
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[34\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 332200
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[35\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 289000
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[4\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 301400
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[5\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 346400
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[7\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 479800
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[6\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 391600
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[32\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 418600
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[31\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 546200
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[30\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 589400
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[29\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 632600
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[9\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 568800
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[8\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 523800
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[10\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 614000
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[28\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 675800
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[27\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 719000
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[26\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 762200
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[13\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 749200
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[12\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 704200
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[11\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 659000
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[25\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 805400
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[24\]
-timestamp 1608238675
+timestamp 1608227261
 transform 1 0 8567 0 1 931224
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[23\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 97200 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[22\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 148600 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[21\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 200000 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[20\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 251400 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[19\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 303000 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[18\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 353400 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[17\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 420800 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[16\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 497800 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[15\]
-timestamp 1608238675
+timestamp 1608227261
 transform 0 1 549200 -1 0 1029813
 box -1620 -364 34000 13964
 use gpio_control_block  gpio_control_in\[14\]
-timestamp 1608238675
+timestamp 1608227261
 transform -1 0 708603 0 1 927600
 box -1620 -364 34000 13964
 use user_project_wrapper  mprj
-timestamp 1608238675
+timestamp 1606942031
 transform 1 0 65308 0 1 278718
 box -8576 -7506 592500 711442
 use chip_io  padframe
-timestamp 1608238675
+timestamp 1607631642
 transform 1 0 0 0 1 0
 box 0 0 717600 1037600
 << properties >>
diff --git a/mag/copyright_block.mag b/mag/copyright_block.mag
new file mode 100644
index 0000000..c033892
--- /dev/null
+++ b/mag/copyright_block.mag
@@ -0,0 +1,252 @@
+magic
+tech sky130A
+magscale 1 2
+timestamp 1608325192
+<< checkpaint >>
+rect 20630 7518 37910 7764
+rect 20630 3780 52056 7518
+rect -1260 3060 2340 3780
+rect 7380 3060 15300 3780
+rect 16020 3060 52056 3780
+rect -1260 -1260 52056 3060
+rect -1142 -5542 52056 -1260
+rect -1024 -6116 2576 -5542
+rect 3178 -6116 6778 -5542
+rect 6896 -6116 10496 -5542
+rect 11458 -6116 20576 -5542
+rect -1024 -10436 20576 -6116
+rect 20630 -10596 52056 -5542
+rect 34776 -10842 52056 -10596
+<< fillblock >>
+rect -262 -266 26658 2764
+rect -140 -5140 35048 -1424
+rect 26 -9464 19562 -6358
+use font_65  font_65_6 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598775915
+transform 1 0 1676 0 1 -9176
+box 0 0 1080 1800
+use font_44  font_44_1 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598763661
+transform 1 0 236 0 1 -9176
+box 0 0 1080 2520
+use font_65  font_65_7
+timestamp 1598775915
+transform 1 0 4556 0 1 -9176
+box 0 0 1080 1800
+use font_63  font_63_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598836169
+transform 1 0 3116 0 1 -9176
+box 0 0 1080 1800
+use font_6D  font_6D_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598776905
+transform 1 0 5996 0 1 -9176
+box 0 0 1800 1800
+use font_65  font_65_8
+timestamp 1598775915
+transform 1 0 9596 0 1 -9176
+box 0 0 1080 1800
+use font_62  font_62_1 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598775406
+transform 1 0 8156 0 1 -9176
+box 0 0 1080 2520
+use font_72  font_72_2 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598777237
+transform 1 0 11036 0 1 -9176
+box 0 0 1080 1800
+use font_20  font_20_4 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598785497
+transform 1 0 12476 0 1 -9176
+box 0 0 1 1
+use font_32  font_32_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598787041
+transform 1 0 13916 0 1 -9176
+box 0 0 1080 2520
+use font_30  font_30_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598786981
+transform 1 0 15356 0 1 -9176
+box 0 0 1080 2520
+use font_32  font_32_1
+timestamp 1598787041
+transform 1 0 16796 0 1 -9176
+box 0 0 1080 2520
+use font_30  font_30_1
+timestamp 1598786981
+transform 1 0 18236 0 1 -9176
+box 0 0 1080 2520
+use font_47  font_47_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598765398
+transform 1 0 118 0 1 -4282
+box 0 0 1080 2520
+use font_6F  font_6F_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598777049
+transform 1 0 1558 0 1 -4282
+box 0 0 1080 1800
+use font_6F  font_6F_1
+timestamp 1598777049
+transform 1 0 2998 0 1 -4282
+box 0 0 1080 1800
+use font_67  font_67_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598776042
+transform 1 0 4438 0 1 -4282
+box 0 -720 1080 1800
+use font_65  font_65_3
+timestamp 1598775915
+transform 1 0 6598 0 1 -4282
+box 0 0 1080 1800
+use font_6C  font_6C_2 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598776550
+transform 1 0 5878 0 1 -4282
+box 0 0 360 2520
+use font_53  font_53_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598768855
+transform 1 0 9838 0 1 -4282
+box 0 0 1080 2520
+use font_79  font_79_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598777870
+transform 1 0 12718 0 1 -4282
+box 0 -720 1080 1800
+use font_6B  font_6B_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598776472
+transform 1 0 11278 0 1 -4282
+box 0 0 1080 2520
+use font_57  font_57_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598769216
+transform 1 0 14158 0 1 -4282
+box 0 0 1800 2520
+use font_74  font_74_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598777367
+transform 1 0 17758 0 1 -4282
+box 0 0 1080 2160
+use font_61  font_61_3 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598775307
+transform 1 0 16318 0 1 -4282
+box 0 0 1080 1800
+use font_65  font_65_4
+timestamp 1598775915
+transform 1 0 19198 0 1 -4282
+box 0 0 1080 1800
+use font_72  font_72_1
+timestamp 1598777237
+transform 1 0 20638 0 1 -4282
+box 0 0 1080 1800
+use font_20  font_20_2
+timestamp 1598785497
+transform 1 0 22078 0 1 -5002
+box 0 0 1 1
+use font_6F  font_6F_2
+timestamp 1598777049
+transform 1 0 23518 0 1 -4282
+box 0 0 1080 1800
+use font_65  font_65_5
+timestamp 1598775915
+transform 1 0 26398 0 1 -4282
+box 0 0 1080 1800
+use font_70  font_70_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598777090
+transform 1 0 24958 0 1 -4282
+box 0 -720 1080 1800
+use font_20  font_20_3
+timestamp 1598785497
+transform 1 0 29278 0 1 -5362
+box 0 0 1 1
+use font_6E  font_6E_1 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598776997
+transform 1 0 27838 0 1 -4282
+box 0 0 1080 1800
+use font_50  font_50_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598768087
+transform 1 0 30718 0 1 -4282
+box 0 0 1080 2520
+use font_44  font_44_0
+timestamp 1598763661
+transform 1 0 32158 0 1 -4282
+box 0 0 1080 2520
+use font_4B  font_4B_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598766293
+transform 1 0 33598 0 1 -4282
+box 0 0 1080 2520
+use font_2D  font_2D_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598786817
+transform 1 0 8038 0 1 -4642
+box 0 1080 1440 1440
+use font_61  font_61_0
+timestamp 1598775307
+transform 1 0 1440 0 1 0
+box 0 0 1080 1800
+use font_43  font_43_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598763351
+transform 1 0 0 0 1 0
+box 0 0 1080 2520
+use font_72  font_72_0
+timestamp 1598777237
+transform 1 0 2880 0 1 0
+box 0 0 1080 1800
+use font_61  font_61_1
+timestamp 1598775307
+transform 1 0 4320 0 1 0
+box 0 0 1080 1800
+use font_65  font_65_0
+timestamp 1598775915
+transform 1 0 7200 0 1 0
+box 0 0 1080 1800
+use font_76  font_76_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598777472
+transform 1 0 5760 0 1 0
+box 0 0 1080 1800
+use font_20  font_20_0
+timestamp 1598785497
+transform 1 0 9360 0 1 0
+box 0 0 1 1
+use font_6C  font_6C_0
+timestamp 1598776550
+transform 1 0 8640 0 1 0
+box 0 0 360 2520
+use font_43  font_43_1
+timestamp 1598763351
+transform 1 0 11880 0 1 0
+box 0 0 1080 2520
+use font_28  font_28_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1606780629
+transform 1 0 10800 0 1 0
+box 0 0 720 2520
+use font_29  font_29_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598786350
+transform 1 0 13320 0 1 0
+box 0 0 720 2520
+use font_65  font_65_1
+timestamp 1598775915
+transform 1 0 15840 0 1 0
+box 0 0 1080 1800
+use font_20  font_20_1
+timestamp 1598785497
+transform 1 0 14400 0 1 0
+box 0 0 1 1
+use font_66  font_66_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598775974
+transform 1 0 17280 0 1 0
+box 0 0 1080 2520
+use font_62  font_62_0
+timestamp 1598775406
+transform 1 0 20160 0 1 0
+box 0 0 1080 2520
+use font_61  font_61_2
+timestamp 1598775307
+transform 1 0 18720 0 1 0
+box 0 0 1080 1800
+use font_65  font_65_2
+timestamp 1598775915
+transform 1 0 22320 0 1 0
+box 0 0 1080 1800
+use font_6C  font_6C_1
+timestamp 1598776550
+transform 1 0 21600 0 1 0
+box 0 0 360 2520
+use font_73  font_73_0 $PDKPATH/libs.ref/sky130_ml_xx_hd/mag
+timestamp 1598777283
+transform 1 0 23760 0 1 0
+box 0 0 1080 1800
+use font_73  font_73_1
+timestamp 1598777283
+transform 1 0 25200 0 1 0
+box 0 0 1080 1800
+<< end >>
diff --git a/mag/hexdigits/alpha_0.mag b/mag/hexdigits/alpha_0.mag
new file mode 100644
index 0000000..5539e99
--- /dev/null
+++ b/mag/hexdigits/alpha_0.mag
@@ -0,0 +1,12 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598786981
+<< metal5 >>
+rect 0 90 45 105
+rect 0 15 15 90
+rect 30 15 45 90
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_1.mag b/mag/hexdigits/alpha_1.mag
new file mode 100644
index 0000000..0de4db8
--- /dev/null
+++ b/mag/hexdigits/alpha_1.mag
@@ -0,0 +1,12 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787010
+<< metal5 >>
+rect 15 90 30 105
+rect 0 75 30 90
+rect 15 15 30 75
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_2.mag b/mag/hexdigits/alpha_2.mag
new file mode 100644
index 0000000..26dc7b0
--- /dev/null
+++ b/mag/hexdigits/alpha_2.mag
@@ -0,0 +1,13 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787041
+<< metal5 >>
+rect 0 90 45 105
+rect 30 75 45 90
+rect 0 60 45 75
+rect 0 15 15 60
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_3.mag b/mag/hexdigits/alpha_3.mag
new file mode 100644
index 0000000..7ec3eac
--- /dev/null
+++ b/mag/hexdigits/alpha_3.mag
@@ -0,0 +1,13 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787077
+<< metal5 >>
+rect 0 90 45 105
+rect 30 75 45 90
+rect 0 60 45 75
+rect 30 15 45 60
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_4.mag b/mag/hexdigits/alpha_4.mag
new file mode 100644
index 0000000..809806a
--- /dev/null
+++ b/mag/hexdigits/alpha_4.mag
@@ -0,0 +1,12 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787136
+<< metal5 >>
+rect 0 75 15 90
+rect 30 75 45 105
+rect 0 60 45 75
+rect 30 0 45 60
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_5.mag b/mag/hexdigits/alpha_5.mag
new file mode 100644
index 0000000..be5ed52
--- /dev/null
+++ b/mag/hexdigits/alpha_5.mag
@@ -0,0 +1,13 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787165
+<< metal5 >>
+rect 0 90 45 105
+rect 0 75 15 90
+rect 0 60 45 75
+rect 30 15 45 60
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_6.mag b/mag/hexdigits/alpha_6.mag
new file mode 100644
index 0000000..91ff49f
--- /dev/null
+++ b/mag/hexdigits/alpha_6.mag
@@ -0,0 +1,14 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787225
+<< metal5 >>
+rect 0 90 45 105
+rect 0 75 15 90
+rect 0 60 45 75
+rect 0 15 15 60
+rect 30 15 45 60
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_7.mag b/mag/hexdigits/alpha_7.mag
new file mode 100644
index 0000000..61a2aeb
--- /dev/null
+++ b/mag/hexdigits/alpha_7.mag
@@ -0,0 +1,10 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787264
+<< metal5 >>
+rect 0 90 45 105
+rect 30 0 45 90
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_8.mag b/mag/hexdigits/alpha_8.mag
new file mode 100644
index 0000000..735bc4c
--- /dev/null
+++ b/mag/hexdigits/alpha_8.mag
@@ -0,0 +1,15 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787297
+<< metal5 >>
+rect 0 90 45 105
+rect 0 75 15 90
+rect 30 75 45 90
+rect 0 60 45 75
+rect 0 15 15 60
+rect 30 15 45 60
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_9.mag b/mag/hexdigits/alpha_9.mag
new file mode 100644
index 0000000..4bf894e
--- /dev/null
+++ b/mag/hexdigits/alpha_9.mag
@@ -0,0 +1,13 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598787355
+<< metal5 >>
+rect 0 90 45 105
+rect 0 75 15 90
+rect 30 75 45 90
+rect 0 60 45 75
+rect 30 0 45 60
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_A.mag b/mag/hexdigits/alpha_A.mag
new file mode 100644
index 0000000..e2e94f4
--- /dev/null
+++ b/mag/hexdigits/alpha_A.mag
@@ -0,0 +1,16 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598763107
+<< metal5 >>
+rect 10 100 35 105
+rect 5 95 40 100
+rect 0 85 45 95
+rect 0 45 15 85
+rect 30 45 45 85
+rect 0 30 45 45
+rect 0 0 15 30
+rect 30 0 45 30
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_B.mag b/mag/hexdigits/alpha_B.mag
new file mode 100644
index 0000000..840c9a8
--- /dev/null
+++ b/mag/hexdigits/alpha_B.mag
@@ -0,0 +1,19 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598763267
+<< metal5 >>
+rect 0 100 35 105
+rect 0 95 40 100
+rect 0 85 45 95
+rect 0 60 15 85
+rect 30 60 45 85
+rect 0 45 45 60
+rect 0 20 15 45
+rect 30 20 45 45
+rect 0 10 45 20
+rect 0 5 40 10
+rect 0 0 35 5
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_C.mag b/mag/hexdigits/alpha_C.mag
new file mode 100644
index 0000000..f853353
--- /dev/null
+++ b/mag/hexdigits/alpha_C.mag
@@ -0,0 +1,15 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598763351
+<< metal5 >>
+rect 10 100 45 105
+rect 5 95 45 100
+rect 0 85 45 95
+rect 0 20 15 85
+rect 0 10 45 20
+rect 5 5 45 10
+rect 10 0 45 5
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_D.mag b/mag/hexdigits/alpha_D.mag
new file mode 100644
index 0000000..c6ce878
--- /dev/null
+++ b/mag/hexdigits/alpha_D.mag
@@ -0,0 +1,16 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598763661
+<< metal5 >>
+rect 0 100 35 105
+rect 0 95 40 100
+rect 0 85 45 95
+rect 0 20 15 85
+rect 30 20 45 85
+rect 0 10 45 20
+rect 0 5 40 10
+rect 0 0 35 5
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_E.mag b/mag/hexdigits/alpha_E.mag
new file mode 100644
index 0000000..b32127a
--- /dev/null
+++ b/mag/hexdigits/alpha_E.mag
@@ -0,0 +1,13 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598765099
+<< metal5 >>
+rect 0 90 45 105
+rect 0 60 15 90
+rect 0 45 30 60
+rect 0 15 15 45
+rect 0 0 45 15
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/alpha_F.mag b/mag/hexdigits/alpha_F.mag
new file mode 100644
index 0000000..867900c
--- /dev/null
+++ b/mag/hexdigits/alpha_F.mag
@@ -0,0 +1,12 @@
+magic
+tech sky130A
+magscale 36 1
+timestamp 1598765253
+<< metal5 >>
+rect 0 90 45 105
+rect 0 60 15 90
+rect 0 45 30 60
+rect 0 0 15 45
+<< properties >>
+string FIXED_BBOX 0 -30 60 105
+<< end >>
diff --git a/mag/hexdigits/open_source.mag b/mag/hexdigits/open_source.mag
new file mode 100644
index 0000000..6a6e87b
--- /dev/null
+++ b/mag/hexdigits/open_source.mag
@@ -0,0 +1,190 @@
+magic
+tech sky130A
+timestamp 1608325192
+<< checkpaint >>
+rect 7176 6798 15816 6886
+rect 6615 6791 15816 6798
+rect 6306 3466 15816 6791
+rect 6306 3371 15698 3466
+rect 6486 3367 15698 3371
+rect 6486 3339 15126 3367
+rect -630 -630 8010 2790
+<< metal5 >>
+rect 3060 7740 3960 7920
+rect 1440 7200 1980 7380
+rect 1260 7020 2340 7200
+rect 2880 7020 4140 7740
+rect 5040 7200 5580 7380
+rect 4680 7020 5760 7200
+rect 1260 6840 2520 7020
+rect 2700 6840 4320 7020
+rect 4500 6840 5760 7020
+rect 1260 6660 5760 6840
+rect 1440 6300 5580 6660
+rect 1620 6120 5400 6300
+rect 1800 5940 5280 6120
+rect 7056 6101 7356 6161
+rect 7776 6101 8076 6161
+rect 8436 6101 8856 6161
+rect 9096 6101 9516 6161
+rect 10296 6101 10716 6161
+rect 11016 6101 11316 6161
+rect 6996 6041 7416 6101
+rect 7716 6041 8136 6101
+rect 1620 5760 3060 5940
+rect 3960 5760 5400 5940
+rect 6936 5921 7476 6041
+rect 900 5580 2880 5760
+rect 4140 5580 6120 5760
+rect 540 4680 2700 5580
+rect 4320 4680 6300 5580
+rect 6936 5501 7116 5921
+rect 7296 5501 7476 5921
+rect 6936 5381 7476 5501
+rect 7656 5921 8196 6041
+rect 7656 5501 7836 5921
+rect 8016 5501 8196 5921
+rect 7656 5381 8196 5501
+rect 8376 5981 8916 6101
+rect 8376 5801 8556 5981
+rect 8736 5801 8916 5981
+rect 8376 5681 8916 5801
+rect 9096 6041 9576 6101
+rect 10236 6041 10716 6101
+rect 10956 6041 11376 6101
+rect 9096 5921 9636 6041
+rect 8376 5621 8856 5681
+rect 8376 5441 8556 5621
+rect 6996 5321 7416 5381
+rect 7656 5321 8136 5381
+rect 8376 5321 8916 5441
+rect 7056 5261 7356 5321
+rect 7656 5261 8076 5321
+rect 8436 5261 8916 5321
+rect 9096 5261 9276 5921
+rect 9456 5261 9636 5921
+rect 10176 5981 10716 6041
+rect 10176 5801 10416 5981
+rect 10896 5921 11436 6041
+rect 10176 5741 10596 5801
+rect 10236 5681 10656 5741
+rect 10296 5621 10716 5681
+rect 10476 5441 10716 5621
+rect 10176 5381 10716 5441
+rect 10896 5501 11076 5921
+rect 11256 5501 11436 5921
+rect 10896 5381 11436 5501
+rect 11616 5501 11796 6161
+rect 11976 5501 12156 6161
+rect 11616 5381 12156 5501
+rect 12336 6101 12756 6161
+rect 13176 6101 13476 6161
+rect 13836 6101 14256 6161
+rect 12336 6041 12816 6101
+rect 13116 6041 13536 6101
+rect 12336 5921 12876 6041
+rect 10176 5321 10656 5381
+rect 10956 5321 11376 5381
+rect 11676 5321 12096 5381
+rect 10176 5261 10596 5321
+rect 11016 5261 11316 5321
+rect 11736 5261 12036 5321
+rect 12336 5261 12516 5921
+rect 12696 5801 12876 5921
+rect 13056 5921 13596 6041
+rect 13056 5501 13236 5921
+rect 13416 5801 13596 5921
+rect 13776 5981 14316 6101
+rect 13776 5801 13956 5981
+rect 14136 5801 14316 5981
+rect 13776 5681 14316 5801
+rect 13776 5621 14256 5681
+rect 13416 5501 13596 5621
+rect 13056 5381 13596 5501
+rect 13776 5441 13956 5621
+rect 13116 5321 13536 5381
+rect 13776 5321 14316 5441
+rect 13176 5261 13476 5321
+rect 13836 5261 14316 5321
+rect 7656 4901 7836 5261
+rect 10176 4901 10356 5261
+rect 7656 4841 8076 4901
+rect 8376 4841 8856 4901
+rect 9096 4841 9516 4901
+rect 9936 4841 10356 4901
+rect 7656 4781 8136 4841
+rect 900 4500 2880 4680
+rect 4140 4500 6120 4680
+rect 7656 4661 8196 4781
+rect 8376 4721 8916 4841
+rect 1620 4320 3060 4500
+rect 1800 4140 3060 4320
+rect 3960 4320 5400 4500
+rect 3960 4140 5220 4320
+rect 1620 3960 2880 4140
+rect 1440 3780 2880 3960
+rect 4140 3960 5400 4140
+rect 7656 4001 7836 4661
+rect 8016 4001 8196 4661
+rect 8736 4541 8916 4721
+rect 8376 4361 8916 4541
+rect 8376 4181 8556 4361
+rect 8736 4181 8916 4361
+rect 8376 4061 8916 4181
+rect 8436 4001 8916 4061
+rect 9096 4781 9576 4841
+rect 9876 4781 10356 4841
+rect 9096 4661 9636 4781
+rect 9096 4001 9276 4661
+rect 9456 4541 9636 4661
+rect 9816 4661 10356 4781
+rect 9816 4241 9996 4661
+rect 10176 4241 10356 4661
+rect 9816 4121 10356 4241
+rect 10536 4241 10716 4901
+rect 10896 4241 11076 4901
+rect 11256 4241 11436 4901
+rect 11616 4841 12096 4901
+rect 12336 4841 12756 4901
+rect 13116 4841 13536 4901
+rect 11616 4721 12156 4841
+rect 11976 4541 12156 4721
+rect 11676 4481 12156 4541
+rect 10536 4121 11436 4241
+rect 11616 4361 12156 4481
+rect 11616 4181 11796 4361
+rect 11976 4181 12156 4361
+rect 9876 4061 10356 4121
+rect 10596 4061 11376 4121
+rect 11616 4061 12156 4181
+rect 9936 4001 10356 4061
+rect 10656 4001 10896 4061
+rect 11076 4001 11316 4061
+rect 11676 4001 12156 4061
+rect 12336 4781 12816 4841
+rect 12336 4661 12876 4781
+rect 12336 4001 12516 4661
+rect 12696 4541 12876 4661
+rect 13056 4721 13596 4841
+rect 13056 4541 13236 4721
+rect 13416 4541 13596 4721
+rect 13056 4361 13596 4541
+rect 13056 4181 13236 4361
+rect 13056 4061 13596 4181
+rect 13116 4001 13596 4061
+rect 4140 3780 5580 3960
+rect 1440 3600 2700 3780
+rect 1260 3420 2700 3600
+rect 4320 3660 5580 3780
+rect 4320 3600 5640 3660
+rect 4320 3420 5760 3600
+rect 1260 3240 2520 3420
+rect 4500 3240 5760 3420
+rect 1260 3060 2340 3240
+rect 4680 3060 5760 3240
+rect 1440 2880 1980 3060
+rect 5040 2880 5580 3060
+<< fillblock >>
+rect 376 2582 6603 8121
+rect 6796 3824 14515 6352
+<< end >>
diff --git a/mag/user_id_textblock.mag b/mag/user_id_textblock.mag
new file mode 100644
index 0000000..8ba2eb0
--- /dev/null
+++ b/mag/user_id_textblock.mag
@@ -0,0 +1,43 @@
+magic
+tech sky130A
+timestamp 1608324878
+<< checkpaint >>
+rect 1495 5490 6500 6570
+rect -630 428 19262 5490
+rect -630 -630 6210 428
+rect 16092 356 18972 428
+<< fillblock >>
+rect -328 754 16860 5172
+use alpha_0  alpha_7 hexdigits
+timestamp 1598786981
+transform 1 0 14887 0 1 1080
+box 0 0 1620 3780
+use alpha_0  alpha_6
+timestamp 1598786981
+transform 1 0 12750 0 1 1080
+box 0 0 1620 3780
+use alpha_0  alpha_5
+timestamp 1598786981
+transform 1 0 10625 0 1 1080
+box 0 0 1620 3780
+use alpha_0  alpha_4
+timestamp 1598786981
+transform 1 0 8500 0 1 1080
+box 0 0 1620 3780
+use alpha_0  alpha_3
+timestamp 1598786981
+transform 1 0 6375 0 1 1080
+box 0 0 1620 3780
+use alpha_0  alpha_2
+timestamp 1598786981
+transform 1 0 4250 0 1 1080
+box 0 0 1620 3780
+use alpha_0  alpha_1
+timestamp 1598786981
+transform 1 0 2125 0 1 1080
+box 0 0 1620 3780
+use alpha_0  alpha_0
+timestamp 1598786981
+transform 1 0 0 0 1 1080
+box 0 0 1620 3780
+<< end >>
diff --git a/scripts/set_user_id.py b/scripts/set_user_id.py
index 3975354..7322e9a 100755
--- a/scripts/set_user_id.py
+++ b/scripts/set_user_id.py
@@ -14,6 +14,7 @@
 # limitations under the License.
 # SPDX-License-Identifier: Apache-2.0
 
+#----------------------------------------------------------------------
 #
 # set_user_id.py ---
 #
@@ -21,7 +22,9 @@
 # user_id_programming block to set the user ID number.
 #
 # The user ID number is a 32-bit value that is passed to this routine
-# as an integer.
+# as an 8-digit hex number.  If not given as an option, then the script
+# will look for the value of the key "project_id" in the info.yaml file
+# in the project top level directory
 #
 # user_id_programming layout map:
 # Positions marked (in microns) for value = 0.  For value = 1, move
@@ -64,14 +67,22 @@
 # mask_rev[29]	27.83 20.23
 # mask_rev[30]	16.33 23.29
 # mask_rev[31]	 8.05 14.79
-#--------------------------------
+#----------------------------------------------------------------------
 
 import os
 import sys
 import re
 
 def usage():
-    print("set_user_id.py <user_id_value> [<path_to_project>]")
+    print("Usage:")
+    print("set_user_id.py [<user_id_value>] [<path_to_project>]")
+    print("")
+    print("where:")
+    print("    <user_id_value>   is a character string of eight hex digits, and")
+    print("    <path_to_project> is the path to the project top level directory.")
+    print("")
+    print("  If <user_id_value> is not given, then it must exist in the info.yaml file.")
+    print("  If <path_to_project> is not given, then it is assumed to be the cwd.")
     return 0
 
 if __name__ == '__main__':
@@ -107,118 +118,203 @@
     if '-debug' in optionlist:
         debugmode = True
 
-    user_id_value = arguments[0]
+    user_id_value = None
+    user_project_path = None
 
-    # Convert to binary
-    user_id_bits = '{0:032b}'.format(int(user_id_value))
+    if len(arguments) > 0:
+        user_id_value = arguments[0]
+
+        # Convert to binary
+        try:
+            user_id_int = int('0x' + user_id_value, 0)
+            user_id_bits = '{0:032b}'.format(user_id_int)
+        except:
+            user_project_path = arguments[0]
 
     if len(arguments) == 2:
         user_project_path = arguments[1]
+    elif user_project_path == None:
+        user_project_path = arguments[0]
     else:
         user_project_path = os.getcwd()
 
+    if not os.path.isdir(user_project_path):
+        print('Error:  Project path "' + user_project_path + '" does not exist or is not readable.')
+        sys.exit(1)
+
+    # Check for valid directories
+
+    if not user_id_value:
+        if os.path.isfile(user_project_path + '/info.yaml'):
+            with open(user_project_path + '/info.yaml', 'r') as ifile:
+                infolines = ifile.read().splitlines()
+                for line in infolines:
+                    key, value = line.split(':').trim()
+                    if key == 'project_id':
+                        user_id_value = value.trim('"')
+
+            if not user_id_value:
+                print('Error:  No project_id key:value pair found in project info.yaml.')
+                sys.exit(1)
+
+            try:
+                user_id_int = int('0x' + user_id_value, 0)
+                user_id_bits = '{0:032b}'.format(user_id_int)
+            except:
+                print('Error:  Cannot parse user ID "' + user_id_value + '" as an 8-digit hex number.')
+                sys.exit(1)
+
+        else:
+            print('Error:  No info.yaml file and no user ID argument given.')
+            sys.exit(1)
+
+    print('Setting project user ID to: ' + user_id_value)
+
     magpath = user_project_path + '/mag'
     gdspath = user_project_path + '/gds'
     vpath = user_project_path + '/verilog'
     errors = 0 
 
-    if os.path.isdir(gdspath):
-
-        # Bytes leading up to via position are:
-        viarec = "00 06 0d 02 00 43 00 06 0e 02 00 2c 00 2c 10 03 "
-        viabytes = bytes.fromhex(viarec)
-
-        # Read the GDS file.  If a backup was made of the zero-value
-        # program, then use it.
-
-        gdsbak = gdspath + '/user_id_prog_zero.gds'
-        gdsfile = gdspath + '/user_id_programming.gds'
-
-        if os.path.isfile(gdsbak):
-            with open(gdsbak, 'rb') as ifile:
-                gdsdata = ifile.read()
-        else:
-            with open(gdsfile, 'rb') as ifile:
-                gdsdata = ifile.read()
-
-        for i in range(0,32):
-            # Ignore any zero bits.
-            if user_id_bits[i] == '0':
-                continue
-
-            coords = mask_rev[i]
-            xum = coords[0]
-            yum = coords[1]
-
-            # Contact is 0.17 x 0.17, so add and subtract 0.085 to get
-            # the corner positions.
-
-            xllum = xum - 0.085
-            yllum = yum - 0.085
-            xurum = xum + 0.085
-            yurum = yum + 0.085
- 
-            # Get the 4-byte hex values for the corner coordinates
-            xllnm = round(xllum * 1000)
-            yllnm = round(yllum * 1000)
-            xllhex = '{0:08x}'.format(xllnm)
-            yllhex = '{0:08x}'.format(yllnm)
-            xurnm = round(xurum * 1000)
-            yurnm = round(yurum * 1000)
-            xurhex = '{0:08x}'.format(xurnm)
-            yurhex = '{0:08x}'.format(yurnm)
-
-            # Magic's GDS output for vias always starts at the lower left
-            # corner and goes counterclockwise, repeating the first point.
-            viaoldposdata = viarec + xllhex + yllhex + xurhex + yllhex
-            viaoldposdata += xurhex + yurhex + xllhex + yurhex + xllhex + yllhex
-            
-            # For "one" bits, the X position is moved 0.92 microns to the left
-            newxllum = xllum - 0.92
-            newxurum = xurum - 0.92
-
-            # Get the 4-byte hex values for the new corner coordinates
-            newxllnm = round(newxllum * 1000)
-            newxllhex = '{0:08x}'.format(newxllnm)
-            newxurnm = round(newxurum * 1000)
-            newxurhex = '{0:08x}'.format(newxurnm)
-
-            vianewposdata = viarec + newxllhex + yllhex + newxurhex + yllhex
-            vianewposdata += newxurhex + yurhex + newxllhex + yurhex + newxllhex + yllhex
-
-            # Diagnostic
-            if debugmode:
-                print('Bit ' + str(i) + ':')
-                print('Via position ({0:3.2f}, {1:3.2f}) to ({2:3.2f}, {3:3.2f})'.format(xllum, yllum, xurum, yurum))
-                print('Old hex string = ' + viaoldposdata)
-                print('New hex string = ' + vianewposdata)
-
-            # Convert hex strings to byte arrays
-            viaoldbytedata = bytearray.fromhex(viaoldposdata)
-            vianewbytedata = bytearray.fromhex(vianewposdata)
-
-            # Replace the old data with the new
-            if viaoldbytedata not in gdsdata:
-                print('Error: via not found for bit position ' + str(i))
-                errors += 1 
-            else:
-                gdsdata = gdsdata.replace(viaoldbytedata, vianewbytedata)
-
-        if errors == 0:
-            # Keep a copy of the original 
-            if not os.path.isfile(gdsbak):
-                os.rename(gdsfile, gdsbak)
-
-            with open(gdsfile, 'wb') as ofile:
-                ofile.write(gdsdata)
-
-            print('Done!')
-            
-        else:
-            print('There were errors in processing.  No file written.')
-            sys.exit(1)
-
-    else:
-        print('No directory ' + gdspath + ' found.')
+    if not os.path.isdir(gdspath):
+        print('No directory ' + gdspath + ' found (path to GDS).')
         sys.exit(1)
+
+    if not os.path.isdir(vpath):
+        print('No directory ' + vpath + ' found (path to verilog).')
+        sys.exit(1)
+
+    if not os.path.isdir(magpath):
+        print('No directory ' + magpath + ' found (path to magic databases).')
+        sys.exit(1)
+
+    print('Step 1:  Modify GDS of the user_id_programming subcell')
+
+    # Bytes leading up to via position are:
+    viarec = "00 06 0d 02 00 43 00 06 0e 02 00 2c 00 2c 10 03 "
+    viabytes = bytes.fromhex(viarec)
+
+    # Read the GDS file.  If a backup was made of the zero-value
+    # program, then use it.
+
+    gdsbak = gdspath + '/user_id_prog_zero.gds'
+    gdsfile = gdspath + '/user_id_programming.gds'
+
+    if os.path.isfile(gdsbak):
+        with open(gdsbak, 'rb') as ifile:
+            gdsdata = ifile.read()
+    else:
+        with open(gdsfile, 'rb') as ifile:
+            gdsdata = ifile.read()
+
+    for i in range(0,32):
+        # Ignore any zero bits.
+        if user_id_bits[i] == '0':
+            continue
+
+        coords = mask_rev[i]
+        xum = coords[0]
+        yum = coords[1]
+
+        # Contact is 0.17 x 0.17, so add and subtract 0.085 to get
+        # the corner positions.
+
+        xllum = xum - 0.085
+        yllum = yum - 0.085
+        xurum = xum + 0.085
+        yurum = yum + 0.085
+ 
+        # Get the 4-byte hex values for the corner coordinates
+        xllnm = round(xllum * 1000)
+        yllnm = round(yllum * 1000)
+        xllhex = '{0:08x}'.format(xllnm)
+        yllhex = '{0:08x}'.format(yllnm)
+        xurnm = round(xurum * 1000)
+        yurnm = round(yurum * 1000)
+        xurhex = '{0:08x}'.format(xurnm)
+        yurhex = '{0:08x}'.format(yurnm)
+
+        # Magic's GDS output for vias always starts at the lower left
+        # corner and goes counterclockwise, repeating the first point.
+        viaoldposdata = viarec + xllhex + yllhex + xurhex + yllhex
+        viaoldposdata += xurhex + yurhex + xllhex + yurhex + xllhex + yllhex
+            
+        # For "one" bits, the X position is moved 0.92 microns to the left
+        newxllum = xllum - 0.92
+        newxurum = xurum - 0.92
+
+        # Get the 4-byte hex values for the new corner coordinates
+        newxllnm = round(newxllum * 1000)
+        newxllhex = '{0:08x}'.format(newxllnm)
+        newxurnm = round(newxurum * 1000)
+        newxurhex = '{0:08x}'.format(newxurnm)
+
+        vianewposdata = viarec + newxllhex + yllhex + newxurhex + yllhex
+        vianewposdata += newxurhex + yurhex + newxllhex + yurhex + newxllhex + yllhex
+
+        # Diagnostic
+        if debugmode:
+            print('Bit ' + str(i) + ':')
+            print('Via position ({0:3.2f}, {1:3.2f}) to ({2:3.2f}, {3:3.2f})'.format(xllum, yllum, xurum, yurum))
+            print('Old hex string = ' + viaoldposdata)
+            print('New hex string = ' + vianewposdata)
+
+        # Convert hex strings to byte arrays
+        viaoldbytedata = bytearray.fromhex(viaoldposdata)
+        vianewbytedata = bytearray.fromhex(vianewposdata)
+
+        # Replace the old data with the new
+        if viaoldbytedata not in gdsdata:
+            print('Error: via not found for bit position ' + str(i))
+            errors += 1 
+        else:
+            gdsdata = gdsdata.replace(viaoldbytedata, vianewbytedata)
+
+    if errors == 0:
+        # Keep a copy of the original 
+        if not os.path.isfile(gdsbak):
+            os.rename(gdsfile, gdsbak)
+
+        with open(gdsfile, 'wb') as ofile:
+            ofile.write(gdsdata)
+
+        print('Done!')
+            
+    else:
+        print('There were errors in processing.  No file written.')
+        sys.exit(1)
+
+    print('Step 2:  Add user project ID parameter to verilog.')
+
+    with open(vpath + '/rtl/caravel.v', 'r') as ifile:
+        vlines = ifile.read().splitlines()
+        outlines = []
+        for line in vlines:
+            oline = re.sub("parameter USER_PROJECT_ID = 32'h0;",
+			"parameter USER_PROJECT_ID = 32'h" + user_id_value + ";",
+			line)
+            outlines.append(oline)
+
+    with open(vpath + '/rtl/caravel.v', 'w') as ofile:
+        for line in outlines:
+            print(line, file=ofile)
+
+    print('Step 3:  Add user project ID text to top level layout.')
+
+    with open(magpath + '/user_id_textblock.mag', 'r') as ifile:
+        maglines = ifile.read().splitlines()
+        outlines = []
+        digit = 0
+        for line in maglines:
+            if 'alpha_0' in line:
+                dchar = user_id_value[digit].upper()
+                oline = re.sub('alpha_0', 'alpha_' + dchar, line)
+                outlines.append(oline)
+                digit += 1
+            else:
+                outlines.append(line)
+
+    with open(magpath + '/user_id_textblock.mag', 'w') as ofile:
+        for line in outlines:
+            print(line, file=ofile)
+
     sys.exit(0)