Jelajahi Sumber

Port of main code to GD32 and cleanup (work in progress).

Separated the platform-specific parts to a library, to simplify future
porting to different boards.

This compiles and does something with SCSI now, but does not work yet.
And the speed-optimized read/write functionality is not yet implemented.
Petteri Aimonen 3 tahun lalu
induk
melakukan
0ef5572e4b

+ 310 - 0
lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.cpp

@@ -0,0 +1,310 @@
+#include "AzulSCSI_platform.h"
+#include "gd32f20x_spi.h"
+#include <SdFat.h>
+
+extern "C" {
+
+static volatile uint32_t g_millisecond_counter;
+
+unsigned long millis()
+{
+    return g_millisecond_counter;
+}
+
+void delay(unsigned long ms)
+{
+    uint32_t start = g_millisecond_counter;
+    while ((uint32_t)(g_millisecond_counter - start) < ms);
+}
+
+void SysTick_Handler(void)
+{
+    g_millisecond_counter++;
+}
+
+// Writes log data to the PB3 SWO pin
+void azplatform_log(const char *s)
+{
+    while (*s)
+    {
+        // Write to SWO pin
+        while (ITM->PORT[0].u32 == 0);
+        ITM->PORT[0].u8 = *s++;
+    }
+}
+
+// Initialize SPI and GPIO configuration
+// Clock has already been initialized by system_gd32f20x.c
+void azplatform_init()
+{
+    SystemCoreClockUpdate();
+
+    // Enable SysTick to drive millis()
+    SysTick_Config(SystemCoreClock / 1000U);
+    NVIC_SetPriority(SysTick_IRQn, 0x00U);
+
+    // Enable debug output on SWO pin
+    DBG_CTL |= DBG_CTL_TRACE_IOEN;
+    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+    TPI->ACPR = SystemCoreClock / 2000000 - 1; // 2 Mbps baudrate for SWO
+    TPI->SPPR = 2;
+    TPI->FFCR = 0x100; // TPIU packet framing disabled
+    // DWT->CTRL = (1 << DWT_CTRL_CYCTAP_Pos)
+    //             | (15 << DWT_CTRL_POSTPRESET_Pos)
+    //             | (1 << DWT_CTRL_PCSAMPLENA_Pos)
+    //             | (3 << DWT_CTRL_SYNCTAP_Pos)
+    //             | (1 << DWT_CTRL_CYCCNTENA_Pos);
+    ITM->LAR = 0xC5ACCE55;
+    ITM->TCR = (1 << ITM_TCR_DWTENA_Pos)
+                | (1 << ITM_TCR_SYNCENA_Pos)
+                | (1 << ITM_TCR_ITMENA_Pos);
+    ITM->TER = 0xFFFFFFFF; // Enable all stimulus ports
+
+    // Enable needed clocks for GPIO
+    rcu_periph_clock_enable(RCU_GPIOA);
+    rcu_periph_clock_enable(RCU_GPIOB);
+    rcu_periph_clock_enable(RCU_GPIOC);
+    rcu_periph_clock_enable(RCU_GPIOD);
+    rcu_periph_clock_enable(RCU_GPIOE);
+    
+    // Switch to SWD debug port (disable JTAG) to release PB4 as GPIO
+    gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);    
+
+    // SCSI pins.
+    // Initialize open drain outputs to high.
+    gpio_bit_set(SCSI_OUT_PORT, SCSI_OUT_MASK);
+    gpio_init(SCSI_OUT_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_MASK);
+    gpio_init(SCSI_IN_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_IN_MASK);
+    gpio_init(SCSI_ATN_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_ATN_PIN);
+    gpio_init(SCSI_BSY_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_BSY_PIN);
+    gpio_init(SCSI_SEL_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_SEL_PIN);
+    gpio_init(SCSI_ACK_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_ACK_PIN);
+    gpio_init(SCSI_RST_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_RST_PIN);
+
+    // Terminator enable
+    gpio_bit_set(SCSI_TERM_EN_PORT, SCSI_TERM_EN_PIN);
+    gpio_init(SCSI_TERM_EN_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, SCSI_TERM_EN_PIN);
+
+    // SD card pins
+    gpio_init(SD_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SD_CS_PIN);
+    gpio_init(SD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SD_CLK_PIN);
+    gpio_init(SD_PORT, GPIO_MODE_IPU, 0, SD_MISO_PIN);
+    gpio_init(SD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SD_MOSI_PIN);
+
+    // DIP switches
+    gpio_init(DIP_PORT, GPIO_MODE_IPD, 0, DIPSW1_PIN | DIPSW2_PIN | DIPSW3_PIN);
+
+    // LED pins
+    gpio_bit_set(LED_PORT, LED_PINS);
+    gpio_init(LED_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, LED_PINS);
+
+    // SWO trace pin on PB3
+    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
+
+    azplatform_log("GPIO init complete\n");    
+}
+
+static void (*g_rst_callback)();
+
+void azplatform_set_rst_callback(void (*callback)())
+{
+    g_rst_callback = callback;
+    gpio_exti_source_select(SCSI_RST_EXTI_SOURCE_PORT, SCSI_RST_EXTI_SOURCE_PIN);
+    exti_init(SCSI_RST_EXTI, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
+    NVIC_SetPriority(SCSI_RST_IRQn, 0x00U);
+}
+
+void SCSI_RST_IRQ (void)
+{
+    if (exti_interrupt_flag_get(SCSI_RST_EXTI))
+    {
+        exti_interrupt_flag_clear(SCSI_RST_EXTI);
+        if (g_rst_callback)
+        {
+            g_rst_callback();
+        }
+    }
+}
+
+/*****************************************/
+/* Crash handlers                        */
+/*****************************************/
+
+void HardFault_Handler(void)
+{
+    while (1);
+}
+
+void MemManage_Handler(void)
+{
+    while (1);
+}
+
+void BusFault_Handler(void)
+{
+    while (1);
+}
+
+void UsageFault_Handler(void)
+{
+    while (1);
+}
+
+} /* extern "C" */
+
+/*****************************************/
+/* Driver for GD32 SPI for SdFat library */
+/*****************************************/
+
+#define SD_SPI SPI0
+class GD32SPIDriver : public SdSpiBaseClass
+{
+public:
+    void begin(SdSpiConfig config) {
+        rcu_periph_clock_enable(RCU_SPI0);
+    }
+        
+    void activate() {
+        spi_parameter_struct config = {
+            SPI_MASTER,
+            SPI_TRANSMODE_FULLDUPLEX,
+            SPI_FRAMESIZE_8BIT,
+            SPI_NSS_SOFT,
+            SPI_ENDIAN_MSB,
+            SPI_CK_PL_LOW_PH_1EDGE,
+            SPI_PSC_256
+        };
+
+        // Select closest available divider based on system frequency
+        int divider = SystemCoreClock / m_sckfreq;
+        if (divider <= 2)
+            config.prescale = SPI_PSC_2;
+        else if (divider <= 4)
+            config.prescale = SPI_PSC_4;
+        else if (divider <= 8)
+            config.prescale = SPI_PSC_8;
+        else if (divider <= 16)
+            config.prescale = SPI_PSC_16;
+        else if (divider <= 32)
+            config.prescale = SPI_PSC_32;
+        else if (divider <= 64)
+            config.prescale = SPI_PSC_64;
+        else if (divider <= 128)
+            config.prescale = SPI_PSC_128;
+        else
+            config.prescale = SPI_PSC_256;
+
+        spi_init(SD_SPI, &config);
+        spi_enable(SD_SPI);
+    }
+    
+    void deactivate() {
+        spi_disable(SD_SPI);
+    }
+
+    void wait_idle() {
+        while (!(SPI_STAT(SD_SPI) & SPI_STAT_TBE));
+        while (SPI_STAT(SD_SPI) & SPI_STAT_TRANS);
+    }
+
+    uint8_t receive() {
+        // Wait for idle and clear RX buffer
+        wait_idle();
+        (void)SPI_DATA(SD_SPI);
+
+        // Send dummy byte and wait for receive
+        SPI_DATA(SD_SPI) = 0xFF;
+        while (!(SPI_STAT(SD_SPI) & SPI_STAT_RBNE));
+        return SPI_DATA(SD_SPI);
+    }
+
+    uint8_t receive(uint8_t* buf, size_t count) {
+        // Wait for idle and clear RX buffer
+        wait_idle();
+        (void)SPI_DATA(SD_SPI);
+
+        for (size_t i = 0; i < count; i++)
+        {
+            while (!(SPI_STAT(SD_SPI) & SPI_STAT_TBE));
+            SPI_DATA(SD_SPI) = 0xFF;
+            while (!(SPI_STAT(SD_SPI) & SPI_STAT_RBNE));
+            buf[i] = SPI_DATA(SD_SPI);
+        }
+
+        return 0;
+    }
+
+    void send(uint8_t data) {
+        SPI_DATA(SD_SPI) = data;
+        wait_idle();
+    }
+
+    void send(const uint8_t* buf, size_t count) {
+        for (size_t i = 0; i < count; i++) {
+            while (!(SPI_STAT(SD_SPI) & SPI_STAT_TBE));
+            SPI_DATA(SD_SPI) = buf[i];
+        }
+        wait_idle();
+    }
+
+    void setSckSpeed(uint32_t maxSck) {
+        m_sckfreq = maxSck;
+    }
+
+private:
+    uint32_t m_sckfreq;
+};
+
+void sdCsInit(SdCsPin_t pin)
+{
+}
+
+void sdCsWrite(SdCsPin_t pin, bool level)
+{
+    if (level)
+        GPIO_BOP(SD_PORT) = SD_CS_PIN;
+    else
+        GPIO_BC(SD_PORT) = SD_CS_PIN;
+}
+
+GD32SPIDriver g_sd_spi_port;
+SdSpiConfig g_sd_spi_config(0, DEDICATED_SPI, SD_SCK_MHZ(25), &g_sd_spi_port);
+
+/**********************************************/
+/* Mapping from data bytes to GPIO BOP values */
+/**********************************************/
+
+#define PARITY(n) ((1 ^ (n) ^ ((n)>>1) ^ ((n)>>2) ^ ((n)>>3) ^ ((n)>>4) ^ ((n)>>5) ^ ((n)>>6) ^ ((n)>>7)) & 1)
+#define X(n) (\
+    ((n & 0x01) ? SCSI_OUT_DB0 : (SCSI_OUT_DB0 << 16)) | \
+    ((n & 0x02) ? SCSI_OUT_DB1 : (SCSI_OUT_DB1 << 16)) | \
+    ((n & 0x04) ? SCSI_OUT_DB2 : (SCSI_OUT_DB2 << 16)) | \
+    ((n & 0x08) ? SCSI_OUT_DB3 : (SCSI_OUT_DB3 << 16)) | \
+    ((n & 0x10) ? SCSI_OUT_DB4 : (SCSI_OUT_DB4 << 16)) | \
+    ((n & 0x20) ? SCSI_OUT_DB5 : (SCSI_OUT_DB5 << 16)) | \
+    ((n & 0x40) ? SCSI_OUT_DB6 : (SCSI_OUT_DB6 << 16)) | \
+    ((n & 0x80) ? SCSI_OUT_DB7 : (SCSI_OUT_DB7 << 16)) | \
+    (PARITY(n)  ? SCSI_OUT_DBP : (SCSI_OUT_DBP << 16)) \
+)
+    
+const uint32_t g_scsi_out_byte_to_bop[256] =
+{
+    X(0x00), X(0x01), X(0x02), X(0x03), X(0x04), X(0x05), X(0x06), X(0x07), X(0x08), X(0x09), X(0x0a), X(0x0b), X(0x0c), X(0x0d), X(0x0e), X(0x0f),
+    X(0x10), X(0x11), X(0x12), X(0x13), X(0x14), X(0x15), X(0x16), X(0x17), X(0x18), X(0x19), X(0x1a), X(0x1b), X(0x1c), X(0x1d), X(0x1e), X(0x1f),
+    X(0x20), X(0x21), X(0x22), X(0x23), X(0x24), X(0x25), X(0x26), X(0x27), X(0x28), X(0x29), X(0x2a), X(0x2b), X(0x2c), X(0x2d), X(0x2e), X(0x2f),
+    X(0x30), X(0x31), X(0x32), X(0x33), X(0x34), X(0x35), X(0x36), X(0x37), X(0x38), X(0x39), X(0x3a), X(0x3b), X(0x3c), X(0x3d), X(0x3e), X(0x3f),
+    X(0x40), X(0x41), X(0x42), X(0x43), X(0x44), X(0x45), X(0x46), X(0x47), X(0x48), X(0x49), X(0x4a), X(0x4b), X(0x4c), X(0x4d), X(0x4e), X(0x4f),
+    X(0x50), X(0x51), X(0x52), X(0x53), X(0x54), X(0x55), X(0x56), X(0x57), X(0x58), X(0x59), X(0x5a), X(0x5b), X(0x5c), X(0x5d), X(0x5e), X(0x5f),
+    X(0x60), X(0x61), X(0x62), X(0x63), X(0x64), X(0x65), X(0x66), X(0x67), X(0x68), X(0x69), X(0x6a), X(0x6b), X(0x6c), X(0x6d), X(0x6e), X(0x6f),
+    X(0x70), X(0x71), X(0x72), X(0x73), X(0x74), X(0x75), X(0x76), X(0x77), X(0x78), X(0x79), X(0x7a), X(0x7b), X(0x7c), X(0x7d), X(0x7e), X(0x7f),
+    X(0x80), X(0x81), X(0x82), X(0x83), X(0x84), X(0x85), X(0x86), X(0x87), X(0x88), X(0x89), X(0x8a), X(0x8b), X(0x8c), X(0x8d), X(0x8e), X(0x8f),
+    X(0x90), X(0x91), X(0x92), X(0x93), X(0x94), X(0x95), X(0x96), X(0x97), X(0x98), X(0x99), X(0x9a), X(0x9b), X(0x9c), X(0x9d), X(0x9e), X(0x9f),
+    X(0xa0), X(0xa1), X(0xa2), X(0xa3), X(0xa4), X(0xa5), X(0xa6), X(0xa7), X(0xa8), X(0xa9), X(0xaa), X(0xab), X(0xac), X(0xad), X(0xae), X(0xaf),
+    X(0xb0), X(0xb1), X(0xb2), X(0xb3), X(0xb4), X(0xb5), X(0xb6), X(0xb7), X(0xb8), X(0xb9), X(0xba), X(0xbb), X(0xbc), X(0xbd), X(0xbe), X(0xbf),
+    X(0xc0), X(0xc1), X(0xc2), X(0xc3), X(0xc4), X(0xc5), X(0xc6), X(0xc7), X(0xc8), X(0xc9), X(0xca), X(0xcb), X(0xcc), X(0xcd), X(0xce), X(0xcf),
+    X(0xd0), X(0xd1), X(0xd2), X(0xd3), X(0xd4), X(0xd5), X(0xd6), X(0xd7), X(0xd8), X(0xd9), X(0xda), X(0xdb), X(0xdc), X(0xdd), X(0xde), X(0xdf),
+    X(0xe0), X(0xe1), X(0xe2), X(0xe3), X(0xe4), X(0xe5), X(0xe6), X(0xe7), X(0xe8), X(0xe9), X(0xea), X(0xeb), X(0xec), X(0xed), X(0xee), X(0xef),
+    X(0xf0), X(0xf1), X(0xf2), X(0xf3), X(0xf4), X(0xf5), X(0xf6), X(0xf7), X(0xf8), X(0xf9), X(0xfa), X(0xfb), X(0xfc), X(0xfd), X(0xfe), X(0xff)
+};
+
+#undef X

+ 66 - 49
src/platform_GD32F205.h → lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.h

@@ -1,4 +1,4 @@
-// Platform-specific definitions.
+// Platform-specific definitions for AzulSCSI.
 // Can be customized for different microcontrollers, this file is for GD32F205VCT6.
 
 #pragma once
@@ -6,6 +6,15 @@
 #include <gd32f20x.h>
 #include <gd32f20x_gpio.h>
 
+#ifdef __cplusplus
+// SD card driver for SdFat
+class SdSpiConfig;
+extern SdSpiConfig g_sd_spi_config;
+#define SD_CONFIG g_sd_spi_config
+
+extern "C" {
+#endif
+
 // GPIO definitions
 
 // SCSI output port.
@@ -28,6 +37,7 @@
 #define SCSI_OUT_RST  GPIO_PIN_13
 #define SCSI_OUT_BSY  GPIO_PIN_14
 #define SCSI_OUT_DBP  GPIO_PIN_15
+#define SCSI_OUT_DATA_MASK (0x00FF | SCSI_OUT_DBP)
 #define SCSI_OUT_MASK 0xFFFF
 
 // SCSI input port
@@ -42,6 +52,7 @@
 #define SCSI_IN_DB0   GPIO_PIN_8
 #define SCSI_IN_DBP   GPIO_PIN_7
 #define SCSI_IN_MASK  (SCSI_IN_DB7|SCSI_IN_DB6|SCSI_IN_DB5|SCSI_IN_DB4|SCSI_IN_DB3|SCSI_IN_DB2|SCSI_IN_DB1|SCSI_IN_DB0|SCSI_IN_DBP)
+#define SCSI_IN_SHIFT 8
 
 // Various SCSI status signals
 #define SCSI_ATN_PORT GPIOB // FIXME: Change to 5V-tolerant pin
@@ -52,8 +63,15 @@
 #define SCSI_SEL_PIN  GPIO_PIN_11
 #define SCSI_ACK_PORT GPIOB
 #define SCSI_ACK_PIN  GPIO_PIN_12
+
+// RST pin uses EXTI interrupt
 #define SCSI_RST_PORT GPIOB
 #define SCSI_RST_PIN  GPIO_PIN_13
+#define SCSI_RST_EXTI EXTI_13
+#define SCSI_RST_EXTI_SOURCE_PORT GPIO_PORT_SOURCE_GPIOB
+#define SCSI_RST_EXTI_SOURCE_PIN GPIO_PIN_SOURCE_13
+#define SCSI_RST_IRQ  EXTI10_15_IRQHandler
+#define SCSI_RST_IRQn EXTI10_15_IRQn
 
 // Terminator enable/disable config, active low
 #define SCSI_TERM_EN_PORT GPIOC
@@ -81,53 +99,52 @@
 #define LED_OFF()    gpio_bit_set(LED_PORT, LED_PINS)
 
 // Debug logging functions
-#define LOG(XX)     //Serial.print(XX)
-#define LOGHEX(XX)  //Serial.print(XX, HEX)
-#define LOGN(XX)    //Serial.println(XX)
-#define LOGHEXN(XX) //Serial.println(XX, HEX)
+void azplatform_log(const char *s);
 
-// Initialize SPI and GPIO configuration
-// Clock has already been initialized by system_gd32f20x.c
-static void platform_init()
+// Minimal millis() implementation as GD32F205 does not
+// have an Arduino core yet.
+unsigned long millis();
+void delay(unsigned long ms);
+
+// Precise nanosecond delays
+static inline void delay_100ns()
 {
-    // Enable needed clocks
-    rcu_periph_clock_enable(RCU_GPIOA);
-    rcu_periph_clock_enable(RCU_GPIOB);
-    rcu_periph_clock_enable(RCU_GPIOC);
-    rcu_periph_clock_enable(RCU_GPIOD);
-    rcu_periph_clock_enable(RCU_GPIOE);
-
-    // Switch to SWD debug port (disable JTAG) to release PB4 as GPIO
-    gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);    
-
-    // SCSI pins.
-    // Initialize open drain outputs to high.
-    gpio_bit_set(SCSI_OUT_PORT, SCSI_OUT_MASK);
-    gpio_init(SCSI_OUT_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_MASK);
-    gpio_init(SCSI_IN_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_IN_MASK);
-    gpio_init(SCSI_ATN_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_ATN_PIN);
-    gpio_init(SCSI_BSY_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_BSY_PIN);
-    gpio_init(SCSI_SEL_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_SEL_PIN);
-    gpio_init(SCSI_ACK_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_ACK_PIN);
-    gpio_init(SCSI_RST_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_RST_PIN);
-
-    // Terminator enable
-    gpio_bit_set(SCSI_TERM_EN_PORT, SCSI_TERM_EN_PIN);
-    gpio_init(SCSI_TERM_EN_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, SCSI_TERM_EN_PIN);
-
-    // SD card pins
-    gpio_init(SD_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SD_CS_PIN);
-    gpio_init(SD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SD_CLK_PIN);
-    gpio_init(SD_PORT, GPIO_MODE_IN_FLOATING, 0, SD_MISO_PIN);
-    gpio_init(SD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SD_MOSI_PIN);
-
-    // DIP switches
-    gpio_init(DIP_PORT, GPIO_MODE_IPD, 0, DIPSW1_PIN | DIPSW2_PIN | DIPSW3_PIN);
-
-    // LED pins
-    gpio_bit_set(LED_PORT, LED_PINS);
-    gpio_init(LED_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, LED_PINS);
-
-    // SWO trace pin on PB3
-    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
-}
+    asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
+}
+
+// Initialize SPI and GPIO configuration
+void azplatform_init();
+
+// Set callback for when SCSI_RST pin goes low
+void azplatform_set_rst_callback(void (*callback)());
+
+// Write a single SCSI pin.
+// Example use: SCSI_OUT(ATN, 1) sets SCSI_ATN to low (active) state.
+#define SCSI_OUT(pin, state) \
+    GPIO_BOP(SCSI_OUT_PORT) = (SCSI_OUT_ ## pin) << (state ? 16 : 0)
+
+// Read a single SCSI pin.
+// Example use: SCSI_IN(ATN), returns 1 for active low state.
+#define SCSI_IN(pin) \
+    ((GPIO_ISTAT(SCSI_ ## pin ## _PORT) & (SCSI_ ## pin ## _PIN)) ? 0 : 1)
+
+// Write SCSI data bus
+extern const uint32_t g_scsi_out_byte_to_bop[256];
+#define SCSI_OUT_DATA(data) \
+    GPIO_BOP(SCSI_OUT_PORT) = g_scsi_out_byte_to_bop[(uint8_t)(data)]
+
+// Release SCSI data bus
+#define SCSI_RELEASE_DATA() \
+    GPIO_BOP(SCSI_OUT_PORT) = SCSI_OUT_DATA_MASK
+
+// Release all SCSI outputs
+#define SCSI_RELEASE_OUTPUTS() \
+    GPIO_BOP(SCSI_OUT_PORT) = SCSI_OUT_MASK
+
+// Read SCSI data bus
+#define SCSI_IN_DATA(data) \
+    ((GPIO_ISTAT(SCSI_IN_PORT) & SCSI_IN_MASK) >> SCSI_IN_SHIFT)
+
+#ifdef __cplusplus
+}
+#endif

+ 435 - 0
lib/AzulSCSI_platform_GD32F205/SdFatConfig.h

@@ -0,0 +1,435 @@
+/**
+ * Copyright (c) 2011-2021 Bill Greiman
+ * This file is part of the SdFat library for SD memory cards.
+ *
+ * MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+/**
+ * \file
+ * \brief configuration definitions
+ */
+#ifndef SdFatConfig_h
+#define SdFatConfig_h
+#include <stdint.h>
+#ifdef __AVR__
+#include <avr/io.h>
+#endif  // __AVR__
+//
+// To try UTF-8 encoded filenames.
+// #define USE_UTF8_LONG_NAMES 1
+//
+// For minimum flash size use these settings:
+// #define USE_FAT_FILE_FLAG_CONTIGUOUS 0
+// #define ENABLE_DEDICATED_SPI 0
+// #define USE_LONG_FILE_NAMES 0
+// #define SDFAT_FILE_TYPE 1
+//
+// Options can be set in a makefile or an IDE like platformIO
+// if they are in a #ifndef/#endif block below.
+//------------------------------------------------------------------------------
+/** For Debug - must be one */
+#define ENABLE_ARDUINO_FEATURES 0
+/** For Debug - must be one */
+#define ENABLE_ARDUINO_SERIAL 0
+/** For Debug - must be one */
+#define ENABLE_ARDUINO_STRING 0
+//------------------------------------------------------------------------------
+#if ENABLE_ARDUINO_FEATURES
+#include "Arduino.h"
+#ifdef PLATFORM_ID
+// Only defined if a Particle device.
+#include "application.h"
+#endif  // PLATFORM_ID
+#else
+#define SS 0
+extern "C" unsigned long millis();
+#endif  // ENABLE_ARDUINO_FEATURES
+//------------------------------------------------------------------------------
+/**
+ * File types for SdFat, File, SdFile, SdBaseFile, fstream,
+ * ifstream, and ofstream.
+ *
+ * Set SDFAT_FILE_TYPE to:
+ *
+ * 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
+ */
+#ifndef SDFAT_FILE_TYPE
+#if defined(__AVR__) && FLASHEND < 0X8000
+// 32K AVR boards.
+#define SDFAT_FILE_TYPE 1
+#else  // defined(__AVR__) && FLASHEND < 0X8000
+// All other boards.
+#define SDFAT_FILE_TYPE 3
+#endif  // defined(__AVR__) && FLASHEND < 0X8000
+#endif  // SDFAT_FILE_TYPE
+//------------------------------------------------------------------------------
+/**
+ * Set USE_FAT_FILE_FLAG_CONTIGUOUS nonzero to optimize access to
+ * contiguous files.  A small amount of flash is flash is used.
+ */
+#ifndef USE_FAT_FILE_FLAG_CONTIGUOUS
+#define USE_FAT_FILE_FLAG_CONTIGUOUS 1
+#endif  // USE_FAT_FILE_FLAG_CONTIGUOUS
+//------------------------------------------------------------------------------
+/**
+ * Set ENABLE_DEDICATED_SPI non-zero to enable dedicated use of the SPI bus.
+ * Selecting dedicated SPI in SdSpiConfig() will produce better
+ * performance by using very large multi-block transfers to and
+ * from the SD card.
+ *
+ * Enabling dedicated SPI will cost extra flash and RAM.
+ */
+#ifndef ENABLE_DEDICATED_SPI
+#if defined(__AVR__) && FLASHEND < 0X8000
+// 32K AVR boards.
+#define ENABLE_DEDICATED_SPI 1
+#else  // defined(__AVR__) && FLASHEND < 0X8000
+// All other boards.
+#define ENABLE_DEDICATED_SPI 1
+#endif  // defined(__AVR__) && FLASHEND < 0X8000
+#endif  // ENABLE_DEDICATED_SPI
+//------------------------------------------------------------------------------
+// Driver options
+/**
+ * If the symbol SPI_DRIVER_SELECT is:
+ *
+ * 0 - An optimized custom SPI driver is used if it exists
+ *     else the standard library driver is used.
+ *
+ * 1 - The standard library driver is always used.
+ *
+ * 2 - An external SPI driver of SoftSpiDriver template class is always used.
+ *
+ * 3 - An external SPI driver derived from SdSpiBaseClass is always used.
+ */
+#ifndef SPI_DRIVER_SELECT
+#define SPI_DRIVER_SELECT 0
+#endif  // SPI_DRIVER_SELECT
+/**
+ * If USE_SPI_ARRAY_TRANSFER is non-zero and the standard SPI library is
+ * use, the array transfer function, transfer(buf, size), will be used.
+ * This option will allocate up to a 512 byte temporary buffer for send.
+ * This may be faster for some boards.  Do not use this with AVR boards.
+ */
+#ifndef USE_SPI_ARRAY_TRANSFER
+#define USE_SPI_ARRAY_TRANSFER 0
+#endif  // USE_SPI_ARRAY_TRANSFER
+/**
+ * SD maximum initialization clock rate.
+ */
+#ifndef SD_MAX_INIT_RATE_KHZ
+#define SD_MAX_INIT_RATE_KHZ 400
+#endif  // SD_MAX_INIT_RATE_KHZ
+/**
+ * Set USE_BLOCK_DEVICE_INTERFACE nonzero to use a generic block device.
+ * This allow use of an external FsBlockDevice driver that is derived from
+ * the FsBlockDeviceInterface like this:
+ *
+ * class UsbMscDriver : public FsBlockDeviceInterface {
+ *   ... code for USB mass storage class driver.
+ * };
+ *
+ * UsbMscDriver usbMsc;
+ * FsVolume key;
+ * ...
+ *
+ *   // Init USB MSC driver.
+ *   if (!usbMsc.begin()) {
+ *     ... handle driver init failure.
+ *   }
+ *   // Init FAT/exFAT volume.
+ *   if (!key.begin(&usbMsc)) {
+ *     ... handle FAT/exFAT failure.
+ *   }
+ */
+#ifndef USE_BLOCK_DEVICE_INTERFACE
+#define USE_BLOCK_DEVICE_INTERFACE 0
+#endif  // USE_BLOCK_DEVICE_INTERFACE
+ /**
+ * SD_CHIP_SELECT_MODE defines how the functions
+ * void sdCsInit(SdCsPin_t pin) {pinMode(pin, OUTPUT);}
+ * and
+ * void sdCsWrite(SdCsPin_t pin, bool level) {digitalWrite(pin, level);}
+ * are defined.
+ *
+ * 0 - Internal definition is a strong symbol and can't be replaced.
+ *
+ * 1 - Internal definition is a weak symbol and can be replaced.
+ *
+ * 2 - No internal definition and must be defined in the application.
+ */
+#ifndef SD_CHIP_SELECT_MODE
+#define SD_CHIP_SELECT_MODE 0
+#endif  // SD_CHIP_SELECT_MODE
+/** Type for card chip select pin. */
+typedef uint8_t SdCsPin_t;
+//------------------------------------------------------------------------------
+/**
+ * Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN) in FAT16/FAT32.
+ * exFAT always uses long file names.
+ *
+ * Long File Name are limited to a maximum length of 255 characters.
+ *
+ * This implementation allows 7-bit characters in the range
+ * 0X20 to 0X7E except the following characters are not allowed:
+ *
+ *  < (less than)
+ *  > (greater than)
+ *  : (colon)
+ *  " (double quote)
+ *  / (forward slash)
+ *  \ (backslash)
+ *  | (vertical bar or pipe)
+ *  ? (question mark)
+ *  * (asterisk)
+ *
+ */
+#ifndef USE_LONG_FILE_NAMES
+#define USE_LONG_FILE_NAMES 1
+#endif  // USE_LONG_FILE_NAMES
+/**
+ * Set USE_UTF8_LONG_NAMES nonzero to use UTF-8 file names. Use of UTF-8 names
+ * will require significantly more flash memory and a small amount of extra
+ * RAM.
+ *
+ * UTF-8 filenames allow encoding of 1,112,064 code points in Unicode using
+ * one to four one-byte (8-bit) code units.
+ *
+ * As of Version 13.0, the Unicode Standard defines 143,859 characters.
+ *
+ * getName() will return UTF-8 strings and printName() will write UTF-8 strings.
+ */
+#ifndef USE_UTF8_LONG_NAMES
+#define USE_UTF8_LONG_NAMES 0
+#endif  // USE_UTF8_LONG_NAMES
+
+#if USE_UTF8_LONG_NAMES && !USE_LONG_FILE_NAMES
+#error "USE_UTF8_LONG_NAMES requires USE_LONG_FILE_NAMES to be non-zero."
+#endif  // USE_UTF8_LONG_NAMES && !USE_LONG_FILE_NAMES
+//------------------------------------------------------------------------------
+/**
+ * Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
+ * updated.  This will increase the speed of the freeClusterCount() call
+ * after the first call.  Extra flash will be required.
+ */
+#ifndef MAINTAIN_FREE_CLUSTER_COUNT
+#define MAINTAIN_FREE_CLUSTER_COUNT 0
+#endif  // MAINTAIN_FREE_CLUSTER_COUNT
+//------------------------------------------------------------------------------
+/**
+ * Set the default file time stamp when a RTC callback is not used.
+ * A valid date and time is required by the FAT/exFAT standard.
+ *
+ * The default below is YYYY-01-01 00:00:00 midnight where YYYY is
+ * the compile year from the __DATE__ macro.  This is easy to recognize
+ * as a placeholder for a correct date/time.
+ *
+ * The full compile date is:
+ * FS_DATE(compileYear(), compileMonth(), compileDay())
+ *
+ * The full compile time is:
+ * FS_TIME(compileHour(), compileMinute(), compileSecond())
+ */
+#define FS_DEFAULT_DATE FS_DATE(compileYear(), 1, 1)
+/** 00:00:00 midnight */
+#define FS_DEFAULT_TIME FS_TIME(0, 0, 0)
+//------------------------------------------------------------------------------
+/**
+ * If CHECK_FLASH_PROGRAMMING is zero, overlap of single sector flash
+ * programming and other operations will be allowed for faster write
+ * performance.
+ *
+ * Some cards will not sleep in low power mode unless CHECK_FLASH_PROGRAMMING
+ * is non-zero.
+ */
+#ifndef CHECK_FLASH_PROGRAMMING
+#define CHECK_FLASH_PROGRAMMING 0
+#endif  // CHECK_FLASH_PROGRAMMING
+//------------------------------------------------------------------------------
+/**
+ * To enable SD card CRC checking for SPI, set USE_SD_CRC nonzero.
+ *
+ * Set USE_SD_CRC to 1 to use a smaller CRC-CCITT function.  This function
+ * is slower for AVR but may be fast for ARM and other processors.
+ *
+ * Set USE_SD_CRC to 2 to used a larger table driven CRC-CCITT function.  This
+ * function is faster for AVR but may be slower for ARM and other processors.
+ */
+#ifndef USE_SD_CRC
+#define USE_SD_CRC 0
+#endif  // USE_SD_CRC
+//------------------------------------------------------------------------------
+/** If the symbol USE_FCNTL_H is nonzero, open flags for access modes O_RDONLY,
+ * O_WRONLY, O_RDWR and the open modifiers O_APPEND, O_CREAT, O_EXCL, O_SYNC
+ * will be defined by including the system file fcntl.h.
+ */
+#ifndef USE_FCNTL_H
+#if defined(__AVR__)
+// AVR fcntl.h does not define open flags.
+#define USE_FCNTL_H 0
+#elif defined(PLATFORM_ID)
+// Particle boards - use fcntl.h.
+#define USE_FCNTL_H 1
+#elif defined(__arm__)
+// ARM gcc defines open flags.
+#define USE_FCNTL_H 1
+#elif defined(ESP32)
+#define USE_FCNTL_H 1
+#else  // defined(__AVR__)
+#define USE_FCNTL_H 0
+#endif  // defined(__AVR__)
+#endif  // USE_FCNTL_H
+//------------------------------------------------------------------------------
+/**
+ * Set INCLUDE_SDIOS nonzero to include sdios.h in SdFat.h.
+ * sdios.h provides C++ style IO Streams.
+ */
+#ifndef INCLUDE_SDIOS
+#define INCLUDE_SDIOS 0
+#endif  // INCLUDE_SDIOS
+//------------------------------------------------------------------------------
+/**
+ * Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes.
+ * FAT12 has not been well tested and requires additional flash.
+ */
+#ifndef FAT12_SUPPORT
+#define FAT12_SUPPORT 0
+#endif  // FAT12_SUPPORT
+//------------------------------------------------------------------------------
+/**
+ * Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
+ *
+ * Causes use of lots of heap in ARM.
+ */
+#ifndef DESTRUCTOR_CLOSES_FILE
+#define DESTRUCTOR_CLOSES_FILE 0
+#endif  // DESTRUCTOR_CLOSES_FILE
+//------------------------------------------------------------------------------
+/**
+ * Call flush for endl if ENDL_CALLS_FLUSH is nonzero
+ *
+ * The standard for iostreams is to call flush.  This is very costly for
+ * SdFat.  Each call to flush causes 2048 bytes of I/O to the SD.
+ *
+ * SdFat has a single 512 byte buffer for SD I/O so it must write the current
+ * data sector to the SD, read the directory sector from the SD, update the
+ * directory entry, write the directory sector to the SD and read the data
+ * sector back into the buffer.
+ *
+ * The SD flash memory controller is not designed for this many rewrites
+ * so performance may be reduced by more than a factor of 100.
+ *
+ * If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
+ * all data to be written to the SD.
+ */
+#ifndef ENDL_CALLS_FLUSH
+#define ENDL_CALLS_FLUSH 0
+#endif  // ENDL_CALLS_FLUSH
+//------------------------------------------------------------------------------
+/**
+ * Set USE_SIMPLE_LITTLE_ENDIAN nonzero for little endian processors
+ * with no memory alignment restrictions.
+ */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\
+  && (defined(__AVR__) || defined(__ARM_FEATURE_UNALIGNED))
+#define USE_SIMPLE_LITTLE_ENDIAN 1
+#else  // __BYTE_ORDER_
+#define USE_SIMPLE_LITTLE_ENDIAN 0
+#endif  // __BYTE_ORDER_
+//------------------------------------------------------------------------------
+/**
+ * Set USE_SEPARATE_FAT_CACHE nonzero to use a second 512 byte cache
+ * for FAT16/FAT32 table entries.  This improves performance for large
+ * writes that are not a multiple of 512 bytes.
+ */
+#ifdef __arm__
+#define USE_SEPARATE_FAT_CACHE 1
+#else  // __arm__
+#define USE_SEPARATE_FAT_CACHE 0
+#endif  // __arm__
+//------------------------------------------------------------------------------
+/**
+ * Set USE_EXFAT_BITMAP_CACHE nonzero to use a second 512 byte cache
+ * for exFAT bitmap entries.  This improves performance for large
+ * writes that are not a multiple of 512 bytes.
+ */
+#ifdef __arm__
+#define USE_EXFAT_BITMAP_CACHE 1
+#else  // __arm__
+#define USE_EXFAT_BITMAP_CACHE 0
+#endif  // __arm__
+//------------------------------------------------------------------------------
+/**
+ * Set USE_MULTI_SECTOR_IO nonzero to use multi-sector SD read/write.
+ *
+ * Don't use mult-sector read/write on small AVR boards.
+ */
+#if defined(RAMEND) && RAMEND < 3000
+#define USE_MULTI_SECTOR_IO 0
+#else  // RAMEND
+#define USE_MULTI_SECTOR_IO 1
+#endif  // RAMEND
+//------------------------------------------------------------------------------
+/** Enable SDIO driver if available. */
+#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
+// Pseudo pin select for SDIO.
+#ifndef BUILTIN_SDCARD
+#define BUILTIN_SDCARD 254
+#endif  // BUILTIN_SDCARD
+// SPI for built-in card.
+#ifndef SDCARD_SPI
+#define SDCARD_SPI      SPI1
+#define SDCARD_MISO_PIN 59
+#define SDCARD_MOSI_PIN 61
+#define SDCARD_SCK_PIN  60
+#define SDCARD_SS_PIN   62
+#endif  // SDCARD_SPI
+#define HAS_SDIO_CLASS 1
+#endif  // defined(__MK64FX512__) || defined(__MK66FX1M0__)
+#if defined(__IMXRT1062__)
+#define HAS_SDIO_CLASS 1
+#endif  // defined(__IMXRT1062__)
+//------------------------------------------------------------------------------
+/**
+ * Determine the default SPI configuration.
+ */
+#if defined(ARDUINO_ARCH_APOLLO3)\
+  || (defined(__AVR__) && defined(SPDR) && defined(SPSR) && defined(SPIF))\
+  || (defined(__AVR__) && defined(SPI0) && defined(SPI_RXCIF_bm))\
+  || defined(ESP8266) || defined(ESP32)\
+  || defined(PLATFORM_ID)\
+  || defined(ARDUINO_SAM_DUE)\
+  || defined(STM32_CORE_VERSION)\
+  || defined(__STM32F1__) || defined(__STM32F4__)\
+  || (defined(CORE_TEENSY) && defined(__arm__))
+#define SD_HAS_CUSTOM_SPI 1
+#else  // SD_HAS_CUSTOM_SPI
+// Use standard SPI library.
+#define SD_HAS_CUSTOM_SPI 0
+#endif  // SD_HAS_CUSTOM_SPI
+//------------------------------------------------------------------------------
+#ifndef HAS_SDIO_CLASS
+/** Default is no SDIO. */
+#define HAS_SDIO_CLASS 0
+#endif  // HAS_SDIO_CLASS
+
+#endif  // SdFatConfig_h
+

+ 10 - 2
platformio.ini

@@ -6,12 +6,20 @@ board = genericGD32F205VC
 board_build.mcu = gd32f205vct6
 board_build.core = gd32
 framework = spl
+lib_compat_mode = off
 lib_deps =
-    greiman/SdFat @ ^2.0.6
+    SdFat_NoArduino
+    minIni
+    AzulSCSI_platform_GD32F205
 upload_protocol = stlink
 platform_packages = 
     toolchain-gccarmnoneeabi@1.60301.0
     framework-spl-gd32@https://github.com/CommunityGD32Cores/gd32-pio-spl-package.git
 
 build_flags = 
-     -Os -Wall -ggdb -g3
+     -Os -Wall -Wno-sign-compare
+     -ggdb -g3 -Isrc
+     -DHXTAL_VALUE=8000000
+     -DSPI_DRIVER_SELECT=3
+     -DSD_CHIP_SELECT_MODE=2
+     -DENABLE_DEDICATED_SPI=1

File diff ditekan karena terlalu besar
+ 216 - 741
src/AzulSCSI.cpp


+ 25 - 0
src/AzulSCSI_config.h

@@ -0,0 +1,25 @@
+// Compile-time configuration parameters.
+// Other settings can be set by ini file at runtime.
+
+#pragma once
+
+// Configuration and log file paths
+#define CONFIGFILE  "azulscsi.ini"
+#define LOGFILE "azullog.txt"
+
+// HDD image file format
+#define HDIMG_ID_POS  2                 // Position to embed ID number
+#define HDIMG_LUN_POS 3                 // Position to embed LUN numbers
+#define HDIMG_BLK_POS 5                 // Position to embed block size numbers
+#define MAX_FILE_PATH 32                // Maximum file name length
+#define MAX_BLOCKSIZE 1024              // Maximum BLOCK size
+
+// SCSI config
+#define NUM_SCSIID  7          // Maximum number of supported SCSI-IDs (The minimum is 0)
+#define NUM_SCSILUN 2          // Maximum number of LUNs supported     (The minimum is 0)
+#define READ_PARITY_CHECK 0    // Perform read parity check (unverified)
+
+// Default SCSI drive information (can be overridden in INI file)
+#define DEFAULT_VENDOR "QUANTUM "
+#define DEFAULT_PRODUCT "FIREBALL1       "
+#define DEFAULT_VERSION "1.0 "

+ 28 - 0
src/AzulSCSI_log.cpp

@@ -0,0 +1,28 @@
+#include "AzulSCSI_log.h"
+#include "AzulSCSI_platform.h"
+
+// This memory buffer can be read by debugger and is also saved to azullog.txt
+char g_logbuffer[4096];
+uint32_t g_logpos = 0;
+
+void azlog(const char *str)
+{
+    const char *p = str;
+    while (*p && g_logpos < sizeof(g_logbuffer) - 1)
+    {
+        g_logbuffer[g_logpos++] = *p++;
+    }
+
+    azplatform_log(str);
+}
+
+uint32_t azlog_get_buffer_len()
+{
+    return g_logpos;
+}
+
+const char *azlog_get_buffer()
+{
+    return g_logbuffer;
+}
+

+ 81 - 0
src/AzulSCSI_log.h

@@ -0,0 +1,81 @@
+// Helpers for log messages.
+
+#pragma once
+
+#include <stdint.h>
+
+// Retrieve stored log buffer
+uint32_t azlog_get_buffer_len();
+const char *azlog_get_buffer();
+
+// Log string
+void azlog(const char *str);
+
+// Log byte as hex
+inline void azlog(uint8_t value)
+{
+    const char *nibble = "0123456789ABCDEF";
+    char hexbuf[5] = {
+        '0', 'x', 
+        nibble[(value >>  4) & 0xF], nibble[(value >>  0) & 0xF],
+        0
+    };
+    azlog(hexbuf);
+}
+
+// Log integer as hex
+inline void azlog(uint32_t value)
+{
+    const char *nibble = "0123456789ABCDEF";
+    char hexbuf[11] = {
+        '0', 'x', 
+        nibble[(value >> 28) & 0xF], nibble[(value >> 24) & 0xF],
+        nibble[(value >> 20) & 0xF], nibble[(value >> 16) & 0xF],
+        nibble[(value >> 12) & 0xF], nibble[(value >>  8) & 0xF],
+        nibble[(value >>  4) & 0xF], nibble[(value >>  0) & 0xF],
+        0
+    };
+    azlog(hexbuf);
+}
+
+// Log integer as decimal
+inline void azlog(int value)
+{
+    char decbuf[16] = {0};
+    char *p = &decbuf[14];
+    int remainder = (value < 0) ? -value : value;
+    do
+    {
+        *--p = '0' + (remainder % 10);
+        remainder /= 10;
+    } while (remainder > 0);
+    
+    if (value < 0)
+    {
+        *--p = '-';
+    }
+
+    azlog(p);
+}
+
+inline void azlog()
+{
+    // End of template recursion
+}
+
+// Variadic template for composing strings
+template<typename T, typename T2, typename... Rest>
+inline void azlog(T first, T2 second, Rest... rest)
+{
+    azlog(first);
+    azlog(second);
+    azlog(rest...);
+}
+
+// Append newline automatically
+template<typename... Params>
+inline void azlogn(Params... params)
+{
+    azlog(params...);
+    azlog("\n");
+}

+ 173 - 0
utils/gdb_macros

@@ -0,0 +1,173 @@
+#
+# Assorted ARMv7M macros for debugging with GDB
+#
+
+echo Loading ARMv7M GDB macros.  Use 'help armv7m' for more information.\n
+
+define armv7m
+	echo Use 'help armv7m' for more information.\n
+end
+
+document armv7m
+. Various macros for working with the ARMv7M family of processors.
+.
+.    vecstate
+.        Print information about the current exception handling state.
+.
+. Use 'help <macro>' for more specific help.
+end
+
+
+define vecstate
+	set $icsr  = *(unsigned *)0xe000ed04
+	set $vect  = $icsr & 0x1ff
+	set $pend  = ($icsr & 0x1ff000) >> 12
+	set $shcsr = *(unsigned *)0xe000ed24
+	set $cfsr  = *(unsigned *)0xe000ed28
+	set $mmfsr = $cfsr & 0xff
+	set $bfsr  = ($cfsr >> 8) & 0xff
+	set $ufsr  = ($cfsr >> 16) & 0xffff
+	set $hfsr  = *(unsigned *)0xe000ed2c
+	set $bfar  = *(unsigned *)0xe000ed38
+	set $mmfar = *(unsigned *)0xe000ed34
+
+	if $vect < 15
+
+		if $hfsr != 0
+			printf "HardFault:"
+			if $hfsr & (1<<1)
+				printf " due to vector table read fault\n"
+			end
+			if $hfsr & (1<<30)
+				printf " forced due to escalated or disabled configurable fault (see below)\n"
+			end
+			if $hfsr & (1<<31)
+				printf " due to an unexpected debug event\n"
+			end
+		end
+		if $mmfsr != 0
+			printf "MemManage:"
+			if $mmfsr & (1<<5)
+				printf " during lazy FP state save"
+			end
+			if $mmfsr & (1<<4)
+				printf " during exception entry"
+			end
+			if $mmfsr & (1<<3)
+				printf " during exception return"
+			end
+			if $mmfsr & (1<<0)
+				printf " during data access"
+			end
+			if $mmfsr & (1<<0)
+				printf " during instruction prefetch"
+			end
+			if $mmfsr & (1<<7)
+				printf " accessing 0x%08x", $mmfar
+			end
+			printf "\n"
+		end
+		if $bfsr != 0
+			printf "BusFault:"
+			if $bfsr & (1<<2)
+				printf " (imprecise)"
+			end
+			if $bfsr & (1<<1)
+				printf " (precise)"
+			end
+			if $bfsr & (1<<5)
+				printf " during lazy FP state save"
+			end
+			if $bfsr & (1<<4)
+				printf " during exception entry"
+			end
+			if $bfsr & (1<<3)
+				printf " during exception return"
+			end
+			if $bfsr & (1<<0)
+				printf " during instruction prefetch"
+			end
+			if $bfsr & (1<<7)
+				printf " accessing 0x%08x", $bfar
+			end
+			printf "\n"
+		end
+		if $ufsr != 0
+			printf "UsageFault"
+			if $ufsr & (1<<9)
+				printf " due to divide-by-zero"
+			end
+			if $ufsr & (1<<8)
+				printf " due to unaligned memory access"
+			end
+			if $ufsr & (1<<3)
+				printf " due to access to disabled/absent coprocessor"
+			end
+			if $ufsr & (1<<2)
+				printf " due to a bad EXC_RETURN value"
+			end
+			if $ufsr & (1<<1)
+				printf " due to bad T or IT bits in EPSR"
+			end
+			if $ufsr & (1<<0)
+				printf " due to executing an undefined instruction"
+			end
+			printf "\n"
+		end
+	else
+		if $vect >= 15
+			printf "Handling vector %u\n", $vect
+		end
+	end
+	if ((unsigned)$lr & 0xf0000000) == 0xf0000000
+		if ($lr & 1)
+			printf "exception frame is on MSP\n"
+			#set $frame_ptr = (unsigned *)$msp
+			set $frame_ptr = (unsigned *)$sp
+		else
+			printf "exception frame is on PSP, backtrace may not be possible\n"
+			#set $frame_ptr = (unsigned *)$psp
+			set $frame_ptr = (unsigned *)$sp
+		end
+		printf "  r0: %08x  r1: %08x  r2: %08x  r3: %08x\n", $frame_ptr[0], $frame_ptr[1], $frame_ptr[2], $frame_ptr[3]
+		printf "  r4: %08x  r5: %08x  r6: %08x  r7: %08x\n", $r4, $r5, $r6, $r7
+		printf "  r8: %08x  r9: %08x r10: %08x r11: %08x\n", $r8, $r9, $r10, $r11
+		printf " r12: %08x  lr: %08x  pc: %08x PSR: %08x\n", $frame_ptr[4], $frame_ptr[5], $frame_ptr[6], $frame_ptr[7]
+
+		# Swap to the context of the faulting code and try to print a backtrace
+		set $saved_sp = $sp
+		if $lr & 0x10
+			set $sp = $frame_ptr + (8 * 4)
+		else
+			set $sp = $frame_ptr + (26 * 4)
+		end
+		set $saved_lr = $lr
+		set $lr = $frame_ptr[5]
+		set $saved_pc = $pc
+		set $pc = $frame_ptr[6]
+		bt
+		set $sp = $saved_sp
+		set $lr = $saved_lr
+		set $pc = $saved_pc
+	else
+		printf "(not currently in exception handler)\n"
+	end
+end
+
+document vecstate
+.    vecstate
+.        Print information about the current exception handling state.
+end
+
+define hf_backtrace
+	set $pc = ((uint32_t*)$psp)[6]
+	set $lr = ((uint32_t*)$psp)[5]
+	set $r12 = ((uint32_t*)$psp)[4]
+	set $r3 = ((uint32_t*)$psp)[3]
+	set $r2 = ((uint32_t*)$psp)[2]
+	set $r1 = ((uint32_t*)$psp)[1]
+	set $r0 = ((uint32_t*)$psp)[0]
+	set $sp = $psp + 4*26
+	bt
+end
+

+ 15 - 0
utils/run_gdb.sh

@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# This script runs GDB with openocd and stlink to
+# allow debugging and seeing the SWO log output in realtime.
+
+killall orbuculum
+killall orbcat
+
+arm-none-eabi-gdb \
+       -iex 'target extended | openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c "gdb_port pipe"' \
+       -iex 'mon halt' \
+       -iex 'mon tpiu config internal swo.log uart false 38400000 2000000' \
+       -iex 'shell bash -m -c "orbuculum -f swo.log &"' \
+       -iex 'shell bash -m -c "orbcat -c 0,%c &"' \
+       .pio/build/genericGD32F205VC/firmware.elf

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini