diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt
index 0349444f528fc1f2f31e3c61c53b77638aa152d2..bcfd9ed2d936d26a7822c4e17a5eb0d3eb5399c4 100644
--- a/firmware/CMakeLists.txt
+++ b/firmware/CMakeLists.txt
@@ -26,7 +26,6 @@ set(CHIBIOS ${PROJECT_SOURCE_DIR}/chibios)
 set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack)
 
 set(EXTRACT_CPLD_DATA ${PROJECT_SOURCE_DIR}/tools/extract_cpld_data.py)
-set(EXTRACT_SVF_DATA_XC2C64A ${PROJECT_SOURCE_DIR}/tools/extract_svf_data_xc2c64a.py)
 set(STRIP_DFU ${PROJECT_SOURCE_DIR}/tools/strip_dfu.py)
 set(MAKE_SPI_IMAGE ${PROJECT_SOURCE_DIR}/tools/make_spi_image.py)
 set(MAKE_IMAGE_CHUNK ${PROJECT_SOURCE_DIR}/tools/make_image_chunk.py)
@@ -40,7 +39,7 @@ ExternalProject_Add(hackrf
 	GIT_REPOSITORY https://github.com/jboone/hackrf.git
 	# SOURCE_SUBDIR firmware
 	# SOURCE_SUBDIR isn't available in CMake 3.5 (Ubuntu 16.04 LTS), so the following is a work-around:
-	CONFIGURE_COMMAND ${CMAKE_COMMAND} -DUSER_INTERFACE=PORTAPACK "-GUnix Makefiles" ../hackrf/firmware
+	CONFIGURE_COMMAND ${CMAKE_COMMAND} "-GUnix Makefiles" ../hackrf/firmware
 	BUILD_COMMAND ${MAKE_EXE} hackrf_usb.dfu
 	INSTALL_COMMAND ""
 )
@@ -54,8 +53,9 @@ set(HACKRF_FIRMWARE_BIN_FILENAME hackrf_usb.bin)
 
 set(HACKRF_FIRMWARE_DFU_IMAGE ${hackrf_BINARY_DIR}/hackrf_usb/${HACKRF_FIRMWARE_DFU_FILENAME})
 set(HACKRF_FIRMWARE_BIN_IMAGE ${hackrf_BINARY_DIR}/hackrf_usb/${HACKRF_FIRMWARE_BIN_FILENAME})
-set(HACKRF_CPLD_SVF_FILENAME default.svf)
-set(HACKRF_CPLD_SVF_PATH ${hackrf_SOURCE_DIR}/firmware/cpld/sgpio_if/${HACKRF_CPLD_SVF_FILENAME})
+set(HACKRF_CPLD_TOOL ${hackrf_SOURCE_DIR}/firmware/tools/cpld_bitstream.py)
+set(HACKRF_CPLD_XSVF_FILENAME default.xsvf)
+set(HACKRF_CPLD_XSVF_PATH ${hackrf_SOURCE_DIR}/firmware/cpld/sgpio_if/${HACKRF_CPLD_XSVF_FILENAME})
 
 add_subdirectory(application)
 add_subdirectory(baseband)
diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt
index 33d90d2649b762ffd5835886d3a671ab8995cd53..c2b488a4f0f9a6d5d577c8b8f345148d16b6ebe4 100644
--- a/firmware/application/CMakeLists.txt
+++ b/firmware/application/CMakeLists.txt
@@ -251,6 +251,7 @@ set(CPPSRC
 	apps/analog_audio_app.cpp
 	apps/capture_app.cpp
 	apps/ert_app.cpp
+	apps/lge_app.cpp
 	apps/pocsag_app.cpp
 	apps/replay_app.cpp
 	apps/soundboard_app.cpp
@@ -404,9 +405,9 @@ add_custom_command(
 )
 
 add_custom_command(
-	OUTPUT ${HACKRF_CPLD_DATA_HPP} ${HACKRF_CPLD_DATA_CPP}
-	COMMAND ${EXTRACT_SVF_DATA_XC2C64A} ${HACKRF_CPLD_SVF_PATH} hackrf::one::cpld::verify_blocks ${HACKRF_CPLD_DATA_CPP}
-	DEPENDS ${EXTRACT_SVF_DATA_XC2C64A} hackrf
+	OUTPUT ${HACKRF_CPLD_DATA_CPP}
+	COMMAND ${HACKRF_CPLD_TOOL} --xsvf ${HACKRF_CPLD_XSVF_PATH} --portapack-data ${HACKRF_CPLD_DATA_CPP}
+	DEPENDS ${HACKRF_CPLD_TOOL} ${HACKRF_CPLD_XSVF_PATH} hackrf
 )
 
 add_executable(${PROJECT_NAME}.elf ${CSRC} ${CPPSRC} ${ASMSRC})
diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp
index 04016b69c2ad057194d27818e6a9e51edd36e540..50872d9e4503fe0525410a49d76ef1e88ae0ca62 100644
--- a/firmware/application/portapack.cpp
+++ b/firmware/application/portapack.cpp
@@ -311,6 +311,12 @@ bool init() {
 		return false;
 	}
 
+	if( !hackrf::cpld::load_sram() ) {
+		chSysHalt();
+	}
+
+	configure_pins_portapack();
+	
 	portapack::io.init();
 
 	clock_manager.init_clock_generator();
diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt
index b56cae869c9da08555107b87e92275e73b2d3ced..a31bd07e78199fdc16452b659f39d0a64d080409 100644
--- a/firmware/baseband/CMakeLists.txt
+++ b/firmware/baseband/CMakeLists.txt
@@ -471,7 +471,7 @@ DeclareTargets(PWFM wfm_audio)
 add_custom_command(
 	OUTPUT hackrf.bin hackrf.img
 	COMMAND ${STRIP_DFU} ${HACKRF_FIRMWARE_DFU_IMAGE} hackrf.bin
-	COMMAND ${MAKE_IMAGE_CHUNK} hackrf.bin HRF1 hackrf.img
+	COMMAND ${MAKE_IMAGE_CHUNK} hackrf.bin HRF1 hackrf.img 98304
 	DEPENDS hackrf ${STRIP_DFU} ${MAKE_IMAGE_CHUNK}
 	VERBATIM
 )
diff --git a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp
index c64bd8d29c0a1f8a588a7122c8433d1f34aa4650..fbfe664b020ff301a1caa53b737d77981ce64ad3 100755
--- a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp
+++ b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp
@@ -50,128 +50,199 @@ const PALConfig pal_default_config = {
   .P = {
     {   // GPIO0
         .data
-            = (1 << 15) // CS_XCVR
-            | (1 << 14) // AMP_BYPASS
-            | (0 <<  9) // 10K PD, BOOT1
-            | (1 <<  8) // 10K PU, BOOT0
+            = (1 << 15) // P1_20: CS_XCVR
+            | (1 << 14) // P2_10: AMP_BYPASS
+            | (0 << 13) // P1_18: SGPIO12, HOST_Q_INVERT
+            | (0 << 12) // P1_17: SGPIO11, HOST_DIRECTION
+            | (1 << 11) // P1_4:  SSP1_MOSI
+            | (1 << 10) // P1_3:  SSP1_MISO
+            | (0 <<  9) // P1_2:  10K PD, BOOT1
+            | (1 <<  8) // P1_1:  10K PU, BOOT0
+            | (1 <<  7) // P2_7:  10K PU, ISP
+            | (0 <<  6) // P3_6:  SPIFI_MISO
+            | (1 <<  5) // P6_6:  SGPIO5, HOST_DATA5
+            | (1 <<  4) // P1_0:  SGPIO7, HOST_DATA7
+            | (1 <<  3) // P1_16: SGPIO3, HOST_DATA3
+            | (1 <<  2) // P1_15: SGPIO2, HOST_DATA2
+            | (1 <<  1) // P0_1:  SGPIO1, HOST_DATA1
+            | (1 <<  0) // P0_0:  SGPIO0, HOST_DATA0
             ,
         .dir
-            = (1 << 15) // CS_XCVR
-            | (1 << 14) // AMP_BYPASS
-            | (0 <<  9) // 10K PD, BOOT1
-            | (0 <<  8) // 10K PU, BOOT0
+            = (1 << 15) // P1_20: CS_XCVR
+            | (1 << 14) // P2_10: AMP_BYPASS
+            | (1 << 13) // P1_18: SGPIO12, HOST_Q_INVERT
+            | (0 << 12) // P1_17: SGPIO11, HOST_DIRECTION
+            | (0 << 11) // P1_4:  SSP1_MOSI
+            | (0 << 10) // P1_3:  SSP1_MISO
+            | (0 <<  9) // P1_2:  10K PD, BOOT1
+            | (0 <<  8) // P1_1:  10K PU, BOOT0
+            | (0 <<  7) // P2_7:  10K PU, ISP
+            | (0 <<  6) // P3_6:  SPIFI_MISO
+            | (0 <<  5) // P6_6:  SGPIO5, HOST_DATA5
+            | (0 <<  4) // P1_0:  SGPIO7, HOST_DATA7
+            | (0 <<  3) // P1_16: SGPIO3, HOST_DATA3
+            | (0 <<  2) // P1_15: SGPIO2, HOST_DATA2
+            | (0 <<  1) // P0_1:  SGPIO1, HOST_DATA1
+            | (0 <<  0) // P0_0:  SGPIO0, HOST_DATA0
     },
     {   // GPIO1
         .data
-            = (1 << 13) // PortaPack P2_13/DIR
-            | (1 << 12) // !RX_AMP_PWR
-            | (0 << 11) // RX_AMP
-            | (1 << 10) // 10K PD, BOOT3, PortaPack P2_9/LCD_WRX
-            | (1 <<  8) // PortaPack CPLD.TDO(O)
-            | (1 <<  1) // PortaPack CPLD.TMS(I)
-            | (0 <<  0) // !MIX_BYPASS
+            = (1 << 15) // P3_5:  SPIFI_SIO2
+            | (1 << 14) // P3_4:  SPIFI_SIO3
+            | (1 << 13) // P2_13: PortaPack DIR
+            | (1 << 12) // P2_12: !RX_AMP_PWR
+            | (0 << 11) // P2_11: RX_AMP
+            | (0 << 10) // P2_9:  10K PD, BOOT3, PortaPack LCD_WRX
+            | (1 <<  9) // P1_6:  SD_CMD
+            | (1 <<  8) // P1_5:  SD_POW, PortaPack CPLD.TDO(O) (input with pull up)
+            | (1 <<  7) // P1_14: SGPIO10, HOST_DISABLE
+            | (1 <<  6) // P1_13: SD_CD
+            | (1 <<  5) // P1_12: SD_DAT3
+            | (1 <<  4) // P1_11: SD_DAT2
+            | (1 <<  3) // P1_10: SD_DAT1
+            | (1 <<  2) // P1_9:  SD_DAT0
+            | (1 <<  1) // P1_8:  PortaPack CPLD.TMS(I)
+            | (0 <<  0) // P1_7:  !MIX_BYPASS
             ,
         .dir
-            = (1 << 13) // PortaPack P2_13/DIR
-            | (1 << 12) // !RX_AMP_PWR
-            | (1 << 11) // RX_AMP
-            | (1 << 10) // 10K PD, BOOT3, PortaPack P2_9/LCD_WRX
-            | (0 <<  8) // PortaPack CPLD.TDO(O) (input with pull up)
-            | (0 <<  1) // PortaPack CPLD.TMS(I) (output only when needed, pull up internal to CPLD)
-            | (1 <<  0) // !MIX_BYPASS
+            = (0 << 15) // P3_5:  SPIFI_SIO2
+            | (0 << 14) // P3_4:  SPIFI_SIO3
+            | (0 << 13) // P2_13: PortaPack DIR
+            | (1 << 12) // P2_12: !RX_AMP_PWR
+            | (1 << 11) // P2_11: RX_AMP
+            | (0 << 10) // P2_9:  10K PD, BOOT3, PortaPack LCD_WRX
+            | (0 <<  9) // P1_6:  SD_CMD
+            | (0 <<  8) // P1_5:  SD_POW, PortaPack CPLD.TDO(O) (input with pull up)
+            | (0 <<  7) // P1_14: SGPIO10, HOST_DISABLE
+            | (0 <<  6) // P1_13: SD_CD
+            | (0 <<  5) // P1_12: SD_DAT3
+            | (0 <<  4) // P1_11: SD_DAT2
+            | (0 <<  3) // P1_10: SD_DAT1
+            | (0 <<  2) // P1_9:  SD_DAT0
+            | (0 <<  1) // P1_8:  PortaPack CPLD.TMS(I) (output only when needed, pull up internal to CPLD)
+            | (1 <<  0) // P1_7:  !MIX_BYPASS
     },
     {   // GPIO2
         .data
-            = (0 << 15) // TX_AMP
-            | (0 << 11) // TX_MIX_BP
-            | (1 << 14) // MIXER_RESETX, 10K PU
-            | (1 << 13) // MIXER_ENX, 10K PU
-            | (1 << 12) // RX_MIX_BP
-            | (0 << 10) // LP
-            | (1 <<  9) // !VAA_ENABLE
-            | (0 <<  8) // LED3 (TX)
-            | (1 <<  7) // CS_AD
-            | (0 <<  6) // XCVR_EN, 10K PD
-            | (0 <<  5) // RXENABLE
-            | (0 <<  4) // TXENABLE
-            | (0 <<  2) // LED2 (RX)
-            | (0 <<  1) // LED1 (USB)
-            | (1 <<  0) // HP
+            = (0 << 15) // P5_6:  TX_AMP
+            | (1 << 14) // P5_5:  MIXER_RESETX, 10K PU
+            | (1 << 13) // P5_4:  MIXER_ENX, 10K PU
+            | (1 << 12) // P5_3:  RX_MIX_BP
+            | (0 << 11) // P5_2:  TX_MIX_BP
+            | (0 << 10) // P5_1:  LP
+            | (1 <<  9) // P5_0:  !VAA_ENABLE
+            | (0 <<  8) // P6_12: LED3 (TX)
+            | (1 <<  7) // P5_7:  CS_AD
+            | (0 <<  6) // P4_6:  XCVR_EN, 10K PD
+            | (0 <<  5) // P4_5:  RXENABLE
+            | (0 <<  4) // P4_4:  TXENABLE
+            | (1 <<  3) // P4_3:  SGPIO9, HOST_CAPTURE
+            | (0 <<  2) // P4_2:  LED2 (RX)
+            | (0 <<  1) // P4_1:  LED1 (USB)
+            | (1 <<  0) // P4_0:  HP
             ,
         .dir
-            = (1 << 15) // TX_AMP
-            | (1 << 14) // MIXER_RESETX, 10K PU
-            | (1 << 13) // MIXER_ENX, 10K PU
-            | (1 << 12) // RX_MIX_BP
-            | (1 << 11) // TX_MIX_BP
-            | (1 << 10) // LP
-            | (1 <<  9) // !VAA_ENABLE
-            | (1 <<  8) // LED3 (TX)
-            | (1 <<  7) // CS_AD
-            | (1 <<  6) // XCVR_EN, 10K PD
-            | (1 <<  5) // RXENABLE
-            | (1 <<  4) // TXENABLE
-            | (1 <<  2) // LED2 (RX)
-            | (1 <<  1) // LED1 (USB)
-            | (1 <<  0) // HP
+            = (1 << 15) // P5_6:  TX_AMP
+            | (1 << 14) // P5_5:  MIXER_RESETX, 10K PU
+            | (1 << 13) // P5_4:  MIXER_ENX, 10K PU
+            | (1 << 12) // P5_3:  RX_MIX_BP
+            | (1 << 11) // P5_2:  TX_MIX_BP
+            | (1 << 10) // P5_1:  LP
+            | (1 <<  9) // P5_0:  !VAA_ENABLE
+            | (1 <<  8) // P6_12: LED3 (TX)
+            | (1 <<  7) // P5_7:  CS_AD
+            | (1 <<  6) // P4_6:  XCVR_EN, 10K PD
+            | (1 <<  5) // P4_5:  RXENABLE
+            | (1 <<  4) // P4_4:  TXENABLE
+            | (0 <<  3) // P4_3:  SGPIO9, HOST_CAPTURE
+            | (1 <<  2) // P4_2:  LED2 (RX)
+            | (1 <<  1) // P4_1:  LED1 (USB)
+            | (1 <<  0) // P4_0:  HP
     },
     {   // GPIO3
         .data
-            = (0 << 15) // PortaPack GPIO3_15(IO)
-            | (0 << 14) // PortaPack GPIO3_14(IO)
-            | (0 << 13) // PortaPack GPIO3_13(IO)
-            | (0 << 12) // PortaPack GPIO3_12(IO)
-            | (0 << 11) // PortaPack GPIO3_11(IO)
-            | (0 << 10) // PortaPack GPIO3_10(IO)
-            | (0 <<  9) // PortaPack GPIO3_9(IO)
-            | (0 <<  8) // PortaPack GPIO3_8(IO)
-            | (0 <<  7) // VREGMODE
-            | (1 <<  6) // EN1V8, 10K PD
-            | (1 <<  5) // !TX_AMP_PWR, 10K PU
-            | (1 <<  4) // HackRF CPLD.TMS(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
-            | (1 <<  1) // HackRF CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
-            | (1 <<  0) // HackRF CPLD.TCK(I), PortaPack CPLD.TCK(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
+            = (1 << 15) // P7_7:  PortaPack GPIO3_15(IO)
+            | (1 << 14) // P7_6:  PortaPack GPIO3_14(IO)
+            | (1 << 13) // P7_5:  PortaPack GPIO3_13(IO)
+            | (1 << 12) // P7_4:  PortaPack GPIO3_12(IO)
+            | (1 << 11) // P7_3:  PortaPack GPIO3_11(IO)
+            | (1 << 10) // P7_2:  PortaPack GPIO3_10(IO)
+            | (1 <<  9) // P7_1:  PortaPack GPIO3_9(IO)
+            | (1 <<  8) // P7_0:  PortaPack GPIO3_8(IO)
+            | (1 <<  7) // P6_11: VREGMODE
+            | (1 <<  6) // P6_10: EN1V8, 10K PD
+            | (1 <<  5) // P6_9:  !TX_AMP_PWR, 10K PU
+            | (1 <<  4) // P6_5:  HackRF CPLD.TMS(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
+            | (1 <<  3) // P6_4:  MIXER_SDATA
+            | (1 <<  2) // P6_3:  SGPIO4, HOST_DATA4
+            | (1 <<  1) // P6_2:  HackRF CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
+            | (1 <<  0) // P6_1:  HackRF CPLD.TCK(I), PortaPack CPLD.TCK(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
             ,
         .dir
-            = (0 << 15) // PortaPack GPIO3_15(IO)
-            | (0 << 14) // PortaPack GPIO3_14(IO)
-            | (0 << 13) // PortaPack GPIO3_13(IO)
-            | (0 << 12) // PortaPack GPIO3_12(IO)
-            | (0 << 11) // PortaPack GPIO3_11(IO)
-            | (0 << 10) // PortaPack GPIO3_10(IO)
-            | (0 <<  9) // PortaPack GPIO3_9(IO)
-            | (0 <<  8) // PortaPack GPIO3_8(IO)
-            | (1 <<  7) // VREGMODE
-            | (1 <<  6) // EN1V8, 10K PD
-            | (1 <<  5) // !TX_AMP_PWR, 10K PU
-            | (0 <<  4) // HackRF CPLD.TMS(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
-            | (0 <<  1) // HackRF CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
-            | (0 <<  0) // HackRF CPLD.TCK(I), PortaPack CPLD.TCK(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
+            = (0 << 15) // P7_7:  PortaPack GPIO3_15(IO)
+            | (0 << 14) // P7_6:  PortaPack GPIO3_14(IO)
+            | (0 << 13) // P7_5:  PortaPack GPIO3_13(IO)
+            | (0 << 12) // P7_4:  PortaPack GPIO3_12(IO)
+            | (0 << 11) // P7_3:  PortaPack GPIO3_11(IO)
+            | (0 << 10) // P7_2:  PortaPack GPIO3_10(IO)
+            | (0 <<  9) // P7_1:  PortaPack GPIO3_9(IO)
+            | (0 <<  8) // P7_0:  PortaPack GPIO3_8(IO)
+            | (1 <<  7) // P6_11: VREGMODE
+            | (1 <<  6) // P6_10: EN1V8, 10K PD
+            | (1 <<  5) // P6_9:  !TX_AMP_PWR, 10K PU
+            | (0 <<  4) // P6_5:  HackRF CPLD.TMS(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
+            | (0 <<  3) // P6_4:  MIXER_SDATA
+            | (0 <<  2) // P6_3:  SGPIO4, HOST_DATA4
+            | (0 <<  1) // P6_2:  HackRF CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
+            | (0 <<  0) // P6_1:  HackRF CPLD.TCK(I), PortaPack CPLD.TCK(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
     },
     {   // GPIO4
-            .data = 0,
-            .dir = 0
+        .data
+            = (1 << 11) // P9_6:  SGPIO8, SGPIO_CLK
+            ,
+        .dir
+            = (0 << 11) // P9_6:  SGPIO8, SGPIO_CLK
     },
     {   // GPIO5
         .data
-            = (1 << 18) // HackRF CPLD.TDO(O) (input with pull up)
-            | (0 << 15) // TX
-            | (1 << 16) // MIX_BYPASS
-            | (1 <<  5) // RX
-            | (1 <<  4) // PortaPack P2_4/LCD_RDX
-            | (0 <<  3) // PortaPack P2_3/LCD_TE
-            | (0 <<  1) // PortaPack P2_1/ADDR
-            | (1 <<  0) // PortaPack P2_0/IO_STBX
+            = (1 << 18) // P9:5:  HackRF CPLD.TDO(O) (input with pull up)
+            | (1 << 16) // P6_8:  MIX_BYPASS
+            | (0 << 15) // P6_7:  TX
+            | (1 << 14) // P4_10: SGPIO15, CPLD (unused)
+            | (1 << 13) // P4_9:  SGPIO14, CPLD (unused)
+            | (0 << 12) // P4_8:  SGPIO13, HOST_SYNC_EN
+            | (1 << 11) // P3_8:  SPIFI_CS
+            | (1 << 10) // P3_7:  SPIFI_MOSI
+            | (1 <<  9) // P3_2:  I2S0_RX_SDA
+            | (1 <<  8) // P3_1:  I2S0_RX_WS
+            | (0 <<  7) // P2_8:  BOOT2
+            | (0 <<  6) // P2_6:  MIXER_SCLK
+            | (1 <<  5) // P2_5:  RX
+            | (1 <<  4) // P2_4:  PortaPack LCD_RDX
+            | (0 <<  3) // P2_3:  PortaPack LCD_TE
+            | (1 <<  2) // P2_2:  SGPIO6, HOST_DATA6
+            | (0 <<  1) // P2_1:  PortaPack ADDR
+            | (1 <<  0) // P2_0:  PortaPack IO_STBX
             ,
         .dir
-            = (0 << 18) // HackRF CPLD.TDO(O) (input with pull up)
-            | (1 << 16) // MIX_BYPASS
-            | (1 << 15) // TX
-            | (1 <<  5) // RX
-            | (1 <<  4) // PortaPack P2_4/LCD_RDX
-            | (0 <<  3) // PortaPack P2_3/LCD_TE
-            | (1 <<  1) // PortaPack P2_1/ADDR
-            | (1 <<  0) // PortaPack P2_0/IO_STBX
+            = (0 << 18) // P9_5:  HackRF CPLD.TDO(O) (input with pull up)
+            | (1 << 16) // P6_8:  MIX_BYPASS
+            | (1 << 15) // P6_7:  TX
+            | (0 << 14) // P4_10: SGPIO15, CPLD (unused)
+            | (0 << 13) // P4_9:  SGPIO14, CPLD (unused)
+            | (0 << 12) // P4_8:  SGPIO13, HOST_SYNC_EN
+            | (0 << 11) // P3_8:  SPIFI_CS
+            | (0 << 10) // P3_7:  SPIFI_MOSI
+            | (0 <<  9) // P3_2:  I2S0_RX_SDA
+            | (0 <<  8) // P3_1:  I2S0_RX_WS
+            | (0 <<  7) // P2_8:  BOOT2
+            | (0 <<  6) // P2_6:  MIXER_SCLK
+            | (1 <<  5) // P2_5:  RX
+            | (0 <<  4) // P2_4:  PortaPack LCD_RDX
+            | (0 <<  3) // P2_3:  PortaPack LCD_TE
+            | (0 <<  2) // P2_2:  SGPIO6, HOST_DATA6
+            | (0 <<  1) // P2_1:  PortaPack ADDR
+            | (0 <<  0) // P2_0:  PortaPack IO_STBX
     },
     {   // GPIO6
         .data = 0,
@@ -186,7 +257,7 @@ const PALConfig pal_default_config = {
     /* Configure GP_CLKIN as soon as possible. It's an output at boot time, and the Si5351C doesn't
      * reset when the reset button is pressed, so it could still be output enabled.
      */
-    {  4,  7, scu_config_normal_drive_t { .mode=1, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=1 } }, /* GP_CLKIN/P72/MCU_CLK: SI5351C.CLK7(O) */
+    {  4,  7, scu_config_normal_drive_t { .mode=1, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=1 } }, /* GP_CLKIN/P72/MCU_CLK: SI5351C.CLK7(O) */
 
     /* HackRF: LEDs. Configured early so we can use them to indicate boot status. */
     {  4,  1, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* LED1: LED1.A(I) */
@@ -221,12 +292,12 @@ const PALConfig pal_default_config = {
     },
 
     /* Radio section control */
-    {  1,  3, scu_config_normal_drive_t { .mode=5, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* SSP1_MISO/P41: MAX2837.DOUT(O) */
-    {  1,  4, scu_config_normal_drive_t { .mode=5, .epd=1, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* SSP1_MOSI/P40: MAX2837.DIN(I), MAX5864.DIN(I) */
+    {  1,  3, scu_config_normal_drive_t { .mode=5, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* SSP1_MISO/P41: MAX2837.DOUT(O) */
+    {  1,  4, scu_config_normal_drive_t { .mode=5, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* SSP1_MOSI/P40: MAX2837.DIN(I), MAX5864.DIN(I) */
     {  1,  7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* !MIX_BYPASS/P35: U1.VCTL1(I), U11.VCTL2(I), U9.V2(I) */
-    {  1, 19, scu_config_normal_drive_t { .mode=1, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */
+    {  1, 19, scu_config_normal_drive_t { .mode=1, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */
     {  1, 20, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CS_XCVR/P53: MAX2837.CS(I) */
-    {  2,  5, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* RX/P43: U7.VCTL1(I), U10.VCTL1(I), U2.VCTL1(I) */
+    {  2,  5, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* RX/P43: U7.VCTL1(I), U10.VCTL1(I), U2.VCTL1(I) */
     {  2,  6, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* MIXER_SCLK/P31: 33pF, RFFC5072.SCLK(I) */
     {  2, 10, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */
     {  2, 11, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* RX_AMP/P49: U12.V1(I), U14.V3(I) */
@@ -242,7 +313,7 @@ const PALConfig pal_default_config = {
     {  5,  5, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* MIXER_RESETX/P33: 10K PU, 33pF, RFFC5072.RESETX(I) */
     {  5,  6, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* TX_AMP/P48: U12.V3(I), U14.V1(I) */
     {  5,  7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CS_AD/P54: MAX5864.CS(I) */
-    {  6,  4, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* MIXER_SDATA/P27: 33pF, RFFC5072.SDATA(IO) */
+    {  6,  4, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* MIXER_SDATA/P27: 33pF, RFFC5072.SDATA(IO) */
     {  6,  7, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* TX/P42: U7.VCTL2(I), U10.VCTL2(I), U2.VCTL2(I) */
     {  6,  8, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* MIX_BYPASS/P34: U1.VCTL2(I), U11.VCTL1(I) */
     {  6,  9, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* !TX_AMP_PWR/P51: 10K PU, Q2.G(I), power to U25 (TX amp) */
@@ -256,11 +327,11 @@ const PALConfig pal_default_config = {
     {  6,  6, scu_config_normal_drive_t { .mode=2, .epd=0, .epun=1, .ehs=1, .ezi=1, .zif=1 } }, /* SGPIO5/BANK2F3M15: CPLD.64/HOST_DATA5(IO) */
     {  2,  2, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=1, .ezi=1, .zif=1 } }, /* SGPIO6/BANK2F3M16: CPLD.61/HOST_DATA6(IO) */
     {  1,  0, scu_config_normal_drive_t { .mode=6, .epd=0, .epun=1, .ehs=1, .ezi=1, .zif=1 } }, /* SGPIO7/P76/BANK2F3M7: CPLD.77/HOST_DATA7(IO) */
-    {  9,  6, scu_config_normal_drive_t { .mode=6, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=1 } }, /* SGPIO8/SGPIO_CLK/P60: SI5351C.CLK2(O) */
+    {  9,  6, scu_config_normal_drive_t { .mode=6, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=1 } }, /* SGPIO8/SGPIO_CLK/P60: SI5351C.CLK2(O) */
     {  4,  3, scu_config_normal_drive_t { .mode=7, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=1 } }, /* SGPIO9/P77/BANK2F3M1: CPLD.91/HOST_CAPTURE(O) */
     {  1, 14, scu_config_normal_drive_t { .mode=6, .epd=0, .epun=0, .ehs=1, .ezi=0, .zif=0 } }, /* SGPIO10/P78/BANK2F3M8: CPLD.76/HOST_DISABLE(I) */
-    {  1, 17, scu_config_normal_drive_t { .mode=6, .epd=0, .epun=0, .ehs=1, .ezi=0, .zif=0 } }, /* SGPIO11/P79/BANK2F3M11: CPLD.71/HOST_DIRECTION(I) */
-    {  1, 18, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_INVERT(I) */
+    {  1, 17, scu_config_normal_drive_t { .mode=6, .epd=1, .epun=1, .ehs=1, .ezi=0, .zif=0 } }, /* SGPIO11/P79/BANK2F3M11: CPLD.71/HOST_DIRECTION(I) */
+    {  1, 18, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_INVERT(I) */
     {  4,  8, scu_config_normal_drive_t { .mode=4, .epd=1, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* SGPIO13/BANK2F3M2: CPLD.90/HOST_SYNC_EN(I) */
     {  4,  9, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* SGPIO14/BANK2F3M4: CPLD.81/CPLD_P81 */
     {  4, 10, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* SGPIO15/BANK2F3M6: CPLD.78/CPLD_P78 */
@@ -269,11 +340,23 @@ const PALConfig pal_default_config = {
     {  6,  1, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CPLD_TCK: CPLD.TCK(I), PortaPack CPLD.TCK(I) */
     {  6,  2, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* CPLD_TDI: CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) */
     {  6,  5, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CPLD_TMS: CPLD.TMS(I) */
-    {  9,  5, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* CPLD_TDO: CPLD.TDO(O) */
+    {  9,  5, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* CPLD_TDO: CPLD.TDO(O) */
 
-    /* PortaPack */
+    /* PortaPack CPLD */
     {  1,  5, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* SD_POW: PortaPack CPLD.TDO(O) */
     {  1,  8, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* SD_VOLT0: PortaPack CPLD.TMS(I) */
+
+    /* Miscellaneous */
+    {  1,  1, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* P1_1/P74: 10K PU, BOOT0 */
+    {  1,  2, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* P1_2/P73: 10K PD, BOOT1 */
+    {  2,  7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* ISP: 10K PU, Unused */
+    {  6,  0, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* I2S0_RX_MCLK: Unused */
+    { 15,  4, scu_config_normal_drive_t { .mode=7, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* I2S0_RX_SCK: Unused */
+  }
+};
+#endif
+
+static const std::array<scu_setup_t, 26> pins_setup_portapack { {
     {  2,  0, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* U0_TXD: PortaPack P2_0/IO_STBX */
     {  2,  1, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* U0_RXD: PortaPack P2_1/ADDR */
     {  2,  3, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* I2C1_SDA: PortaPack P2_3/LCD_TE */
@@ -281,14 +364,14 @@ const PALConfig pal_default_config = {
     {  2,  8, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* P2_8: 10K PD, BOOT2, DFU switch, PortaPack P2_8/<unused> */
     {  2,  9, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* P2_9: 10K PD, BOOT3, PortaPack P2_9/LCD_WRX */
     {  2, 13, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* P2_13: PortaPack P2_13/DIR */
-    {  7,  0, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_8: PortaPack GPIO3_8(IO) */
-    {  7,  1, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_9: PortaPack GPIO3_9(IO) */
-    {  7,  2, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_10: PortaPack GPIO3_10(IO) */
-    {  7,  3, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_11: PortaPack GPIO3_11(IO) */
-    {  7,  4, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_12: PortaPack GPIO3_12(IO) */
-    {  7,  5, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_13: PortaPack GPIO3_13(IO) */
-    {  7,  6, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_14: PortaPack GPIO3_14(IO) */
-    {  7,  7, scu_config_normal_drive_t { .mode=0, .epd=1, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_15: PortaPack GPIO3_15(IO) */
+    {  7,  0, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_8: PortaPack GPIO3_8(IO) */
+    {  7,  1, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_9: PortaPack GPIO3_9(IO) */
+    {  7,  2, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_10: PortaPack GPIO3_10(IO) */
+    {  7,  3, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_11: PortaPack GPIO3_11(IO) */
+    {  7,  4, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_12: PortaPack GPIO3_12(IO) */
+    {  7,  5, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_13: PortaPack GPIO3_13(IO) */
+    {  7,  6, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_14: PortaPack GPIO3_14(IO) */
+    {  7,  7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_15: PortaPack GPIO3_15(IO) */
 
     /* PortaPack: Audio */
     {  3,  0, scu_config_normal_drive_t { .mode=2, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* I2S0_TX_SCK: PortaPack I2S0_TX_SCK(I) */
@@ -304,16 +387,7 @@ const PALConfig pal_default_config = {
     {  1, 11, scu_config_normal_drive_t { .mode=7, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=1 } }, /* SD_DAT2: PortaPack SD.DAT2(IO) */
     {  1, 12, scu_config_normal_drive_t { .mode=7, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=1 } }, /* SD_DAT3: PortaPack SD.DAT3(IO) */
     {  1, 13, scu_config_normal_drive_t { .mode=7, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* SD_CD: PortaPack SD.CD(O) */
-
-    /* Miscellaneous */
-    {  1,  1, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* P1_1/P74: 10K PU, BOOT0 */
-    {  1,  2, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* P1_2/P73: 10K PD, BOOT1 */
-    {  2,  7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* ISP: 10K PU, Unused */
-    {  6,  0, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* I2S0_RX_MCLK: Unused */
-    { 15,  4, scu_config_normal_drive_t { .mode=7, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* I2S0_RX_SCK: Unused */
-  }
-};
-#endif
+} };
 
 static const std::array<scu_setup_t, 6> pins_setup_spifi { {
     {  3,  3, scu_config_normal_drive_t { .mode=3, .epd=0, .epun=1, .ehs=1, .ezi=1, .zif=1 } }, /* SPIFI_SCK: W25Q80BV.CLK(I), enable input buffer for timing feedback */
@@ -361,6 +435,13 @@ static void configure_spifi(void) {
         ;
 }
 
+void configure_pins_portapack(void) {
+    LPC_GPIO->DIR[1] |= (1 << 13) | (1 << 10);
+    LPC_GPIO->DIR[3] |= (0xff << 8);
+    LPC_GPIO->DIR[5] |= (1 <<  4) | (1 <<  1) | (1 <<  0);
+    setup_pins(pins_setup_portapack);
+}
+
 static const motocon_pwm_resources_t motocon_pwm_resources = {
   .base = { .clk = &LPC_CGU->BASE_APB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 1) },
   .branch = { .cfg = &LPC_CCU1->CLK_APB1_MOTOCON_PWM_CFG, .stat = &LPC_CCU1->CLK_APB1_MOTOCON_PWM_STAT },
diff --git a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.h b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.h
index c65fa732e5c7102a9d969fe89555cb5976114f1d..972e360fae49d0d7f52a37d0c26aebbedc30d91f 100755
--- a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.h
+++ b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.h
@@ -35,6 +35,8 @@ extern "C" {
 #endif
   void boardInit(void);
 
+  void configure_pins_portapack(void);
+
   void vaa_power_on(void);
   void vaa_power_off(void);
 #ifdef __cplusplus
diff --git a/firmware/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.h b/firmware/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.h
index 925c60f9a612258ad5356aabb4621f0c03e26f49..f76694632c442b527d5737a146e08f7882a16da5 100644
--- a/firmware/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.h
+++ b/firmware/chibios-portapack/os/hal/platforms/LPC43xx/pal_lld.h
@@ -53,7 +53,7 @@
 typedef struct {
   /** @brief GPIO setup data.*/
   gpio_setup_t    P[8];
-  scu_setup_t     SCU[86];
+  scu_setup_t     SCU[60];
 } PALConfig;
 
 /**
diff --git a/firmware/tools/extract_svf_data_xc2c64a.py b/firmware/tools/extract_svf_data_xc2c64a.py
deleted file mode 100755
index a82ca538231fe2f88c71e66d4bba9f3eef3c7231..0000000000000000000000000000000000000000
--- a/firmware/tools/extract_svf_data_xc2c64a.py
+++ /dev/null
@@ -1,343 +0,0 @@
-#!/usr/bin/env python
-
-#
-# Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
-#
-# This file is part of PortaPack.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-#
-
-# Very fragile code to extract data from Xilinx XC2C64A CPLD SVF
-
-import sys
-import re
-import os.path
-import argparse
-
-def crack_variable_path(variable_path):
-	tmp = args.variable_path.split('::')
-	namespaces, variable_name = tmp[:-1], tmp[-1]
-	return namespaces, variable_name
-
-parser = argparse.ArgumentParser()
-parser.add_argument('input_file_path', type=str)
-parser.add_argument('variable_path', type=str)
-# parser.add_argument('header_file_path', type=str)
-parser.add_argument('data_file_path', type=str)
-args = parser.parse_args()
-
-f = open(args.input_file_path, 'r')
-namespaces, variable_name = crack_variable_path(args.variable_path)
-
-def to_hex(value, length_bits):
-	return ('%x' % value).zfill((length_bits + 3) >> 2)
-
-def long_int_to_bytes(n, bit_count):
-	byte_count = (bit_count + 7) >> 3
-	h = ('%x' % n).zfill(byte_count * 2)
-	return [int(h[n:n+2], 16) for n in range(0, len(h), 2)]
-
-re_sdr = re.compile(r'^(?P<length>\d+)\s*TDI\s*\((?P<tdi>[0-9A-F]+)\)(|\s*SMASK\s*\((?P<smask>[0-9A-F]+)\))(|\s*TDO\s*\((?P<tdo>[0-9A-F]+)\))(|\s*MASK\s*\((?P<mask>[0-9A-F]+)\))\s*;$')
-re_sir = re_sdr
-
-class SIR_or_SDR(object):	
-	def __init__(self, name, s):
-		self.name = name
-		match = re_sdr.match(s)
-		self.length = int(match.group('length'))
-		self.tdi = self._bits(match.group('tdi'))
-		self.smask = self._optional_bits(match.group('smask'))
-		self.tdo = self._optional_bits(match.group('tdo'))
-		self.mask = self._optional_bits(match.group('mask'))
-
-	def __repr__(self):
-		result = [self.name, str(self.length)]
-		result.append('TDI (%s)' % to_hex(self.tdi, self.length))
-		if self.smask:
-			result.append('SMASK (%s)' % to_hex(self.smask, self.length))
-		if self.tdo:
-			result.append('TDO (%s)' % to_hex(self.tdo, self.length))
-		if self.mask:
-			result.append('MASK (%s)' % to_hex(self.mask, self.length))
-		result.append(';')
-		return ' '.join(result)
-
-	def _bits(self, matched):
-		return int(matched, 16)
-
-	def _optional_bits(self, matched):
-		return self._bits(matched) if matched else None
-
-class SDR(SIR_or_SDR):
-	def __init__(self, s):
-		SIR_or_SDR.__init__(self, 'SDR', s)
-
-class SIR(SIR_or_SDR):
-	def __init__(self, s):
-		SIR_or_SDR.__init__(self, 'SIR', s)
-
-class SVFParser(object):
-	instruction_parsers = {
-		'SIR': SIR,
-		'SDR': SDR,	
-	}
-
-	def parse(self, f, instruction_handler_map):
-		complete_line = ''
-		for line in f:
-			line = line.strip().upper()
-			if line.startswith('//'):
-				continue
-
-			complete_line += line
-			if not line.endswith(';'):
-				continue
-
-			instruction_name, args_string = complete_line.split(None, 1)
-			instruction = self.instruction_parser(instruction_name, args_string)
-			if instruction:
-				instruction_type = type(instruction)
-				if instruction_type in instruction_handler_map:
-					instruction_handler_map[instruction_type](instruction)
-
-			if complete_line.endswith(';'):
-				complete_line = ''
-
-	def instruction_parser(self, instruction_name, args_string):
-		if instruction_name in self.instruction_parsers:
-			parser = self.instruction_parsers[instruction_name]
-			return parser(args_string)
-		else:
-			return None
-
-class ProgramExtractor(object):
-	idcode = int('0bXXXX0110111001011XXX000010010011'.replace('X', '0'), 2)
-	idcode_mask = None
-	id_bits = 7
-	block_bits = 274
-	block_ordinals = frozenset(list(range(64)) + list(range(80, 82)) + list(range(96, 128)))
-	block_count = len(block_ordinals)
-
-	def __init__(self):
-		self.tap_instruction = None
-		self.program_data = []
-		self.verify_data = []
-		self.sdr_smask = None
-		self.sdr_mask = None
-
-	def map(self):
-		return {
-			SIR: self.on_sir,
-			SDR: self.on_sdr,
-		}
-
-	def on_sir(self, o):
-		assert(o.length == 8)
-
-		if o.tdi == 0x01:
-			self.tap_instruction = 'idcode'
-		elif o.tdi == 0xea:
-			self.tap_instruction = 'program'
-			self.program_data.append([])
-		elif o.tdi == 0xee:
-			self.tap_instruction = 'verify'
-			self.verify_data.append([])
-			self.verify_block_id = None
-		else:
-			self.tap_instruction = None
-
-	def on_sdr(self, o):
-		if o.smask:
-			self.sdr_smask = o.smask
-		if o.mask:
-			self.sdr_mask = o.mask
-
-		if self.tap_instruction == 'idcode':
-			assert(o.length == 32)
-			assert(self.sdr_smask == 0xffffffff)
-			assert((o.tdo & self.sdr_mask) == self.idcode)
-			if self.idcode_mask is None:
-				self.idcode_mask = self.sdr_mask
-			else:
-				assert(self.idcode_mask == self.sdr_mask)
-
-		elif self.tap_instruction == 'program':
-			assert(o.length == (self.id_bits + self.block_bits))
-			assert(self.sdr_smask == ((1 << o.length) - 1))
-			assert(o.tdo is None)
-			assert(o.mask is None)
-			block_id = o.tdi >> (o.length - 7)
-			mask = (1 << (o.length - 7)) - 1
-			self.program_data[-1].append({
-				'id': block_id,
-				'tdi': o.tdi & mask,
-				'length': o.length - 7,
-			})
-		elif self.tap_instruction == 'verify':
-			assert(o.length in (self.id_bits, self.block_bits))
-
-			if o.length == self.id_bits:
-				assert(o.smask == ((1 << self.id_bits) - 1))
-				assert(o.tdo is None)
-				assert(o.mask is None)
-				self.verify_block_id = o.tdi
-
-			elif o.length == self.block_bits:
-				assert(o.tdi == (1 << o.length) - 1)
-				assert(o.smask == (1 << o.length) - 1)
-				self.verify_data[-1].append({
-					'id': self.verify_block_id,
-					'tdo': o.tdo,
-					'mask': o.mask,
-					'length': o.length,
-				})
-				self.verify_block_id = None
-
-program_extractor = ProgramExtractor()
-
-parser = SVFParser()
-parser.parse(f, program_extractor.map())
-
-def has_all_blocks(blocks):
-	ordinals = set()
-
-	for block in blocks:
-		ordinal = int(bin(block['id'])[2:].zfill(7)[::-1], 2)
-		ordinals.add(ordinal)
-
-	return ordinals == program_extractor.block_ordinals
-
-def is_verify_blank(blocks):
-	for block in blocks:
-		length = block['length']
-		mask = (1 << length) - 1
-		if block['tdo'] != mask:
-			return False
-		if block['mask'] != mask:
-			return False
-	return True
-
-def deduplicate(passes):
-	result = [passes[0]]
-	for this_pass in passes[1:]:
-		if this_pass != result[0]:
-			result.append(this_pass)
-	return result
-
-def program_and_verify_match(program, verify):
-	for program_block, verify_block in zip(program, verify):
-		if program_block['tdi'] != verify_block['tdo']:
-			return False
-	return True
-
-program_passes = [blocks for blocks in program_extractor.program_data if has_all_blocks(blocks)]
-program_done = [blocks for blocks in program_extractor.program_data if len(blocks) == 1][0]
-if len(program_passes) == 0:
-	raise RuntimeError('no complete program passes')
-if len(program_passes) > 1:
-	raise RuntimeError('too many program passes')
-program = program_passes[0]
-
-verify_passes = [blocks for blocks in program_extractor.verify_data if has_all_blocks(blocks) and not is_verify_blank(blocks)]
-verify_passes = deduplicate(verify_passes)
-if len(verify_passes) == 0:
-	raise RuntimeError('no complete verify passes')
-if len(verify_passes) > 1:
-	raise RuntimeError('too many verify passes')
-verify = verify_passes[0]
-
-if not program_and_verify_match(program, verify):
-	raise RuntimeError('program and verify data do not match')
-
-class FileGen(object):
-	def comment_header(self):
-		return ['/*' , ' * WARNING: Auto-generated file. Do not edit.', '*/']
-
-	def includes(self, filenames):
-		return ['#include "%s"' % filename for filename in filenames]
-
-	def _namespaces(self, ns_list, line_format):
-		return [line_format % ns for ns in ns_list]
-
-	def namespaces_start(self, ns_list):
-		return self._namespaces(ns_list, 'namespace %s {')
-		
-	def namespaces_end(self, ns_list):
-		return self._namespaces(ns_list, '} /* namespace %s */')
-
-	def verify_block(self, block):
-		tdo_bytes = long_int_to_bytes(block['tdo'], block['length'])
-		mask_bytes = long_int_to_bytes(block['mask'], block['length'])
-		tdo_cpp_s = ', '.join(['0x%02x' % b for b in tdo_bytes]);
-		mask_cpp_s = ', '.join(['0x%02x' % b for b in mask_bytes]);
-		return '\t{ 0x%02x, { { %s } }, { { %s } } },' % (block['id'], tdo_cpp_s, mask_cpp_s)
-
-	def verify_blocks_declaration(self, type_name, variable_name):
-		return ['extern const %s %s;' % (type_name, variable_name)]
-
-	def verify_blocks_definition(self, type_name, variable_name, blocks):
-		return ['const %s %s { {' % (type_name, variable_name)] \
-			+ [self.verify_block(block) for block in blocks] \
-			+ ['} };']
-
-	# def cpp_program_t(block):
-	# 	tdi_bytes = long_int_to_bytes(block['tdi'], block['length'])
-	# 	tdi_cpp_s = ', '.join(['0x%02x' % b for b in tdi_bytes]);
-	# 	return '0x%02x, { { %s } }' % (block['id'], tdi_cpp_s)
-
-	def __repr__(self):
-		return '\n'.join(self.lines)
-
-	def to_file(self, file_path):
-		f = open(file_path, 'w')
-		f.write(str(self))
-		f.close()
-
-class HeaderGen(FileGen):
-	def __init__(self, includes, namespaces, type_name, variable_name):
-		self.lines = self.comment_header() \
-			+ self.includes(includes) \
-			+ self.namespaces_start(namespaces) \
-			+ self.verify_blocks_declaration(type_name, variable_name) \
-			+ self.namespaces_end(namespaces) \
-			+ ['']
-
-class DataGen(FileGen):
-	def __init__(self, includes, namespaces, type_name, variable_name, verify_blocks):
-		self.lines = self.comment_header() \
-			+ self.includes(includes) \
-			+ self.namespaces_start(namespaces) \
-			+ self.verify_blocks_definition(type_name, variable_name, verify_blocks) \
-			+ self.namespaces_end(namespaces) \
-			+ ['']
-
-# Tricky (a.k.a. "brittle") code to set DONE bit
-for block in verify:
-	if block['id'] == 0x05:
-		block['tdo'] = program_done[0]['tdi']
-
-# header_file_name = os.path.split(args.header_file_path)[1]
-header_file_name = 'hackrf_cpld_data.hpp'
-
-# header_includes = ('cpld_xilinx.hpp',)
-data_includes = (header_file_name,)
-
-type_name = '::cpld::xilinx::XC2C64A::verify_blocks_t'
-
-# HeaderGen(header_includes, namespaces, type_name, variable_name).to_file(args.header_file_path)
-DataGen(data_includes, namespaces, type_name, variable_name, verify).to_file(args.data_file_path)
-
diff --git a/firmware/tools/make_image_chunk.py b/firmware/tools/make_image_chunk.py
index ed3463bc34ee4b8ddfeaa46dd6bada0c886c8e66..5bcf4fb47526ac0e4dda89586a065d6f4a4c9ee3 100755
--- a/firmware/tools/make_image_chunk.py
+++ b/firmware/tools/make_image_chunk.py
@@ -27,7 +27,7 @@ import struct
 usage_message = """
 PortaPack image chunk writer
 
-Usage: <command> <input_binary> <four-characer tag> <output_tagged_binary>
+Usage: <command> <input_binary> <four-characer tag> <output_tagged_binary> [<chunk max size>]
 """
 
 def read_image(path):
@@ -41,10 +41,13 @@ def write_image(data, path):
 	f.write(data)
 	f.close()
 
-if len(sys.argv) == 4:
+input_image_max_length = 32768
+if len(sys.argv) in (4, 5):
 	input_image = read_image(sys.argv[1])
 	tag = tuple(map(ord, sys.argv[2]))
 	output_path = sys.argv[3]
+	if len(sys.argv) == 5:
+		input_image_max_length = int(sys.argv[4])
 elif len(sys.argv) == 2:
 	input_image = bytearray()
 	tag = (0, 0, 0, 0)
@@ -57,7 +60,6 @@ if len(tag) != 4:
 	print(usage_message)
 	sys.exit(-2)
 
-input_image_max_length = 32768
 if len(input_image) > input_image_max_length:
 	raise RuntimeError('image size of %d exceeds device size of %d bytes' % (len(input_image), input_image_max_length))
 if (len(input_image) & 3) != 0: