aboutsummaryrefslogtreecommitdiff
path: root/contrib/firmware/angie
diff options
context:
space:
mode:
authorAhmed BOUDJELIDA <aboudjelida@nanoxplore.com>2023-06-16 23:19:05 +0200
committerAntonio Borneo <borneo.antonio@gmail.com>2023-08-12 16:42:19 +0000
commit9c91ce8d24d0789a0f25affb73201c9e0a6b89d8 (patch)
tree7782a66ae9474632384136dac1c6723332d0c488 /contrib/firmware/angie
parent3b78b5c1db68841fdc18ee48b6011f4affff2bfd (diff)
downloadriscv-openocd-9c91ce8d24d0789a0f25affb73201c9e0a6b89d8.zip
riscv-openocd-9c91ce8d24d0789a0f25affb73201c9e0a6b89d8.tar.gz
riscv-openocd-9c91ce8d24d0789a0f25affb73201c9e0a6b89d8.tar.bz2
contrib/firmware: add new adapter ANGIE's firmware/bitstream code
This is ANGIE's firmware and bitstream code. The 'Embeded C' code is based on the openULINK project. The hdl bitstream source code is for the spartan-6 FPGA included in ANGIE. Since ANGIE has a different microcontroller (EZ-USB FX2) than openULINK (EZ-USB AN2131), the registers file (reg_ezusb.h) has been changed completely, so are the descriptors, interruptions and the endpoints configuration. Change-Id: I70590c7c58bac6f1939c5ffba57e87d86850664d Signed-off-by: Ahmed BOUDJELIDA <aboudjelida@nanoxplore.com> Reviewed-on: https://review.openocd.org/c/openocd/+/7701 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Diffstat (limited to 'contrib/firmware/angie')
-rw-r--r--contrib/firmware/angie/c/Makefile75
-rw-r--r--contrib/firmware/angie/c/README37
-rw-r--r--contrib/firmware/angie/c/include/delay.h50
-rw-r--r--contrib/firmware/angie/c/include/fx2macros.h31
-rw-r--r--contrib/firmware/angie/c/include/io.h65
-rw-r--r--contrib/firmware/angie/c/include/jtag.h31
-rw-r--r--contrib/firmware/angie/c/include/msgtypes.h171
-rw-r--r--contrib/firmware/angie/c/include/protocol.h20
-rw-r--r--contrib/firmware/angie/c/include/reg_ezusb.h656
-rw-r--r--contrib/firmware/angie/c/include/serial.h47
-rw-r--r--contrib/firmware/angie/c/include/usb.h273
-rw-r--r--contrib/firmware/angie/c/src/USBJmpTb.a51125
-rw-r--r--contrib/firmware/angie/c/src/delay.c49
-rw-r--r--contrib/firmware/angie/c/src/gpif.c98
-rw-r--r--contrib/firmware/angie/c/src/jtag.c674
-rw-r--r--contrib/firmware/angie/c/src/main.c85
-rw-r--r--contrib/firmware/angie/c/src/protocol.c189
-rw-r--r--contrib/firmware/angie/c/src/serial.c77
-rw-r--r--contrib/firmware/angie/c/src/usb.c784
-rw-r--r--contrib/firmware/angie/hdl/Makefile109
-rw-r--r--contrib/firmware/angie/hdl/README18
-rw-r--r--contrib/firmware/angie/hdl/set_env.sh14
-rw-r--r--contrib/firmware/angie/hdl/src/angie_openocd.ucf35
-rw-r--r--contrib/firmware/angie/hdl/src/angie_openocd.vhd66
24 files changed, 3779 insertions, 0 deletions
diff --git a/contrib/firmware/angie/c/Makefile b/contrib/firmware/angie/c/Makefile
new file mode 100644
index 0000000..80e8cbe
--- /dev/null
+++ b/contrib/firmware/angie/c/Makefile
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#****************************************************************************
+# File : Makefile *
+# Contents : Code for NanoXplore USB-JTAG ANGIE adapter hardware. *
+# Based on openULINK project by: Martin Schmoelzer. *
+# Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+# <aboudjelida@nanoxplore.com> *
+# <ahmederrachedbjld@gmail.com> *
+# ***************************************************************************/
+
+# Define the name of tools.
+PREFIX =
+
+# Small Device C Compiler: http://sdcc.sourceforge.net/
+CC = $(PREFIX)sdcc
+
+# 8051 assembler, part of the SDCC software package.
+AS = $(PREFIX)sdas8051
+
+# SDCC produces quite messy Intel HEX files. This tool is be used to re-format
+# those files. It is not required for the firmware download functionality in
+# the OpenOCD driver, but the resulting file is smaller.
+PACKIHX = $(PREFIX)packihx
+
+# GNU binutils size. Used to print the size of the IHX file generated by SDCC.
+SIZE = size
+
+# Source and header directories.
+SRC_DIR = src
+INCLUDE_DIR = include
+
+CODE_SIZE = 0x3C00
+XRAM_LOC = 0x3C00
+XRAM_SIZE = 0x0400
+
+CFLAGS = --std-sdcc99 --opt-code-size --model-small
+LDFLAGS = --code-loc 0x0000 --code-size $(CODE_SIZE) --xram-loc $(XRAM_LOC) \
+ --xram-size $(XRAM_SIZE) --iram-size 256 --model-small
+
+# list of base object files
+OBJECTS = main.rel usb.rel protocol.rel jtag.rel delay.rel USBJmpTb.rel serial.rel gpif.rel
+HEADERS = $(INCLUDE_DIR)/usb.h \
+ $(INCLUDE_DIR)/protocol.h \
+ $(INCLUDE_DIR)/jtag.h \
+ $(INCLUDE_DIR)/delay.h \
+ $(INCLUDE_DIR)/reg_ezusb.h \
+ $(INCLUDE_DIR)/io.h \
+ $(INCLUDE_DIR)/serial.h \
+ $(INCLUDE_DIR)/fx2macros.h \
+ $(INCLUDE_DIR)/msgtypes.h
+
+# Disable all built-in rules.
+.SUFFIXES:
+
+# Targets which are executed even when identically named file is present.
+.PHONY: all, clean
+
+all: angie_firmware.ihx
+ $(SIZE) angie_firmware.ihx
+
+angie_firmware.ihx: $(OBJECTS)
+ $(CC) -mmcs51 $(LDFLAGS) -o $@ $^
+
+# Rebuild every C module (there are only 5 of them) if any header changes.
+%.rel: $(SRC_DIR)/%.c $(HEADERS)
+ $(CC) -c $(CFLAGS) -mmcs51 -I$(INCLUDE_DIR) -o $@ $<
+
+%.rel: $(SRC_DIR)/%.a51
+ $(AS) -lsgo $@ $<
+
+clean:
+ rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lk *.map *.mem
+
+bin: angie_firmware.ihx
+ makebin -p angie_firmware.ihx angie_firmware.bin
diff --git a/contrib/firmware/angie/c/README b/contrib/firmware/angie/c/README
new file mode 100644
index 0000000..04ed0be
--- /dev/null
+++ b/contrib/firmware/angie/c/README
@@ -0,0 +1,37 @@
+#SPDX-License-Identifier: GPL-2.0-or-later
+
+This is the ANGIE firmware for ANGIE USB-JTAG adapter.
+
+The main components of ANGIE adapter are:
+- Cypress EZ-USB FX2 microcontroller
+- Spartan-6 FPGA
+- SRAM memory chip
+- Pin headers for various JTAG pin assignments
+
+To compile the firmware, the SDCC compiler package is required. Most Linux
+distributions include SDCC in their official package repositories. The SDCC
+source code can be found at http://sdcc.sourceforge.net/
+
+Simply type "make hex" in the ANGIE directory to compile the firmware.
+"make clean" will remove all generated files except the Intel HEX file
+required for downloading the firmware to ANGIE.
+
+Note that the EZ-USB FX2 microcontroller does not have on-chip flash,
+ANGIE include on-board EEPROM memory to store the firmware program of
+the FX2, but we are not going to use this method.
+
+Instead, upon initial connection of the ANGIE adapter to the host PC
+via USB, the EZ-USB FX2 core has enough intelligence to act as a
+stand-alone USB device, responding to USB control requests and allowing
+firmware download via a special VENDOR-type control request. Then, the
+EZ-USB microcontroller simulates a disconnect and re-connect to the USB bus.
+It may take up to two seconds for the host to recognize the newly connected
+device before OpenOCD can proceed to execute JTAG commands. This delay is
+only visible when OpenOCD first uses a blank (unconfigured) ANGIE device.
+
+Once the firmware downloaded, the FX2 microcontroller activate its GPIF mode,
+download the Spartan-6 FPGA's bitstream, program the FPGA rapidly, and switch
+back to default io mode.
+
+Once the user disconnects the ANGIE adapter, all its memory contents are lost
+and the firmware & bitstream download process has to be executed again.
diff --git a/contrib/firmware/angie/c/include/delay.h b/contrib/firmware/angie/c/include/delay.h
new file mode 100644
index 0000000..0397941
--- /dev/null
+++ b/contrib/firmware/angie/c/include/delay.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/****************************************************************
+ File : delay.h *
+ Contents : Delays handling header file for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************/
+
+#ifndef __DELAY_H
+#define __DELAY_H
+
+#include <stdint.h>
+
+void syncdelay(uint8_t count);
+void delay_5us(void);
+void delay_1ms(void);
+void delay_us(uint16_t delay);
+void delay_ms(uint16_t delay);
+
+#ifndef _IFREQ
+#define _IFREQ 48000 /* IFCLK frequency in kHz */
+#endif
+
+/* CFREQ can be any one of: 48000, 24000, or 12000 */
+#ifndef _CFREQ
+#define _CFREQ 48000 /* CLKOUT frequency in kHz */
+#endif
+
+#if (_IFREQ < 5000)
+#error "_IFREQ too small! Valid Range: 5000 to 48000..."
+#endif
+
+#if (_IFREQ > 48000)
+#error "_IFREQ too large! Valid Range: 5000 to 48000..."
+#endif
+
+#if (_CFREQ != 48000)
+#if (_CFREQ != 24000)
+#if (_CFREQ != 12000)
+#error "_CFREQ invalid! Valid values: 48000, 24000, 12000..."
+#endif
+#endif
+#endif
+
+/* Synchronization Delay formula: see TRM section 15-14 */
+#define _SCYCL (3 * (_CFREQ) + 5 * (_IFREQ) - 1) / (2 * (_IFREQ))
+#endif
diff --git a/contrib/firmware/angie/c/include/fx2macros.h b/contrib/firmware/angie/c/include/fx2macros.h
new file mode 100644
index 0000000..9067b56
--- /dev/null
+++ b/contrib/firmware/angie/c/include/fx2macros.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+/*
+ * This code was taken from the fx2lib project from this link:
+ * https://github.com/djmuhlestein/fx2lib
+ *
+ * Copyright (C) 2009 Ubixum, Inc.
+*/
+
+/*! \file
+ * Macros for simple common tasks in fx2 firmware.
+ * */
+
+#ifndef FX2MACROS_H
+#define FX2MACROS_H
+
+#include "reg_ezusb.h"
+
+typedef enum {FALSE = 0, TRUE} BOOL_VALS;
+
+/**
+ * \brief Used for getting and setting the CPU clock speed.
+ **/
+typedef enum {CLK_12M = 0, CLK_24M, CLK_48M} CLK_SPD;
+
+/**
+ * \brief Evaluates to a CLK_SPD enum.
+ **/
+#define CPUFREQ (CLK_SPD)((CPUCS & bmclkspd) >> 3)
+
+#endif
diff --git a/contrib/firmware/angie/c/include/io.h b/contrib/firmware/angie/c/include/io.h
new file mode 100644
index 0000000..35afa62
--- /dev/null
+++ b/contrib/firmware/angie/c/include/io.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/****************************************************************************
+ File : io.h *
+ Contents : input/output declaration header file for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#ifndef __IO_H
+#define __IO_H
+
+#include "reg_ezusb.h"
+
+/***************************************************************************
+ * JTAG Signals: *
+ ***************************************************************************
+ * TMS ....... Test Mode Select *
+ * TCK ....... Test Clock *
+ * TDI ....... Test Data Input (from device point of view, not JTAG *
+ * adapter point of view!) *
+ * TDO ....... Test Data Output (from device point of view, not JTAG *
+ * adapter point of view!) *
+ * TRST ...... Test Reset: Used to reset the TAP Finite State Machine *
+ * into the Test Logic Reset state *
+ * SRST ..... Chip Reset *
+ ***************************************************************************/
+
+/* PORT A */
+/* PA0 Not Connected */
+/* PA1 Not Connected */
+#define PIN_RDWR_B IOA2
+#define PIN_CSI_B IOA3
+#define PIN_INIT_B IOA4
+#define PIN_PROGRAM_B IOA5
+/* PA6 Not Connected */
+/* PA7 Not Connected */
+
+/* PORT B */
+#define PIN_TRST IOB0
+#define PIN_TMS IOB1
+#define PIN_TCK IOB2
+#define PIN_TDI IOB3
+#define PIN_TDO IOB4
+#define PIN_SRST IOB5
+/* PA6 Not Connected */
+/* PA7 Not Connected */
+
+/* JTAG Signals with direction 'OUT' on port B */
+/* PIN_TDI - PIN_TCK - PIN_TMS - PIN_TRST - PIN_SRST */
+#define MASK_PORTB_DIRECTION_OUT (bmbit0 | bmbit1 | bmbit2 | bmbit3 | bmbit5)
+
+/* PORT C */ // Debug:
+#define PIN_T0 IOC0
+#define PIN_T1 IOC1
+#define PIN_T2 IOC2
+#define PIN_T3 IOC3
+#define PIN_T4 IOC4
+/* PC5 Not Connected */
+/* PC6 Not Connected */
+/* PC7 Not Connected */
+
+#endif
diff --git a/contrib/firmware/angie/c/include/jtag.h b/contrib/firmware/angie/c/include/jtag.h
new file mode 100644
index 0000000..6d5df64
--- /dev/null
+++ b/contrib/firmware/angie/c/include/jtag.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/****************************************************************************
+ File : jtag.h *
+ Contents : Jtag handling functions header file for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#ifndef __JTAG_H
+#define __JTAG_H
+
+#include <stdint.h>
+
+uint16_t jtag_get_signals(void);
+void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out,
+ uint8_t scan_io, uint8_t tck, uint8_t tms);
+void jtag_clock_tms(uint8_t count, uint8_t sequence);
+void jtag_slow_clock_tms(uint8_t count, uint8_t sequence);
+void jtag_set_signals(uint8_t low, uint8_t high);
+void jtag_clock_tck(uint16_t count);
+void jtag_slow_clock_tck(uint16_t count);
+void jtag_scan_in(uint8_t out_offset, uint8_t in_offset);
+void jtag_scan_out(uint8_t out_offset);
+void jtag_scan_io(uint8_t out_offset, uint8_t in_offset);
+void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset);
+void jtag_slow_scan_out(uint8_t out_offset);
+void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset);
+#endif
diff --git a/contrib/firmware/angie/c/include/msgtypes.h b/contrib/firmware/angie/c/include/msgtypes.h
new file mode 100644
index 0000000..9111690
--- /dev/null
+++ b/contrib/firmware/angie/c/include/msgtypes.h
@@ -0,0 +1,171 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/****************************************************************************
+ File : msgtypes.h *
+ Contents : Definition of the commands supported by NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+/**
+ * @file
+ * Definition of the commands supported by the ANGIE firmware.
+ *
+ * Basically, two types of commands can be distinguished:
+ * - Commands with fixed payload size
+ * - Commands with variable payload size
+ *
+ * SCAN commands (in all variations) carry payloads of variable size, all
+ * other commands carry payloads of fixed size.
+ *
+ * In the case of SCAN commands, the payload size (n) is calculated by
+ * dividing the scan_size_bits variable by 8, rounding up the result.
+ *
+ * Offset zero always contains the command ID.
+ *
+ ****************************************************************************
+ * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: *
+ * *
+ * OUT: *
+ * offset 1: scan_size_bytes *
+ * offset 2: bits_last_byte *
+ * offset 3: tms_count_start + tms_count_end *
+ * offset 4: tms_sequence_start *
+ * offset 5: tms_sequence_end *
+ * *
+ * IN: *
+ * offset 0..n: TDO data *
+ ****************************************************************************
+ * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: *
+ * *
+ * OUT: *
+ * offset 1: scan_size_bytes *
+ * offset 2: bits_last_byte *
+ * offset 3: tms_count_start + tms_count_end *
+ * offset 4: tms_sequence_start *
+ * offset 5: tms_sequence_end *
+ * offset 6..x: TDI data *
+ ****************************************************************************
+ * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: *
+ * *
+ * OUT: *
+ * offset 1: scan_size_bytes *
+ * offset 2: bits_last_byte *
+ * offset 3: tms_count_start + tms_count_end *
+ * offset 4: tms_sequence_start *
+ * offset 5: tms_sequence_end *
+ * offset 6..x: TDI data *
+ * *
+ * IN: *
+ * offset 0..n: TDO data *
+ ****************************************************************************
+ * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: *
+ * *
+ * OUT: *
+ * offset 1: tms_count *
+ * offset 2: tms_sequence *
+ ****************************************************************************
+ * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: *
+ * *
+ * OUT: *
+ * offset 1: low byte of tck_count *
+ * offset 2: high byte of tck_count *
+ ****************************************************************************
+ * CMD_CLOCK_SLEEP_US: *
+ * *
+ * OUT: *
+ * offset 1: low byte of sleep_us *
+ * offset 2: high byte of sleep_us *
+ ****************************************************************************
+ * CMD_CLOCK_SLEEP_MS: *
+ * *
+ * OUT: *
+ * offset 1: low byte of sleep_ms *
+ * offset 2: high byte of sleep_ms *
+ ****************************************************************************
+ * CMD_GET_SIGNALS: *
+ * *
+ * IN: *
+ * offset 0: current state of input signals *
+ * offset 1: current state of output signals *
+ ****************************************************************************
+ * CMD_SET_SIGNALS: *
+ * *
+ * OUT: *
+ * offset 1: signals that should be de-asserted *
+ * offset 2: signals that should be asserted *
+ ****************************************************************************
+ * CMD_CONFIGURE_TCK_FREQ: *
+ * *
+ * OUT: *
+ * offset 1: delay value for scan_in function *
+ * offset 2: delay value for scan_out function *
+ * offset 3: delay value for scan_io function *
+ * offset 4: delay value for clock_tck function *
+ * offset 5: delay value for clock_tms function *
+ ****************************************************************************
+ * CMD_SET_LEDS: *
+ * *
+ * OUT: *
+ * offset 1: LED states: *
+ * Bit 0: turn COM LED on *
+ * Bit 1: turn RUN LED on *
+ * Bit 2: turn COM LED off *
+ * Bit 3: turn RUN LED off *
+ * Bits 7..4: Reserved *
+ ****************************************************************************
+ * CMD_TEST: *
+ * *
+ * OUT: *
+ * offset 1: unused dummy value *
+ ****************************************************************************
+ */
+
+#ifndef __MSGTYPES_H
+#define __MSGTYPES_H
+
+/*
+ * Command IDs:
+ *
+ * Bits 7..6: Reserved, should always be zero
+ * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs,
+ * the IDs 0x00..0x1F are commands with variable payload size,
+ * the IDs 0x20..0x3F are commands with fixed payload size.
+ */
+
+#define CMD_ID_MASK 0x3F
+
+/* Commands with variable payload size */
+#define CMD_SCAN_IN 0x00
+#define CMD_SLOW_SCAN_IN 0x01
+#define CMD_SCAN_OUT 0x02
+#define CMD_SLOW_SCAN_OUT 0x03
+#define CMD_SCAN_IO 0x04
+#define CMD_SLOW_SCAN_IO 0x05
+
+/* Commands with fixed payload size */
+#define CMD_CLOCK_TMS 0x20
+#define CMD_SLOW_CLOCK_TMS 0x21
+#define CMD_CLOCK_TCK 0x22
+#define CMD_SLOW_CLOCK_TCK 0x23
+#define CMD_SLEEP_US 0x24
+#define CMD_SLEEP_MS 0x25
+#define CMD_GET_SIGNALS 0x26
+#define CMD_SET_SIGNALS 0x27
+#define CMD_CONFIGURE_TCK_FREQ 0x28
+#define CMD_SET_LEDS 0x29
+#define CMD_TEST 0x2A
+
+/* JTAG signal definition for jtag_get_signals() -- Input signals! */
+#define SIGNAL_TDO 1
+
+/* JTAG signal definition for jtag_get_signals() -- Output signals! */
+#define SIGNAL_TDI 8
+#define SIGNAL_TMS 2
+#define SIGNAL_TCK 4
+#define SIGNAL_TRST 1
+#define SIGNAL_SRST 32
+
+#endif
diff --git a/contrib/firmware/angie/c/include/protocol.h b/contrib/firmware/angie/c/include/protocol.h
new file mode 100644
index 0000000..a12644b
--- /dev/null
+++ b/contrib/firmware/angie/c/include/protocol.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/****************************************************************************
+ File : protocol.h *
+ Contents : Jtag commands handling protocol header file for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#ifndef __PROTOCOL_H
+#define __PROTOCOL_H
+
+#include <stdbool.h>
+
+bool execute_command(void);
+void command_loop(void);
+
+#endif
diff --git a/contrib/firmware/angie/c/include/reg_ezusb.h b/contrib/firmware/angie/c/include/reg_ezusb.h
new file mode 100644
index 0000000..c22476a
--- /dev/null
+++ b/contrib/firmware/angie/c/include/reg_ezusb.h
@@ -0,0 +1,656 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/****************************************************************************
+ File : reg_ezusb.h *
+ Contents : FX2 microcontroller registers file for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#ifndef REG_EZUSB_H
+#define REG_EZUSB_H
+
+/**
+ * @file
+ * All information in this file was taken from the EZ-USB FX2 Technical
+ * Reference Manual, Cypress Semiconductor, 3901 North First Street
+ * San Jose, CA 95134 (www.cypress.com).
+ *
+ * The EZ-USB Technical Reference Manual is called "EZ-USB FX2 TRM" hereafter.
+ */
+
+/* Compiler-specific definitions of SBIT, SFR, SFRX, ... macros */
+#include <mcs51/compiler.h>
+
+/* Bit vectors */
+#define bmbit0 0x01
+#define bmbit1 0x02
+#define bmbit2 0x04
+#define bmbit3 0x08
+#define bmbit4 0x10
+#define bmbit5 0x20
+#define bmbit6 0x40
+#define bmbit7 0x80
+
+/**************************************************************************
+ ************************ Special Function Registers **********************
+ ***************************************************************************/
+SFR(IOA, 0x80);
+SBIT(IOA0, 0x80, 0);
+SBIT(IOA1, 0x80, 1);
+SBIT(IOA2, 0x80, 2);
+SBIT(IOA3, 0x80, 3);
+SBIT(IOA4, 0x80, 4);
+SBIT(IOA5, 0x80, 5);
+SBIT(IOA6, 0x80, 6);
+SBIT(IOA7, 0x80, 7);
+
+SFR(SP, 0x81);
+SFR(DPL0, 0x82);
+SFR(DPH0, 0x83);
+SFR(DPL1, 0x84);
+SFR(DPL2, 0x85);
+
+SFR(DPS, 0x86);
+#define SEL bmbit0
+/* Bit 1 read-only, always reads '0' */
+/* Bit 2 read-only, always reads '0' */
+/* Bit 3 read-only, always reads '0' */
+/* Bit 4 read-only, always reads '0' */
+/* Bit 5 read-only, always reads '0' */
+/* Bit 6 read-only, always reads '0' */
+/* Bit 7 read-only, always reads '0' */
+
+SFR(PCON, 0x87);
+#define IDLE bmbit0
+#define STOP bmbit1
+#define GF0 bmbit2
+#define GF1 bmbit3
+/* Bit 4 read-only, always reads '1' */
+/* Bit 5 read-only, always reads '1' */
+/* Bit 6 unused */
+#define SMOD0 bmbit7
+
+SFR(TCON, 0x88);
+SBIT(IT0, 0x88, 0);
+SBIT(IE0, 0x88, 1);
+SBIT(IT1, 0x88, 2);
+SBIT(IE1, 0x88, 3);
+SBIT(TR0, 0x88, 4);
+SBIT(TF0, 0x88, 5);
+SBIT(TR1, 0x88, 6);
+SBIT(TF1, 0x88, 7);
+
+SFR(TMOD, 0x89);
+SFR(TL0, 0x8A);
+SFR(TL1, 0x8B);
+SFR(TH0, 0x8C);
+SFR(TH1, 0x8D);
+
+SFR(CKCON, 0x8E);
+#define MD0 bmbit0
+#define MD1 bmbit1
+#define MD2 bmbit2
+#define T0M bmbit3
+#define T1M bmbit4
+#define T2M bmbit5
+/* Bit 6 unused */
+/* Bit 7 unused */
+
+SFR(SPC_FNC, 0x8F);
+#define BMWRS bmbit0
+/* Bit 1 read-only, always reads '0' */
+/* Bit 2 read-only, always reads '0' */
+/* Bit 3 read-only, always reads '0' */
+/* Bit 4 read-only, always reads '0' */
+/* Bit 5 read-only, always reads '0' */
+/* Bit 6 read-only, always reads '0' */
+/* Bit 7 read-only, always reads '0' */
+
+SFR(IOB, 0x90);
+SBIT(IOB0, 0x90, 0);
+SBIT(IOB1, 0x90, 1);
+SBIT(IOB2, 0x90, 2);
+SBIT(IOB3, 0x90, 3);
+SBIT(IOB4, 0x90, 4);
+SBIT(IOB5, 0x90, 5);
+SBIT(IOB6, 0x90, 6);
+SBIT(IOB7, 0x90, 7);
+
+SFR(EXIF, 0x91);
+SBIT(USBINT, 0x91, 4);
+SBIT(I2CINT, 0x91, 5);
+SBIT(IE4, 0x91, 6);
+SBIT(IE5, 0x91, 7);
+
+SFR(MPAGE, 0x92);
+SFR(SCON0, 0x98);
+SBIT(RI, 0x98, 0);
+SBIT(TI, 0x98, 1);
+SBIT(RB8, 0x98, 2);
+SBIT(TB8, 0x98, 3);
+SBIT(REN, 0x98, 4);
+SBIT(SM2, 0x98, 5);
+SBIT(SM1, 0x98, 6);
+SBIT(SM0, 0x98, 7);
+
+SFR(SBUF0, 0x99);
+SFR(AUTOPTRH1, 0x9A);
+SFR(AUTOPTRL1, 0x9B);
+SFR(AUTOPTRH2, 0x9D);
+SFR(AUTOPTRL2, 0x9E);
+
+#define AUTOPTR1H AUTOPTRH1 /* for backwards compatibility with examples */
+#define AUTOPTR1L AUTOPTRL1 /* for backwards compatibility with examples */
+#define APTR1H AUTOPTRH1 /* for backwards compatibility with examples */
+#define APTR1L AUTOPTRL1 /* for backwards compatibility with examples */
+
+SFR(IOC, 0xA0);
+SBIT(IOC0, 0xA0, 0);
+SBIT(IOC1, 0xA0, 1);
+SBIT(IOC2, 0xA0, 2);
+SBIT(IOC3, 0xA0, 3);
+SBIT(IOC4, 0xA0, 4);
+SBIT(IOC5, 0xA0, 5);
+SBIT(IOC6, 0xA0, 6);
+SBIT(IOC7, 0xA0, 7);
+
+SFR(INT2CLR, 0xA1);
+SFR(INT4CLR, 0xA2);
+SFR(IE, 0xA8);
+SBIT(EX0, 0xA8, 0);
+SBIT(ET0, 0xA8, 1);
+SBIT(EX1, 0xA8, 2);
+SBIT(ET1, 0xA8, 3);
+SBIT(ES0, 0xA8, 4);
+SBIT(ET2, 0xA8, 5);
+SBIT(ES1, 0xA8, 6);
+SBIT(EA, 0xA8, 7);
+
+SFR(EP2468STAT, 0xAA);
+#define EP8F bmbit7
+#define EP8E bmbit6
+#define EP6F bmbit5
+#define EP6E bmbit4
+#define EP4F bmbit3
+#define EP4E bmbit2
+#define EP2F bmbit1
+#define EP2E bmbit0
+
+SFR(EP24FIFOFLGS, 0xAB);
+SFR(EP68FIFOFLGS, 0xAC);
+SFR(AUTOPTRSETUP, 0xAF);
+SFR(IOD, 0xB0);
+SBIT(IOD0, 0xB0, 0);
+SBIT(IOD1, 0xB0, 1);
+SBIT(IOD2, 0xB0, 2);
+SBIT(IOD3, 0xB0, 3);
+SBIT(IOD4, 0xB0, 4);
+SBIT(IOD5, 0xB0, 5);
+SBIT(IOD6, 0xB0, 6);
+SBIT(IOD7, 0xB0, 7);
+
+SFR(IOE, 0xB1);
+SFR(OEA, 0xB2);
+SFR(OEB, 0xB3);
+SFR(OEC, 0xB4);
+SFR(OED, 0xB5);
+SFR(OEE, 0xB6);
+
+SFR(IP, 0xB8);
+SBIT(PX0, 0xB8, 0);
+SBIT(PT0, 0xB8, 1);
+SBIT(PX1, 0xB8, 2);
+SBIT(PT1, 0xB8, 3);
+SBIT(PS0, 0xB8, 4);
+SBIT(PT2, 0xB8, 5);
+SBIT(PS1, 0xB8, 6);
+/* Bit 7 read-only, always reads '1' */
+
+SFR(EP01STAT, 0xBA);
+SFR(GPIFTRIG, 0xBB);
+#define BMGPIFDONE bmbit7
+#define BMGPIFREAD bmbit2
+#define GPIF_EP2 0
+#define GPIF_EP4 1
+#define GPIF_EP6 2
+#define GPIF_EP8 3
+
+SFR(GPIFSGLDATH, 0xBD);
+SFR(GPIFSGLDATLX, 0xBE);
+SFR(GPIFSGLDATLNOX, 0xBF);
+
+SFR(SCON1, 0xC0);
+SBIT(RI_1, 0xC0, 0);
+SBIT(TI_1, 0xC0, 1);
+SBIT(RB8_1, 0xC0, 2);
+SBIT(TB8_1, 0xC0, 3);
+SBIT(REN_1, 0xC0, 4);
+SBIT(SM2_1, 0xC0, 5);
+SBIT(SM1_1, 0xC0, 6);
+SBIT(SM0_1, 0xC0, 7);
+
+SFR(SBUF1, 0xC1);
+SFR(T2CON, 0xC8);
+SBIT(CPRL2, 0xC8, 0);
+SBIT(C_T2, 0xC8, 1);
+SBIT(TR2, 0xC8, 2);
+SBIT(EXEN2, 0xC8, 3);
+SBIT(TCLK, 0xC8, 4);
+SBIT(RCLK, 0xC8, 5);
+SBIT(EXF2, 0xC8, 6);
+SBIT(TF2, 0xC8, 7);
+
+SFR(RCAP2L, 0xCA);
+SFR(RCAP2H, 0xCB);
+SFR(TL2, 0xCC);
+SFR(TH2, 0xCD);
+SFR(PSW, 0xD0);
+SBIT(P, 0xD0, 0);
+SBIT(F1, 0xD0, 1);
+SBIT(OV, 0xD0, 2);
+SBIT(RS0, 0xD0, 3);
+SBIT(RS1, 0xD0, 4);
+SBIT(F0, 0xD0, 5);
+SBIT(AC, 0xD0, 6);
+SBIT(CY, 0xD0, 7);
+
+SFR(EICON, 0xD8);
+/* Bit 0 read-only, always reads '0' */
+/* Bit 1 read-only, always reads '0' */
+/* Bit 2 read-only, always reads '0' */
+SBIT(INT6, 0xD8, 3);
+SBIT(RESI, 0xD8, 4);
+SBIT(ERESI, 0xD8, 5);
+/* Bit 6 read-only, always reads '1' */
+SBIT(SMOD1, 0xD8, 7);
+
+SFR(ACC, 0xE0);
+SFR(EIE, 0xE8);
+SBIT(EUSB, 0xE8, 0);
+SBIT(EI2C, 0xE8, 1);
+SBIT(EX4, 0xE8, 2);
+SBIT(EX5, 0xE8, 3);
+SBIT(EWDI, 0xE8, 4);
+/* Bit 5 read-only, always reads '1' */
+/* Bit 6 read-only, always reads '1' */
+/* Bit 7 read-only, always reads '1' */
+
+SFR(B, 0xF0);
+SFR(EIP, 0xF8);
+SBIT(PUSB, 0xF8, 0);
+SBIT(PI2C, 0xF8, 1);
+SBIT(PX4, 0xF8, 2);
+SBIT(PX5, 0xF8, 3);
+SBIT(PX6, 0xF8, 4);
+/* Bit 5 read-only, always reads '1' */
+/* Bit 6 read-only, always reads '1' */
+/* Bit 7 read-only, always reads '1' */
+
+/**************************************************************************
+ ***************************** XDATA Registers ****************************
+ ***************************************************************************/
+
+SFRX(GPIF_WAVE_DATA, 0xE400);
+SFRX(RES_WAVEDATA_END, 0xE480);
+
+/* General Configuration */
+SFRX(CPUCS, 0xE600);
+#define RES8051 bmbit0
+#define CLKOE bmbit1
+#define BMCLKINV bmbit2
+#define bmclkspd0 bmbit3
+#define bmclkspd1 bmbit4
+#define bmclkspd (bmbit4 | bmbit3)
+#define BMPRTCSTB bmbit5
+
+/* PCON register */
+#define BMSMOD0 bmbit7
+
+SFRX(IFCONFIG, 0xE601);
+#define BMIFCLKSRC bmbit7
+#define BM3048MHZ bmbit6
+#define BMIFCLKOE bmbit5
+#define BMIFCLKPOL bmbit4
+#define BMASYNC bmbit3
+#define BMGSTATE bmbit2
+#define BMIFCFG1 bmbit1
+#define BMIFCFG0 bmbit0
+#define BMIFCFGMASK (BMIFCFG0 | BMIFCFG1)
+#define BMIFGPIF BMIFCFG1
+
+SFRX(PINFLAGSAB, 0xE602);
+SFRX(PINFLAGSCD, 0xE603);
+SFRX(FIFORESET, 0xE604);
+#define BMNAKALL bmbit7
+
+SFRX(BREAKPT, 0xE605);
+#define BMBREAK bmbit3
+#define BMBPPULSE bmbit2
+#define BMBPEN bmbit1
+
+SFRX(BPADDRH, 0xE606);
+SFRX(BPADDRL, 0xE607);
+SFRX(UART230, 0xE608);
+SFRX(FIFOPINPOLAR, 0xE609);
+SFRX(REVID, 0xE60A);
+SFRX(REVCTL, 0xE60B);
+#define BMNOAUTOARM bmbit1
+#define BMSKIPCOMMIT bmbit0
+
+/* Endpoint Configuration */
+SFRX(EP1OUTCFG, 0xE610);
+SFRX(EP1INCFG, 0xE611);
+SFRX(EP2CFG, 0xE612);
+SFRX(EP4CFG, 0xE613);
+SFRX(EP6CFG, 0xE614);
+SFRX(EP8CFG, 0xE615);
+SFRX(EP2FIFOCFG, 0xE618);
+SFRX(EP4FIFOCFG, 0xE619);
+SFRX(EP6FIFOCFG, 0xE61A);
+SFRX(EP8FIFOCFG, 0xE61B);
+#define BMINFM bmbit6
+#define BMOEP bmbit5
+#define BMAUTOOUT bmbit4
+#define BMAUTOIN bmbit3
+#define BMZEROLENIN bmbit2
+#define BMWORDWIDE bmbit0
+
+SFRX(EP2AUTOINLENH, 0xE620);
+SFRX(EP2AUTOINLENL, 0xE621);
+SFRX(EP4AUTOINLENH, 0xE622);
+SFRX(EP4AUTOINLENL, 0xE623);
+SFRX(EP6AUTOINLENH, 0xE612);
+SFRX(EP6AUTOINLENL, 0xE613);
+SFRX(EP8AUTOINLENH, 0xE614);
+SFRX(EP8AUTOINLENL, 0xE615);
+SFRX(EP2FIFOPFH, 0xE630);
+SFRX(EP2FIFOPFL, 0xE631);
+SFRX(EP4FIFOPFH, 0xE632);
+SFRX(EP4FIFOPFL, 0xE633);
+SFRX(EP6FIFOPFH, 0xE634);
+SFRX(EP6FIFOPFL, 0xE635);
+SFRX(EP8FIFOPFH, 0xE636);
+SFRX(EP8FIFOPFL, 0xE637);
+SFRX(EP2ISOINPKTS, 0xE640);
+SFRX(EP4ISOINPKTS, 0xE641);
+SFRX(EP6ISOINPKTS, 0xE642);
+SFRX(EP8ISOINPKTS, 0xE643);
+SFRX(INPKTEND, 0xE648);
+SFRX(OUTPKTEND, 0xE649);
+
+/* Interrupts */
+SFRX(EP2FIFOIE, 0xE650);
+SFRX(EP2FIFOIRQ, 0xE651);
+SFRX(EP4FIFOIE, 0xE652);
+SFRX(EP4FIFOIRQ, 0xE653);
+SFRX(EP6FIFOIE, 0xE654);
+SFRX(EP6FIFOIRQ, 0xE655);
+SFRX(EP8FIFOIE, 0xE656);
+SFRX(EP8FIFOIRQ, 0xE657);
+SFRX(IBNIE, 0xE658);
+SFRX(IBNIRQ, 0xE659);
+#define EP0IBN bmbit0
+#define EP1IBN bmbit1
+#define EP2IBN bmbit2
+#define EP4IBN bmbit3
+#define EP6IBN bmbit4
+#define EP8IBN bmbit5
+
+SFRX(NAKIE, 0xE65A);
+SFRX(NAKIRQ, 0xE65B);
+#define EP8PING bmbit7
+#define EP6PING bmbit6
+#define EP4PING bmbit5
+#define EP2PING bmbit4
+#define EP1PING bmbit3
+#define EP0PING bmbit2
+#define IBN bmbit0
+
+SFRX(USBIEN, 0xE65C);
+SFRX(USBIRQ, 0xE65D);
+#define SUDAVI bmbit0
+#define SOFI bmbit1
+#define SUTOKI bmbit2
+#define SUSPI bmbit3
+#define URESI bmbit4
+#define HSGRANT bmbit5
+#define EP0ACK bmbit6
+
+SFRX(EPIE, 0xE65E);
+SFRX(EPIRQ, 0xE65F);
+SFRX(GPIFIE, 0xE660);
+SFRX(GPIFIRQ, 0xE661);
+SFRX(USBERRIE, 0xE662);
+SFRX(USBERRIRQ, 0xE663);
+SFRX(ERRCNTLIM, 0xE664);
+SFRX(CLRERRCNT, 0xE665);
+SFRX(INT2IVEC, 0xE666);
+#define I2V0 bmbit2
+#define I2V1 bmbit3
+#define I2V2 bmbit4
+#define I2V3 bmbit5
+#define I2V4 bmbit6
+
+SFRX(INT4IVEC, 0xE667);
+SFRX(INTSETUP, 0xE668);
+#define AV4EN bmbit0
+#define INT4IN bmbit1
+#define AV2EN bmbit3
+
+/* Input/Output */
+SFRX(PORTACFG, 0xE670);
+#define BMINT0 bmbit0
+#define BMINT1 bmbit1
+#define BMFLAGD bmbit7
+
+SFRX(PORTCCFG, 0xE671);
+#define BMGPIFA0 bmbit0
+#define BMGPIFA1 bmbit1
+#define BMGPIFA2 bmbit2
+#define BMGPIFA3 bmbit3
+#define BMGPIFA4 bmbit4
+#define BMGPIFA5 bmbit5
+#define BMGPIFA6 bmbit6
+#define BMGPIFA7 bmbit7
+
+SFRX(PORTECFG, 0xE672);
+#define BMT0OUT bmbit0
+#define BMT1OUT bmbit1
+#define BMT2OUT bmbit2
+#define BMRXD0OUT bmbit3
+#define BMRXD1OUT bmbit4
+#define BMINT6 bmbit5
+#define BMT2EX bmbit6
+#define BMGPIFA8 bmbit7
+
+SFRX(I2CS, 0xE678);
+#define BMDONE bmbit0
+#define BMACK bmbit1
+#define BMBERR bmbit2
+#define BMID (bmbit4 | bmbit3)
+#define BMLASTRD bmbit5
+#define BMSTOP bmbit6
+#define BMSTART bmbit7
+
+SFRX(I2DAT, 0xE679);
+SFRX(I2CTL, 0xE67A);
+#define BMSTOPIE bmbit1
+#define BM400KHZ bmbit0
+
+SFRX(XAUTODAT1, 0xE67B);
+SFRX(XAUTODAT2, 0xE67C);
+#define EXTAUTODAT1 XAUTODAT1
+#define EXTAUTODAT2 XAUTODAT2
+
+/* USB Control */
+SFRX(USBCS, 0xE680);
+#define SIGRSUME bmbit0
+#define RENUM bmbit1
+#define NOSYNSOF bmbit2
+#define DISCON bmbit3
+#define HSM bmbit7
+
+SFRX(SUSPEND, 0xE681);
+SFRX(WAKEUPCS, 0xE682);
+#define BMWU2 bmbit7
+#define BMWU bmbit6
+#define BMWU2POL bmbit5
+#define BMWUPOL bmbit4
+#define BMDPEN bmbit2
+#define BMWU2EN bmbit1
+#define BMWUEN bmbit0
+
+SFRX(TOGCTL, 0xE683);
+#define BMTOGCTLEPMASK bmbit3 | bmbit2 | bmbit1 | bmbit0
+#define BMRESETTOGGLE bmbit5
+#define BMSETTOGGLE bmbit6
+#define BMQUERYTOGGLE bmbit7
+
+SFRX(USBFRAMEH, 0xE684);
+SFRX(USBFRAMEL, 0xE685);
+SFRX(MICROFRAME, 0xE686);
+SFRX(FNADDR, 0xE687);
+
+/* Endpoints */
+SFRX(EP0BCH, 0xE68A);
+SFRX(EP0BCL, 0xE68B);
+SFRX(EP1OUTBC, 0xE68D);
+SFRX(EP1INBC, 0xE68F);
+SFRX(EP2BCH, 0xE690);
+SFRX(EP2BCL, 0xE691);
+SFRX(EP4BCH, 0xE694);
+SFRX(EP4BCL, 0xE695);
+SFRX(EP6BCH, 0xE698);
+SFRX(EP6BCL, 0xE699);
+SFRX(EP8BCH, 0xE69C);
+SFRX(EP8BCL, 0xE69D);
+SFRX(EP0CS, 0xE6A0);
+#define HSNAK bmbit7
+
+SFRX(EP1INCS, 0xE6A2);
+SFRX(EP1OUTCS, 0xE6A1);
+#define EPSTALL bmbit0
+#define EPBSY bmbit1
+
+SFRX(EP2CS, 0xE6A3);
+SFRX(EP4CS, 0xE6A4);
+SFRX(EP6CS, 0xE6A5);
+SFRX(EP8CS, 0xE6A6);
+#define BMEPEMPTY bmbit2
+#define BMEPFULL bmbit3
+#define BMNPAK (bmbit6 | bmbit5 | bmbit4)
+
+SFRX(EP2FIFOFLGS, 0xE6A7);
+SFRX(EP4FIFOFLGS, 0xE6A8);
+SFRX(EP6FIFOFLGS, 0xE6A9);
+SFRX(EP8FIFOFLGS, 0xE6AA);
+SFRX(EP2FIFOBCH, 0xE6AB);
+SFRX(EP2FIFOBCL, 0xE6AC);
+SFRX(EP4FIFOBCH, 0xE6AD);
+SFRX(EP4FIFOBCL, 0xE6AE);
+SFRX(EP6FIFOBCH, 0xE6AF);
+SFRX(EP6FIFOBCL, 0xE6B0);
+SFRX(EP8FIFOBCH, 0xE6B1);
+SFRX(EP8FIFOBCL, 0xE6B2);
+SFRX(SUDPTRH, 0xE6B3);
+SFRX(SUDPTRL, 0xE6B4);
+
+SFRX(SUDPTRCTL, 0xE6B5);
+#define BMSDPAUTO bmbit0
+
+SFRX(SETUPDAT[8], 0xE6B8);
+
+/* GPIF */
+SFRX(GPIFWFSELECT, 0xE6C0);
+SFRX(GPIFIDLECS, 0xE6C1);
+SFRX(GPIFIDLECTL, 0xE6C2);
+SFRX(GPIFCTLCFG, 0xE6C3);
+SFRX(GPIFADRH, 0xE6C4);
+SFRX(GPIFADRL, 0xE6C5);
+SFRX(GPIFTCB3, 0xE6CE);
+SFRX(GPIFTCB2, 0xE6CF);
+SFRX(GPIFTCB1, 0xE6D0);
+SFRX(GPIFTCB0, 0xE6D1);
+
+#define EP2GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */
+#define EP2GPIFTCL GPIFTCB0
+#define EP4GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */
+#define EP4GPIFTCL GPIFTCB0
+#define EP6GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */
+#define EP6GPIFTCL GPIFTCB0
+#define EP8GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */
+#define EP8GPIFTCL GPIFTCB0
+
+SFRX(EP2GPIFFLGSEL, 0xE6D2);
+SFRX(EP2GPIFPFSTOP, 0xE6D3);
+SFRX(EP2GPIFTRIG, 0xE6D4);
+SFRX(EP4GPIFFLGSEL, 0xE6DA);
+SFRX(EP4GPIFPFSTOP, 0xE6DB);
+SFRX(EP4GPIFTRIG, 0xE6DC);
+SFRX(EP6GPIFFLGSEL, 0xE6E2);
+SFRX(EP6GPIFPFSTOP, 0xE6E3);
+SFRX(EP6GPIFTRIG, 0xE6E4);
+SFRX(EP8GPIFFLGSEL, 0xE6EA);
+SFRX(EP8GPIFPFSTOP, 0xE6EB);
+SFRX(EP8GPIFTRIG, 0xE6EC);
+SFRX(XGPIFSGLDATH, 0xE6F0);
+SFRX(XGPIFSGLDATLX, 0xE6F1);
+SFRX(XGPIFSGLDATLNOX, 0xE6F2);
+SFRX(GPIFREADYCFG, 0xE6F3);
+SFRX(GPIFREADYSTAT, 0xE6F4);
+SFRX(GPIFABORT, 0xE6F5);
+
+// UDMA
+SFRX(FLOWSTATE, 0xE6C6);
+SFRX(FLOWLOGIC, 0xE6C7);
+SFRX(FLOWEQ0CTL, 0xE6C8);
+SFRX(FLOWEQ1CTL, 0xE6C9);
+SFRX(FLOWHOLDOFF, 0xE6CA);
+SFRX(FLOWSTB, 0xE6CB);
+SFRX(FLOWSTBEDGE, 0xE6CC);
+SFRX(FLOWSTBHPERIOD, 0xE6CD);
+SFRX(GPIFHOLDAMOUNT, 0xE60C);
+SFRX(UDMACRCH, 0xE67D);
+SFRX(UDMACRCL, 0xE67E);
+SFRX(UDMACRCQUAL, 0xE67F);
+
+/* Debug/Test
+ * The following registers are for Cypress's internal testing purposes only.
+ * These registers are not documented in the datasheet or the Technical Reference
+ * Manual as they were not designed for end user application usage
+ */
+SFRX(DBUG, 0xE6F8);
+SFRX(TESTCFG, 0xE6F9);
+SFRX(USBTEST, 0xE6FA);
+SFRX(CT1, 0xE6FB);
+SFRX(CT2, 0xE6FC);
+SFRX(CT3, 0xE6FD);
+SFRX(CT4, 0xE6FE);
+
+/* Endpoint Buffers */
+SFRX(EP0BUF[64], 0xE740);
+SFRX(EP1INBUF[64], 0xE7C0);
+SFRX(EP1OUTBUF[64], 0xE780);
+SFRX(EP2FIFOBUF[512], 0xF000);
+SFRX(EP4FIFOBUF[512], 0xF400);
+SFRX(EP6FIFOBUF[512], 0xF800);
+SFRX(EP8FIFOBUF[512], 0xFC00);
+
+/* Error Correction Code (ECC) Registers (FX2LP/FX1 only) */
+SFRX(ECCCFG, 0xE628);
+SFRX(ECCRESET, 0xE629);
+SFRX(ECC1B0, 0xE62A);
+SFRX(ECC1B1, 0xE62B);
+SFRX(ECC1B2, 0xE62C);
+SFRX(ECC2B0, 0xE62D);
+SFRX(ECC2B1, 0xE62E);
+SFRX(ECC2B2, 0xE62F);
+
+/* Feature Registers (FX2LP/FX1 only) */
+SFRX(GPCR2, 0xE50D);
+#define BMFULLSPEEDONLY bmbit4
+
+#endif
diff --git a/contrib/firmware/angie/c/include/serial.h b/contrib/firmware/angie/c/include/serial.h
new file mode 100644
index 0000000..548c005
--- /dev/null
+++ b/contrib/firmware/angie/c/include/serial.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+/**
+ * This code was taken from the fx2lib project from this link:
+ * https://github.com/djmuhlestein/fx2lib
+ *
+ * Copyright (C) 2009 Ubixum, Inc.
+ **/
+
+/** \file serial.h
+ * defines functions to print to a serial console with SIO0
+ **/
+
+#include "fx2macros.h"
+#include <stdint.h>
+/**
+ * This function inits sio0 to use T2CON (timer 2)
+ * See TRM 14.3.4.1 (Table 14-16)
+ * Certain baud rates have too high an error rate to work. All baud rates are .16%
+ * except:
+ *
+ * 12MHZ 24MHZ
+ * \li 57600 -6.99%
+ * \li 38400 -2.34% -2.34%
+ * \li 19200 -2.34%
+ *
+ * Possible Baud rates:
+ * \li 2400
+ * \li 4800
+ * \li 9600
+ * \li 19200
+ * \li 28800
+ * \li 38400
+ * \li 57600
+ *
+ * Any of these rates should work except 57600 at 12mhz. -2.34% is pushing
+ * most hardware specs for working. All rates at 48mhz work at .16%
+ **/
+
+void sio0_init(uint32_t baud_rate) __critical; /* baud_rate max should be 57600 since int=2 bytes */
+
+/**
+ * putchar('\\n') or putchar('\\r') both transmit \\r\\n
+ * Just use one or the other. (This makes terminal echo easy)
+ **/
+int putchar(char c);
+int getchar(void);
diff --git a/contrib/firmware/angie/c/include/usb.h b/contrib/firmware/angie/c/include/usb.h
new file mode 100644
index 0000000..0450d1d
--- /dev/null
+++ b/contrib/firmware/angie/c/include/usb.h
@@ -0,0 +1,273 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/****************************************************************************
+ File : usb.h *
+ Contents : usb communication handling header file for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#ifndef __USB_H
+#define __USB_H
+
+#include "reg_ezusb.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+/* High and Low byte of a word (uint16_t) */
+#define HI8(word) (uint8_t)(((uint16_t)(word) >> 8) & 0xff)
+#define LO8(word) (uint8_t)((uint16_t)(word) & 0xff)
+
+/* Convenience functions */
+#define STALL_EP0() (EP0CS |= EPSTALL)
+#define CLEAR_IRQ() (USBINT = 0)
+
+/*********** USB descriptors. See section 9.5 of the USB 1.1 spec **********/
+
+/* USB Descriptor Types. See USB 1.1 spec, page 187, table 9-5 */
+#define DESCRIPTOR_TYPE_DEVICE 0x01
+#define DESCRIPTOR_TYPE_CONFIGURATION 0x02
+#define DESCRIPTOR_TYPE_STRING 0x03
+#define DESCRIPTOR_TYPE_INTERFACE 0x04
+#define DESCRIPTOR_TYPE_ENDPOINT 0x05
+
+#define STR_DESCR(len, ...) { (len) * 2 + 2, DESCRIPTOR_TYPE_STRING, { __VA_ARGS__ } }
+
+/** USB Device Descriptor. See USB 1.1 spec, pp. 196 - 198 */
+struct usb_device_descriptor {
+ uint8_t blength; /**< Size of this descriptor in bytes. */
+ uint8_t bdescriptortype; /**< DEVICE Descriptor Type. */
+ uint16_t bcdusb; /**< USB specification release number (BCD). */
+ uint8_t bdeviceclass; /**< Class code. */
+ uint8_t bdevicesubclass; /**< Subclass code. */
+ uint8_t bdeviceprotocol; /**< Protocol code. */
+ uint8_t bmaxpacketsize0; /**< Maximum packet size for EP0 (8, 16, 32, 64). */
+ uint16_t idvendor; /**< USB Vendor ID. */
+ uint16_t idproduct; /**< USB Product ID. */
+ uint16_t bcddevice; /**< Device Release Number (BCD). */
+ uint8_t imanufacturer; /**< Index of manufacturer string descriptor. */
+ uint8_t iproduct; /**< Index of product string descriptor. */
+ uint8_t iserialnumber; /**< Index of string descriptor containing serial #. */
+ uint8_t bnumconfigurations; /**< Number of possible configurations. */
+};
+
+/** USB Configuration Descriptor. See USB 1.1 spec, pp. 199 - 200 */
+struct usb_config_descriptor {
+ uint8_t blength; /**< Size of this descriptor in bytes. */
+ uint8_t bdescriptortype; /**< CONFIGURATION descriptor type. */
+ uint16_t wtotallength; /**< Combined total length of all descriptors. */
+ uint8_t bnuminterfaces; /**< Number of interfaces in this configuration. */
+ uint8_t bconfigurationvalue; /**< Value used to select this configuration. */
+ uint8_t iconfiguration; /**< Index of configuration string descriptor. */
+ uint8_t bmattributes; /**< Configuration characteristics. */
+ uint8_t maxpower; /**< Maximum power consumption in 2 mA units. */
+};
+
+/** USB Interface Descriptor. See USB 1.1 spec, pp. 201 - 203 */
+struct usb_interface_descriptor {
+ uint8_t blength; /**< Size of this descriptor in bytes. */
+ uint8_t bdescriptortype; /**< INTERFACE descriptor type. */
+ uint8_t binterfacenumber; /**< Interface number. */
+ uint8_t balternatesetting; /**< Value used to select alternate setting. */
+ uint8_t bnumendpoints; /**< Number of endpoints used by this interface. */
+ uint8_t binterfaceclass; /**< Class code. */
+ uint8_t binterfacesubclass; /**< Subclass code. */
+ uint8_t binterfaceprotocol; /**< Protocol code. */
+ uint8_t iinterface; /**< Index of interface string descriptor. */
+};
+
+/** USB Endpoint Descriptor. See USB 1.1 spec, pp. 203 - 204 */
+struct usb_endpoint_descriptor {
+ uint8_t blength; /**< Size of this descriptor in bytes. */
+ uint8_t bdescriptortype; /**< ENDPOINT descriptor type. */
+ uint8_t bendpointaddress; /**< Endpoint Address: IN/OUT + EP number. */
+ uint8_t bmattributes; /**< Endpoint Attributes: BULK/INTR/ISO/CTRL. */
+ uint16_t wmaxpacketsize; /**< Maximum packet size for this endpoint. */
+ uint8_t binterval; /**< Polling interval (in ms) for this endpoint. */
+};
+
+/** USB Language Descriptor. See USB 1.1 spec, pp. 204 - 205 */
+struct usb_language_descriptor {
+ uint8_t blength; /**< Size of this descriptor in bytes. */
+ uint8_t bdescriptortype; /**< STRING descriptor type. */
+ uint16_t wlangid[]; /**< LANGID codes. */
+};
+
+/** USB String Descriptor. See USB 1.1 spec, pp. 204 - 205 */
+struct usb_string_descriptor {
+ uint8_t blength; /**< Size of this descriptor in bytes. */
+ uint8_t bdescriptortype; /**< STRING descriptor type. */
+ uint16_t bstring[]; /**< UNICODE encoded string. */
+};
+
+/********************** USB Control Endpoint 0 related *********************/
+
+/** USB Control Setup Data. See USB 1.1 spec, pp. 183 - 185 */
+struct setup_data {
+ uint8_t bmrequesttype; /**< Characteristics of a request. */
+ uint8_t brequest; /**< Specific request. */
+ uint16_t wvalue; /**< Field that varies according to request. */
+ uint16_t windex; /**< Field that varies according to request. */
+ uint16_t wlength; /**< Number of bytes to transfer in data stage. */
+};
+
+/* External declarations for variables that need to be accessed outside of
+ * the USB module */
+extern volatile bool ep1_out;
+extern volatile bool ep1_in;
+
+extern volatile __xdata __at 0xE6B8 struct setup_data setup_data;
+
+/*
+ * USB Request Types (bmRequestType): See USB 1.1 spec, page 183, table 9-2
+ *
+ * Bit 7: Data transfer direction
+ * 0 = Host-to-device
+ * 1 = Device-to-host
+ * Bit 6...5: Type
+ * 0 = Standard
+ * 1 = Class
+ * 2 = Vendor
+ * 3 = Reserved
+ * Bit 4...0: Recipient
+ * 0 = Device
+ * 1 = Interface
+ * 2 = Endpoint
+ * 3 = Other
+ * 4...31 = Reserved
+ */
+
+#define USB_DIR_OUT 0x00
+#define USB_DIR_IN 0x80
+
+#define USB_REQ_TYPE_STANDARD (0x00 << 5)
+#define USB_REQ_TYPE_CLASS (0x01 << 5)
+#define USB_REQ_TYPE_VENDOR (0x02 << 5)
+#define USB_REQ_TYPE_RESERVED (0x03 << 5)
+
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/* Clear Interface Request */
+#define CF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define CF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+#define CF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* Get Configuration Request */
+#define GC_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Get Descriptor Request */
+#define GD_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Get Interface Request */
+#define GI_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+
+/* Get Status Request: See USB 1.1 spec, page 190 */
+#define GS_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define GS_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+#define GS_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* Set Address Request is handled by EZ-USB core */
+
+/* Set Configuration Request */
+#define SC_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Set Descriptor Request */
+#define SD_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Set Feature Request */
+#define SF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define SF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+#define SF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* Set Interface Request */
+#define SI_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+
+/* Synch Frame Request */
+#define SY_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* USB Requests (bRequest): See USB 1.1 spec, table 9-4 on page 187 */
+#define GET_STATUS 0
+#define CLEAR_FEATURE 1
+/* Value '2' is reserved for future use */
+#define SET_FEATURE 3
+/* Value '4' is reserved for future use */
+#define SET_ADDRESS 5
+#define GET_DESCRIPTOR 6
+#define SET_DESCRIPTOR 7
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+#define GET_INTERFACE 10
+#define SET_INTERFACE 11
+#define SYNCH_FRAME 12
+
+/* Standard Feature Selectors: See USB 1.1 spec, table 9-6 on page 188 */
+#define DEVICE_REMOTE_WAKEUP 1
+#define ENDPOINT_HALT 0
+
+/************************** EZ-USB specific stuff **************************/
+/** USB Interrupts. See AN2131-TRM, page 9-4 for details */
+enum usb_isr {
+ SUDAV_ISR = 13,
+ SOF_ISR,
+ SUTOK_ISR,
+ SUSPEND_ISR,
+ USBRESET_ISR,
+ HIGHSPEED_ISR,
+ EP0ACK_ISR,
+ STUB_ISR,
+ EP0IN_ISR,
+ EP0OUT_ISR,
+ EP1IN_ISR,
+ EP1OUT_ISR,
+ EP2_ISR,
+ EP4_ISR,
+ EP6_ISR,
+ EP8_ISR,
+ IBN_ISR,
+ EP0PINGNAK_ISR,
+ EP1PINGNAK_ISR,
+ EP2PINGNAK_ISR,
+ EP4PINGNAK_ISR,
+ EP6PINGNAK_ISR,
+ EP8PINGNAK_ISR,
+ ERRORLIMIT_ISR,
+ EP2PIDERROR_ISR,
+ EP4PIDERROR_ISR,
+ EP6PIDERROR_ISR,
+ EP8PIDERROR_ISR,
+ EP2PFLAG_ISR,
+ EP4PFLAG_ISR,
+ EP6PFLAG_ISR,
+ EP8PFLAG_ISR,
+ EP2EFLAG_ISR,
+ EP4EFLAG_ISR,
+ EP6EFLAG_ISR,
+ EP8EFLAG_ISR,
+ EP2FFLAG_ISR,
+ EP4FFLAG_ISR,
+ EP6FFLAG_ISR,
+ EP8FFLAG_ISR,
+ GPIFCOMPLETE_ISR,
+ GPIFWAVEFORM_ISR
+};
+
+/*************************** Function Prototypes ***************************/
+__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep);
+void usb_reset_data_toggle(uint8_t ep);
+bool usb_handle_get_status(void);
+bool usb_handle_clear_feature(void);
+bool usb_handle_set_feature(void);
+bool usb_handle_get_descriptor(void);
+void usb_handle_set_interface(void);
+void usb_handle_setup_data(void);
+
+void ep_init(void);
+void interrupt_init(void);
+void io_init(void);
+
+#endif
diff --git a/contrib/firmware/angie/c/src/USBJmpTb.a51 b/contrib/firmware/angie/c/src/USBJmpTb.a51
new file mode 100644
index 0000000..13b5f72
--- /dev/null
+++ b/contrib/firmware/angie/c/src/USBJmpTb.a51
@@ -0,0 +1,125 @@
+; SPDX-License-Identifier: GPL-2.0-or-later
+;****************************************************************************
+; File : USBJmpTb.a51 *
+; Contents : Interruptions vector configuration. *
+; Based on openULINK project code by: Martin Schmoelzer. *
+; Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+; <aboudjelida@nanoxplore.com> *
+; <ahmederrachedbjld@gmail.com> *
+;****************************************************************************
+.module JUMPTABLE
+
+.globl USB_AutoVector
+.globl USB_Jump_Table
+
+.globl _sudav_isr, _sof_isr, _sutok_isr, _suspend_isr, _usbreset_isr, _highspeed_isr, _ep0ack_isr, _stub_isr, _ep0in_isr, _ep0out_isr, _ep1in_isr, _ep1out_isr, _ep2_isr, _ep4_isr, _ep6_isr, _ep8_isr, _ibn_isr
+.globl _ep0pingnak_isr, _ep1pingnak_isr, _ep2pingnak_isr, _ep4pingnak_isr, _ep6pingnak_isr, _ep8pingnak_isr, _errorlimit_isr, _stub_isr, _stub_isr, _stub_isr, _ep2piderror_isr, _ep4piderror_isr, _ep6piderror_isr, _ep8piderror_isr
+.globl _ep2pflag_isr, _ep4pflag_isr, _ep6pflag_isr, _ep8pflag_isr, _ep2eflag_isr, _ep4eflag_isr, _ep6eflag_isr, _ep8eflag_isr, _ep2fflag_isr, _ep4fflag_isr, _ep6fflag_isr, _ep8fflag_isr, _gpifcomplete_isr, _gpifwaveform_isr
+
+;--------------------------------------------------------------------------;
+; Interrupt Vectors ;
+;--------------------------------------------------------------------------;
+.area USB_JV (ABS,OVR) ; Absolute, Overlay
+.org 0x43 ; USB interrupt (INT2) jumps here
+USB_AutoVector = #. + 2
+ ljmp USB_Jump_Table ; Autovector will replace byte 45
+
+;--------------------------------------------------------------------------;
+; USB Jump Table ;
+;--------------------------------------------------------------------------;
+.area USB_JT (ABS) ; Absolute placement
+.org 0x0200 ; Place jump table at 0x0200
+
+USB_Jump_Table: ; autovector jump table
+ ljmp _sudav_isr ; (00) Setup Data Available
+ .db 0
+ ljmp _sof_isr ; (04) Start of Frame
+ .db 0
+ ljmp _sutok_isr ; (08) Setup Data Loading
+ .db 0
+ ljmp _suspend_isr ; (0C) Global Suspend
+ .db 0
+ ljmp _usbreset_isr ; (10) USB Reset
+ .db 0
+ ljmp _highspeed_isr ; (14) Entered High Speed
+ .db 0
+ ljmp _ep0ack_isr ; (18) EP0ACK
+ .db 0
+ ljmp _stub_isr ; (1C) Reserved
+ .db 0
+ ljmp _ep0in_isr ; (20) EP0 In
+ .db 0
+ ljmp _ep0out_isr ; (24) EP0 Out
+ .db 0
+ ljmp _ep1in_isr ; (28) EP1 In
+ .db 0
+ ljmp _ep1out_isr ; (2C) EP1 Out
+ .db 0
+ ljmp _ep2_isr ; (30) EP2 In/Out
+ .db 0
+ ljmp _ep4_isr ; (34) EP4 In/Out
+ .db 0
+ ljmp _ep6_isr ; (38) EP6 In/Out
+ .db 0
+ ljmp _ep8_isr ; (3C) EP8 In/Out
+ .db 0
+ ljmp _ibn_isr ; (40) IBN
+ .db 0
+ ljmp _stub_isr ; (44) Reserved
+ .db 0
+ ljmp _ep0pingnak_isr ; (48) EP0 PING NAK
+ .db 0
+ ljmp _ep1pingnak_isr ; (4C) EP1 PING NAK
+ .db 0
+ ljmp _ep2pingnak_isr ; (50) EP2 PING NAK
+ .db 0
+ ljmp _ep4pingnak_isr ; (54) EP4 PING NAK
+ .db 0
+ ljmp _ep6pingnak_isr ; (58) EP6 PING NAK
+ .db 0
+ ljmp _ep8pingnak_isr ; (5C) EP8 PING NAK
+ .db 0
+ ljmp _errorlimit_isr ; (60) Error Limit
+ .db 0
+ ljmp _stub_isr ; (64) Reserved
+ .db 0
+ ljmp _stub_isr ; (68) Reserved
+ .db 0
+ ljmp _stub_isr ; (6C) Reserved
+ .db 0
+ ljmp _ep2piderror_isr ; (70) EP2 ISO Pid Sequence Error
+ .db 0
+ ljmp _ep4piderror_isr ; (74) EP4 ISO Pid Sequence Error
+ .db 0
+ ljmp _ep6piderror_isr ; (78) EP6 ISO Pid Sequence Error
+ .db 0
+ ljmp _ep8piderror_isr ; (7C) EP8 ISO Pid Sequence Error
+ .db 0
+ ljmp _ep2pflag_isr ; (80) EP2 Programmable Flag
+ .db 0
+ ljmp _ep4pflag_isr ; (84) EP4 Programmable Flag
+ .db 0
+ ljmp _ep6pflag_isr ; (88) EP6 Programmable Flag
+ .db 0
+ ljmp _ep8pflag_isr ; (8C) EP8 Programmable Flag
+ .db 0
+ ljmp _ep2eflag_isr ; (90) EP2 Empty Flag
+ .db 0
+ ljmp _ep4eflag_isr ; (94) EP4 Empty Flag
+ .db 0
+ ljmp _ep6eflag_isr ; (98) EP6 Empty Flag
+ .db 0
+ ljmp _ep8eflag_isr ; (9C) EP8 Empty Flag
+ .db 0
+ ljmp _ep2fflag_isr ; (A0) EP2 Full Flag
+ .db 0
+ ljmp _ep4fflag_isr ; (A4) EP4 Full Flag
+ .db 0
+ ljmp _ep6fflag_isr ; (A8) EP6 Full Flag
+ .db 0
+ ljmp _ep8fflag_isr ; (AC) EP8 Full Flag
+ .db 0
+ ljmp _gpifcomplete_isr ; (B0) GPIF Operation Complete
+ .db 0
+ ljmp _gpifwaveform_isr ; (B4) GPIF Waveform
+ .db 0
diff --git a/contrib/firmware/angie/c/src/delay.c b/contrib/firmware/angie/c/src/delay.c
new file mode 100644
index 0000000..471e160
--- /dev/null
+++ b/contrib/firmware/angie/c/src/delay.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/****************************************************************************
+ File : delay.c *
+ Contents : Delays handling fucntions code for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#include "delay.h"
+#include <mcs51/compiler.h>
+
+void syncdelay(uint8_t count)
+{
+ for (uint8_t i = 0; i < count; i++)
+ NOP();
+}
+
+void delay_5us(void)
+{
+ NOP();
+}
+
+void delay_1ms(void)
+{
+ uint16_t i;
+
+ for (i = 0; i < 598; i++)
+ ;
+}
+
+void delay_us(uint16_t delay)
+{
+ uint16_t i;
+ uint16_t maxcount = (delay / 5);
+
+ for (i = 0; i < maxcount; i++)
+ delay_5us();
+}
+
+void delay_ms(uint16_t delay)
+{
+ uint16_t i;
+
+ for (i = 0; i < delay; i++)
+ delay_1ms();
+}
diff --git a/contrib/firmware/angie/c/src/gpif.c b/contrib/firmware/angie/c/src/gpif.c
new file mode 100644
index 0000000..80a9571
--- /dev/null
+++ b/contrib/firmware/angie/c/src/gpif.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ This program configures the General Programmable Interface (GPIF) for FX2.
+ Please do not modify sections of text which are marked as "DO NOT EDIT ...".
+*/
+
+/* GPIF Program Code */
+
+#include "reg_ezusb.h"
+#include "delay.h"
+
+/****************************** GPIF PROGRAM CODE ********************************/
+/* DO NOT EDIT ... */
+const char wavedata[128] = {
+/* Wave 0 */
+/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07,
+/* Opcode*/ 0x02, 0x07, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00,
+/* Output*/ 0x04, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* LFun */ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+/* Wave 1 */
+/* LenBr */ 0x88, 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x07,
+/* Opcode*/ 0x01, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* Output*/ 0x07, 0x05, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* LFun */ 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x3F,
+/* Wave 2 */
+/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07,
+/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* Output*/ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+/* Wave 3 */
+/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07,
+/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* Output*/ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+};
+/* END DO NOT EDIT */
+
+/* DO NOT EDIT ... */
+const char flowstates[36] = {
+/* Wave 0 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* Wave 1 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* Wave 2 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* Wave 3 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+/* END DO NOT EDIT */
+
+/* DO NOT EDIT ... */
+const char initdata[7] = {
+/* Regs */ 0xE0, 0x00, 0x00, 0x07, 0xEE, 0xF2, 0x00
+};
+/* END DO NOT EDIT */
+
+void gpif_init(void)
+{
+ uint8_t i;
+
+ IFCONFIG = 0xEE;
+
+ GPIFABORT = 0xFF; /* abort any waveforms pending */
+ GPIFREADYCFG = initdata[0];
+ GPIFCTLCFG = initdata[1];
+ GPIFIDLECS = initdata[2];
+ GPIFIDLECTL = initdata[3];
+ GPIFWFSELECT = initdata[5];
+ GPIFREADYSTAT = initdata[6];
+
+ /* use dual autopointer feature... */
+ AUTOPTRSETUP = 0x07;
+
+ /* source */
+ AUTOPTRH1 = (uint8_t)(((uint16_t)(&wavedata) >> 8) & 0xff);
+ AUTOPTRL1 = (uint8_t)((uint16_t)(&wavedata) & 0xff);
+
+ /* destination */
+ AUTOPTRH2 = 0xE4;
+ AUTOPTRL2 = 0x00;
+
+ /* transfer */
+ for (i = 0x00; i < 128; i++)
+ EXTAUTODAT2 = EXTAUTODAT1;
+
+ /* GPIF address pins update when GPIFADRH/L written */
+ syncdelay(3);
+ GPIFADRH = 0x00; /* bits[7:1] always 0 */
+ syncdelay(3);
+ GPIFADRL = 0x00; /* point to PERIPHERAL address 0x0000 */
+
+ /* Configure GPIF flowstates registers for Wave 0 of wavedata */
+ FLOWSTATE = flowstates[0];
+ FLOWLOGIC = flowstates[1];
+ FLOWEQ0CTL = flowstates[2];
+ FLOWEQ1CTL = flowstates[3];
+ FLOWHOLDOFF = flowstates[4];
+ FLOWSTB = flowstates[5];
+ FLOWSTBEDGE = flowstates[6];
+ FLOWSTBHPERIOD = flowstates[7];
+}
diff --git a/contrib/firmware/angie/c/src/jtag.c b/contrib/firmware/angie/c/src/jtag.c
new file mode 100644
index 0000000..9a44cd0
--- /dev/null
+++ b/contrib/firmware/angie/c/src/jtag.c
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/****************************************************************************
+ File : jtag.c *
+ Contents : Jtag handling functions code for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#include "jtag.h"
+#include "io.h"
+#include "msgtypes.h"
+#include "reg_ezusb.h"
+#include <stdbool.h>
+#include <serial.h>
+#include <stdio.h>
+
+/** Delay value for SCAN_IN operations with less than maximum TCK frequency */
+uint8_t delay_scan_in;
+
+/** Delay value for SCAN_OUT operations with less than maximum TCK frequency */
+uint8_t delay_scan_out;
+
+/** Delay value for SCAN_IO operations with less than maximum TCK frequency */
+uint8_t delay_scan_io;
+
+/** Delay value for CLOCK_TCK operations with less than maximum frequency */
+uint8_t delay_tck;
+
+/** Delay value for CLOCK_TMS operations with less than maximum frequency */
+uint8_t delay_tms;
+
+/**
+ * Perform JTAG SCAN-IN operation at maximum TCK frequency.
+ *
+ * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
+ * stored in the EP2 IN buffer.
+ *
+ * Maximum achievable TCK frequency is 182 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param out_offset offset in EP1OUTBUF where payload data starts
+ * @param in_offset
+ */
+void jtag_scan_in(uint8_t out_offset, uint8_t in_offset)
+{
+ uint8_t scan_size_bytes, bits_last_byte;
+ uint8_t tms_count_start, tms_count_end;
+ uint8_t tms_sequence_start, tms_sequence_end;
+ uint8_t tdo_data, i, j;
+
+ uint8_t outb_buffer;
+
+ /* Get parameters from EP1OUTBUF */
+ scan_size_bytes = EP1OUTBUF[out_offset];
+ bits_last_byte = EP1OUTBUF[out_offset + 1];
+ tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = EP1OUTBUF[out_offset + 3];
+ tms_sequence_end = EP1OUTBUF[out_offset + 4];
+
+ if (tms_count_start > 0)
+ jtag_clock_tms(tms_count_start, tms_sequence_start);
+
+ outb_buffer = IOB & ~(bmbit1 | bmbit2 | bmbit3);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdo_data = 0;
+
+ for (j = 0; j < 8; j++) {
+ IOB = outb_buffer; /* TCK changes here */
+ tdo_data = tdo_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+ }
+ tdo_data = 0;
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ /* Assert TMS signal if requested and this is the last bit */
+ if (j == (bits_last_byte - 1) && tms_count_end > 0) {
+ outb_buffer |= bmbit1;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+
+ IOB = outb_buffer; /* TCK changes here */
+ tdo_data = tdo_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+ tdo_data = tdo_data >> (8 - bits_last_byte);
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+
+ /* Move to correct end state */
+ if (tms_count_end > 0)
+ jtag_clock_tms(tms_count_end, tms_sequence_end);
+}
+
+
+/**
+ * Perform JTAG SCAN-IN operation at variable TCK frequency.
+ *
+ * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
+ * stored in the EP2 IN buffer.
+ *
+ * Maximum achievable TCK frequency is 113 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param out_offset offset in EP1OUTBUF where payload data starts
+ * @param in_offset
+ */
+void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset)
+{
+ uint8_t scan_size_bytes, bits_last_byte;
+ uint8_t tms_count_start, tms_count_end;
+ uint8_t tms_sequence_start, tms_sequence_end;
+ uint8_t tdo_data, i, j, k;
+ uint8_t outb_buffer;
+
+ /* Get parameters from EP1OUTBUF */
+ scan_size_bytes = EP1OUTBUF[out_offset];
+ bits_last_byte = EP1OUTBUF[out_offset + 1];
+ tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = EP1OUTBUF[out_offset + 3];
+ tms_sequence_end = EP1OUTBUF[out_offset + 4];
+
+ if (tms_count_start > 0)
+ jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
+
+ outb_buffer = IOB & ~(bmbit3 | bmbit2 | bmbit1);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdo_data = 0;
+
+ for (j = 0; j < 8; j++) {
+ IOB = outb_buffer; /* TCK changes here */
+ for (k = 0; k < delay_scan_in; k++)
+ ;
+ tdo_data = tdo_data >> 1;
+
+ IOB = (outb_buffer | bmbit2);
+ for (k = 0; k < delay_scan_in; k++)
+ ;
+
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+ }
+
+ tdo_data = 0;
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ /* Assert TMS signal if requested and this is the last bit */
+ if (j == (bits_last_byte - 1) && tms_count_end > 0) {
+ outb_buffer |= bmbit1;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+
+ IOB = outb_buffer; /* TCK changes here */
+ for (k = 0; k < delay_scan_in; k++)
+ ;
+ tdo_data = tdo_data >> 1;
+
+ IOB = (outb_buffer | bmbit2);
+ for (k = 0; k < delay_scan_in; k++)
+ ;
+
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+ tdo_data = tdo_data >> (8 - bits_last_byte);
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+
+ /* Move to correct end state */
+ if (tms_count_end > 0)
+ jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
+}
+
+
+/**
+ * Perform JTAG SCAN-OUT operation at maximum TCK frequency.
+ *
+ * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
+ * data is not sampled.
+ * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
+ *
+ * Maximum achievable TCK frequency is 142 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param out_offset offset in EP1OUTBUF where payload data starts
+ */
+void jtag_scan_out(uint8_t out_offset)
+{
+ uint8_t scan_size_bytes, bits_last_byte;
+ uint8_t tms_count_start, tms_count_end;
+ uint8_t tms_sequence_start, tms_sequence_end;
+ uint8_t tdi_data, i, j;
+ uint8_t outb_buffer;
+
+ /* Get parameters from EP1OUTBUF */
+ scan_size_bytes = EP1OUTBUF[out_offset];
+ bits_last_byte = EP1OUTBUF[out_offset + 1];
+ tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = EP1OUTBUF[out_offset + 3];
+ tms_sequence_end = EP1OUTBUF[out_offset + 4];
+
+ if (tms_count_start > 0)
+ jtag_clock_tms(tms_count_start, tms_sequence_start);
+ outb_buffer = IOB & ~(bmbit2 | bmbit1);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+
+ for (j = 0; j < 8; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+
+ IOB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ }
+ }
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+
+ /* Assert TMS signal if requested and this is the last bit */
+ if (j == (bits_last_byte - 1) && tms_count_end > 0) {
+ outb_buffer |= bmbit1;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+ IOB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ }
+
+ /* Move to correct end state */
+ if (tms_count_end > 0)
+ jtag_clock_tms(tms_count_end, tms_sequence_end);
+}
+
+/**
+ * Perform JTAG SCAN-OUT operation at maximum TCK frequency.
+ *
+ * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
+ * data is not sampled.
+ * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
+ *
+ * Maximum achievable TCK frequency is 97 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param out_offset offset in EP1OUTBUF where payload data starts
+ */
+void jtag_slow_scan_out(uint8_t out_offset)
+{
+ uint8_t scan_size_bytes, bits_last_byte;
+ uint8_t tms_count_start, tms_count_end;
+ uint8_t tms_sequence_start, tms_sequence_end;
+ uint8_t tdi_data, i, j, k;
+ uint8_t outb_buffer;
+
+ /* Get parameters from EP1OUTBUF */
+ scan_size_bytes = EP1OUTBUF[out_offset];
+ bits_last_byte = EP1OUTBUF[out_offset + 1];
+ tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = EP1OUTBUF[out_offset + 3];
+ tms_sequence_end = EP1OUTBUF[out_offset + 4];
+
+ if (tms_count_start > 0)
+ jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
+ outb_buffer = IOB & ~(bmbit2 | bmbit1);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+
+ for (j = 0; j < 8; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+ IOB = outb_buffer; /* TDI and TCK change here */
+ for (k = 0; k < delay_scan_out; k++)
+ ;
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ for (k = 0; k < delay_scan_out; k++)
+ ;
+ }
+ }
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+
+ /* Assert TMS signal if requested and this is the last bit */
+ if (j == (bits_last_byte - 1) && tms_count_end > 0) {
+ outb_buffer |= bmbit1;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+ IOB = outb_buffer; /* TDI and TCK change here */
+ for (k = 0; k < delay_scan_out; k++)
+ ;
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ for (k = 0; k < delay_scan_out; k++)
+ ;
+ }
+
+ /* Move to correct end state */
+ if (tms_count_end > 0)
+ jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
+}
+
+
+/**
+ * Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
+ *
+ * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
+ * data is sampled and stored in the EP2 IN buffer.
+ * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
+ *
+ * Maximum achievable TCK frequency is 100 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param out_offset offset in EP1OUTBUF where payload data starts
+ * @param in_offset
+ */
+int it;
+void jtag_scan_io(uint8_t out_offset, uint8_t in_offset)
+{
+ uint8_t scan_size_bytes, bits_last_byte;
+ uint8_t tms_count_start, tms_count_end;
+ uint8_t tms_sequence_start, tms_sequence_end;
+ uint8_t tdi_data, tdo_data, i, j;
+ uint8_t outb_buffer;
+
+ it++;
+ /* Get parameters from EP1OUTBUF */
+ scan_size_bytes = EP1OUTBUF[out_offset];
+ bits_last_byte = EP1OUTBUF[out_offset + 1];
+ tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = EP1OUTBUF[out_offset + 3];
+ tms_sequence_end = EP1OUTBUF[out_offset + 4];
+
+ if (tms_count_start > 0)
+ jtag_clock_tms(tms_count_start, tms_sequence_start);
+ outb_buffer = IOB & ~(bmbit2 | bmbit1);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+ tdo_data = 0;
+ for (j = 0; j < 8; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+ IOB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ tdo_data = tdo_data >> 1;
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+ }
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+ tdo_data = 0;
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+
+ /* Assert TMS signal if requested and this is the last bit */
+ if (j == (bits_last_byte - 1) && tms_count_end > 0) {
+ outb_buffer |= bmbit1;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+ IOB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ tdo_data = tdo_data >> 1;
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+ tdo_data = tdo_data >> (8 - bits_last_byte);
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+
+ /* Move to correct end state */
+ if (tms_count_end > 0)
+ jtag_clock_tms(tms_count_end, tms_sequence_end);
+}
+
+/**
+ * Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
+ *
+ * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
+ * data is sampled and stored in the EP2 IN buffer.
+ * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
+ *
+ * Maximum achievable TCK frequency is 78 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param out_offset offset in EP1OUTBUF where payload data starts
+ * @param in_offset
+ */
+void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset)
+{
+ uint8_t scan_size_bytes, bits_last_byte;
+ uint8_t tms_count_start, tms_count_end;
+ uint8_t tms_sequence_start, tms_sequence_end;
+ uint8_t tdi_data, tdo_data, i, j, k;
+ uint8_t outb_buffer;
+
+ /* Get parameters from EP1OUTBUF */
+ scan_size_bytes = EP1OUTBUF[out_offset];
+ bits_last_byte = EP1OUTBUF[out_offset + 1];
+ tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = EP1OUTBUF[out_offset + 3];
+ tms_sequence_end = EP1OUTBUF[out_offset + 4];
+
+ if (tms_count_start > 0)
+ jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
+ outb_buffer = IOB & ~(bmbit2 | bmbit1);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+ tdo_data = 0;
+ for (j = 0; j < 8; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+ IOB = outb_buffer; /* TDI and TCK change here */
+ for (k = 0; k < delay_scan_io; k++)
+ ;
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ for (k = 0; k < delay_scan_io; k++)
+ ;
+ tdo_data = tdo_data >> 1;
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+ }
+ tdi_data = EP1OUTBUF[i + out_offset + 5];
+ tdo_data = 0;
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ if (tdi_data & 0x01)
+ outb_buffer |= bmbit3;
+ else
+ outb_buffer &= ~bmbit3;
+
+ /* Assert TMS signal if requested and this is the last bit */
+ if (j == (bits_last_byte - 1) && tms_count_end > 0) {
+ outb_buffer |= bmbit1;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+ IOB = outb_buffer; /* TDI and TCK change here */
+ for (k = 0; k < delay_scan_io; k++)
+ ;
+ tdi_data = tdi_data >> 1;
+ IOB = (outb_buffer | bmbit2);
+ for (k = 0; k < delay_scan_io; k++)
+ ;
+ tdo_data = tdo_data >> 1;
+ if (PIN_TDO)
+ tdo_data |= 0x80;
+ }
+ tdo_data = tdo_data >> (8 - bits_last_byte);
+
+ /* Copy TDO data to EP1INBUF */
+ EP1INBUF[i + in_offset] = tdo_data;
+
+ /* Move to correct end state */
+ if (tms_count_end > 0)
+ jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
+}
+
+/**
+ * Generate TCK clock cycles.
+ *
+ * Maximum achievable TCK frequency is 375 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param count number of TCK clock cycles to generate.
+ */
+void jtag_clock_tck(uint16_t count)
+{
+ uint16_t i;
+ uint8_t outb_buffer = IOB & ~(bmbit2);
+
+ for (i = 0; i < count; i++) {
+ IOB = outb_buffer;
+ IOB = outb_buffer | bmbit2;
+ }
+}
+
+/**
+ * Generate TCK clock cycles at variable frequency.
+ *
+ * Maximum achievable TCK frequency is 166.6 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param count number of TCK clock cycles to generate.
+ */
+void jtag_slow_clock_tck(uint16_t count)
+{
+ uint16_t i;
+ uint8_t j;
+ uint8_t outb_buffer = IOB & ~(bmbit2);
+
+ for (i = 0; i < count; i++) {
+ IOB = outb_buffer;
+ for (j = 0; j < delay_tck; j++)
+ ;
+ IOB = outb_buffer | bmbit2;
+ for (j = 0; j < delay_tck; j++)
+ ;
+ }
+}
+
+/**
+ * Perform TAP FSM state transitions at maximum TCK frequency.
+ *
+ * Maximum achievable TCK frequency is 176 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param count the number of state transitions to perform.
+ * @param sequence the TMS pin levels for each state transition, starting with
+ * the least-significant bit.
+ */
+void jtag_clock_tms(uint8_t count, uint8_t sequence)
+{
+ uint8_t outb_buffer = IOB & ~(bmbit2);
+ uint8_t i;
+
+ for (i = 0; i < count; i++) {
+ /* Set TMS pin according to sequence parameter */
+ if (sequence & 0x1)
+ outb_buffer |= bmbit1;
+ else
+ outb_buffer &= ~bmbit1;
+ IOB = outb_buffer;
+ sequence = sequence >> 1;
+ IOB = outb_buffer | bmbit2;
+ }
+}
+
+/**
+ * Perform TAP-FSM state transitions at less than maximum TCK frequency.
+ *
+ * Maximum achievable TCK frequency is 117 kHz for ANGIE clocked at 24 MHz.
+ *
+ * @param count the number of state transitions to perform.
+ * @param sequence the TMS pin levels for each state transition, starting with
+ * the least-significant bit.
+ */
+void jtag_slow_clock_tms(uint8_t count, uint8_t sequence)
+{
+ uint8_t outb_buffer = IOB & ~(bmbit2);
+ uint8_t i, j;
+
+ for (i = 0; i < count; i++) {
+ /* Set TMS pin according to sequence parameter */
+ if (sequence & 0x1)
+ outb_buffer |= bmbit1;
+ else
+ outb_buffer &= ~bmbit1;
+ IOB = outb_buffer;
+ for (j = 0; j < delay_tms; j++)
+ ;
+ sequence = sequence >> 1;
+ IOB = outb_buffer | bmbit2;
+ for (j = 0; j < delay_tms; j++)
+ ;
+ }
+}
+
+uint16_t jtag_get_signals(void)
+{
+ uint8_t input_signal_state, output_signal_state;
+ input_signal_state = 0;
+ output_signal_state = 0;
+
+ /* Get states of input pins */
+ if (PIN_TDO)
+ input_signal_state |= SIGNAL_TDO;
+
+ /* Get states of output pins */
+ output_signal_state = IOB & MASK_PORTB_DIRECTION_OUT;
+
+ return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state);
+}
+
+/**
+ * Set state of JTAG output signals.
+ *
+ * @param low signals which should be de-asserted.
+ * @param high signals which should be asserted.
+ */
+void jtag_set_signals(uint8_t low, uint8_t high)
+{
+ IOB &= ~(low & MASK_PORTB_DIRECTION_OUT);
+ IOB |= (high & MASK_PORTB_DIRECTION_OUT);
+}
+
+/**
+ * Configure TCK delay parameters.
+ *
+ * @param scan_in number of delay cycles in scan_in operations.
+ * @param scan_out number of delay cycles in scan_out operations.
+ * @param scan_io number of delay cycles in scan_io operations.
+ * @param tck number of delay cycles in clock_tck operations.
+ * @param tms number of delay cycles in clock_tms operations.
+ */
+void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out,
+ uint8_t scan_io, uint8_t tck, uint8_t tms)
+{
+ delay_scan_in = scan_in;
+ delay_scan_out = scan_out;
+ delay_scan_io = scan_io;
+ delay_tck = tck;
+ delay_tms = tms;
+}
diff --git a/contrib/firmware/angie/c/src/main.c b/contrib/firmware/angie/c/src/main.c
new file mode 100644
index 0000000..9290af2
--- /dev/null
+++ b/contrib/firmware/angie/c/src/main.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/****************************************************************************
+ File : main.c *
+ Contents : main code for NanoXplore USB-JTAG ANGIE adapter *
+ hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#include "usb.h"
+#include "delay.h"
+#include "protocol.h"
+#include "reg_ezusb.h"
+#include <serial.h>
+#include <stdio.h>
+
+extern void sudav_isr(void)__interrupt SUDAV_ISR;
+extern void sof_isr(void)__interrupt;
+extern void sutok_isr(void)__interrupt;
+extern void suspend_isr(void)__interrupt;
+extern void usbreset_isr(void)__interrupt;
+extern void highspeed_isr(void)__interrupt;
+extern void ep0ack_isr(void)__interrupt;
+extern void stub_isr(void)__interrupt;
+extern void ep0in_isr(void)__interrupt;
+extern void ep0out_isr(void)__interrupt;
+extern void ep1in_isr(void)__interrupt;
+extern void ep1out_isr(void)__interrupt;
+extern void ep2_isr(void)__interrupt;
+extern void ep4_isr(void)__interrupt;
+extern void ep6_isr(void)__interrupt;
+extern void ep8_isr(void)__interrupt;
+extern void ibn_isr(void)__interrupt;
+extern void ep0pingnak_isr(void)__interrupt;
+extern void ep1pingnak_isr(void)__interrupt;
+extern void ep2pingnak_isr(void)__interrupt;
+extern void ep4pingnak_isr(void)__interrupt;
+extern void ep6pingnak_isr(void)__interrupt;
+extern void ep8pingnak_isr(void)__interrupt;
+extern void errorlimit_isr(void)__interrupt;
+extern void ep2piderror_isr(void)__interrupt;
+extern void ep4piderror_isr(void)__interrupt;
+extern void ep6piderror_isr(void)__interrupt;
+extern void ep8piderror_isr(void)__interrupt;
+extern void ep2pflag_isr(void)__interrupt;
+extern void ep4pflag_isr(void)__interrupt;
+extern void ep6pflag_isr(void)__interrupt;
+extern void ep8pflag_isr(void)__interrupt;
+extern void ep2eflag_isr(void)__interrupt;
+extern void ep4eflag_isr(void)__interrupt;
+extern void ep6eflag_isr(void)__interrupt;
+extern void ep8eflag_isr(void)__interrupt;
+extern void ep2fflag_isr(void)__interrupt;
+extern void ep4fflag_isr(void)__interrupt;
+extern void ep6fflag_isr(void)__interrupt;
+extern void ep8fflag_isr(void)__interrupt;
+extern void gpifcomplete_isr(void)__interrupt;
+extern void gpifwaveform_isr(void)__interrupt;
+
+void gpif_init(void);
+
+int main(void)
+{
+ CPUCS = ((CPUCS & ~bmclkspd) | (CLK_48M << 3) | CLKOE); /* required for sio0_init */
+ sio0_init(57600); /* needed for printf */
+
+ ep_init();
+ gpif_init();
+ interrupt_init();
+ io_init();
+
+ /* Perform ReNumeration */
+ USBCS |= (DISCON | RENUM);
+ delay_ms(250);
+ USBCS &= ~DISCON;
+
+ /* Begin executing command(s). This function never returns. */
+ command_loop();
+
+ /* Never reached, but SDCC complains about missing return statement */
+ return 0;
+}
diff --git a/contrib/firmware/angie/c/src/protocol.c b/contrib/firmware/angie/c/src/protocol.c
new file mode 100644
index 0000000..3f3aaaf
--- /dev/null
+++ b/contrib/firmware/angie/c/src/protocol.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/****************************************************************************
+ File : protocol.c *
+ Contents : Jtag commands handling protocol code for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#include "usb.h"
+#include "protocol.h"
+#include "jtag.h"
+#include "delay.h"
+#include "io.h"
+#include "msgtypes.h"
+#include "reg_ezusb.h"
+#include <serial.h>
+#include <stdio.h>
+
+/** Index in EP1 Bulk-OUT data buffer that contains the current command ID */
+volatile uint8_t cmd_id_index;
+
+/** Number of data bytes already in EP1 Bulk-IN buffer */
+volatile uint8_t payload_index_in;
+
+/**
+ * Executes one command and updates global command indexes.
+ *
+ * @return true if this command was the last command.
+ * @return false if there are more commands within the current contents of the
+ * Bulk EP1-OUT data buffer.
+ */
+bool execute_command(void)
+{
+ uint8_t usb_out_bytecount, usb_in_bytecount;
+ uint16_t signal_state = 0;
+ uint16_t count;
+
+ /* Most commands do not transfer IN data. To save code space, we write 0 to
+ * usb_in_bytecount here, then modify it in the switch statement below where
+ * necessary */
+ usb_in_bytecount = 0;
+
+ switch (EP1OUTBUF[cmd_id_index] /* Command ID */) {
+ case CMD_SCAN_IN:
+ usb_out_bytecount = 5;
+ usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
+ jtag_scan_in((cmd_id_index + 1), payload_index_in);
+ break;
+ case CMD_SCAN_OUT:
+ usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5;
+ jtag_scan_out(cmd_id_index + 1);
+ break;
+ case CMD_SCAN_IO:
+ usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
+ usb_out_bytecount = usb_in_bytecount + 5;
+ jtag_scan_io((cmd_id_index + 1), payload_index_in);
+ break;
+ case CMD_CLOCK_TMS:
+ usb_out_bytecount = 2;
+ jtag_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
+ break;
+ case CMD_CLOCK_TCK:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ jtag_clock_tck(count);
+ break;
+ case CMD_SLOW_SCAN_IN:
+ usb_out_bytecount = 5;
+ usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
+ jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_SLOW_SCAN_OUT:
+ usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5;
+ jtag_slow_scan_out(cmd_id_index + 1);
+ break;
+ case CMD_SLOW_SCAN_IO:
+ usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
+ usb_out_bytecount = usb_in_bytecount + 5;
+ jtag_slow_scan_io(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_SLOW_CLOCK_TMS:
+ usb_out_bytecount = 2;
+ jtag_slow_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
+ break;
+ case CMD_SLOW_CLOCK_TCK:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ jtag_slow_clock_tck(count);
+ break;
+ case CMD_SLEEP_US:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ delay_us(count);
+ break;
+ case CMD_SLEEP_MS:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ delay_ms(count);
+ break;
+ case CMD_GET_SIGNALS:
+ usb_out_bytecount = 0;
+ usb_in_bytecount = 2;
+ signal_state = jtag_get_signals();
+ EP1INBUF[payload_index_in] = (signal_state >> 8);
+ EP1INBUF[payload_index_in + 1] = (signal_state & 0xFF);
+ break;
+ case CMD_SET_SIGNALS:
+ usb_out_bytecount = 2;
+ jtag_set_signals(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
+ break;
+ case CMD_CONFIGURE_TCK_FREQ:
+ usb_out_bytecount = 5;
+ jtag_configure_tck_delay(EP1OUTBUF[cmd_id_index + 1], /* scan_in */
+ EP1OUTBUF[cmd_id_index + 2], /* scan_out */
+ EP1OUTBUF[cmd_id_index + 3], /* scan_io */
+ EP1OUTBUF[cmd_id_index + 4], /* clock_tck */
+ EP1OUTBUF[cmd_id_index + 5]); /* clock_tms */
+ break;
+ case CMD_TEST:
+ usb_out_bytecount = 1;
+ /* Do nothing... This command is only used to test if the device is ready
+ * to accept new commands */
+ break;
+ default:
+ /* Should never be reached */
+ usb_out_bytecount = 0;
+ break;
+ }
+
+ /* Update EP1 Bulk-IN data byte count */
+ payload_index_in += usb_in_bytecount;
+
+ /* Determine if this was the last command */
+ if ((cmd_id_index + usb_out_bytecount + 1) >= EP1OUTBC) {
+ return true;
+ /* Line between return and else required by checkpatch: */
+ uint8_t a = 0;
+ } else {
+ /* Not the last command, update cmd_id_index */
+ cmd_id_index += (usb_out_bytecount + 1);
+ return false;
+ }
+}
+
+/**
+ * Forever wait for commands and execute them as they arrive.
+ */
+void command_loop(void)
+{
+ bool last_command;
+ while (1) {
+ cmd_id_index = 0;
+ payload_index_in = 0;
+
+ /* Wait until host sends EP1 Bulk-OUT packet */
+ while (!ep1_out)
+ ;
+ ep1_out = false;
+
+ /* Execute the commands */
+ last_command = false;
+ while (!last_command)
+ last_command = execute_command();
+
+ /* Send back EP6 Bulk-IN packet if required */
+ if (payload_index_in > 0) {
+ EP1INBC = payload_index_in;
+ syncdelay(3);
+
+ while (!ep1_in)
+ ;
+ ep1_in = false;
+ }
+
+ /* Re-arm EP1-OUT after command execution */
+ EP1OUTBC = 0;
+ syncdelay(3);
+ EP1OUTBC = 0;
+ syncdelay(3);
+ }
+}
diff --git a/contrib/firmware/angie/c/src/serial.c b/contrib/firmware/angie/c/src/serial.c
new file mode 100644
index 0000000..0398cb2
--- /dev/null
+++ b/contrib/firmware/angie/c/src/serial.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/*
+ * This code was taken from the fx2lib project from this link:
+ * https://github.com/djmuhlestein/fx2lib
+ *
+ * Copyright (C) 2009 Ubixum, Inc.
+*/
+
+#include <reg_ezusb.h>
+#include <fx2macros.h>
+#include <serial.h>
+#include <stdint.h>
+/**
+ * using the comp port implies that timer 2 will be used as
+ * a baud rate generator. (Don't use timer 2)
+ **/
+void sio0_init(uint32_t baud_rate) __critical
+{
+ uint16_t hl; /* hl value for reload */
+ uint8_t mult; /* multiplier for clock speed */
+ uint32_t tmp; /* scratch for mult/divide */
+
+ mult = (CPUFREQ == CLK_12M) ? 1 : ((CPUFREQ == CLK_24M) ? 2 : 4);
+
+ /* set the clock rate */
+ /* use clock 2 */
+ RCLK = 1; TCLK = 1;
+ tmp = mult * 375000L * 2;
+ tmp /= baud_rate;
+ tmp += 1;
+ tmp /= 2;
+ hl = 0xFFFF - (uint16_t)tmp;
+ RCAP2H = (uint8_t)(((uint16_t)(hl) >> 8) & 0xff);
+
+ /* seems that the 24/48mhz calculations are always one less than suggested values */
+ /* trm table 14-16 */
+ RCAP2L = ((uint8_t)((uint16_t)(hl) & 0xff)) + (mult > 0 ? 1 : 0);
+
+ /* start the timer */
+ TR2 = 1;
+
+ /* set up the serial port */
+ SM0 = 0; SM1 = 1; /* serial mode 1 (asyncronous) */
+ SM2 = 0 ; /* has to do with receiving */
+ REN = 1 ; /* to enable receiving */
+ PCON |= 0x80; /* SET SMOD0, baud rate doubler */
+ TI = 1; /* we send initial byte */
+}
+
+int getchar(void)
+{
+ char c;
+ while (!RI)
+ ;
+ c = SBUF0;
+ RI = 0;
+ return c;
+}
+
+void _transchar(char c)
+{
+ while (!TI)
+ ; /* wait for TI=1 */
+ TI = 0;
+ SBUF0 = c;
+}
+
+int putchar (char c)
+{
+ if (c == '\n')
+ _transchar('\r'); /* transmit \r\n */
+ _transchar(c);
+ if (c == '\r')
+ _transchar('\n'); /* transmit \r\n */
+ return c;
+}
diff --git a/contrib/firmware/angie/c/src/usb.c b/contrib/firmware/angie/c/src/usb.c
new file mode 100644
index 0000000..8fd4de6
--- /dev/null
+++ b/contrib/firmware/angie/c/src/usb.c
@@ -0,0 +1,784 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/****************************************************************************
+ File : usb.c *
+ Contents : usb communication handling code for NanoXplore USB-JTAG *
+ ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#include "usb.h"
+#include "stdint.h"
+#include "delay.h"
+#include "io.h"
+#include "reg_ezusb.h"
+#include <fx2macros.h>
+#include <serial.h>
+#include <stdio.h>
+
+/* Also update external declarations in "include/usb.h" if making changes to
+ * these variables!
+ */
+volatile bool ep1_out;
+volatile bool ep1_in;
+
+volatile __xdata __at 0xE6B8 struct setup_data setup_data;
+
+/* Define number of endpoints (except Control Endpoint 0) in a central place.
+ * Be sure to include the necessary endpoint descriptors!
+ */
+#define NUM_ENDPOINTS 3
+
+__code struct usb_device_descriptor device_descriptor = {
+ .blength = sizeof(struct usb_device_descriptor),
+ .bdescriptortype = DESCRIPTOR_TYPE_DEVICE,
+ .bcdusb = 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */
+ .bdeviceclass = 0xFF, /* 0xFF = vendor-specific */
+ .bdevicesubclass = 0xFF,
+ .bdeviceprotocol = 0xFF,
+ .bmaxpacketsize0 = 64,
+ .idvendor = 0x584e,
+ .idproduct = 0x424e,
+ .bcddevice = 0x0000,
+ .imanufacturer = 1,
+ .iproduct = 2,
+ .iserialnumber = 3,
+ .bnumconfigurations = 1
+};
+
+/* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
+
+__code struct usb_config_descriptor config_descriptor = {
+ .blength = sizeof(struct usb_config_descriptor),
+ .bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION,
+ .wtotallength = sizeof(struct usb_config_descriptor) +
+ sizeof(struct usb_interface_descriptor) +
+ (NUM_ENDPOINTS * sizeof(struct usb_endpoint_descriptor)),
+ .bnuminterfaces = 1,
+ .bconfigurationvalue = 1,
+ .iconfiguration = 4, /* String describing this configuration */
+ .bmattributes = 0x80, /* Only MSB set according to USB spec */
+ .maxpower = 50 /* 100 mA */
+};
+
+__code struct usb_interface_descriptor interface_descriptor00 = {
+ .blength = sizeof(struct usb_interface_descriptor),
+ .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE,
+ .binterfacenumber = 0,
+ .balternatesetting = 0,
+ .bnumendpoints = NUM_ENDPOINTS,
+ .binterfaceclass = 0xFF,
+ .binterfacesubclass = 0xFF,
+ .binterfaceprotocol = 0xFF,
+ .iinterface = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep1_out_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (1 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 64,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep1_in_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (1 | USB_DIR_IN),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 64,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (2 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep4_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (4 | USB_DIR_IN),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep6_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (6 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep8_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (8 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_language_descriptor language_descriptor = {
+ .blength = 4,
+ .bdescriptortype = DESCRIPTOR_TYPE_STRING,
+ .wlangid = {0x0409 /* US English */}
+};
+
+__code struct usb_string_descriptor strmanufacturer =
+ STR_DESCR(16, 'N', 'a', 'n', 'o', 'X', 'p', 'l', 'o', 'r', 'e', ',', ' ', 'S', 'A', 'S', '.');
+
+__code struct usb_string_descriptor strproduct =
+ STR_DESCR(13, 'A', 'N', 'G', 'I', 'E', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
+
+__code struct usb_string_descriptor strserialnumber =
+ STR_DESCR(6, '0', '0', '0', '0', '0', '1');
+
+__code struct usb_string_descriptor strconfigdescr =
+ STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
+
+/* Table containing pointers to string descriptors */
+__code struct usb_string_descriptor *__code en_string_descriptors[4] = {
+ &strmanufacturer,
+ &strproduct,
+ &strserialnumber,
+ &strconfigdescr
+};
+void sudav_isr(void)__interrupt SUDAV_ISR
+{
+ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
+ USBIRQ = SUDAVI;
+ EP0CS |= HSNAK;
+ usb_handle_setup_data();
+}
+void sof_isr(void)__interrupt SOF_ISR
+{
+}
+void sutok_isr(void)__interrupt SUTOK_ISR
+{
+}
+void suspend_isr(void)__interrupt SUSPEND_ISR
+{
+}
+void usbreset_isr(void)__interrupt USBRESET_ISR
+{
+}
+void highspeed_isr(void)__interrupt HIGHSPEED_ISR
+{
+}
+void ep0ack_isr(void)__interrupt EP0ACK_ISR
+{
+}
+void stub_isr(void)__interrupt STUB_ISR
+{
+}
+void ep0in_isr(void)__interrupt EP0IN_ISR
+{
+}
+void ep0out_isr(void)__interrupt EP0OUT_ISR
+{
+}
+void ep1in_isr(void)__interrupt EP1IN_ISR
+{
+ ep1_in = true;
+
+ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
+ EPIRQ = 0x04; /* Clear individual EP1IN IRQ */
+}
+void ep1out_isr(void)__interrupt EP1OUT_ISR
+{
+ ep1_out = true;
+
+ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
+ EPIRQ = 0x08; /* Clear individual EP1OUT IRQ */
+}
+void ep2_isr(void)__interrupt EP2_ISR
+{
+ ep1_out = false; /* Does nothing but required by the compiler */
+}
+void ep4_isr(void)__interrupt EP4_ISR
+{
+}
+void ep6_isr(void)__interrupt EP6_ISR
+{
+}
+void ep8_isr(void)__interrupt EP8_ISR
+{
+}
+void ibn_isr(void)__interrupt IBN_ISR
+{
+}
+void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR
+{
+}
+void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR
+{
+}
+void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR
+{
+}
+void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR
+{
+}
+void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR
+{
+}
+void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR
+{
+}
+void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR
+{
+}
+void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR
+{
+}
+void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR
+{
+}
+void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR
+{
+}
+void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR
+{
+}
+void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR
+{
+}
+void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR
+{
+}
+void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR
+{
+}
+void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR
+{
+}
+void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR
+{
+}
+void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR
+{
+}
+void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR
+{
+}
+void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR
+{
+}
+void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR
+{
+}
+void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR
+{
+}
+void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR
+{
+}
+void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR
+{
+}
+void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR
+{
+}
+void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR
+{
+}
+
+/**
+ * Return the control/status register for an endpoint
+ *
+ * @param ep endpoint address
+ * @return on success: pointer to Control & Status register for endpoint
+ * specified in \a ep
+ * @return on failure: NULL
+ */
+__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep)
+{
+ /* Mask direction bit */
+ uint8_t ep_num = ep & ~0x80;
+
+ switch (ep_num) {
+ case 0:
+ return &EP0CS;
+ case 1:
+ return ep & 0x80 ? &EP1INCS : &EP1OUTCS;
+ case 2:
+ return &EP2CS;
+ case 4:
+ return &EP4CS;
+ case 6:
+ return &EP6CS;
+ case 8:
+ return &EP8CS;
+ default:
+ return NULL;
+ }
+}
+
+void usb_reset_data_toggle(uint8_t ep)
+{
+ /* TOGCTL register:
+ +----+-----+-----+------+-----+-------+-------+-------+
+ | Q | S | R | IO | EP3 | EP2 | EP1 | EP0 |
+ +----+-----+-----+------+-----+-------+-------+-------+
+
+ To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
+ to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
+ separate write cycle, the R bit needs to be set.
+ */
+ TOGCTL = (((ep & 0x80) >> 3) + (ep & 0x0F));
+ TOGCTL |= BMRESETTOGGLE;
+}
+
+/**
+ * Handle GET_STATUS request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_get_status(void)
+{
+ uint8_t *ep_cs;
+ switch (setup_data.bmrequesttype) {
+ case GS_DEVICE:
+ /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
+ * Byte 1: reserved, reset to zero */
+ EP0BUF[0] = 0;
+ EP0BUF[1] = 0;
+
+ /* Send response */
+ EP0BCH = 0;
+ syncdelay(3);
+ EP0BCL = 2;
+ syncdelay(3);
+ break;
+ case GS_INTERFACE:
+ /* Always return two zero bytes according to USB 1.1 spec, p. 191 */
+ EP0BUF[0] = 0;
+ EP0BUF[1] = 0;
+
+ /* Send response */
+ EP0BCH = 0;
+ syncdelay(3);
+ EP0BCL = 2;
+ syncdelay(3);
+ break;
+ case GS_ENDPOINT:
+ /* Get stall bit for endpoint specified in low byte of wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.windex & 0xff);
+
+ if (*ep_cs & EPSTALL)
+ EP0BUF[0] = 0x01;
+ else
+ EP0BUF[0] = 0x00;
+
+ /* Second byte sent has to be always zero */
+ EP0BUF[1] = 0;
+
+ /* Send response */
+ EP0BCH = 0;
+ syncdelay(3);
+ EP0BCL = 2;
+ syncdelay(3);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Handle CLEAR_FEATURE request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_clear_feature(void)
+{
+ __xdata uint8_t *ep_cs;
+
+ switch (setup_data.bmrequesttype) {
+ case CF_DEVICE:
+ /* Clear remote wakeup not supported: stall EP0 */
+ STALL_EP0();
+ break;
+ case CF_ENDPOINT:
+ if (setup_data.wvalue == 0) {
+ /* Unstall the endpoint specified in wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.windex);
+ if (!ep_cs)
+ return false;
+ *ep_cs &= ~EPSTALL;
+ } else {
+ /* Unsupported feature, stall EP0 */
+ STALL_EP0();
+ }
+ break;
+ default:
+ /* Vendor commands... */
+ break;
+ }
+ return true;
+}
+
+/**
+ * Handle SET_FEATURE request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_set_feature(void)
+{
+ __xdata uint8_t *ep_cs;
+
+ switch (setup_data.bmrequesttype) {
+ case SF_DEVICE:
+ if (setup_data.wvalue == 2)
+ return true;
+ break;
+ case SF_ENDPOINT:
+ if (setup_data.wvalue == 0) {
+ /* Stall the endpoint specified in wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.windex);
+ if (!ep_cs)
+ return false;
+ *ep_cs |= EPSTALL;
+ } else {
+ /* Unsupported endpoint feature */
+ return false;
+ }
+ break;
+ default:
+ /* Vendor commands... */
+ break;
+ }
+
+ return true;
+}
+
+/**
+ * Handle GET_DESCRIPTOR request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_get_descriptor(void)
+{
+ __xdata uint8_t descriptor_type;
+ __xdata uint8_t descriptor_index;
+
+ descriptor_type = (setup_data.wvalue & 0xff00) >> 8;
+ descriptor_index = setup_data.wvalue & 0x00ff;
+
+ switch (descriptor_type) {
+ case DESCRIPTOR_TYPE_DEVICE:
+ SUDPTRH = HI8(&device_descriptor);
+ SUDPTRL = LO8(&device_descriptor);
+ break;
+ case DESCRIPTOR_TYPE_CONFIGURATION:
+ SUDPTRH = HI8(&config_descriptor);
+ SUDPTRL = LO8(&config_descriptor);
+ break;
+ case DESCRIPTOR_TYPE_STRING:
+ if (setup_data.windex == 0) {
+ /* Supply language descriptor */
+ SUDPTRH = HI8(&language_descriptor);
+ SUDPTRL = LO8(&language_descriptor);
+ } else if (setup_data.windex == 0x0409 /* US English */) {
+ /* Supply string descriptor */
+ SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]);
+ SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]);
+ } else {
+ return false;
+ }
+ break;
+ default:
+ /* Unsupported descriptor type */
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Handle SET_INTERFACE request.
+ */
+void usb_handle_set_interface(void)
+{
+ /* Reset Data Toggle */
+ usb_reset_data_toggle(USB_DIR_IN | 4);
+ usb_reset_data_toggle(USB_DIR_OUT | 2);
+
+ /* Unstall & clear busy flag of all valid IN endpoints */
+ EP1INCS = 0 | EPBSY;
+
+ /* Unstall all valid OUT endpoints, reset bytecounts */
+ EP1OUTCS = 0;
+ EP1OUTBC = 0;
+ syncdelay(3);
+}
+
+/* Initialize GPIF interface transfer count */
+void set_gpif_cnt(uint32_t count)
+{
+ GPIFTCB3 = (uint8_t)(((uint32_t)(count) >> 24) & 0x000000ff);
+ syncdelay(3);
+ GPIFTCB2 = (uint8_t)(((uint32_t)(count) >> 16) & 0x000000ff);
+ syncdelay(3);
+ GPIFTCB1 = (uint8_t)(((uint32_t)(count) >> 8) & 0x000000ff);
+ syncdelay(3);
+ GPIFTCB0 = (uint8_t)((uint32_t)(count) & 0x000000ff);
+}
+
+/*
+ * Vendor commands handling:
+*/
+#define VR_CFGOPEN 0xB0
+#define VR_CFGCLOSE 0xB1
+
+uint8_t ix;
+uint8_t bcnt;
+uint8_t __xdata *eptr;
+uint16_t wcnt;
+uint32_t __xdata gcnt;
+bool usb_handle_send_bitstream(void)
+{
+ eptr = EP0BUF; /* points to EP0BUF 64-byte register */
+ wcnt = setup_data.wlength; /* total transfer count */
+
+ /* Clear EP0BUF for OUT requests */
+ if (setup_data.bmrequesttype & 0x80) {
+ bcnt = ((wcnt > 64) ? 64 : wcnt);
+ for (ix = 0; ix < bcnt; ix++)
+ eptr[ix] = 0;
+ }
+
+ switch (setup_data.brequest) {
+ case VR_CFGOPEN:
+ /* Clear bytecount / to allow new data in / to stops NAKing */
+ EP0BCH = 0;
+ EP0BCL = 0;
+ while (EP0CS & EPBSY)
+ ; /* wait to finish transferring in EP0BUF, until not busy */
+ gcnt = ((uint32_t)(eptr[0]) << 24) | ((uint32_t)(eptr[1]) << 16)
+ | ((uint32_t)(eptr[2]) << 8) | (uint32_t)(eptr[3]);
+ /* Angie board FPGA bitstream download */
+ switch ((setup_data.wvalue) & 0x00C0) {
+ case 0x00:
+ PIN_PROGRAM_B = 0; /* Apply RPGM- pulse */
+ GPIFWFSELECT = 0xF2; /* Restore Config mode waveforms select */
+ syncdelay(3);
+ EP2FIFOCFG = BMAUTOOUT; /* and Automatic 8-bit GPIF OUT mode */
+ syncdelay(3);
+ PIN_PROGRAM_B = 1; /* Negate RPGM- pulse */
+ delay_ms(10); /* FPGA init time < 10mS */
+ set_gpif_cnt(gcnt); /* Initialize GPIF interface transfer count */
+ PIN_RDWR_B = 0;
+ PIN_CSI_B = 0;
+ GPIFTRIG = GPIF_EP2; /* Trigger GPIF OUT transfer on EP2 */
+ syncdelay(3);
+ break;
+ default:
+ break;
+ }
+ break;
+ case VR_CFGCLOSE:
+ ix = 10;
+ /* wait until GPIF transaction has been completed */
+ while ((GPIFTRIG & BMGPIFDONE) == 0) {
+ if (ix-- == 0) {
+ printf("GPIF done time out\n");
+ break;
+ }
+ delay_ms(1);
+ }
+ switch ((setup_data.wvalue) & 0x00C0) {
+ case 0x00:
+ PIN_CSI_B = 1;
+ PIN_RDWR_B = 1;
+ IFCONFIG &= 0xFC; /* Exit gpif mode */
+ break;
+ default:
+ break;
+ }
+ EP0BCH = 0;
+ EP0BCL = (uint8_t)(setup_data.wlength); /* Signal buffer is filled */
+ break;
+ default:
+ return true; /* Error: unknown VR command */
+ }
+ return false; /* no error; command handled OK */
+}
+
+/**
+ * Handle the arrival of a USB Control Setup Packet.
+ */
+void usb_handle_setup_data(void)
+{
+ switch (setup_data.brequest) {
+ case GET_STATUS:
+ if (!usb_handle_get_status())
+ STALL_EP0();
+ break;
+ case CLEAR_FEATURE:
+ if (!usb_handle_clear_feature())
+ STALL_EP0();
+ break;
+ case 2: case 4:
+ /* Reserved values */
+ STALL_EP0();
+ break;
+ case SET_FEATURE:
+ if (!usb_handle_set_feature())
+ STALL_EP0();
+ break;
+ case SET_ADDRESS:
+ /* Handled by USB core */
+ break;
+ case SET_DESCRIPTOR:
+ /* Set Descriptor not supported. */
+ STALL_EP0();
+ break;
+ case GET_DESCRIPTOR:
+ if (!usb_handle_get_descriptor())
+ STALL_EP0();
+ break;
+ case GET_CONFIGURATION:
+ /* ANGIE has only one configuration, return its index */
+ EP0BUF[0] = config_descriptor.bconfigurationvalue;
+ EP0BCH = 0;
+ EP0BCL = 1;
+ syncdelay(3);
+ break;
+ case SET_CONFIGURATION:
+ /* ANGIE has only one configuration -> nothing to do */
+ break;
+ case GET_INTERFACE:
+ /* ANGIE only has one interface, return its number */
+ EP0BUF[0] = interface_descriptor00.binterfacenumber;
+ EP0BCH = 0;
+ EP0BCL = 1;
+ syncdelay(3);
+ break;
+ case SET_INTERFACE:
+ usb_handle_set_interface();
+ break;
+ case SYNCH_FRAME:
+ /* Isochronous endpoints not used -> nothing to do */
+ break;
+ default:
+ /* if not Vendor command, Stall EndPoint 0 */
+ if (usb_handle_send_bitstream())
+ STALL_EP0();
+ break;
+ }
+}
+
+/**
+ * Handle the initialization of endpoints.
+ */
+void ep_init(void)
+{
+ EP1INCFG = 0xA0;
+ syncdelay(3);
+ EP1OUTCFG = 0xA0;
+ syncdelay(3);
+ EP2CFG = 0xA0;
+ syncdelay(3);
+ EP4CFG = 0x00;
+ syncdelay(3);
+ EP6CFG = 0x00;
+ syncdelay(3);
+ EP8CFG = 0x00;
+ syncdelay(3);
+
+ /* arm EP1-OUT */
+ EP1OUTBC = 0;
+ syncdelay(3);
+ EP1OUTBC = 0;
+ syncdelay(3);
+
+ /* arm EP1-IN */
+ EP1INBC = 0;
+ syncdelay(3);
+ EP1INBC = 0;
+ syncdelay(3);
+
+ /* Standard procedure to reset FIFOs */
+ FIFORESET = BMNAKALL; /* NAK all transfers during the reset */
+ syncdelay(3);
+ FIFORESET = 0x02; /* reset EP2 FIFO */
+ syncdelay(3);
+ FIFORESET = 0x00; /* deactivate the NAK all */
+ syncdelay(3);
+ EP2FIFOCFG = 0x00;
+ syncdelay(3);
+ EP2FIFOCFG = BMAUTOOUT; /* Automatic 8-bit GPIF OUT mode */
+ syncdelay(3);
+}
+
+/**
+ * Interrupt initialization. Configures USB interrupts.
+ */
+void interrupt_init(void)
+{
+ /* Enable Interrupts */
+ EA = 1;
+
+ /* Enable USB interrupt (EIE register) */
+ EUSB = 1;
+ EICON |= 0x20;
+
+ /* Enable INT 2 & 4 Autovectoring */
+ INTSETUP |= (AV2EN | AV4EN);
+
+ /* Enable individual EP1OUT&IN interrupts */
+ EPIE |= 0x0C;
+
+ /* Clear individual USB interrupt IRQ */
+ EPIRQ = 0x0C;
+
+ /* Enable SUDAV interrupt */
+ USBIEN |= SUDAVI;
+
+ /* Clear SUDAV interrupt */
+ USBIRQ = SUDAVI;
+}
+
+/**
+ * Handle the initialization of io ports.
+ */
+void io_init(void)
+{
+ /* PORT A */
+ PORTACFG = 0x01; /* 0: normal ou 1: alternate function (each bit) */
+ OEA = 0xEF; /* all OUT exept INIT_B IN */
+ IOA = 0xFF;
+ PIN_RDWR_B = 1;
+ PIN_CSI_B = 1;
+ PIN_PROGRAM_B = 1;
+
+ /* PORT B */
+ OEB = 0xEF; /* all OUT exept TDO */
+ IOB = 0xFF;
+ PIN_TRST = 1;
+ PIN_TMS = 0;
+ PIN_TCK = 0;
+ PIN_TDI = 0;
+ PIN_SRST = 1;
+
+ /* PORT C */
+ PORTCCFG = 0x00; /* 0: normal ou 1: alternate function (each bit) */
+ OEC = 0xEF;
+ IOC = 0xFF;
+}
diff --git a/contrib/firmware/angie/hdl/Makefile b/contrib/firmware/angie/hdl/Makefile
new file mode 100644
index 0000000..c2c74a0
--- /dev/null
+++ b/contrib/firmware/angie/hdl/Makefile
@@ -0,0 +1,109 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (C) 2023 by NanoXplore, France - all rights reserved
+
+# Needed by timing test
+export PROJECT := angie_openocd
+TARGET_PART := xc6slx9-2tqg144
+export TOPLEVEL := S609
+
+# Detects the ROOT dir from the .git marker
+sp :=
+sp +=
+_walk = $(if $1,$(wildcard /$(subst $(sp),/,$1)/$2) $(call _walk,$(wordlist 2,$(words $1),x $1),$2))
+_find = $(firstword $(call _walk,$(strip $(subst /, ,$1)),$2))
+_ROOT := $(patsubst %/.git,%,$(call _find,$(CURDIR),.git))
+
+SHELL := /bin/bash
+TOP_DIR := $(realpath $(_ROOT))
+HDL_DIR := $(CURDIR)
+SRC_DIR := $(HDL_DIR)/src
+TOOLS_DIR := $(TOP_DIR)/tools/build
+COMMON_DIR := $(TOP_DIR)/common/hdl
+COMMON_HDL_DIR := $(COMMON_DIR)/src
+COMMON_LIBS := $(COMMON_DIR)/libs
+HDL_BUILD_DIR := $(HDL_DIR)/build
+OUTPUT_DIR ?= $(HDL_BUILD_DIR)/output
+FINAL_OUTPUT_DIR := $(OUTPUT_DIR)/$(PROJECT)
+
+# Tools
+MKDIR := mkdir -p
+CP := cp -f
+
+HDL_SRC_PATH := $(addprefix $(COMMON_DIR)/ips/, $(HDL_IPS)) $(HDL_DIR)
+VHDSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.vhd))
+VSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.v))
+VSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.vh))
+
+CONSTRAINTS ?= $(SRC_DIR)/$(PROJECT).ucf
+
+COMMON_OPTS := -intstyle xflow
+XST_OPTS :=
+NGDBUILD_OPTS :=
+MAP_OPTS := -mt 2
+PAR_OPTS := -mt 4
+BITGEN_OPTS := -g Binary:Yes
+
+XILINX_PLATFORM := lin64
+PATH := $(PATH):$(XILINX_HOME)/bin/$(XILINX_PLATFORM)
+
+RUN = @echo -ne "\n\n\e[1;33m======== $(1) ========\e[m\n\n"; \
+ cd $(HDL_BUILD_DIR) && $(XILINX_HOME)/bin/$(XILINX_PLATFORM)/$(1)
+
+compile: $(HDL_BUILD_DIR)/$(PROJECT).bin
+
+install: $(HDL_BUILD_DIR)/$(PROJECT).bin
+ $(MKDIR) $(FINAL_OUTPUT_DIR)
+ $(CP) $(HDL_BUILD_DIR)/$(PROJECT).bin $(FINAL_OUTPUT_DIR)
+
+clean:
+ rm -rf $(HDL_BUILD_DIR)
+
+$(HDL_BUILD_DIR)/$(PROJECT).bin: $(HDL_BUILD_DIR)/$(PROJECT).ncd
+ $(call RUN,bitgen) $(COMMON_OPTS) $(BITGEN_OPTS) \
+ -w $(PROJECT).ncd $(PROJECT).bit
+
+$(HDL_BUILD_DIR)/$(PROJECT).ncd: $(HDL_BUILD_DIR)/$(PROJECT).map.ncd
+ $(call RUN,par) $(COMMON_OPTS) $(PAR_OPTS) \
+ -w $(PROJECT).map.ncd $(PROJECT).ncd $(PROJECT).pcf
+
+$(HDL_BUILD_DIR)/$(PROJECT).map.ncd: $(HDL_BUILD_DIR)/$(PROJECT).ngd
+ $(call RUN,map) $(COMMON_OPTS) $(MAP_OPTS) \
+ -p $(TARGET_PART) \
+ -w $(PROJECT).ngd -o $(PROJECT).map.ncd $(PROJECT).pcf
+
+$(HDL_BUILD_DIR)/$(PROJECT).ngd: $(HDL_BUILD_DIR)/$(PROJECT).ngc
+ $(call RUN,ngdbuild) $(COMMON_OPTS) $(NGDBUILD_OPTS) \
+ -p $(TARGET_PART) -uc $(CONSTRAINTS) \
+ $(PROJECT).ngc $(PROJECT).ngd
+
+$(HDL_BUILD_DIR)/$(PROJECT).ngc: $(HDL_BUILD_DIR)/$(PROJECT).prj $(HDL_BUILD_DIR)/$(PROJECT).scr
+ $(call RUN,xst) $(COMMON_OPTS) -ifn $(PROJECT).scr
+
+$(HDL_BUILD_DIR)/$(PROJECT).scr: | $(HDL_BUILD_DIR)
+ @echo "Updating $@"
+ @mkdir -p $(HDL_BUILD_DIR)
+ @rm -f $@
+ @echo "run" \
+ "-ifn $(PROJECT).prj" \
+ "-ofn $(PROJECT).ngc" \
+ "-ifmt mixed" \
+ "$(XST_OPTS)" \
+ "-top $(TOPLEVEL)" \
+ "-ofmt NGC" \
+ "-p $(TARGET_PART)" \
+ > $(HDL_BUILD_DIR)/$(PROJECT).scr
+
+$(HDL_BUILD_DIR)/$(PROJECT).prj: | $(HDL_BUILD_DIR)
+ @echo "Updating $@"
+ @rm -f $@
+ @$(foreach file,$(VSOURCE),echo "verilog work \"$(file)\"" >> $@;)
+ @$(foreach file,$(VHDSOURCE),echo "vhdl work \"$(file)\"" >> $@;)
+ @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.vhd),echo "vhdl $(lib) \"$(file)\"" >> $@;))
+ @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.v),echo "verilog $(lib) \"$(file)\"" >> $@;))
+ @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.vh),echo "verilog $(lib) \"$(file)\"" >> $@;))
+
+$(HDL_BUILD_DIR):
+ $(MKDIR) $(HDL_BUILD_DIR)
+
+.PHONY: clean compile install
+
diff --git a/contrib/firmware/angie/hdl/README b/contrib/firmware/angie/hdl/README
new file mode 100644
index 0000000..00578ff
--- /dev/null
+++ b/contrib/firmware/angie/hdl/README
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (C) 2023 by NanoXplore, France - all rights reserved
+
+This is the source code of Nanoxplore USB-JTAG Adapter Angie's bitstream.
+This bitstream is for the "xc6slx9-2tqg144" Spartan-6 Xilinx FPGA.
+
+To generate this bitstream, you need to install Xilinx ISE Webpack 14.7
+You will need to give the ISE software path : export XILINX_HOME=path/to/ise/sw
+Please set the enviromnent first by executing the ". ./set_env.sh"
+
+All you have to do now is to write your vhd and constrains codes.
+
+One all is setup, you can use the make commands:
+ make compile : to compile your (.vhd & .ucf) files in the "src" directory
+ A directory named "build" will be created, which contains all the generated
+ files including the bitstream file.
+
+ make clean : to delete the build directory.
diff --git a/contrib/firmware/angie/hdl/set_env.sh b/contrib/firmware/angie/hdl/set_env.sh
new file mode 100644
index 0000000..60e9737
--- /dev/null
+++ b/contrib/firmware/angie/hdl/set_env.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (C) 2023 by NanoXplore, France - all rights reserved
+
+[ -z "${XILINX_HOME}" ] && export XILINX_HOME=/home/software/Xilinx/ISE/14.7/ISE_DS/ISE
+export PATH="$XILINX_HOME:$PATH"
+echo "SET XILINX_HOME to ${XILINX_HOME}"
+# This is needed for isim
+XILINX_HOME_BASE=${XILINX_HOME}/..
+for part in common EDK PlanAhead ISE
+do
+ el=${XILINX_HOME_BASE}/${part}
+ . ${el}/.settings64.sh ${el}
+done
diff --git a/contrib/firmware/angie/hdl/src/angie_openocd.ucf b/contrib/firmware/angie/hdl/src/angie_openocd.ucf
new file mode 100644
index 0000000..fda3cda
--- /dev/null
+++ b/contrib/firmware/angie/hdl/src/angie_openocd.ucf
@@ -0,0 +1,35 @@
+## SPDX-License-Identifier: BSD-3-Clause
+##--------------------------------------------------------------------------
+## Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6
+## Design Name: NJTAG USB-JTAG Adapter FPGA source code
+## Module Name: _angie_openocd.ucf
+## Target Device: XC6SLX9-2 TQ144
+## Tool versions: ISE Webpack 13.2 -> 14.2
+## Author: Ahmed BOUDJELIDA nanoXplore SAS
+##--------------------------------------------------------------------------
+# WARNING: PullUps on JTAG inputs should be enabled after configuration
+# (bitgen option) since the pins are not connected.
+
+net TRST LOC = 'P48' ;
+net TMS LOC = 'P43' ;
+net TCK LOC = 'P44' ;
+net TDI LOC = 'P45' ;
+net TDO LOC = 'P46' ;
+net SRST LOC = 'P61' ;
+net SI_TDO LOC = 'P16' ;
+net SO_TRST LOC = 'P32' ;
+net SO_TMS LOC = 'P27' ;
+net SO_TCK LOC = 'P30' ;
+net SO_TDI LOC = 'P26' ;
+net SO_SRST LOC = 'P12' ;
+net ST_0 LOC = 'P29' ;
+net ST_1 LOC = 'P21' ;
+net ST_2 LOC = 'P11' ;
+net FTP<0> LOC = 'P121' ;
+net FTP<1> LOC = 'P120' ;
+net FTP<2> LOC = 'P119' ;
+net FTP<3> LOC = 'P116' ;
+net FTP<4> LOC = 'P111' ;
+net FTP<5> LOC = 'P112' ;
+net FTP<6> LOC = 'P115' ;
+net FTP<7> LOC = 'P114' ;
diff --git a/contrib/firmware/angie/hdl/src/angie_openocd.vhd b/contrib/firmware/angie/hdl/src/angie_openocd.vhd
new file mode 100644
index 0000000..d79c0fe
--- /dev/null
+++ b/contrib/firmware/angie/hdl/src/angie_openocd.vhd
@@ -0,0 +1,66 @@
+-- SPDX-License-Identifier: BSD-3-Clause
+----------------------------------------------------------------------------
+-- Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6
+-- Design Name: NJTAG USB-JTAG Adapter FPGA source code
+-- Module Name: _angie_openocd.vhd
+-- Target Device: XC6SLX9-2 TQ144
+-- Tool versions: ISE Webpack 13.2 -> 14.2
+-- Author: Ahmed BOUDJELIDA nanoXplore SAS
+----------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+library UNISIM;
+use UNISIM.VComponents.all;
+
+entity S609 is port(
+ TRST : in std_logic;
+ TMS : in std_logic;
+ TCK : in std_logic;
+ TDI : in std_logic;
+ TDO : out std_logic;
+ SRST : in std_logic;
+ FTP : out std_logic_vector(7 downto 0); -- Test points
+ SI_TDO : in std_logic;
+ ST_0 : out std_logic;
+ ST_1 : out std_logic;
+ ST_2 : out std_logic;
+ SO_TRST : out std_logic;
+ SO_TMS : out std_logic;
+ SO_TCK : out std_logic;
+ SO_TDI : out std_logic;
+ SO_SRST :out std_logic
+);
+end S609;
+
+architecture A_S609 of S609 is
+begin
+
+--Directions:
+ST_0 <= '0';
+ST_1 <= '1';
+
+--TDO:
+TDO <= not SI_TDO;
+
+--TRST - TCK - TMS - TDI:
+SO_TRST <= TRST;
+SO_TMS <= TMS;
+SO_TCK <= TCK;
+SO_TDI <= TDI;
+ST_2 <= SRST;
+SO_SRST <= '0';
+
+--Points de test:
+FTP(0) <= TRST;
+FTP(1) <= TMS;
+FTP(2) <= TCK;
+FTP(3) <= TDI;
+FTP(5) <= SRST;
+FTP(4) <= SI_TDO;
+FTP(6) <= '1';
+FTP(7) <= '1';
+
+end A_S609;