From f152bed4b4f7b470ebec2045dab6008ef7add856 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Sat, 12 Oct 2019 00:00:36 +0800 Subject: [PATCH 01/27] fomu: initial commit Signed-off-by: Sean Cross --- hw/bsp/fomu/board.mk | 29 ++ hw/bsp/fomu/bsp.c | 129 ++++++ hw/bsp/fomu/crt0-vexriscv.S | 91 ++++ hw/bsp/fomu/fomu.ld | 61 +++ hw/bsp/fomu/include/csr.h | 709 ++++++++++++++++++++++++++++++++ hw/bsp/fomu/include/hw/common.h | 33 ++ hw/bsp/fomu/include/irq.h | 71 ++++ hw/bsp/fomu/output_format.ld | 1 + hw/bsp/fomu/regions.ld | 6 + 9 files changed, 1130 insertions(+) create mode 100644 hw/bsp/fomu/board.mk create mode 100644 hw/bsp/fomu/bsp.c create mode 100644 hw/bsp/fomu/crt0-vexriscv.S create mode 100644 hw/bsp/fomu/fomu.ld create mode 100644 hw/bsp/fomu/include/csr.h create mode 100644 hw/bsp/fomu/include/hw/common.h create mode 100644 hw/bsp/fomu/include/irq.h create mode 100644 hw/bsp/fomu/output_format.ld create mode 100644 hw/bsp/fomu/regions.ld diff --git a/hw/bsp/fomu/board.mk b/hw/bsp/fomu/board.mk new file mode 100644 index 000000000..86f8df23f --- /dev/null +++ b/hw/bsp/fomu/board.mk @@ -0,0 +1,29 @@ +CFLAGS += \ + -march=rv32i \ + -mabi=ilp32 \ + -nostdlib \ + -DCFG_TUSB_MCU=OPT_MCU_FOMU_EPTRI + +MCU_DIR = hw/mcu/fomu +BSP_DIR = hw/bsp/fomu + +# All source paths should be relative to the top level. +LD_FILE = hw/bsp/fomu/fomu.ld + +# TODO remove later +SRC_C += src/portable/$(VENDOR)/$(CHIP_FAMILY)/hal_$(CHIP_FAMILY).c + +SRC_C += + +SRC_S += hw/bsp/fomu/crt0-vexriscv.S + +INC += \ + $(TOP)/$(BSP_DIR)/include + +# For TinyUSB port source +VENDOR = foosn +CHIP_FAMILY = fomu + +# flash using dfu-util +flash: $(BUILD)/$(BOARD)-firmware.dfu + dfu-util -D $^ diff --git a/hw/bsp/fomu/bsp.c b/hw/bsp/fomu/bsp.c new file mode 100644 index 000000000..861c223f2 --- /dev/null +++ b/hw/bsp/fomu/bsp.c @@ -0,0 +1,129 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include +#include +#include "common/tusb_common.h" +#include "csr.h" +#include "irq.h" + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void hal_dcd_isr(uint8_t rhport); + +void mputs(const char *str) { + (void)str; + while (*str) { + if (! (messible_status_read() & CSR_MESSIBLE_STATUS_FULL_OFFSET)) + messible_in_write(*str); + str++; + } +} + +void mputln(const char *str) { + mputs(str); + mputs("\n"); +} + +void fomu_error(uint32_t line) +{ + (void)line; + TU_BREAKPOINT(); + while (1) {} +} + +volatile uint32_t system_ticks = 0; +static void timer_init(void) +{ + int t; + + timer0_en_write(0); + t = CONFIG_CLOCK_FREQUENCY / 1000; // 1000 kHz tick + timer0_reload_write(t); + timer0_load_write(t); + timer0_en_write(1); + timer0_ev_enable_write(1); + timer0_ev_pending_write(1); + irq_setmask(irq_getmask() | (1 << TIMER0_INTERRUPT)); +} + +void isr(void) +{ + unsigned int irqs; + + irqs = irq_pending() & irq_getmask(); + + if (irqs & (1 << USB_INTERRUPT)) { + hal_dcd_isr(0); + } + if (irqs & (1 << TIMER0_INTERRUPT)) { + system_ticks++; + timer0_ev_pending_write(1); + } +} + +void board_init(void) +{ + mputln("Fomu Initializing"); + irq_setmask(0); + irq_setie(1); + timer_init(); + return; +} + +void board_led_write(bool state) +{ + rgb_ctrl_write(0xff); + rgb_raw_write(state); +} + +uint32_t board_button_read(void) +{ + return 0; +} + +int board_uart_read(uint8_t* buf, int len) +{ + (void) buf; + (void) len; + return 0; +} + +int board_uart_write(void const * buf, int len) +{ + (void) buf; + (void) len; + return 0; +} + +#if CFG_TUSB_OS == OPT_OS_NONE +uint32_t board_millis(void) +{ + return system_ticks; +} +#endif \ No newline at end of file diff --git a/hw/bsp/fomu/crt0-vexriscv.S b/hw/bsp/fomu/crt0-vexriscv.S new file mode 100644 index 000000000..931d50a04 --- /dev/null +++ b/hw/bsp/fomu/crt0-vexriscv.S @@ -0,0 +1,91 @@ +.global main +.global isr + +.section .text.start +.global _start + +_start: + j crt_init + nop + nop + nop + nop + nop + nop + nop + +.section .text +.global trap_entry +trap_entry: + sw x1, - 1*4(sp) + sw x5, - 2*4(sp) + sw x6, - 3*4(sp) + sw x7, - 4*4(sp) + sw x10, - 5*4(sp) + sw x11, - 6*4(sp) + sw x12, - 7*4(sp) + sw x13, - 8*4(sp) + sw x14, - 9*4(sp) + sw x15, -10*4(sp) + sw x16, -11*4(sp) + sw x17, -12*4(sp) + sw x28, -13*4(sp) + sw x29, -14*4(sp) + sw x30, -15*4(sp) + sw x31, -16*4(sp) + addi sp,sp,-16*4 + call isr + lw x1 , 15*4(sp) + lw x5, 14*4(sp) + lw x6, 13*4(sp) + lw x7, 12*4(sp) + lw x10, 11*4(sp) + lw x11, 10*4(sp) + lw x12, 9*4(sp) + lw x13, 8*4(sp) + lw x14, 7*4(sp) + lw x15, 6*4(sp) + lw x16, 5*4(sp) + lw x17, 4*4(sp) + lw x28, 3*4(sp) + lw x29, 2*4(sp) + lw x30, 1*4(sp) + lw x31, 0*4(sp) + addi sp,sp,16*4 + mret + .text + + +crt_init: + la sp, _fstack + 4 + la a0, trap_entry + csrw mtvec, a0 + +bss_init: + la a0, _fbss + la a1, _ebss +bss_loop: + beq a0,a1,bss_done + sw zero,0(a0) + add a0,a0,4 + j bss_loop +bss_done: + + /* Load DATA */ + la t0, _erodata + la t1, _fdata + la t2, _edata +3: + lw t3, 0(t0) + sw t3, 0(t1) + /* _edata is aligned to 16 bytes. Use word-xfers. */ + addi t0, t0, 4 + addi t1, t1, 4 + bltu t1, t2, 3b + + li a0, 0x880 //880 enable timer + external interrupt sources (until mstatus.MIE is set, they will never trigger an interrupt) + csrw mie,a0 + + call main +infinit_loop: + j infinit_loop diff --git a/hw/bsp/fomu/fomu.ld b/hw/bsp/fomu/fomu.ld new file mode 100644 index 000000000..f39d62f35 --- /dev/null +++ b/hw/bsp/fomu/fomu.ld @@ -0,0 +1,61 @@ +OUTPUT_FORMAT("elf32-littleriscv") +ENTRY(_start) + +__DYNAMIC = 0; + +MEMORY { + csr : ORIGIN = 0x60000000, LENGTH = 0x01000000 + vexriscv_debug : ORIGIN = 0xf00f0000, LENGTH = 0x00000100 + sram : ORIGIN = 0x10000000, LENGTH = 0x00020000 + rom : ORIGIN = 0x2001a000, LENGTH = 0x00200000 - 0x1a000 +} + +SECTIONS +{ + .text : + { + _ftext = .; + *(.text.start) + *(.text .stub .text.* .gnu.linkonce.t.*) + _etext = .; + } > rom + + .rodata : + { + . = ALIGN(4); + _frodata = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.srodata) + _erodata = .; + } > rom + + .data : AT (ADDR(.rodata) + SIZEOF (.rodata)) + { + . = ALIGN(4); + _fdata = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + _gp = ALIGN(16); + *(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*) + _edata = ALIGN(16); /* Make sure _edata is >= _gp. */ + } > sram + + .bss : + { + . = ALIGN(4); + _fbss = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + _end = .; + PROVIDE(end = .); + } > sram +} + +PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4); diff --git a/hw/bsp/fomu/include/csr.h b/hw/bsp/fomu/include/csr.h new file mode 100644 index 000000000..b9bffada3 --- /dev/null +++ b/hw/bsp/fomu/include/csr.h @@ -0,0 +1,709 @@ +//-------------------------------------------------------------------------------- +// Auto-generated by Migen (f4fcd10) & LiteX (1425a68d) on 2019-10-11 22:01:17 +//-------------------------------------------------------------------------------- +#ifndef __GENERATED_CSR_H +#define __GENERATED_CSR_H +#include +#ifdef CSR_ACCESSORS_DEFINED +extern void csr_writeb(uint8_t value, unsigned long addr); +extern uint8_t csr_readb(unsigned long addr); +extern void csr_writew(uint16_t value, unsigned long addr); +extern uint16_t csr_readw(unsigned long addr); +extern void csr_writel(uint32_t value, unsigned long addr); +extern uint32_t csr_readl(unsigned long addr); +#else /* ! CSR_ACCESSORS_DEFINED */ +#include +#endif /* ! CSR_ACCESSORS_DEFINED */ + +/* ctrl */ +#define CSR_CTRL_BASE 0xe0000000L +#define CSR_CTRL_RESET_ADDR 0xe0000000L +#define CSR_CTRL_RESET_SIZE 1 +static inline unsigned char ctrl_reset_read(void) { + unsigned char r = csr_readl(0xe0000000L); + return r; +} +static inline void ctrl_reset_write(unsigned char value) { + csr_writel(value, 0xe0000000L); +} +#define CSR_CTRL_SCRATCH_ADDR 0xe0000004L +#define CSR_CTRL_SCRATCH_SIZE 4 +static inline unsigned int ctrl_scratch_read(void) { + unsigned int r = csr_readl(0xe0000004L); + r <<= 8; + r |= csr_readl(0xe0000008L); + r <<= 8; + r |= csr_readl(0xe000000cL); + r <<= 8; + r |= csr_readl(0xe0000010L); + return r; +} +static inline void ctrl_scratch_write(unsigned int value) { + csr_writel(value >> 24, 0xe0000004L); + csr_writel(value >> 16, 0xe0000008L); + csr_writel(value >> 8, 0xe000000cL); + csr_writel(value, 0xe0000010L); +} +#define CSR_CTRL_BUS_ERRORS_ADDR 0xe0000014L +#define CSR_CTRL_BUS_ERRORS_SIZE 4 +static inline unsigned int ctrl_bus_errors_read(void) { + unsigned int r = csr_readl(0xe0000014L); + r <<= 8; + r |= csr_readl(0xe0000018L); + r <<= 8; + r |= csr_readl(0xe000001cL); + r <<= 8; + r |= csr_readl(0xe0000020L); + return r; +} + +/* lxspi */ +#define CSR_LXSPI_BASE 0xe0007800L +#define CSR_LXSPI_BITBANG_ADDR 0xe0007800L +#define CSR_LXSPI_BITBANG_SIZE 1 +static inline unsigned char lxspi_bitbang_read(void) { + unsigned char r = csr_readl(0xe0007800L); + return r; +} +static inline void lxspi_bitbang_write(unsigned char value) { + csr_writel(value, 0xe0007800L); +} +#define CSR_LXSPI_BITBANG_MOSI_OFFSET 0 +#define CSR_LXSPI_BITBANG_MOSI_SIZE 1 +#define CSR_LXSPI_BITBANG_CLK_OFFSET 1 +#define CSR_LXSPI_BITBANG_CLK_SIZE 1 +#define CSR_LXSPI_BITBANG_CS_N_OFFSET 2 +#define CSR_LXSPI_BITBANG_CS_N_SIZE 1 +#define CSR_LXSPI_BITBANG_DIR_OFFSET 3 +#define CSR_LXSPI_BITBANG_DIR_SIZE 1 +#define CSR_LXSPI_MISO_ADDR 0xe0007804L +#define CSR_LXSPI_MISO_SIZE 1 +static inline unsigned char lxspi_miso_read(void) { + unsigned char r = csr_readl(0xe0007804L); + return r; +} +#define CSR_LXSPI_BITBANG_EN_ADDR 0xe0007808L +#define CSR_LXSPI_BITBANG_EN_SIZE 1 +static inline unsigned char lxspi_bitbang_en_read(void) { + unsigned char r = csr_readl(0xe0007808L); + return r; +} +static inline void lxspi_bitbang_en_write(unsigned char value) { + csr_writel(value, 0xe0007808L); +} + +/* messible */ +#define CSR_MESSIBLE_BASE 0xe0008000L +#define CSR_MESSIBLE_IN_ADDR 0xe0008000L +#define CSR_MESSIBLE_IN_SIZE 1 +static inline unsigned char messible_in_read(void) { + unsigned char r = csr_readl(0xe0008000L); + return r; +} +static inline void messible_in_write(unsigned char value) { + csr_writel(value, 0xe0008000L); +} +#define CSR_MESSIBLE_OUT_ADDR 0xe0008004L +#define CSR_MESSIBLE_OUT_SIZE 1 +static inline unsigned char messible_out_read(void) { + unsigned char r = csr_readl(0xe0008004L); + return r; +} +#define CSR_MESSIBLE_STATUS_ADDR 0xe0008008L +#define CSR_MESSIBLE_STATUS_SIZE 1 +static inline unsigned char messible_status_read(void) { + unsigned char r = csr_readl(0xe0008008L); + return r; +} +#define CSR_MESSIBLE_STATUS_FULL_OFFSET 0 +#define CSR_MESSIBLE_STATUS_FULL_SIZE 1 +#define CSR_MESSIBLE_STATUS_HAVE_OFFSET 1 +#define CSR_MESSIBLE_STATUS_HAVE_SIZE 1 + +/* reboot */ +#define CSR_REBOOT_BASE 0xe0006000L +#define CSR_REBOOT_CTRL_ADDR 0xe0006000L +#define CSR_REBOOT_CTRL_SIZE 1 +static inline unsigned char reboot_ctrl_read(void) { + unsigned char r = csr_readl(0xe0006000L); + return r; +} +static inline void reboot_ctrl_write(unsigned char value) { + csr_writel(value, 0xe0006000L); +} +#define CSR_REBOOT_CTRL_IMAGE_OFFSET 0 +#define CSR_REBOOT_CTRL_IMAGE_SIZE 2 +#define CSR_REBOOT_CTRL_KEY_OFFSET 2 +#define CSR_REBOOT_CTRL_KEY_SIZE 6 +#define CSR_REBOOT_ADDR_ADDR 0xe0006004L +#define CSR_REBOOT_ADDR_SIZE 4 +static inline unsigned int reboot_addr_read(void) { + unsigned int r = csr_readl(0xe0006004L); + r <<= 8; + r |= csr_readl(0xe0006008L); + r <<= 8; + r |= csr_readl(0xe000600cL); + r <<= 8; + r |= csr_readl(0xe0006010L); + return r; +} +static inline void reboot_addr_write(unsigned int value) { + csr_writel(value >> 24, 0xe0006004L); + csr_writel(value >> 16, 0xe0006008L); + csr_writel(value >> 8, 0xe000600cL); + csr_writel(value, 0xe0006010L); +} + +/* rgb */ +#define CSR_RGB_BASE 0xe0006800L +#define CSR_RGB_DAT_ADDR 0xe0006800L +#define CSR_RGB_DAT_SIZE 1 +static inline unsigned char rgb_dat_read(void) { + unsigned char r = csr_readl(0xe0006800L); + return r; +} +static inline void rgb_dat_write(unsigned char value) { + csr_writel(value, 0xe0006800L); +} +#define CSR_RGB_ADDR_ADDR 0xe0006804L +#define CSR_RGB_ADDR_SIZE 1 +static inline unsigned char rgb_addr_read(void) { + unsigned char r = csr_readl(0xe0006804L); + return r; +} +static inline void rgb_addr_write(unsigned char value) { + csr_writel(value, 0xe0006804L); +} +#define CSR_RGB_CTRL_ADDR 0xe0006808L +#define CSR_RGB_CTRL_SIZE 1 +static inline unsigned char rgb_ctrl_read(void) { + unsigned char r = csr_readl(0xe0006808L); + return r; +} +static inline void rgb_ctrl_write(unsigned char value) { + csr_writel(value, 0xe0006808L); +} +#define CSR_RGB_CTRL_EXE_OFFSET 0 +#define CSR_RGB_CTRL_EXE_SIZE 1 +#define CSR_RGB_CTRL_CURREN_OFFSET 1 +#define CSR_RGB_CTRL_CURREN_SIZE 1 +#define CSR_RGB_CTRL_RGBLEDEN_OFFSET 2 +#define CSR_RGB_CTRL_RGBLEDEN_SIZE 1 +#define CSR_RGB_CTRL_RRAW_OFFSET 3 +#define CSR_RGB_CTRL_RRAW_SIZE 1 +#define CSR_RGB_CTRL_GRAW_OFFSET 4 +#define CSR_RGB_CTRL_GRAW_SIZE 1 +#define CSR_RGB_CTRL_BRAW_OFFSET 5 +#define CSR_RGB_CTRL_BRAW_SIZE 1 +#define CSR_RGB_RAW_ADDR 0xe000680cL +#define CSR_RGB_RAW_SIZE 1 +static inline unsigned char rgb_raw_read(void) { + unsigned char r = csr_readl(0xe000680cL); + return r; +} +static inline void rgb_raw_write(unsigned char value) { + csr_writel(value, 0xe000680cL); +} +#define CSR_RGB_RAW_R_OFFSET 0 +#define CSR_RGB_RAW_R_SIZE 1 +#define CSR_RGB_RAW_G_OFFSET 1 +#define CSR_RGB_RAW_G_SIZE 1 +#define CSR_RGB_RAW_B_OFFSET 2 +#define CSR_RGB_RAW_B_SIZE 1 + +/* timer0 */ +#define CSR_TIMER0_BASE 0xe0002800L +#define CSR_TIMER0_LOAD_ADDR 0xe0002800L +#define CSR_TIMER0_LOAD_SIZE 4 +static inline unsigned int timer0_load_read(void) { + unsigned int r = csr_readl(0xe0002800L); + r <<= 8; + r |= csr_readl(0xe0002804L); + r <<= 8; + r |= csr_readl(0xe0002808L); + r <<= 8; + r |= csr_readl(0xe000280cL); + return r; +} +static inline void timer0_load_write(unsigned int value) { + csr_writel(value >> 24, 0xe0002800L); + csr_writel(value >> 16, 0xe0002804L); + csr_writel(value >> 8, 0xe0002808L); + csr_writel(value, 0xe000280cL); +} +#define CSR_TIMER0_RELOAD_ADDR 0xe0002810L +#define CSR_TIMER0_RELOAD_SIZE 4 +static inline unsigned int timer0_reload_read(void) { + unsigned int r = csr_readl(0xe0002810L); + r <<= 8; + r |= csr_readl(0xe0002814L); + r <<= 8; + r |= csr_readl(0xe0002818L); + r <<= 8; + r |= csr_readl(0xe000281cL); + return r; +} +static inline void timer0_reload_write(unsigned int value) { + csr_writel(value >> 24, 0xe0002810L); + csr_writel(value >> 16, 0xe0002814L); + csr_writel(value >> 8, 0xe0002818L); + csr_writel(value, 0xe000281cL); +} +#define CSR_TIMER0_EN_ADDR 0xe0002820L +#define CSR_TIMER0_EN_SIZE 1 +static inline unsigned char timer0_en_read(void) { + unsigned char r = csr_readl(0xe0002820L); + return r; +} +static inline void timer0_en_write(unsigned char value) { + csr_writel(value, 0xe0002820L); +} +#define CSR_TIMER0_UPDATE_VALUE_ADDR 0xe0002824L +#define CSR_TIMER0_UPDATE_VALUE_SIZE 1 +static inline unsigned char timer0_update_value_read(void) { + unsigned char r = csr_readl(0xe0002824L); + return r; +} +static inline void timer0_update_value_write(unsigned char value) { + csr_writel(value, 0xe0002824L); +} +#define CSR_TIMER0_VALUE_ADDR 0xe0002828L +#define CSR_TIMER0_VALUE_SIZE 4 +static inline unsigned int timer0_value_read(void) { + unsigned int r = csr_readl(0xe0002828L); + r <<= 8; + r |= csr_readl(0xe000282cL); + r <<= 8; + r |= csr_readl(0xe0002830L); + r <<= 8; + r |= csr_readl(0xe0002834L); + return r; +} +#define CSR_TIMER0_EV_STATUS_ADDR 0xe0002838L +#define CSR_TIMER0_EV_STATUS_SIZE 1 +static inline unsigned char timer0_ev_status_read(void) { + unsigned char r = csr_readl(0xe0002838L); + return r; +} +static inline void timer0_ev_status_write(unsigned char value) { + csr_writel(value, 0xe0002838L); +} +#define CSR_TIMER0_EV_PENDING_ADDR 0xe000283cL +#define CSR_TIMER0_EV_PENDING_SIZE 1 +static inline unsigned char timer0_ev_pending_read(void) { + unsigned char r = csr_readl(0xe000283cL); + return r; +} +static inline void timer0_ev_pending_write(unsigned char value) { + csr_writel(value, 0xe000283cL); +} +#define CSR_TIMER0_EV_ENABLE_ADDR 0xe0002840L +#define CSR_TIMER0_EV_ENABLE_SIZE 1 +static inline unsigned char timer0_ev_enable_read(void) { + unsigned char r = csr_readl(0xe0002840L); + return r; +} +static inline void timer0_ev_enable_write(unsigned char value) { + csr_writel(value, 0xe0002840L); +} + +/* touch */ +#define CSR_TOUCH_BASE 0xe0005800L +#define CSR_TOUCH_O_ADDR 0xe0005800L +#define CSR_TOUCH_O_SIZE 1 +static inline unsigned char touch_o_read(void) { + unsigned char r = csr_readl(0xe0005800L); + return r; +} +static inline void touch_o_write(unsigned char value) { + csr_writel(value, 0xe0005800L); +} +#define CSR_TOUCH_O_O_OFFSET 0 +#define CSR_TOUCH_O_O_SIZE 4 +#define CSR_TOUCH_OE_ADDR 0xe0005804L +#define CSR_TOUCH_OE_SIZE 1 +static inline unsigned char touch_oe_read(void) { + unsigned char r = csr_readl(0xe0005804L); + return r; +} +static inline void touch_oe_write(unsigned char value) { + csr_writel(value, 0xe0005804L); +} +#define CSR_TOUCH_OE_OE_OFFSET 0 +#define CSR_TOUCH_OE_OE_SIZE 4 +#define CSR_TOUCH_I_ADDR 0xe0005808L +#define CSR_TOUCH_I_SIZE 1 +static inline unsigned char touch_i_read(void) { + unsigned char r = csr_readl(0xe0005808L); + return r; +} +#define CSR_TOUCH_I_I_OFFSET 0 +#define CSR_TOUCH_I_I_SIZE 4 + +/* usb */ +#define CSR_USB_BASE 0xe0004800L +#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800L +#define CSR_USB_PULLUP_OUT_SIZE 1 +static inline unsigned char usb_pullup_out_read(void) { + unsigned char r = csr_readl(0xe0004800L); + return r; +} +static inline void usb_pullup_out_write(unsigned char value) { + csr_writel(value, 0xe0004800L); +} +#define CSR_USB_SETUP_DATA_ADDR 0xe0004804L +#define CSR_USB_SETUP_DATA_SIZE 1 +static inline unsigned char usb_setup_data_read(void) { + unsigned char r = csr_readl(0xe0004804L); + return r; +} +#define CSR_USB_SETUP_DATA_DATA_OFFSET 0 +#define CSR_USB_SETUP_DATA_DATA_SIZE 8 +#define CSR_USB_SETUP_CTRL_ADDR 0xe0004808L +#define CSR_USB_SETUP_CTRL_SIZE 1 +static inline unsigned char usb_setup_ctrl_read(void) { + unsigned char r = csr_readl(0xe0004808L); + return r; +} +static inline void usb_setup_ctrl_write(unsigned char value) { + csr_writel(value, 0xe0004808L); +} +#define CSR_USB_SETUP_CTRL_HANDLED_OFFSET 1 +#define CSR_USB_SETUP_CTRL_HANDLED_SIZE 1 +#define CSR_USB_SETUP_CTRL_RESET_OFFSET 2 +#define CSR_USB_SETUP_CTRL_RESET_SIZE 1 +#define CSR_USB_SETUP_STATUS_ADDR 0xe000480cL +#define CSR_USB_SETUP_STATUS_SIZE 1 +static inline unsigned char usb_setup_status_read(void) { + unsigned char r = csr_readl(0xe000480cL); + return r; +} +#define CSR_USB_SETUP_STATUS_HAVE_OFFSET 0 +#define CSR_USB_SETUP_STATUS_HAVE_SIZE 1 +#define CSR_USB_SETUP_STATUS_IS_IN_OFFSET 1 +#define CSR_USB_SETUP_STATUS_IS_IN_SIZE 1 +#define CSR_USB_SETUP_STATUS_EPNO_OFFSET 2 +#define CSR_USB_SETUP_STATUS_EPNO_SIZE 4 +#define CSR_USB_SETUP_STATUS_PEND_OFFSET 6 +#define CSR_USB_SETUP_STATUS_PEND_SIZE 1 +#define CSR_USB_SETUP_STATUS_DATA_OFFSET 7 +#define CSR_USB_SETUP_STATUS_DATA_SIZE 1 +#define CSR_USB_SETUP_EV_STATUS_ADDR 0xe0004810L +#define CSR_USB_SETUP_EV_STATUS_SIZE 1 +static inline unsigned char usb_setup_ev_status_read(void) { + unsigned char r = csr_readl(0xe0004810L); + return r; +} +static inline void usb_setup_ev_status_write(unsigned char value) { + csr_writel(value, 0xe0004810L); +} +#define CSR_USB_SETUP_EV_PENDING_ADDR 0xe0004814L +#define CSR_USB_SETUP_EV_PENDING_SIZE 1 +static inline unsigned char usb_setup_ev_pending_read(void) { + unsigned char r = csr_readl(0xe0004814L); + return r; +} +static inline void usb_setup_ev_pending_write(unsigned char value) { + csr_writel(value, 0xe0004814L); +} +#define CSR_USB_SETUP_EV_ENABLE_ADDR 0xe0004818L +#define CSR_USB_SETUP_EV_ENABLE_SIZE 1 +static inline unsigned char usb_setup_ev_enable_read(void) { + unsigned char r = csr_readl(0xe0004818L); + return r; +} +static inline void usb_setup_ev_enable_write(unsigned char value) { + csr_writel(value, 0xe0004818L); +} +#define CSR_USB_IN_DATA_ADDR 0xe000481cL +#define CSR_USB_IN_DATA_SIZE 1 +static inline unsigned char usb_in_data_read(void) { + unsigned char r = csr_readl(0xe000481cL); + return r; +} +static inline void usb_in_data_write(unsigned char value) { + csr_writel(value, 0xe000481cL); +} +#define CSR_USB_IN_DATA_DATA_OFFSET 0 +#define CSR_USB_IN_DATA_DATA_SIZE 8 +#define CSR_USB_IN_STATUS_ADDR 0xe0004820L +#define CSR_USB_IN_STATUS_SIZE 1 +static inline unsigned char usb_in_status_read(void) { + unsigned char r = csr_readl(0xe0004820L); + return r; +} +#define CSR_USB_IN_STATUS_HAVE_OFFSET 0 +#define CSR_USB_IN_STATUS_HAVE_SIZE 1 +#define CSR_USB_IN_STATUS_IDLE_OFFSET 1 +#define CSR_USB_IN_STATUS_IDLE_SIZE 1 +#define CSR_USB_IN_STATUS_PEND_OFFSET 6 +#define CSR_USB_IN_STATUS_PEND_SIZE 1 +#define CSR_USB_IN_CTRL_ADDR 0xe0004824L +#define CSR_USB_IN_CTRL_SIZE 1 +static inline unsigned char usb_in_ctrl_read(void) { + unsigned char r = csr_readl(0xe0004824L); + return r; +} +static inline void usb_in_ctrl_write(unsigned char value) { + csr_writel(value, 0xe0004824L); +} +#define CSR_USB_IN_CTRL_EP_OFFSET 0 +#define CSR_USB_IN_CTRL_EP_SIZE 4 +#define CSR_USB_IN_CTRL_STALL_OFFSET 4 +#define CSR_USB_IN_CTRL_STALL_SIZE 1 +#define CSR_USB_IN_CTRL_RESET_OFFSET 5 +#define CSR_USB_IN_CTRL_RESET_SIZE 1 +#define CSR_USB_IN_EV_STATUS_ADDR 0xe0004828L +#define CSR_USB_IN_EV_STATUS_SIZE 1 +static inline unsigned char usb_in_ev_status_read(void) { + unsigned char r = csr_readl(0xe0004828L); + return r; +} +static inline void usb_in_ev_status_write(unsigned char value) { + csr_writel(value, 0xe0004828L); +} +#define CSR_USB_IN_EV_PENDING_ADDR 0xe000482cL +#define CSR_USB_IN_EV_PENDING_SIZE 1 +static inline unsigned char usb_in_ev_pending_read(void) { + unsigned char r = csr_readl(0xe000482cL); + return r; +} +static inline void usb_in_ev_pending_write(unsigned char value) { + csr_writel(value, 0xe000482cL); +} +#define CSR_USB_IN_EV_ENABLE_ADDR 0xe0004830L +#define CSR_USB_IN_EV_ENABLE_SIZE 1 +static inline unsigned char usb_in_ev_enable_read(void) { + unsigned char r = csr_readl(0xe0004830L); + return r; +} +static inline void usb_in_ev_enable_write(unsigned char value) { + csr_writel(value, 0xe0004830L); +} +#define CSR_USB_OUT_DATA_ADDR 0xe0004834L +#define CSR_USB_OUT_DATA_SIZE 1 +static inline unsigned char usb_out_data_read(void) { + unsigned char r = csr_readl(0xe0004834L); + return r; +} +#define CSR_USB_OUT_DATA_DATA_OFFSET 0 +#define CSR_USB_OUT_DATA_DATA_SIZE 8 +#define CSR_USB_OUT_STATUS_ADDR 0xe0004838L +#define CSR_USB_OUT_STATUS_SIZE 1 +static inline unsigned char usb_out_status_read(void) { + unsigned char r = csr_readl(0xe0004838L); + return r; +} +#define CSR_USB_OUT_STATUS_HAVE_OFFSET 0 +#define CSR_USB_OUT_STATUS_HAVE_SIZE 1 +#define CSR_USB_OUT_STATUS_IDLE_OFFSET 1 +#define CSR_USB_OUT_STATUS_IDLE_SIZE 1 +#define CSR_USB_OUT_STATUS_EPNO_OFFSET 2 +#define CSR_USB_OUT_STATUS_EPNO_SIZE 4 +#define CSR_USB_OUT_STATUS_PEND_OFFSET 6 +#define CSR_USB_OUT_STATUS_PEND_SIZE 1 +#define CSR_USB_OUT_CTRL_ADDR 0xe000483cL +#define CSR_USB_OUT_CTRL_SIZE 1 +static inline unsigned char usb_out_ctrl_read(void) { + unsigned char r = csr_readl(0xe000483cL); + return r; +} +static inline void usb_out_ctrl_write(unsigned char value) { + csr_writel(value, 0xe000483cL); +} +#define CSR_USB_OUT_CTRL_ENABLE_OFFSET 1 +#define CSR_USB_OUT_CTRL_ENABLE_SIZE 1 +#define CSR_USB_OUT_CTRL_RESET_OFFSET 2 +#define CSR_USB_OUT_CTRL_RESET_SIZE 1 +#define CSR_USB_OUT_STALL_ADDR 0xe0004840L +#define CSR_USB_OUT_STALL_SIZE 1 +static inline unsigned char usb_out_stall_read(void) { + unsigned char r = csr_readl(0xe0004840L); + return r; +} +static inline void usb_out_stall_write(unsigned char value) { + csr_writel(value, 0xe0004840L); +} +#define CSR_USB_OUT_STALL_EPNO_OFFSET 0 +#define CSR_USB_OUT_STALL_EPNO_SIZE 4 +#define CSR_USB_OUT_STALL_STALL_OFFSET 4 +#define CSR_USB_OUT_STALL_STALL_SIZE 1 +#define CSR_USB_OUT_EV_STATUS_ADDR 0xe0004844L +#define CSR_USB_OUT_EV_STATUS_SIZE 1 +static inline unsigned char usb_out_ev_status_read(void) { + unsigned char r = csr_readl(0xe0004844L); + return r; +} +static inline void usb_out_ev_status_write(unsigned char value) { + csr_writel(value, 0xe0004844L); +} +#define CSR_USB_OUT_EV_PENDING_ADDR 0xe0004848L +#define CSR_USB_OUT_EV_PENDING_SIZE 1 +static inline unsigned char usb_out_ev_pending_read(void) { + unsigned char r = csr_readl(0xe0004848L); + return r; +} +static inline void usb_out_ev_pending_write(unsigned char value) { + csr_writel(value, 0xe0004848L); +} +#define CSR_USB_OUT_EV_ENABLE_ADDR 0xe000484cL +#define CSR_USB_OUT_EV_ENABLE_SIZE 1 +static inline unsigned char usb_out_ev_enable_read(void) { + unsigned char r = csr_readl(0xe000484cL); + return r; +} +static inline void usb_out_ev_enable_write(unsigned char value) { + csr_writel(value, 0xe000484cL); +} +#define CSR_USB_ADDRESS_ADDR 0xe0004850L +#define CSR_USB_ADDRESS_SIZE 1 +static inline unsigned char usb_address_read(void) { + unsigned char r = csr_readl(0xe0004850L); + return r; +} +static inline void usb_address_write(unsigned char value) { + csr_writel(value, 0xe0004850L); +} +#define CSR_USB_ADDRESS_ADDR_OFFSET 0 +#define CSR_USB_ADDRESS_ADDR_SIZE 7 +#define CSR_USB_STAGE_NUM_ADDR 0xe0004854L +#define CSR_USB_STAGE_NUM_SIZE 1 +static inline unsigned char usb_stage_num_read(void) { + unsigned char r = csr_readl(0xe0004854L); + return r; +} +#define CSR_USB_LAST_STAGE_NUM_ADDR 0xe0004858L +#define CSR_USB_LAST_STAGE_NUM_SIZE 1 +static inline unsigned char usb_last_stage_num_read(void) { + unsigned char r = csr_readl(0xe0004858L); + return r; +} + +/* version */ +#define CSR_VERSION_BASE 0xe0007000L +#define CSR_VERSION_MAJOR_ADDR 0xe0007000L +#define CSR_VERSION_MAJOR_SIZE 1 +static inline unsigned char version_major_read(void) { + unsigned char r = csr_readl(0xe0007000L); + return r; +} +#define CSR_VERSION_MINOR_ADDR 0xe0007004L +#define CSR_VERSION_MINOR_SIZE 1 +static inline unsigned char version_minor_read(void) { + unsigned char r = csr_readl(0xe0007004L); + return r; +} +#define CSR_VERSION_REVISION_ADDR 0xe0007008L +#define CSR_VERSION_REVISION_SIZE 1 +static inline unsigned char version_revision_read(void) { + unsigned char r = csr_readl(0xe0007008L); + return r; +} +#define CSR_VERSION_GITREV_ADDR 0xe000700cL +#define CSR_VERSION_GITREV_SIZE 4 +static inline unsigned int version_gitrev_read(void) { + unsigned int r = csr_readl(0xe000700cL); + r <<= 8; + r |= csr_readl(0xe0007010L); + r <<= 8; + r |= csr_readl(0xe0007014L); + r <<= 8; + r |= csr_readl(0xe0007018L); + return r; +} +#define CSR_VERSION_GITEXTRA_ADDR 0xe000701cL +#define CSR_VERSION_GITEXTRA_SIZE 2 +static inline unsigned short int version_gitextra_read(void) { + unsigned short int r = csr_readl(0xe000701cL); + r <<= 8; + r |= csr_readl(0xe0007020L); + return r; +} +#define CSR_VERSION_DIRTY_ADDR 0xe0007024L +#define CSR_VERSION_DIRTY_SIZE 1 +static inline unsigned char version_dirty_read(void) { + unsigned char r = csr_readl(0xe0007024L); + return r; +} +#define CSR_VERSION_DIRTY_DIRTY_OFFSET 0 +#define CSR_VERSION_DIRTY_DIRTY_SIZE 1 +#define CSR_VERSION_MODEL_ADDR 0xe0007028L +#define CSR_VERSION_MODEL_SIZE 1 +static inline unsigned char version_model_read(void) { + unsigned char r = csr_readl(0xe0007028L); + return r; +} +#define CSR_VERSION_MODEL_MODEL_OFFSET 0 +#define CSR_VERSION_MODEL_MODEL_SIZE 8 +#define CSR_VERSION_SEED_ADDR 0xe000702cL +#define CSR_VERSION_SEED_SIZE 4 +static inline unsigned int version_seed_read(void) { + unsigned int r = csr_readl(0xe000702cL); + r <<= 8; + r |= csr_readl(0xe0007030L); + r <<= 8; + r |= csr_readl(0xe0007034L); + r <<= 8; + r |= csr_readl(0xe0007038L); + return r; +} + +/* constants */ +#define TIMER0_INTERRUPT 2 +static inline int timer0_interrupt_read(void) { + return 2; +} +#define USB_INTERRUPT 3 +static inline int usb_interrupt_read(void) { + return 3; +} +#define SPI_BOOT 1 +static inline int spi_boot_read(void) { + return 1; +} +#define SPI_ENTRYPOINT 536977408 +static inline int spi_entrypoint_read(void) { + return 536977408; +} +#define CONFIG_BITSTREAM_SYNC_HEADER1 2123999870 +static inline int config_bitstream_sync_header1_read(void) { + return 2123999870; +} +#define CONFIG_BITSTREAM_SYNC_HEADER2 2125109630 +static inline int config_bitstream_sync_header2_read(void) { + return 2125109630; +} +#define CONFIG_CLOCK_FREQUENCY 12000000 +static inline int config_clock_frequency_read(void) { + return 12000000; +} +#define CONFIG_CPU_RESET_ADDR 0 +static inline int config_cpu_reset_addr_read(void) { + return 0; +} +#define CONFIG_CPU_TYPE "VEXRISCV" +static inline const char * config_cpu_type_read(void) { + return "VEXRISCV"; +} +#define CONFIG_CPU_TYPE_VEXRISCV 1 +static inline int config_cpu_type_vexriscv_read(void) { + return 1; +} +#define CONFIG_CPU_VARIANT "MIN" +static inline const char * config_cpu_variant_read(void) { + return "MIN"; +} +#define CONFIG_CPU_VARIANT_MIN 1 +static inline int config_cpu_variant_min_read(void) { + return 1; +} +#define CONFIG_CSR_ALIGNMENT 32 +static inline int config_csr_alignment_read(void) { + return 32; +} +#define CONFIG_CSR_DATA_WIDTH 8 +static inline int config_csr_data_width_read(void) { + return 8; +} + +#endif diff --git a/hw/bsp/fomu/include/hw/common.h b/hw/bsp/fomu/include/hw/common.h new file mode 100644 index 000000000..6a97ca2e9 --- /dev/null +++ b/hw/bsp/fomu/include/hw/common.h @@ -0,0 +1,33 @@ +#ifndef _HW_COMMON_H_ +#define _HW_COMMON_H_ +#include +static inline void csr_writeb(uint8_t value, uint32_t addr) +{ + *((volatile uint8_t *)addr) = value; +} + +static inline uint8_t csr_readb(uint32_t addr) +{ + return *(volatile uint8_t *)addr; +} + +static inline void csr_writew(uint16_t value, uint32_t addr) +{ + *((volatile uint16_t *)addr) = value; +} + +static inline uint16_t csr_readw(uint32_t addr) +{ + return *(volatile uint16_t *)addr; +} + +static inline void csr_writel(uint32_t value, uint32_t addr) +{ + *((volatile uint32_t *)addr) = value; +} + +static inline uint32_t csr_readl(uint32_t addr) +{ + return *(volatile uint32_t *)addr; +} +#endif /* _HW_COMMON_H_ */ \ No newline at end of file diff --git a/hw/bsp/fomu/include/irq.h b/hw/bsp/fomu/include/irq.h new file mode 100644 index 000000000..a82218907 --- /dev/null +++ b/hw/bsp/fomu/include/irq.h @@ -0,0 +1,71 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define CSR_MSTATUS_MIE 0x8 + +#define CSR_IRQ_MASK 0xBC0 +#define CSR_IRQ_PENDING 0xFC0 + +#define CSR_DCACHE_INFO 0xCC0 + +#define csrr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define csrw(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define csrs(reg, bit) ({ \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs x0, " #reg ", %0" :: "i"(bit)); \ + else \ + asm volatile ("csrrs x0, " #reg ", %0" :: "r"(bit)); }) + +#define csrc(reg, bit) ({ \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc x0, " #reg ", %0" :: "i"(bit)); \ + else \ + asm volatile ("csrrc x0, " #reg ", %0" :: "r"(bit)); }) + +static inline unsigned int irq_getie(void) +{ + return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; +} + +static inline void irq_setie(unsigned int ie) +{ + if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); +} + +static inline unsigned int irq_getmask(void) +{ + unsigned int mask; + asm volatile ("csrr %0, %1" : "=r"(mask) : "i"(CSR_IRQ_MASK)); + return mask; +} + +static inline void irq_setmask(unsigned int mask) +{ + asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask)); +} + +static inline unsigned int irq_pending(void) +{ + unsigned int pending; + asm volatile ("csrr %0, %1" : "=r"(pending) : "i"(CSR_IRQ_PENDING)); + return pending; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __IRQ_H */ \ No newline at end of file diff --git a/hw/bsp/fomu/output_format.ld b/hw/bsp/fomu/output_format.ld new file mode 100644 index 000000000..5e76f5f4e --- /dev/null +++ b/hw/bsp/fomu/output_format.ld @@ -0,0 +1 @@ +OUTPUT_FORMAT("elf32-littleriscv") diff --git a/hw/bsp/fomu/regions.ld b/hw/bsp/fomu/regions.ld new file mode 100644 index 000000000..51811f66e --- /dev/null +++ b/hw/bsp/fomu/regions.ld @@ -0,0 +1,6 @@ +MEMORY { + csr : ORIGIN = 0x60000000, LENGTH = 0x01000000 + vexriscv_debug : ORIGIN = 0xf00f0000, LENGTH = 0x00000100 + sram : ORIGIN = 0x10000000, LENGTH = 0x00020000 + rom : ORIGIN = 0x00000000, LENGTH = 0x00002000 +} From 36ede44885365faa230b63867e8392addd48e7b3 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Sat, 12 Oct 2019 10:25:10 +0800 Subject: [PATCH 02/27] fomu: wip support Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 335 +++++++++++++++++++++++++++++ src/portable/foosn/fomu/dcd_fomu.h | 151 +++++++++++++ src/portable/foosn/fomu/hal_fomu.c | 33 +++ 3 files changed, 519 insertions(+) create mode 100644 src/portable/foosn/fomu/dcd_fomu.c create mode 100644 src/portable/foosn/fomu/dcd_fomu.h create mode 100644 src/portable/foosn/fomu/hal_fomu.c diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c new file mode 100644 index 000000000..d7f9d3d1e --- /dev/null +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -0,0 +1,335 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +// #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) +#if 1 + +#include "device/dcd.h" +#include "dcd_fomu.h" +#include "csr.h" +#include "irq.h" +void fomu_error(uint32_t line); +void mputs(const char *str); +void mputln(const char *str); + +//--------------------------------------------------------------------+ +// SIE Command +//--------------------------------------------------------------------+ + +static uint8_t volatile out_buffer_length[16]; +static uint8_t volatile * out_buffer[16]; +static uint8_t volatile out_buffer_max[16]; + +static volatile bool tx_in_progress; +static volatile uint8_t tx_ep; +static volatile uint16_t tx_len; + +//--------------------------------------------------------------------+ +// PIPE HELPER +//--------------------------------------------------------------------+ + +static void finish_tx(void) { + // // Don't allow requeueing -- only queue more data if the system is idle. + // if (!(usb_in_status_read() & 2)) { + // return; + // } + + // Don't send empty data + if (!tx_in_progress) { + return; + } + + tx_in_progress = 0; + dcd_event_xfer_complete(0, tx_ep, tx_len, XFER_RESULT_SUCCESS, true); + return; +} + +static void process_rx(bool in_isr) { + // If there isn't any data in the FIFO, don't do anything. + if (!(usb_out_status_read() & 1)) + return; + + uint8_t out_ep = (usb_out_status_read() >> 2) & 0xf; + uint32_t total_read = 0; + uint32_t current_offset = out_buffer_length[out_ep]; + while (usb_out_status_read() & 1) { + uint8_t c = usb_out_data_read(); + total_read++; + if (out_buffer_length[out_ep] < out_buffer_max[out_ep]) + out_buffer[out_ep][current_offset++] = c; + } + + // Strip off the CRC16 + total_read -= 2; + out_buffer_length[out_ep] += total_read; + if (out_buffer_length[out_ep] > out_buffer_max[out_ep]) + out_buffer_length[out_ep] = out_buffer_max[out_ep]; + + if (out_buffer_max[out_ep] == out_buffer_length[out_ep]) { + out_buffer[out_ep] = NULL; + dcd_event_xfer_complete(0, tu_edpt_addr(out_ep, TUSB_DIR_OUT), out_buffer_length[out_ep], XFER_RESULT_SUCCESS, in_isr); + } + + // Acknowledge having received the data + usb_out_ctrl_write(2); +} + +//--------------------------------------------------------------------+ +// CONTROLLER API +//--------------------------------------------------------------------+ + +// Initializes the USB peripheral for device mode and enables it. +void dcd_init(uint8_t rhport) +{ + (void) rhport; + + usb_pullup_out_write(0); + usb_address_write(0); + usb_out_ctrl_write(0); + + usb_setup_ev_enable_write(0); + usb_in_ev_enable_write(0); + usb_out_ev_enable_write(0); + + // Reset the IN handler + usb_in_ctrl_write(0x20); + + // Reset the SETUP handler + usb_setup_ctrl_write(0x04); + + // Reset the OUT handler + usb_out_ctrl_write(0x04); + + // Enable all event handlers and clear their contents + usb_setup_ev_pending_write(usb_setup_ev_pending_read()); + usb_in_ev_pending_write(usb_in_ev_pending_read()); + usb_out_ev_pending_write(usb_out_ev_pending_read()); + usb_setup_ev_enable_write(3); + usb_in_ev_enable_write(1); + usb_out_ev_enable_write(1); + + // Accept incoming data by default. + usb_out_ctrl_write(2); + + // Turn on the external pullup + usb_pullup_out_write(1); + + dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, false); +} + +// Enables or disables the USB device interrupt(s). May be used to +// prevent concurrency issues when mutating data structures shared +// between main code and the interrupt handler. +void dcd_int_enable(uint8_t rhport) +{ + (void) rhport; + irq_setmask(irq_getmask() | (1 << USB_INTERRUPT)); +} + +void dcd_int_disable(uint8_t rhport) +{ + (void) rhport; + irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT)); +} + +// Called when the device is given a new bus address. +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) +{ + (void)rhport; + // Set address and then acknowledge the SETUP packet + usb_address_write(dev_addr); + + // ACK the transfer (sets the address) + usb_setup_ctrl_write(2); +} + +// Called when the device received SET_CONFIG request, you can leave this +// empty if your peripheral does not require any specific action. +void dcd_set_config(uint8_t rhport, uint8_t config_num) +{ + (void) rhport; + (void) config_num; +} + +// Called to remote wake up host when suspended (e.g hid keyboard) +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + +//--------------------------------------------------------------------+ +// DCD Endpoint Port +//--------------------------------------------------------------------+ +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +{ + (void) rhport; + + if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) + return false; // Not supported + + return true; +} + +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) + usb_out_stall_write((1 << CSR_USB_OUT_STALL_STALL_OFFSET) | tu_edpt_number(ep_addr)); + else { + usb_in_ctrl_write((1 << CSR_USB_IN_CTRL_STALL_OFFSET) | tu_edpt_number(ep_addr)); + } +} + +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) + usb_out_stall_write((0 << CSR_USB_OUT_STALL_STALL_OFFSET) | tu_edpt_number(ep_addr)); + // IN endpoints will get unstalled when more data is written. +} + +__attribute__((used)) +uint8_t *last_tx_buffer; +__attribute__((used)) +uint16_t last_tx_bytes; + +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +{ + (void)rhport; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + // These sorts of transfers are handled in hardware + if ((tu_edpt_number(ep_addr) == 0) && (total_bytes == 0) && (buffer == 0)) { + dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); + return true; + } + uint32_t offset; + // Wait for the tx pipe to free up + while (tx_in_progress) + ; + tx_in_progress = 1; + tx_ep = ep_addr; + tx_len = total_bytes; + + for (offset = 0; offset < total_bytes; offset++) { + usb_in_data_write(buffer[offset]); + } + // Updating the epno queues the data + usb_in_ctrl_write(tu_edpt_number(ep_addr) & 0xf); + last_tx_buffer = buffer; + last_tx_bytes = total_bytes; + } + else if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { + + // Wait for the rx pipe to free up + while (out_buffer[tu_edpt_number(ep_addr)]) + ; + out_buffer_max[tu_edpt_number(ep_addr)] = total_bytes; + out_buffer[tu_edpt_number(ep_addr)] = buffer; + out_buffer_length[tu_edpt_number(ep_addr)] = 0; + process_rx(false); + } + return true; +} + +//--------------------------------------------------------------------+ +// ISR +//--------------------------------------------------------------------+ + +void hal_dcd_isr(uint8_t rhport) +{ + uint8_t setup_pending = usb_setup_ev_pending_read(); + uint8_t in_pending = usb_in_ev_pending_read(); + uint8_t out_pending = usb_out_ev_pending_read(); + usb_setup_ev_pending_write(setup_pending); + usb_in_ev_pending_write(in_pending); + usb_out_ev_pending_write(out_pending); + + // This event means a bus reset occurred. Reset everything, and + // abandon any further processing. + if (setup_pending & 2) { + usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET); + usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET); + usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET); + + dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); + return; + } + + // An "IN" transaction just completed. + // Note that due to the way tinyusb's callback system is implemented, + // we must handle IN and OUT packets before we handle SETUP packets. + // This ensures that any responses to SETUP packets aren't overwritten. + // For example, oftentimes a host will request part of a descriptor + // to begin with, then make a subsequent request. If we don't handle + // the IN packets first, then the second request will be truncated. + if (in_pending) { + finish_tx(); + } + + // An "OUT" transaction just completed so we have new data. + // (But only if we can accept the data) + if (out_pending) { + process_rx(true); + } + + // We got a SETUP packet. Copy it to the setup buffer and clear + // the "pending" bit. + if (setup_pending & 1) { + // Setup packets are always 8 bytes, plus two bytes + // of crc16 + uint8_t setup_packet[10]; + uint32_t setup_length = 0; + + if (!(usb_setup_status_read() & 1)) + fomu_error(__LINE__); + + while (usb_setup_status_read() & 1) { + uint8_t c = usb_setup_data_read(); + if (setup_length < sizeof(setup_packet)) + setup_packet[setup_length] = c; + setup_length++; + } + + // If we have 10 bytes, that's a full SETUP packet plus CRC16. + // Otherwise, it was an RX error. + if (setup_length == 10) { + dcd_event_setup_received(rhport, setup_packet, true); + // Acknowledge the packet, so long as it isn't a SET_ADDRESS + // packet. If it is, leave it unacknowledged and we'll do this + // in the `dcd_set_address` function instead. + if (!((setup_packet[0] == 0x00) && (setup_packet[1] == 0x05))) + usb_setup_ctrl_write(2); + } + else { + fomu_error(__LINE__); + } + } +} + +#endif diff --git a/src/portable/foosn/fomu/dcd_fomu.h b/src/portable/foosn/fomu/dcd_fomu.h new file mode 100644 index 000000000..60bc1240f --- /dev/null +++ b/src/portable/foosn/fomu/dcd_fomu.h @@ -0,0 +1,151 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DCD_FOMU_H_ +#define _TUSB_DCD_FOMU_H_ + +#include "common/tusb_common.h" +#ifdef __cplusplus + extern "C" { +#endif + +// //--------------------------------------------------------------------+ +// // Register Interface +// //--------------------------------------------------------------------+ + +// //------------- USB Interrupt USBIntSt -------------// +// //enum { +// // DCD_USB_REQ_LOW_PRIO_MASK = TU_BIT(0), +// // DCD_USB_REQ_HIGH_PRIO_MASK = TU_BIT(1), +// // DCD_USB_REQ_DMA_MASK = TU_BIT(2), +// // DCD_USB_REQ_NEED_CLOCK_MASK = TU_BIT(8), +// // DCD_USB_REQ_ENABLE_MASK = TU_BIT(31) +// //}; + +// //------------- Device Interrupt USBDevInt -------------// +// enum { +// DEV_INT_FRAME_MASK = TU_BIT(0), +// DEV_INT_ENDPOINT_FAST_MASK = TU_BIT(1), +// DEV_INT_ENDPOINT_SLOW_MASK = TU_BIT(2), +// DEV_INT_DEVICE_STATUS_MASK = TU_BIT(3), +// DEV_INT_COMMAND_CODE_EMPTY_MASK = TU_BIT(4), +// DEV_INT_COMMAND_DATA_FULL_MASK = TU_BIT(5), +// DEV_INT_RX_ENDPOINT_PACKET_MASK = TU_BIT(6), +// DEV_INT_TX_ENDPOINT_PACKET_MASK = TU_BIT(7), +// DEV_INT_ENDPOINT_REALIZED_MASK = TU_BIT(8), +// DEV_INT_ERROR_MASK = TU_BIT(9) +// }; + +// //------------- DMA Interrupt USBDMAInt-------------// +// enum { +// DMA_INT_END_OF_XFER_MASK = TU_BIT(0), +// DMA_INT_NEW_DD_REQUEST_MASK = TU_BIT(1), +// DMA_INT_ERROR_MASK = TU_BIT(2) +// }; + +// //------------- USBCtrl -------------// +// enum { +// USBCTRL_READ_ENABLE_MASK = TU_BIT(0), +// USBCTRL_WRITE_ENABLE_MASK = TU_BIT(1), +// }; + +// //------------- USBRxPLen -------------// +// enum { +// USBRXPLEN_PACKET_LENGTH_MASK = (TU_BIT(10)-1), +// USBRXPLEN_DATA_VALID_MASK = TU_BIT(10), +// USBRXPLEN_PACKET_READY_MASK = TU_BIT(11), +// }; + +// //------------- SIE Command Code -------------// +// typedef enum +// { +// SIE_CMDPHASE_WRITE = 1, +// SIE_CMDPHASE_READ = 2, +// SIE_CMDPHASE_COMMAND = 5 +// } sie_cmdphase_t; + +// enum { +// // device commands +// SIE_CMDCODE_SET_ADDRESS = 0xd0, +// SIE_CMDCODE_CONFIGURE_DEVICE = 0xd8, +// SIE_CMDCODE_SET_MODE = 0xf3, +// SIE_CMDCODE_READ_FRAME_NUMBER = 0xf5, +// SIE_CMDCODE_READ_TEST_REGISTER = 0xfd, +// SIE_CMDCODE_DEVICE_STATUS = 0xfe, +// SIE_CMDCODE_GET_ERROR = 0xff, +// SIE_CMDCODE_READ_ERROR_STATUS = 0xfb, + +// // endpoint commands +// SIE_CMDCODE_ENDPOINT_SELECT = 0x00, // + endpoint index +// SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT = 0x40, // + endpoint index, should use USBEpIntClr instead +// SIE_CMDCODE_ENDPOINT_SET_STATUS = 0x40, // + endpoint index +// SIE_CMDCODE_BUFFER_CLEAR = 0xf2, +// SIE_CMDCODE_BUFFER_VALIDATE = 0xfa +// }; + +// //------------- SIE Device Status (get/set from SIE_CMDCODE_DEVICE_STATUS) -------------// +// enum { +// SIE_DEV_STATUS_CONNECT_STATUS_MASK = TU_BIT(0), +// SIE_DEV_STATUS_CONNECT_CHANGE_MASK = TU_BIT(1), +// SIE_DEV_STATUS_SUSPEND_MASK = TU_BIT(2), +// SIE_DEV_STATUS_SUSPEND_CHANGE_MASK = TU_BIT(3), +// SIE_DEV_STATUS_RESET_MASK = TU_BIT(4) +// }; + +// //------------- SIE Select Endpoint Command -------------// +// enum { +// SIE_SELECT_ENDPOINT_FULL_EMPTY_MASK = TU_BIT(0), // 0: empty, 1 full. IN endpoint checks empty, OUT endpoint check full +// SIE_SELECT_ENDPOINT_STALL_MASK = TU_BIT(1), +// SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK = TU_BIT(2), // clear by SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT +// SIE_SELECT_ENDPOINT_PACKET_OVERWRITTEN_MASK = TU_BIT(3), // previous packet is overwritten by a SETUP packet +// SIE_SELECT_ENDPOINT_NAK_MASK = TU_BIT(4), // last packet response is NAK (auto clear by an ACK) +// SIE_SELECT_ENDPOINT_BUFFER1_FULL_MASK = TU_BIT(5), +// SIE_SELECT_ENDPOINT_BUFFER2_FULL_MASK = TU_BIT(6) +// }; + +// typedef enum +// { +// SIE_SET_ENDPOINT_STALLED_MASK = TU_BIT(0), +// SIE_SET_ENDPOINT_DISABLED_MASK = TU_BIT(5), +// SIE_SET_ENDPOINT_RATE_FEEDBACK_MASK = TU_BIT(6), +// SIE_SET_ENDPOINT_CONDITION_STALLED_MASK = TU_BIT(7), +// }sie_endpoint_set_status_mask_t; + +// //------------- DMA Descriptor Status -------------// +// enum { +// DD_STATUS_NOT_SERVICED = 0, +// DD_STATUS_BEING_SERVICED, +// DD_STATUS_NORMAL, +// DD_STATUS_DATA_UNDERUN, // short packet +// DD_STATUS_DATA_OVERRUN, +// DD_STATUS_SYSTEM_ERROR +// }; + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DCD_FOMU_H_ */ diff --git a/src/portable/foosn/fomu/hal_fomu.c b/src/portable/foosn/fomu/hal_fomu.c new file mode 100644 index 000000000..ebc0a1d93 --- /dev/null +++ b/src/portable/foosn/fomu/hal_fomu.c @@ -0,0 +1,33 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "common/tusb_common.h" + +#if (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) + +// No HAL-specific stuff here! + +#endif From ba889eeb9e99500736a1aec38f38645a335bd5a1 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Sat, 12 Oct 2019 14:51:40 +0800 Subject: [PATCH 03/27] bsp: fomu: fix linker script overlap The end of the data section was overlapping the start of the bss. Signed-off-by: Sean Cross --- hw/bsp/fomu/fomu.ld | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/bsp/fomu/fomu.ld b/hw/bsp/fomu/fomu.ld index f39d62f35..2a3f2376a 100644 --- a/hw/bsp/fomu/fomu.ld +++ b/hw/bsp/fomu/fomu.ld @@ -27,6 +27,7 @@ SECTIONS *(.rodata .rodata.* .gnu.linkonce.r.*) *(.rodata1) *(.srodata) + . = ALIGN(4); _erodata = .; } > rom @@ -38,12 +39,12 @@ SECTIONS *(.data1) _gp = ALIGN(16); *(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*) - _edata = ALIGN(16); /* Make sure _edata is >= _gp. */ + . = ALIGN(16); + _edata = .; /* Make sure _edata is >= _gp. */ } > sram .bss : { - . = ALIGN(4); _fbss = .; *(.dynsbss) *(.sbss .sbss.* .gnu.linkonce.sb.*) From 32bb68409ea904af52f6044dd9448ed62226da25 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Sat, 12 Oct 2019 14:52:15 +0800 Subject: [PATCH 04/27] portable: fomu: get msc to enumerate Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 158 +++++++++++++++++------------ 1 file changed, 94 insertions(+), 64 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index d7f9d3d1e..f49e9e508 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -41,105 +41,130 @@ void mputln(const char *str); // SIE Command //--------------------------------------------------------------------+ -static uint8_t volatile out_buffer_length[16]; -static uint8_t volatile * out_buffer[16]; -static uint8_t volatile out_buffer_max[16]; +#define EP_SIZE 64 + +static uint16_t volatile rx_buffer_length[16]; +static uint8_t volatile * rx_buffer[16]; +static uint16_t volatile rx_buffer_max[16]; static volatile bool tx_in_progress; static volatile uint8_t tx_ep; static volatile uint16_t tx_len; +static uint8_t volatile * tx_buffer; +static volatile uint16_t tx_offset; //--------------------------------------------------------------------+ // PIPE HELPER //--------------------------------------------------------------------+ static void finish_tx(void) { - // // Don't allow requeueing -- only queue more data if the system is idle. - // if (!(usb_in_status_read() & 2)) { - // return; - // } - - // Don't send empty data - if (!tx_in_progress) { - return; - } + // Don't send empty data + if (!tx_in_progress) { + return; + } + tx_offset += EP_SIZE; + if (tx_offset >= tx_len) { tx_in_progress = 0; + tx_buffer = NULL; dcd_event_xfer_complete(0, tx_ep, tx_len, XFER_RESULT_SUCCESS, true); return; + } + + // Send more data + uint8_t added_bytes; + for (added_bytes = 0; (added_bytes < EP_SIZE) && (added_bytes + tx_offset < tx_len); added_bytes++) { + usb_in_data_write(tx_buffer[added_bytes + tx_offset]); + } + + // Updating the epno queues the data + usb_in_ctrl_write(tu_edpt_number(tx_ep) & 0xf); + return; } static void process_rx(bool in_isr) { // If there isn't any data in the FIFO, don't do anything. - if (!(usb_out_status_read() & 1)) - return; + if (!(usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET))) + return; + + uint8_t out_ep = (usb_out_status_read() >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf; + + // If the destination buffer doesn't exist, don't drain the hardware + // fifo. Note that this can cause deadlocks if the host is waiting + // on some other endpoint's data! + if (rx_buffer[out_ep] == NULL) + return; - uint8_t out_ep = (usb_out_status_read() >> 2) & 0xf; uint32_t total_read = 0; - uint32_t current_offset = out_buffer_length[out_ep]; - while (usb_out_status_read() & 1) { + uint32_t current_offset = rx_buffer_length[out_ep]; + while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) { uint8_t c = usb_out_data_read(); total_read++; - if (out_buffer_length[out_ep] < out_buffer_max[out_ep]) - out_buffer[out_ep][current_offset++] = c; + if (rx_buffer_length[out_ep] < rx_buffer_max[out_ep]) + rx_buffer[out_ep][current_offset++] = c; } // Strip off the CRC16 - total_read -= 2; - out_buffer_length[out_ep] += total_read; - if (out_buffer_length[out_ep] > out_buffer_max[out_ep]) - out_buffer_length[out_ep] = out_buffer_max[out_ep]; + rx_buffer_length[out_ep] += (total_read - 2); + if (rx_buffer_length[out_ep] > rx_buffer_max[out_ep]) + rx_buffer_length[out_ep] = rx_buffer_max[out_ep]; - if (out_buffer_max[out_ep] == out_buffer_length[out_ep]) { - out_buffer[out_ep] = NULL; - dcd_event_xfer_complete(0, tu_edpt_addr(out_ep, TUSB_DIR_OUT), out_buffer_length[out_ep], XFER_RESULT_SUCCESS, in_isr); + if (rx_buffer_max[out_ep] == rx_buffer_length[out_ep]) { + rx_buffer[out_ep] = NULL; + uint16_t len = rx_buffer_length[out_ep]; + dcd_event_xfer_complete(0, tu_edpt_addr(out_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr); } - // Acknowledge having received the data - usb_out_ctrl_write(2); + // Acknowledge having received the data, and re-enable data reception + usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET); } //--------------------------------------------------------------------+ // CONTROLLER API //--------------------------------------------------------------------+ +static void dcd_reset(void) +{ + usb_address_write(0); + + // Reset all three FIFO handlers + usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET); + usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET); + usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET); + + // Accept incoming data by default. + usb_out_ctrl_write(CSR_USB_OUT_CTRL_ENABLE_OFFSET); + + memset(rx_buffer, 0, sizeof(rx_buffer)); + tx_in_progress = 0; + tx_len = 0; + tx_buffer = NULL; + tx_offset = 0; + + dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); +} + // Initializes the USB peripheral for device mode and enables it. void dcd_init(uint8_t rhport) { (void) rhport; usb_pullup_out_write(0); - usb_address_write(0); - usb_out_ctrl_write(0); usb_setup_ev_enable_write(0); usb_in_ev_enable_write(0); usb_out_ev_enable_write(0); - // Reset the IN handler - usb_in_ctrl_write(0x20); - - // Reset the SETUP handler - usb_setup_ctrl_write(0x04); - - // Reset the OUT handler - usb_out_ctrl_write(0x04); - // Enable all event handlers and clear their contents usb_setup_ev_pending_write(usb_setup_ev_pending_read()); usb_in_ev_pending_write(usb_in_ev_pending_read()); usb_out_ev_pending_write(usb_out_ev_pending_read()); - usb_setup_ev_enable_write(3); usb_in_ev_enable_write(1); usb_out_ev_enable_write(1); - - // Accept incoming data by default. - usb_out_ctrl_write(2); + usb_setup_ev_enable_write(3); // Turn on the external pullup usb_pullup_out_write(1); - - dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, false); } // Enables or disables the USB device interrupt(s). May be used to @@ -222,36 +247,45 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t { (void)rhport; + // These sorts of transfers are handled in hardware + if ((tu_edpt_number(ep_addr) == 0) && (total_bytes == 0) && (buffer == NULL)) { + dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); + + // An IN packet is sent to acknowledge an OUT token. Re-enable OUT after this. + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) + usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET); + return true; + } + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { - // These sorts of transfers are handled in hardware - if ((tu_edpt_number(ep_addr) == 0) && (total_bytes == 0) && (buffer == 0)) { - dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); - return true; - } uint32_t offset; + // Wait for the tx pipe to free up while (tx_in_progress) ; tx_in_progress = 1; tx_ep = ep_addr; tx_len = total_bytes; + tx_buffer = buffer; + tx_offset = 0; - for (offset = 0; offset < total_bytes; offset++) { + for (offset = 0; (offset < EP_SIZE) && (offset < total_bytes); offset++) { usb_in_data_write(buffer[offset]); } // Updating the epno queues the data usb_in_ctrl_write(tu_edpt_number(ep_addr) & 0xf); - last_tx_buffer = buffer; - last_tx_bytes = total_bytes; } else if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { + TU_ASSERT(rx_buffer[tu_edpt_number(ep_addr)] == NULL); - // Wait for the rx pipe to free up - while (out_buffer[tu_edpt_number(ep_addr)]) - ; - out_buffer_max[tu_edpt_number(ep_addr)] = total_bytes; - out_buffer[tu_edpt_number(ep_addr)] = buffer; - out_buffer_length[tu_edpt_number(ep_addr)] = 0; + rx_buffer_length[tu_edpt_number(ep_addr)] = 0; + rx_buffer_max[tu_edpt_number(ep_addr)] = total_bytes; + rx_buffer[tu_edpt_number(ep_addr)] = buffer; + + // If there's data in the buffer already, we'll try draining it + // into the current fifo immediately. Note that since this + // bit is set, an interrupt won't fire again, so there is + // no need for a lock here. process_rx(false); } return true; @@ -273,11 +307,7 @@ void hal_dcd_isr(uint8_t rhport) // This event means a bus reset occurred. Reset everything, and // abandon any further processing. if (setup_pending & 2) { - usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET); - usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET); - usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET); - - dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); + dcd_reset(); return; } From 470d827f13e22dea083266b96c7bd724a08b0b65 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 14 Oct 2019 11:08:27 +0800 Subject: [PATCH 05/27] docs: porting: remove invalid information and fix typo It is no longer the case that boards need to be added to this file. Signed-off-by: Sean Cross --- docs/porting.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/porting.md b/docs/porting.md index a38ff0192..7ed21d75a 100644 --- a/docs/porting.md +++ b/docs/porting.md @@ -25,8 +25,6 @@ Unless, you've read ahead, this will fail miserably. Now, lets get it to fail le One of the first things to change is the `-DCFG_TUSB_MCU` cflag in the `board.mk` file. This is used to tell TinyUSB what platform is being built. So, add an entry to `src/tusb_option.h` and update the CFLAG to match. -Also, add an entry for the board in `hw/bsp/board.h`. The CFLAG is auto-added. - Update `board.mk`'s VENDOR and CHIP_FAMILY values when creating the directory for the struct files. Duplicate one of the other sources from `src/portable` into `src/portable//` and delete all of the implementation internals. We'll cover what everything there does later. For now, get it compiling. ## Implementation @@ -104,7 +102,7 @@ Calls to this look like: dcd_event_setup_received(0, setup, true); -As before with `dcd_event_bus_signal` the first argument is the USB peripheral number and the third is true to signal its being called from an interrup handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue. +As before with `dcd_event_bus_signal` the first argument is the USB peripheral number and the third is true to signal its being called from an interrupt handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue. #### Endpoints From ef07427e06b1fa868ac7b96b18e77270f2231aed Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 14 Oct 2019 11:30:05 +0800 Subject: [PATCH 06/27] bsp: fomu: update Signed-off-by: Sean Cross --- hw/bsp/fomu/bsp.c | 8 ++- hw/bsp/fomu/crt0-vexriscv.S | 14 ++-- hw/bsp/fomu/fomu.ld | 130 ++++++++++++++++++++++++------------ 3 files changed, 98 insertions(+), 54 deletions(-) diff --git a/hw/bsp/fomu/bsp.c b/hw/bsp/fomu/bsp.c index 861c223f2..2bba0ce2c 100644 --- a/hw/bsp/fomu/bsp.c +++ b/hw/bsp/fomu/bsp.c @@ -116,9 +116,11 @@ int board_uart_read(uint8_t* buf, int len) int board_uart_write(void const * buf, int len) { - (void) buf; - (void) len; - return 0; + int32_t offset = 0; + for (offset = 0; offset < len; offset++) + if (! (messible_status_read() & CSR_MESSIBLE_STATUS_FULL_OFFSET)) + messible_in_write(((uint8_t *)buf)[offset]); + return len; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/fomu/crt0-vexriscv.S b/hw/bsp/fomu/crt0-vexriscv.S index 931d50a04..46dca5577 100644 --- a/hw/bsp/fomu/crt0-vexriscv.S +++ b/hw/bsp/fomu/crt0-vexriscv.S @@ -57,13 +57,13 @@ trap_entry: crt_init: - la sp, _fstack + 4 + la sp, _estack - 4 la a0, trap_entry csrw mtvec, a0 bss_init: - la a0, _fbss - la a1, _ebss + la a0, _sbss + la a1, _ebss + 4 bss_loop: beq a0,a1,bss_done sw zero,0(a0) @@ -72,13 +72,13 @@ bss_loop: bss_done: /* Load DATA */ - la t0, _erodata - la t1, _fdata - la t2, _edata + la t0, _etext + la t1, _srelocate + la t2, _erelocate + 4 3: lw t3, 0(t0) sw t3, 0(t1) - /* _edata is aligned to 16 bytes. Use word-xfers. */ + /* _edata is aligned to 4 bytes. Use word-xfers. */ addi t0, t0, 4 addi t1, t1, 4 bltu t1, t2, 3b diff --git a/hw/bsp/fomu/fomu.ld b/hw/bsp/fomu/fomu.ld index 2a3f2376a..abc91b8ea 100644 --- a/hw/bsp/fomu/fomu.ld +++ b/hw/bsp/fomu/fomu.ld @@ -6,57 +6,99 @@ __DYNAMIC = 0; MEMORY { csr : ORIGIN = 0x60000000, LENGTH = 0x01000000 vexriscv_debug : ORIGIN = 0xf00f0000, LENGTH = 0x00000100 - sram : ORIGIN = 0x10000000, LENGTH = 0x00020000 + ram : ORIGIN = 0x10000000, LENGTH = 0x00020000 rom : ORIGIN = 0x2001a000, LENGTH = 0x00200000 - 0x1a000 } +/* The stack size used by the application. NOTE: you need to adjust according to your application. */ +STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x2000; + +/* Section Definitions */ SECTIONS { - .text : - { - _ftext = .; + .text : + { + . = ALIGN(4); + _ftext = .; *(.text.start) - *(.text .stub .text.* .gnu.linkonce.t.*) - _etext = .; - } > rom + *(.text .text.* .gnu.linkonce.t.*) + *(.glue_7t) *(.glue_7) + *(.rodata .rodata* .gnu.linkonce.r.*) - .rodata : - { - . = ALIGN(4); - _frodata = .; - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - *(.srodata) - . = ALIGN(4); - _erodata = .; - } > rom + /* Support C constructors, and C destructors in both user code + and the C library. This also provides support for C++ code. */ + . = ALIGN(4); + KEEP(*(.init)) + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; - .data : AT (ADDR(.rodata) + SIZEOF (.rodata)) - { - . = ALIGN(4); - _fdata = .; - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - _gp = ALIGN(16); - *(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*) - . = ALIGN(16); - _edata = .; /* Make sure _edata is >= _gp. */ - } > sram + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; - .bss : - { - _fbss = .; - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - . = ALIGN(4); - _ebss = .; - _end = .; - PROVIDE(end = .); - } > sram -} + . = ALIGN(4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) -PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4); + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + } > rom + + . = ALIGN(4); + _etext = .; /* End of text section */ + + .relocate : AT (_etext) + { + . = ALIGN(4); + _srelocate = .; + *(.ramfunc .ramfunc.*); + *(.data .data.*); + . = ALIGN(4); + _erelocate = .; + } > ram + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + _sbss = . ; + _szero = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + *(COMMON) + . = ALIGN(4); + _ebss = . ; + _ezero = .; + end = .; + } > ram + + /* stack section */ + .stack (NOLOAD): + { + . = ALIGN(8); + _sstack = .; + . = . + STACK_SIZE; + . = ALIGN(8); + _estack = .; + } > ram + + . = ALIGN(4); + _end = . ; +} \ No newline at end of file From 359189ea2d791ab895dc29cbfa4e3eba14caf65f Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 14 Oct 2019 11:58:17 +0800 Subject: [PATCH 07/27] tusb_verify: add riscv assert support This simply executes an "ebreak" instruction. Signed-off-by: Sean Cross --- src/common/tusb_verify.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h index e59481352..2b63ab946 100644 --- a/src/common/tusb_verify.h +++ b/src/common/tusb_verify.h @@ -89,9 +89,13 @@ volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \ if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \ } while(0) +#else +#if defined(__riscv) + #define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0) #else #define TU_BREAKPOINT() #endif +#endif /*------------------------------------------------------------------*/ /* Macro Generator From 0559fd13fb43aa991200c3bddc146c5828fc48b0 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 14 Oct 2019 11:59:17 +0800 Subject: [PATCH 08/27] fomu: fix some issues with dcd_fomu Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 179 ++++++++++++++++++----------- 1 file changed, 109 insertions(+), 70 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index f49e9e508..73cf018eb 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -43,31 +43,34 @@ void mputln(const char *str); #define EP_SIZE 64 -static uint16_t volatile rx_buffer_length[16]; -static uint8_t volatile * rx_buffer[16]; -static uint16_t volatile rx_buffer_max[16]; +uint16_t volatile rx_buffer_offset[16]; +uint8_t volatile * rx_buffer[16]; +uint16_t volatile rx_buffer_max[16]; -static volatile bool tx_in_progress; -static volatile uint8_t tx_ep; -static volatile uint16_t tx_len; -static uint8_t volatile * tx_buffer; -static volatile uint16_t tx_offset; +volatile uint8_t tx_ep; +volatile uint16_t tx_len; +uint8_t volatile * tx_buffer; +volatile uint16_t tx_offset; +volatile uint8_t reset_count; //--------------------------------------------------------------------+ // PIPE HELPER //--------------------------------------------------------------------+ static void finish_tx(void) { - // Don't send empty data - if (!tx_in_progress) { + // Ignore "ACK" packets where there was no data to send. + if (!tx_buffer) { return; } + uint8_t in_status = usb_in_status_read(); + if (!(in_status & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) + fomu_error(__LINE__); + tx_offset += EP_SIZE; if (tx_offset >= tx_len) { - tx_in_progress = 0; + dcd_event_xfer_complete(0, tu_edpt_addr(tx_ep, TUSB_DIR_IN), tx_len, XFER_RESULT_SUCCESS, true); tx_buffer = NULL; - dcd_event_xfer_complete(0, tx_ep, tx_len, XFER_RESULT_SUCCESS, true); return; } @@ -78,41 +81,49 @@ static void finish_tx(void) { } // Updating the epno queues the data - usb_in_ctrl_write(tu_edpt_number(tx_ep) & 0xf); + usb_in_ctrl_write(tx_ep & 0xf); return; } static void process_rx(bool in_isr) { - // If there isn't any data in the FIFO, don't do anything. - if (!(usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET))) + // If the OUT handler is still waiting to send, don't do anything. + uint8_t out_status = usb_out_status_read(); + if (!(out_status & (1 << CSR_USB_OUT_STATUS_IDLE_OFFSET))) return; - uint8_t out_ep = (usb_out_status_read() >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf; + uint8_t rx_ep = (out_status >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf; + if ((rx_ep != 0) && (rx_ep != 2) && (rx_ep != 3)) + fomu_error(__LINE__); // If the destination buffer doesn't exist, don't drain the hardware // fifo. Note that this can cause deadlocks if the host is waiting // on some other endpoint's data! - if (rx_buffer[out_ep] == NULL) + if (rx_buffer[rx_ep] == NULL) return; uint32_t total_read = 0; - uint32_t current_offset = rx_buffer_length[out_ep]; + uint32_t current_offset = rx_buffer_offset[rx_ep]; + if (current_offset > rx_buffer_max[rx_ep]) + fomu_error(__LINE__); while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) { uint8_t c = usb_out_data_read(); total_read++; - if (rx_buffer_length[out_ep] < rx_buffer_max[out_ep]) - rx_buffer[out_ep][current_offset++] = c; + if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) + rx_buffer[rx_ep][current_offset++] = c; } // Strip off the CRC16 - rx_buffer_length[out_ep] += (total_read - 2); - if (rx_buffer_length[out_ep] > rx_buffer_max[out_ep]) - rx_buffer_length[out_ep] = rx_buffer_max[out_ep]; + rx_buffer_offset[rx_ep] += (total_read - 2); + if (rx_buffer_offset[rx_ep] > rx_buffer_max[rx_ep]) + rx_buffer_offset[rx_ep] = rx_buffer_max[rx_ep]; - if (rx_buffer_max[out_ep] == rx_buffer_length[out_ep]) { - rx_buffer[out_ep] = NULL; - uint16_t len = rx_buffer_length[out_ep]; - dcd_event_xfer_complete(0, tu_edpt_addr(out_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr); + if ((rx_ep == 3) && (rx_buffer[rx_ep][0] == 0x80) && (rx_buffer[rx_ep][1] == 0x25)) + fomu_error(__LINE__); + + if (rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep]) { + rx_buffer[rx_ep] = NULL; + uint16_t len = rx_buffer_offset[rx_ep]; + dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr); } // Acknowledge having received the data, and re-enable data reception @@ -125,6 +136,11 @@ static void process_rx(bool in_isr) { static void dcd_reset(void) { + reset_count++; + usb_setup_ev_enable_write(0); + usb_in_ev_enable_write(0); + usb_out_ev_enable_write(0); + usb_address_write(0); // Reset all three FIFO handlers @@ -132,14 +148,24 @@ static void dcd_reset(void) usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET); usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET); - // Accept incoming data by default. - usb_out_ctrl_write(CSR_USB_OUT_CTRL_ENABLE_OFFSET); - - memset(rx_buffer, 0, sizeof(rx_buffer)); - tx_in_progress = 0; + memset((void *)rx_buffer, 0, sizeof(rx_buffer)); + memset((void *)rx_buffer_max, 0, sizeof(rx_buffer_max)); + memset((void *)rx_buffer_offset, 0, sizeof(rx_buffer_offset)); tx_len = 0; tx_buffer = NULL; tx_offset = 0; + tx_ep = 0; + + // Accept incoming data by default. + usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET); + + // Enable all event handlers and clear their contents + usb_setup_ev_pending_write(usb_setup_ev_pending_read()); + usb_in_ev_pending_write(usb_in_ev_pending_read()); + usb_out_ev_pending_write(usb_out_ev_pending_read()); + usb_in_ev_enable_write(1); + usb_out_ev_enable_write(1); + usb_setup_ev_enable_write(3); dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); } @@ -151,10 +177,6 @@ void dcd_init(uint8_t rhport) usb_pullup_out_write(0); - usb_setup_ev_enable_write(0); - usb_in_ev_enable_write(0); - usb_out_ev_enable_write(0); - // Enable all event handlers and clear their contents usb_setup_ev_pending_write(usb_setup_ev_pending_read()); usb_in_ev_pending_write(usb_in_ev_pending_read()); @@ -190,7 +212,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) usb_address_write(dev_addr); // ACK the transfer (sets the address) - usb_setup_ctrl_write(2); + usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_HANDLED_OFFSET); } // Called when the device received SET_CONFIG request, you can leave this @@ -213,10 +235,18 @@ void dcd_remote_wakeup(uint8_t rhport) bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { (void) rhport; + uint8_t ep_num = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t ep_dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) return false; // Not supported + if (ep_dir == TUSB_DIR_OUT) { + rx_buffer_offset[ep_num] = 0; + rx_buffer_max[ep_num] = 0; + rx_buffer[ep_num] = NULL; + } + return true; } @@ -238,55 +268,64 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) // IN endpoints will get unstalled when more data is written. } -__attribute__((used)) -uint8_t *last_tx_buffer; -__attribute__((used)) -uint16_t last_tx_bytes; - bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { (void)rhport; + uint8_t ep_num = tu_edpt_number(ep_addr); + uint8_t ep_dir = tu_edpt_dir(ep_addr); - // These sorts of transfers are handled in hardware - if ((tu_edpt_number(ep_addr) == 0) && (total_bytes == 0) && (buffer == NULL)) { + // These sorts of transfers are handled in hardware automatically, so simply inform + // the core that the transfer was processed. + if ((ep_num == 0) && (total_bytes == 0) && (buffer == NULL)) { dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); // An IN packet is sent to acknowledge an OUT token. Re-enable OUT after this. - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) - usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET); + // if (ep_dir == TUSB_DIR_IN) { + // usb_out_ev_enable_write(0); + // process_rx(false); + // usb_out_ev_enable_write(1); + // } return true; } - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + TU_ASSERT(((uint32_t)buffer) >= 0x10000000); + TU_ASSERT(((uint32_t)buffer) <= 0x10020000); + + if (ep_dir == TUSB_DIR_IN) { uint32_t offset; // Wait for the tx pipe to free up - while (tx_in_progress) + uint8_t previous_reset_count = reset_count; + while ((tx_buffer != NULL) || !(usb_in_status_read() & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) ; - tx_in_progress = 1; - tx_ep = ep_addr; + // If a reset happens while we're waiting, abort the transfer + if (previous_reset_count != reset_count) + return true; + + tx_ep = ep_num; tx_len = total_bytes; - tx_buffer = buffer; tx_offset = 0; + tx_buffer = buffer; for (offset = 0; (offset < EP_SIZE) && (offset < total_bytes); offset++) { - usb_in_data_write(buffer[offset]); + usb_in_data_write(buffer[offset]); } // Updating the epno queues the data - usb_in_ctrl_write(tu_edpt_number(ep_addr) & 0xf); + usb_in_ctrl_write(ep_num & 0xf); } - else if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { - TU_ASSERT(rx_buffer[tu_edpt_number(ep_addr)] == NULL); + else if (ep_dir == TUSB_DIR_OUT) { + TU_ASSERT(rx_buffer[ep_num] == NULL); + TU_ASSERT((ep_num == 0) || (ep_num == 2) || (ep_num == 3)); - rx_buffer_length[tu_edpt_number(ep_addr)] = 0; - rx_buffer_max[tu_edpt_number(ep_addr)] = total_bytes; - rx_buffer[tu_edpt_number(ep_addr)] = buffer; + rx_buffer_offset[ep_num] = 0; + rx_buffer_max[ep_num] = total_bytes; + rx_buffer[ep_num] = buffer; // If there's data in the buffer already, we'll try draining it - // into the current fifo immediately. Note that since this - // bit is set, an interrupt won't fire again, so there is - // no need for a lock here. + // into the current fifo immediately. + usb_out_ev_enable_write(0); process_rx(false); + usb_out_ev_enable_write(1); } return true; } @@ -311,6 +350,13 @@ void hal_dcd_isr(uint8_t rhport) return; } + // An "OUT" transaction just completed so we have new data. + // (But only if we can accept the data) + // if (out_pending) { + if (usb_out_ev_enable_read() && out_pending) { + process_rx(true); + } + // An "IN" transaction just completed. // Note that due to the way tinyusb's callback system is implemented, // we must handle IN and OUT packets before we handle SETUP packets. @@ -322,17 +368,10 @@ void hal_dcd_isr(uint8_t rhport) finish_tx(); } - // An "OUT" transaction just completed so we have new data. - // (But only if we can accept the data) - if (out_pending) { - process_rx(true); - } - // We got a SETUP packet. Copy it to the setup buffer and clear // the "pending" bit. if (setup_pending & 1) { - // Setup packets are always 8 bytes, plus two bytes - // of crc16 + // Setup packets are always 8 bytes, plus two bytes of crc16. uint8_t setup_packet[10]; uint32_t setup_length = 0; @@ -354,7 +393,7 @@ void hal_dcd_isr(uint8_t rhport) // packet. If it is, leave it unacknowledged and we'll do this // in the `dcd_set_address` function instead. if (!((setup_packet[0] == 0x00) && (setup_packet[1] == 0x05))) - usb_setup_ctrl_write(2); + usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_HANDLED_OFFSET); } else { fomu_error(__LINE__); From 4a8475b8a7a2417b7b6dd27e071774d926130087 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 14 Oct 2019 11:59:40 +0800 Subject: [PATCH 09/27] src: add eptri to tusb Signed-off-by: Sean Cross --- src/tusb_option.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tusb_option.h b/src/tusb_option.h index fc509ae76..d2a9ad804 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -70,6 +70,8 @@ #define OPT_MCU_CXD56 400 ///< SONY CXD56 +#define OPT_MCU_FOMU_EPTRI 600 ///< Fomu eptri config + /** @} */ /** \defgroup group_supported_os Supported RTOS From 22fd7bf85ecc4f1e58f8e6827431d0ae0b5700d1 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 14 Oct 2019 23:02:05 +0800 Subject: [PATCH 10/27] fomu: first fully-working release This is able to transfer lots of data back and forth across MSC. Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index 73cf018eb..96ac3a9fc 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -63,6 +63,7 @@ static void finish_tx(void) { return; } + // If the system isn't idle, then something is very wrong. uint8_t in_status = usb_in_status_read(); if (!(in_status & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) fomu_error(__LINE__); @@ -92,8 +93,6 @@ static void process_rx(bool in_isr) { return; uint8_t rx_ep = (out_status >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf; - if ((rx_ep != 0) && (rx_ep != 2) && (rx_ep != 3)) - fomu_error(__LINE__); // If the destination buffer doesn't exist, don't drain the hardware // fifo. Note that this can cause deadlocks if the host is waiting @@ -117,9 +116,6 @@ static void process_rx(bool in_isr) { if (rx_buffer_offset[rx_ep] > rx_buffer_max[rx_ep]) rx_buffer_offset[rx_ep] = rx_buffer_max[rx_ep]; - if ((rx_ep == 3) && (rx_buffer[rx_ep][0] == 0x80) && (rx_buffer[rx_ep][1] == 0x25)) - fomu_error(__LINE__); - if (rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep]) { rx_buffer[rx_ep] = NULL; uint16_t len = rx_buffer_offset[rx_ep]; @@ -273,6 +269,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t (void)rhport; uint8_t ep_num = tu_edpt_number(ep_addr); uint8_t ep_dir = tu_edpt_dir(ep_addr); + TU_ASSERT(tx_ep < 16); // These sorts of transfers are handled in hardware automatically, so simply inform // the core that the transfer was processed. @@ -296,7 +293,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t // Wait for the tx pipe to free up uint8_t previous_reset_count = reset_count; - while ((tx_buffer != NULL) || !(usb_in_status_read() & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) + while (!((tx_buffer == NULL) + && (usb_in_status_read() & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET)) + && !(usb_in_status_read() & (1 << CSR_USB_IN_STATUS_HAVE_OFFSET)))) ; // If a reset happens while we're waiting, abort the transfer if (previous_reset_count != reset_count) @@ -315,7 +314,6 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t } else if (ep_dir == TUSB_DIR_OUT) { TU_ASSERT(rx_buffer[ep_num] == NULL); - TU_ASSERT((ep_num == 0) || (ep_num == 2) || (ep_num == 3)); rx_buffer_offset[ep_num] = 0; rx_buffer_max[ep_num] = total_bytes; @@ -324,7 +322,8 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t // If there's data in the buffer already, we'll try draining it // into the current fifo immediately. usb_out_ev_enable_write(0); - process_rx(false); + if (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) + process_rx(false); usb_out_ev_enable_write(1); } return true; From 843136d0e4467e1c554f246d1b69fed3172b6cc0 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 29 Oct 2019 21:35:03 +0800 Subject: [PATCH 11/27] fomu: commit latest version Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 298 ++++++++++++++++++----------- 1 file changed, 181 insertions(+), 117 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index 96ac3a9fc..8b2212c16 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -48,19 +48,49 @@ uint8_t volatile * rx_buffer[16]; uint16_t volatile rx_buffer_max[16]; volatile uint8_t tx_ep; -volatile uint16_t tx_len; -uint8_t volatile * tx_buffer; -volatile uint16_t tx_offset; +volatile uint16_t tx_buffer_offset[16]; +uint8_t volatile * tx_buffer[16]; +volatile uint16_t tx_buffer_max[16]; volatile uint8_t reset_count; +__attribute__((used)) uint8_t volatile * last_tx_buffer; +__attribute__((used)) volatile uint8_t last_tx_ep; + +uint8_t setup_packet_bfr[10]; + //--------------------------------------------------------------------+ // PIPE HELPER //--------------------------------------------------------------------+ -static void finish_tx(void) { - // Ignore "ACK" packets where there was no data to send. - if (!tx_buffer) { - return; +static bool advance_tx_ep(void) { + // Move on to the next transmit buffer in a round-robin manner + uint8_t prev_tx_ep = tx_ep; + for (tx_ep = (tx_ep + 1) & 0xf; tx_ep != prev_tx_ep; tx_ep = ((tx_ep + 1) & 0xf)) { + if (tx_buffer[tx_ep]) + return true; + } + if (!tx_buffer[tx_ep]) + return false; + return true; +} + +static void tx_more_data(void) { + // Send more data + uint8_t added_bytes; + for (added_bytes = 0; (added_bytes < EP_SIZE) && (added_bytes + tx_buffer_offset[tx_ep] < tx_buffer_max[tx_ep]); added_bytes++) { + usb_in_data_write(tx_buffer[tx_ep][added_bytes + tx_buffer_offset[tx_ep]]); + } + + // Updating the epno queues the data + usb_in_ctrl_write(tx_ep & 0xf); +} + +static void process_tx(bool in_isr) { + // If the buffer is now empty, search for the next buffer to fill. + if (!tx_buffer[tx_ep]) { + if (advance_tx_ep()) + tx_more_data(); + return; } // If the system isn't idle, then something is very wrong. @@ -68,62 +98,78 @@ static void finish_tx(void) { if (!(in_status & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) fomu_error(__LINE__); - tx_offset += EP_SIZE; - if (tx_offset >= tx_len) { - dcd_event_xfer_complete(0, tu_edpt_addr(tx_ep, TUSB_DIR_IN), tx_len, XFER_RESULT_SUCCESS, true); - tx_buffer = NULL; - return; + tx_buffer_offset[tx_ep] += EP_SIZE; + + if (tx_buffer_offset[tx_ep] >= tx_buffer_max[tx_ep]) { + last_tx_buffer = tx_buffer[tx_ep]; + last_tx_ep = tx_ep; + tx_buffer[tx_ep] = NULL; + + dcd_event_xfer_complete(0, tu_edpt_addr(tx_ep, TUSB_DIR_IN), tx_buffer_max[tx_ep], XFER_RESULT_SUCCESS, in_isr); + if (!advance_tx_ep()) + return; } - // Send more data - uint8_t added_bytes; - for (added_bytes = 0; (added_bytes < EP_SIZE) && (added_bytes + tx_offset < tx_len); added_bytes++) { - usb_in_data_write(tx_buffer[added_bytes + tx_offset]); - } - - // Updating the epno queues the data - usb_in_ctrl_write(tx_ep & 0xf); + tx_more_data(); return; } static void process_rx(bool in_isr) { - // If the OUT handler is still waiting to send, don't do anything. - uint8_t out_status = usb_out_status_read(); - if (!(out_status & (1 << CSR_USB_OUT_STATUS_IDLE_OFFSET))) - return; + // If the OUT handler is still waiting to send, don't do anything. + uint8_t out_status = usb_out_status_read(); + if (!(out_status & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET))) + fomu_error(__LINE__); + // return; - uint8_t rx_ep = (out_status >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf; + uint8_t rx_ep = (out_status >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf; - // If the destination buffer doesn't exist, don't drain the hardware - // fifo. Note that this can cause deadlocks if the host is waiting - // on some other endpoint's data! + // If the destination buffer doesn't exist, don't drain the hardware + // fifo. Note that this can cause deadlocks if the host is waiting + // on some other endpoint's data! + if (rx_buffer[rx_ep] == NULL) { + fomu_error(__LINE__); + return; + } + + uint32_t total_read = 0; + uint32_t current_offset = rx_buffer_offset[rx_ep]; + if (current_offset > rx_buffer_max[rx_ep]) + fomu_error(__LINE__); + while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) { + uint8_t c = usb_out_data_read(); + total_read++; + if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) + rx_buffer[rx_ep][current_offset++] = c; + } + if (total_read > 66) + fomu_error(__LINE__); + + // Strip off the CRC16 + rx_buffer_offset[rx_ep] += (total_read - 2); + if (rx_buffer_offset[rx_ep] > rx_buffer_max[rx_ep]) + rx_buffer_offset[rx_ep] = rx_buffer_max[rx_ep]; + + if (rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep]) { if (rx_buffer[rx_ep] == NULL) - return; - - uint32_t total_read = 0; - uint32_t current_offset = rx_buffer_offset[rx_ep]; - if (current_offset > rx_buffer_max[rx_ep]) fomu_error(__LINE__); - while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) { - uint8_t c = usb_out_data_read(); - total_read++; - if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) - rx_buffer[rx_ep][current_offset++] = c; - } - // Strip off the CRC16 - rx_buffer_offset[rx_ep] += (total_read - 2); - if (rx_buffer_offset[rx_ep] > rx_buffer_max[rx_ep]) - rx_buffer_offset[rx_ep] = rx_buffer_max[rx_ep]; + // Disable this endpoint (causing it to respond NAK) until we have + // a buffer to place the data into. + rx_buffer[rx_ep] = NULL; + uint16_t len = rx_buffer_offset[rx_ep]; - if (rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep]) { - rx_buffer[rx_ep] = NULL; - uint16_t len = rx_buffer_offset[rx_ep]; - dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr); - } + // uint16_t ep_en_mask = usb_out_enable_status_read(); + // int i; + // for (i = 0; i < 16; i++) { + // if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) + // fomu_error(__LINE__); + // } + dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr); + return; + } - // Acknowledge having received the data, and re-enable data reception - usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET); + // If there's more data, re-enable data reception + usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | rx_ep); } //--------------------------------------------------------------------+ @@ -147,18 +193,16 @@ static void dcd_reset(void) memset((void *)rx_buffer, 0, sizeof(rx_buffer)); memset((void *)rx_buffer_max, 0, sizeof(rx_buffer_max)); memset((void *)rx_buffer_offset, 0, sizeof(rx_buffer_offset)); - tx_len = 0; - tx_buffer = NULL; - tx_offset = 0; + + memset((void *)tx_buffer, 0, sizeof(tx_buffer)); + memset((void *)tx_buffer_max, 0, sizeof(tx_buffer_max)); + memset((void *)tx_buffer_offset, 0, sizeof(tx_buffer_offset)); tx_ep = 0; - // Accept incoming data by default. - usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET); - // Enable all event handlers and clear their contents - usb_setup_ev_pending_write(usb_setup_ev_pending_read()); - usb_in_ev_pending_write(usb_in_ev_pending_read()); - usb_out_ev_pending_write(usb_out_ev_pending_read()); + usb_setup_ev_pending_write(-1); + usb_in_ev_pending_write(-1); + usb_out_ev_pending_write(-1); usb_in_ev_enable_write(1); usb_out_ev_enable_write(1); usb_setup_ev_enable_write(3); @@ -203,12 +247,15 @@ void dcd_int_disable(uint8_t rhport) // Called when the device is given a new bus address. void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void)rhport; - // Set address and then acknowledge the SETUP packet - usb_address_write(dev_addr); + // Respond with ACK status first before changing device address + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); - // ACK the transfer (sets the address) - usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_HANDLED_OFFSET); + // Wait for the response packet to get sent + while (tx_buffer[0] != NULL) + ; + + // Activate the new address + usb_address_write(dev_addr); } // Called when the device received SET_CONFIG request, you can leave this @@ -243,24 +290,36 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) rx_buffer[ep_num] = NULL; } + else if (ep_dir == TUSB_DIR_OUT) { + tx_buffer_offset[ep_num] = 0; + tx_buffer_max[ep_num] = 0; + tx_buffer[ep_num] = NULL; + } + return true; } void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; + if (tu_edpt_number(ep_addr) == 2) + fomu_error(__LINE__); + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) - usb_out_stall_write((1 << CSR_USB_OUT_STALL_STALL_OFFSET) | tu_edpt_number(ep_addr)); - else { + usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_STALL_OFFSET) | (1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | tu_edpt_number(ep_addr)); + else usb_in_ctrl_write((1 << CSR_USB_IN_CTRL_STALL_OFFSET) | tu_edpt_number(ep_addr)); - } } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; - if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) - usb_out_stall_write((0 << CSR_USB_OUT_STALL_STALL_OFFSET) | tu_edpt_number(ep_addr)); + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { + uint8_t enable = 0; + if (rx_buffer[ep_addr]) + enable = 1; + usb_out_ctrl_write((0 << CSR_USB_OUT_CTRL_STALL_OFFSET) | (enable << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | tu_edpt_number(ep_addr)); + } // IN endpoints will get unstalled when more data is written. } @@ -269,62 +328,64 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t (void)rhport; uint8_t ep_num = tu_edpt_number(ep_addr); uint8_t ep_dir = tu_edpt_dir(ep_addr); - TU_ASSERT(tx_ep < 16); + TU_ASSERT(ep_num < 16); - // These sorts of transfers are handled in hardware automatically, so simply inform - // the core that the transfer was processed. - if ((ep_num == 0) && (total_bytes == 0) && (buffer == NULL)) { - dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); - - // An IN packet is sent to acknowledge an OUT token. Re-enable OUT after this. - // if (ep_dir == TUSB_DIR_IN) { - // usb_out_ev_enable_write(0); - // process_rx(false); - // usb_out_ev_enable_write(1); - // } - return true; + // Give a nonzero buffer when we transmit 0 bytes, so that the + // system doesn't think the endpoint is idle. + if ((buffer == NULL) && (total_bytes == 0)) { + buffer = (uint8_t *)0xffffffff; } - TU_ASSERT(((uint32_t)buffer) >= 0x10000000); - TU_ASSERT(((uint32_t)buffer) <= 0x10020000); + TU_ASSERT(buffer != NULL); if (ep_dir == TUSB_DIR_IN) { - uint32_t offset; - // Wait for the tx pipe to free up uint8_t previous_reset_count = reset_count; - while (!((tx_buffer == NULL) - && (usb_in_status_read() & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET)) - && !(usb_in_status_read() & (1 << CSR_USB_IN_STATUS_HAVE_OFFSET)))) + // Continue until the buffer is empty, the system is idle, and the fifo is empty. + while (tx_buffer[ep_num] != NULL) ; + // If a reset happens while we're waiting, abort the transfer if (previous_reset_count != reset_count) return true; - tx_ep = ep_num; - tx_len = total_bytes; - tx_offset = 0; - tx_buffer = buffer; + dcd_int_disable(0); + TU_ASSERT(tx_buffer[ep_num] == NULL); + tx_buffer_offset[ep_num] = 0; + tx_buffer_max[ep_num] = total_bytes; + tx_buffer[ep_num] = buffer; - for (offset = 0; (offset < EP_SIZE) && (offset < total_bytes); offset++) { - usb_in_data_write(buffer[offset]); + // If the current buffer is NULL, then that means the tx logic is idle. + // Update the tx_ep to point to our endpoint number and queue the data. + // Otherwise, let it be and it'll get picked up after the next transfer + // finishes. + if ((tx_buffer[tx_ep] == NULL) || (tx_ep == ep_num)) { + tx_ep = ep_num; + tx_more_data(); } - // Updating the epno queues the data - usb_in_ctrl_write(ep_num & 0xf); + dcd_int_enable(0); } else if (ep_dir == TUSB_DIR_OUT) { - TU_ASSERT(rx_buffer[ep_num] == NULL); + while (rx_buffer[ep_num] != NULL) + ; rx_buffer_offset[ep_num] = 0; rx_buffer_max[ep_num] = total_bytes; - rx_buffer[ep_num] = buffer; - // If there's data in the buffer already, we'll try draining it - // into the current fifo immediately. - usb_out_ev_enable_write(0); - if (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) - process_rx(false); - usb_out_ev_enable_write(1); + dcd_int_disable(0); + rx_buffer[ep_num] = buffer; + usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | ep_num); + + // uint16_t ep_en_mask = usb_out_enable_status_read(); + // int i; + // for (i = 0; i < 16; i++) { + // if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { + // if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i) + // continue; + // fomu_error(__LINE__); + // } + // } + dcd_int_enable(0); } return true; } @@ -339,8 +400,6 @@ void hal_dcd_isr(uint8_t rhport) uint8_t in_pending = usb_in_ev_pending_read(); uint8_t out_pending = usb_out_ev_pending_read(); usb_setup_ev_pending_write(setup_pending); - usb_in_ev_pending_write(in_pending); - usb_out_ev_pending_write(out_pending); // This event means a bus reset occurred. Reset everything, and // abandon any further processing. @@ -352,7 +411,10 @@ void hal_dcd_isr(uint8_t rhport) // An "OUT" transaction just completed so we have new data. // (But only if we can accept the data) // if (out_pending) { - if (usb_out_ev_enable_read() && out_pending) { + if (out_pending) { + if (!usb_out_ev_enable_read()) + fomu_error(__LINE__); + usb_out_ev_pending_write(out_pending); process_rx(true); } @@ -364,35 +426,37 @@ void hal_dcd_isr(uint8_t rhport) // to begin with, then make a subsequent request. If we don't handle // the IN packets first, then the second request will be truncated. if (in_pending) { - finish_tx(); + if (!usb_in_ev_enable_read()) + fomu_error(__LINE__); + usb_in_ev_pending_write(in_pending); + process_tx(true); } // We got a SETUP packet. Copy it to the setup buffer and clear // the "pending" bit. if (setup_pending & 1) { // Setup packets are always 8 bytes, plus two bytes of crc16. - uint8_t setup_packet[10]; uint32_t setup_length = 0; - if (!(usb_setup_status_read() & 1)) + if (!(usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET))) fomu_error(__LINE__); - while (usb_setup_status_read() & 1) { + while (usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)) { uint8_t c = usb_setup_data_read(); - if (setup_length < sizeof(setup_packet)) - setup_packet[setup_length] = c; + if (setup_length < sizeof(setup_packet_bfr)) + setup_packet_bfr[setup_length] = c; setup_length++; } // If we have 10 bytes, that's a full SETUP packet plus CRC16. // Otherwise, it was an RX error. if (setup_length == 10) { - dcd_event_setup_received(rhport, setup_packet, true); + dcd_event_setup_received(rhport, setup_packet_bfr, true); // Acknowledge the packet, so long as it isn't a SET_ADDRESS // packet. If it is, leave it unacknowledged and we'll do this // in the `dcd_set_address` function instead. - if (!((setup_packet[0] == 0x00) && (setup_packet[1] == 0x05))) - usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_HANDLED_OFFSET); + // if (!((setup_packet_bfr[0] == 0x00) && (setup_packet_bfr[1] == 0x05))) + usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_ACK_OFFSET); } else { fomu_error(__LINE__); From 83bca4a74fce268082996ac098e998445a8a9987 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Oct 2019 08:34:35 +0800 Subject: [PATCH 12/27] fomu: semi-working commit Signed-off-by: Sean Cross --- hw/bsp/fomu/bsp.c | 7 +- hw/bsp/fomu/include/csr.h | 227 ++++++++++++++++++-------------------- 2 files changed, 112 insertions(+), 122 deletions(-) diff --git a/hw/bsp/fomu/bsp.c b/hw/bsp/fomu/bsp.c index 2bba0ce2c..3910cff44 100644 --- a/hw/bsp/fomu/bsp.c +++ b/hw/bsp/fomu/bsp.c @@ -39,8 +39,9 @@ void hal_dcd_isr(uint8_t rhport); void mputs(const char *str) { (void)str; while (*str) { - if (! (messible_status_read() & CSR_MESSIBLE_STATUS_FULL_OFFSET)) - messible_in_write(*str); + while ( (messible_status_read() & CSR_MESSIBLE_STATUS_FULL_OFFSET)) + ; + messible_in_write(*str); str++; } } @@ -54,7 +55,7 @@ void fomu_error(uint32_t line) { (void)line; TU_BREAKPOINT(); - while (1) {} + // while (1) {} } volatile uint32_t system_ticks = 0; diff --git a/hw/bsp/fomu/include/csr.h b/hw/bsp/fomu/include/csr.h index b9bffada3..bcd48eb42 100644 --- a/hw/bsp/fomu/include/csr.h +++ b/hw/bsp/fomu/include/csr.h @@ -1,5 +1,5 @@ //-------------------------------------------------------------------------------- -// Auto-generated by Migen (f4fcd10) & LiteX (1425a68d) on 2019-10-11 22:01:17 +// Auto-generated by Migen (f4fcd10) & LiteX (1425a68d) on 2019-10-30 21:48:57 //-------------------------------------------------------------------------------- #ifndef __GENERATED_CSR_H #define __GENERATED_CSR_H @@ -351,93 +351,92 @@ static inline unsigned char usb_pullup_out_read(void) { static inline void usb_pullup_out_write(unsigned char value) { csr_writel(value, 0xe0004800L); } -#define CSR_USB_SETUP_DATA_ADDR 0xe0004804L +#define CSR_USB_ADDRESS_ADDR 0xe0004804L +#define CSR_USB_ADDRESS_SIZE 1 +static inline unsigned char usb_address_read(void) { + unsigned char r = csr_readl(0xe0004804L); + return r; +} +static inline void usb_address_write(unsigned char value) { + csr_writel(value, 0xe0004804L); +} +#define CSR_USB_ADDRESS_ADDR_OFFSET 0 +#define CSR_USB_ADDRESS_ADDR_SIZE 7 +#define CSR_USB_SETUP_DATA_ADDR 0xe0004808L #define CSR_USB_SETUP_DATA_SIZE 1 static inline unsigned char usb_setup_data_read(void) { - unsigned char r = csr_readl(0xe0004804L); + unsigned char r = csr_readl(0xe0004808L); return r; } #define CSR_USB_SETUP_DATA_DATA_OFFSET 0 #define CSR_USB_SETUP_DATA_DATA_SIZE 8 -#define CSR_USB_SETUP_CTRL_ADDR 0xe0004808L +#define CSR_USB_SETUP_CTRL_ADDR 0xe000480cL #define CSR_USB_SETUP_CTRL_SIZE 1 static inline unsigned char usb_setup_ctrl_read(void) { - unsigned char r = csr_readl(0xe0004808L); - return r; -} -static inline void usb_setup_ctrl_write(unsigned char value) { - csr_writel(value, 0xe0004808L); -} -#define CSR_USB_SETUP_CTRL_HANDLED_OFFSET 1 -#define CSR_USB_SETUP_CTRL_HANDLED_SIZE 1 -#define CSR_USB_SETUP_CTRL_RESET_OFFSET 2 -#define CSR_USB_SETUP_CTRL_RESET_SIZE 1 -#define CSR_USB_SETUP_STATUS_ADDR 0xe000480cL -#define CSR_USB_SETUP_STATUS_SIZE 1 -static inline unsigned char usb_setup_status_read(void) { unsigned char r = csr_readl(0xe000480cL); return r; } -#define CSR_USB_SETUP_STATUS_HAVE_OFFSET 0 -#define CSR_USB_SETUP_STATUS_HAVE_SIZE 1 -#define CSR_USB_SETUP_STATUS_IS_IN_OFFSET 1 -#define CSR_USB_SETUP_STATUS_IS_IN_SIZE 1 -#define CSR_USB_SETUP_STATUS_EPNO_OFFSET 2 -#define CSR_USB_SETUP_STATUS_EPNO_SIZE 4 -#define CSR_USB_SETUP_STATUS_PEND_OFFSET 6 -#define CSR_USB_SETUP_STATUS_PEND_SIZE 1 -#define CSR_USB_SETUP_STATUS_DATA_OFFSET 7 -#define CSR_USB_SETUP_STATUS_DATA_SIZE 1 -#define CSR_USB_SETUP_EV_STATUS_ADDR 0xe0004810L -#define CSR_USB_SETUP_EV_STATUS_SIZE 1 -static inline unsigned char usb_setup_ev_status_read(void) { +static inline void usb_setup_ctrl_write(unsigned char value) { + csr_writel(value, 0xe000480cL); +} +#define CSR_USB_SETUP_CTRL_ACK_OFFSET 1 +#define CSR_USB_SETUP_CTRL_ACK_SIZE 1 +#define CSR_USB_SETUP_CTRL_RESET_OFFSET 5 +#define CSR_USB_SETUP_CTRL_RESET_SIZE 1 +#define CSR_USB_SETUP_STATUS_ADDR 0xe0004810L +#define CSR_USB_SETUP_STATUS_SIZE 1 +static inline unsigned char usb_setup_status_read(void) { unsigned char r = csr_readl(0xe0004810L); return r; } -static inline void usb_setup_ev_status_write(unsigned char value) { - csr_writel(value, 0xe0004810L); -} -#define CSR_USB_SETUP_EV_PENDING_ADDR 0xe0004814L -#define CSR_USB_SETUP_EV_PENDING_SIZE 1 -static inline unsigned char usb_setup_ev_pending_read(void) { +#define CSR_USB_SETUP_STATUS_EPNO_OFFSET 0 +#define CSR_USB_SETUP_STATUS_EPNO_SIZE 4 +#define CSR_USB_SETUP_STATUS_HAVE_OFFSET 4 +#define CSR_USB_SETUP_STATUS_HAVE_SIZE 1 +#define CSR_USB_SETUP_STATUS_PEND_OFFSET 5 +#define CSR_USB_SETUP_STATUS_PEND_SIZE 1 +#define CSR_USB_SETUP_STATUS_IS_IN_OFFSET 6 +#define CSR_USB_SETUP_STATUS_IS_IN_SIZE 1 +#define CSR_USB_SETUP_STATUS_DATA_OFFSET 7 +#define CSR_USB_SETUP_STATUS_DATA_SIZE 1 +#define CSR_USB_SETUP_EV_STATUS_ADDR 0xe0004814L +#define CSR_USB_SETUP_EV_STATUS_SIZE 1 +static inline unsigned char usb_setup_ev_status_read(void) { unsigned char r = csr_readl(0xe0004814L); return r; } -static inline void usb_setup_ev_pending_write(unsigned char value) { +static inline void usb_setup_ev_status_write(unsigned char value) { csr_writel(value, 0xe0004814L); } -#define CSR_USB_SETUP_EV_ENABLE_ADDR 0xe0004818L -#define CSR_USB_SETUP_EV_ENABLE_SIZE 1 -static inline unsigned char usb_setup_ev_enable_read(void) { +#define CSR_USB_SETUP_EV_PENDING_ADDR 0xe0004818L +#define CSR_USB_SETUP_EV_PENDING_SIZE 1 +static inline unsigned char usb_setup_ev_pending_read(void) { unsigned char r = csr_readl(0xe0004818L); return r; } -static inline void usb_setup_ev_enable_write(unsigned char value) { +static inline void usb_setup_ev_pending_write(unsigned char value) { csr_writel(value, 0xe0004818L); } -#define CSR_USB_IN_DATA_ADDR 0xe000481cL -#define CSR_USB_IN_DATA_SIZE 1 -static inline unsigned char usb_in_data_read(void) { +#define CSR_USB_SETUP_EV_ENABLE_ADDR 0xe000481cL +#define CSR_USB_SETUP_EV_ENABLE_SIZE 1 +static inline unsigned char usb_setup_ev_enable_read(void) { unsigned char r = csr_readl(0xe000481cL); return r; } -static inline void usb_in_data_write(unsigned char value) { +static inline void usb_setup_ev_enable_write(unsigned char value) { csr_writel(value, 0xe000481cL); } -#define CSR_USB_IN_DATA_DATA_OFFSET 0 -#define CSR_USB_IN_DATA_DATA_SIZE 8 -#define CSR_USB_IN_STATUS_ADDR 0xe0004820L -#define CSR_USB_IN_STATUS_SIZE 1 -static inline unsigned char usb_in_status_read(void) { +#define CSR_USB_IN_DATA_ADDR 0xe0004820L +#define CSR_USB_IN_DATA_SIZE 1 +static inline unsigned char usb_in_data_read(void) { unsigned char r = csr_readl(0xe0004820L); return r; } -#define CSR_USB_IN_STATUS_HAVE_OFFSET 0 -#define CSR_USB_IN_STATUS_HAVE_SIZE 1 -#define CSR_USB_IN_STATUS_IDLE_OFFSET 1 -#define CSR_USB_IN_STATUS_IDLE_SIZE 1 -#define CSR_USB_IN_STATUS_PEND_OFFSET 6 -#define CSR_USB_IN_STATUS_PEND_SIZE 1 +static inline void usb_in_data_write(unsigned char value) { + csr_writel(value, 0xe0004820L); +} +#define CSR_USB_IN_DATA_DATA_OFFSET 0 +#define CSR_USB_IN_DATA_DATA_SIZE 8 #define CSR_USB_IN_CTRL_ADDR 0xe0004824L #define CSR_USB_IN_CTRL_SIZE 1 static inline unsigned char usb_in_ctrl_read(void) { @@ -447,61 +446,59 @@ static inline unsigned char usb_in_ctrl_read(void) { static inline void usb_in_ctrl_write(unsigned char value) { csr_writel(value, 0xe0004824L); } -#define CSR_USB_IN_CTRL_EP_OFFSET 0 -#define CSR_USB_IN_CTRL_EP_SIZE 4 -#define CSR_USB_IN_CTRL_STALL_OFFSET 4 -#define CSR_USB_IN_CTRL_STALL_SIZE 1 +#define CSR_USB_IN_CTRL_EPNO_OFFSET 0 +#define CSR_USB_IN_CTRL_EPNO_SIZE 4 #define CSR_USB_IN_CTRL_RESET_OFFSET 5 #define CSR_USB_IN_CTRL_RESET_SIZE 1 -#define CSR_USB_IN_EV_STATUS_ADDR 0xe0004828L -#define CSR_USB_IN_EV_STATUS_SIZE 1 -static inline unsigned char usb_in_ev_status_read(void) { +#define CSR_USB_IN_CTRL_STALL_OFFSET 6 +#define CSR_USB_IN_CTRL_STALL_SIZE 1 +#define CSR_USB_IN_STATUS_ADDR 0xe0004828L +#define CSR_USB_IN_STATUS_SIZE 1 +static inline unsigned char usb_in_status_read(void) { unsigned char r = csr_readl(0xe0004828L); return r; } -static inline void usb_in_ev_status_write(unsigned char value) { - csr_writel(value, 0xe0004828L); -} -#define CSR_USB_IN_EV_PENDING_ADDR 0xe000482cL -#define CSR_USB_IN_EV_PENDING_SIZE 1 -static inline unsigned char usb_in_ev_pending_read(void) { +#define CSR_USB_IN_STATUS_IDLE_OFFSET 0 +#define CSR_USB_IN_STATUS_IDLE_SIZE 1 +#define CSR_USB_IN_STATUS_HAVE_OFFSET 4 +#define CSR_USB_IN_STATUS_HAVE_SIZE 1 +#define CSR_USB_IN_STATUS_PEND_OFFSET 5 +#define CSR_USB_IN_STATUS_PEND_SIZE 1 +#define CSR_USB_IN_EV_STATUS_ADDR 0xe000482cL +#define CSR_USB_IN_EV_STATUS_SIZE 1 +static inline unsigned char usb_in_ev_status_read(void) { unsigned char r = csr_readl(0xe000482cL); return r; } -static inline void usb_in_ev_pending_write(unsigned char value) { +static inline void usb_in_ev_status_write(unsigned char value) { csr_writel(value, 0xe000482cL); } -#define CSR_USB_IN_EV_ENABLE_ADDR 0xe0004830L -#define CSR_USB_IN_EV_ENABLE_SIZE 1 -static inline unsigned char usb_in_ev_enable_read(void) { +#define CSR_USB_IN_EV_PENDING_ADDR 0xe0004830L +#define CSR_USB_IN_EV_PENDING_SIZE 1 +static inline unsigned char usb_in_ev_pending_read(void) { unsigned char r = csr_readl(0xe0004830L); return r; } -static inline void usb_in_ev_enable_write(unsigned char value) { +static inline void usb_in_ev_pending_write(unsigned char value) { csr_writel(value, 0xe0004830L); } -#define CSR_USB_OUT_DATA_ADDR 0xe0004834L +#define CSR_USB_IN_EV_ENABLE_ADDR 0xe0004834L +#define CSR_USB_IN_EV_ENABLE_SIZE 1 +static inline unsigned char usb_in_ev_enable_read(void) { + unsigned char r = csr_readl(0xe0004834L); + return r; +} +static inline void usb_in_ev_enable_write(unsigned char value) { + csr_writel(value, 0xe0004834L); +} +#define CSR_USB_OUT_DATA_ADDR 0xe0004838L #define CSR_USB_OUT_DATA_SIZE 1 static inline unsigned char usb_out_data_read(void) { - unsigned char r = csr_readl(0xe0004834L); + unsigned char r = csr_readl(0xe0004838L); return r; } #define CSR_USB_OUT_DATA_DATA_OFFSET 0 #define CSR_USB_OUT_DATA_DATA_SIZE 8 -#define CSR_USB_OUT_STATUS_ADDR 0xe0004838L -#define CSR_USB_OUT_STATUS_SIZE 1 -static inline unsigned char usb_out_status_read(void) { - unsigned char r = csr_readl(0xe0004838L); - return r; -} -#define CSR_USB_OUT_STATUS_HAVE_OFFSET 0 -#define CSR_USB_OUT_STATUS_HAVE_SIZE 1 -#define CSR_USB_OUT_STATUS_IDLE_OFFSET 1 -#define CSR_USB_OUT_STATUS_IDLE_SIZE 1 -#define CSR_USB_OUT_STATUS_EPNO_OFFSET 2 -#define CSR_USB_OUT_STATUS_EPNO_SIZE 4 -#define CSR_USB_OUT_STATUS_PEND_OFFSET 6 -#define CSR_USB_OUT_STATUS_PEND_SIZE 1 #define CSR_USB_OUT_CTRL_ADDR 0xe000483cL #define CSR_USB_OUT_CTRL_SIZE 1 static inline unsigned char usb_out_ctrl_read(void) { @@ -511,23 +508,26 @@ static inline unsigned char usb_out_ctrl_read(void) { static inline void usb_out_ctrl_write(unsigned char value) { csr_writel(value, 0xe000483cL); } -#define CSR_USB_OUT_CTRL_ENABLE_OFFSET 1 +#define CSR_USB_OUT_CTRL_EPNO_OFFSET 0 +#define CSR_USB_OUT_CTRL_EPNO_SIZE 4 +#define CSR_USB_OUT_CTRL_ENABLE_OFFSET 4 #define CSR_USB_OUT_CTRL_ENABLE_SIZE 1 -#define CSR_USB_OUT_CTRL_RESET_OFFSET 2 +#define CSR_USB_OUT_CTRL_RESET_OFFSET 5 #define CSR_USB_OUT_CTRL_RESET_SIZE 1 -#define CSR_USB_OUT_STALL_ADDR 0xe0004840L -#define CSR_USB_OUT_STALL_SIZE 1 -static inline unsigned char usb_out_stall_read(void) { +#define CSR_USB_OUT_CTRL_STALL_OFFSET 6 +#define CSR_USB_OUT_CTRL_STALL_SIZE 1 +#define CSR_USB_OUT_STATUS_ADDR 0xe0004840L +#define CSR_USB_OUT_STATUS_SIZE 1 +static inline unsigned char usb_out_status_read(void) { unsigned char r = csr_readl(0xe0004840L); return r; } -static inline void usb_out_stall_write(unsigned char value) { - csr_writel(value, 0xe0004840L); -} -#define CSR_USB_OUT_STALL_EPNO_OFFSET 0 -#define CSR_USB_OUT_STALL_EPNO_SIZE 4 -#define CSR_USB_OUT_STALL_STALL_OFFSET 4 -#define CSR_USB_OUT_STALL_STALL_SIZE 1 +#define CSR_USB_OUT_STATUS_EPNO_OFFSET 0 +#define CSR_USB_OUT_STATUS_EPNO_SIZE 4 +#define CSR_USB_OUT_STATUS_HAVE_OFFSET 4 +#define CSR_USB_OUT_STATUS_HAVE_SIZE 1 +#define CSR_USB_OUT_STATUS_PEND_OFFSET 5 +#define CSR_USB_OUT_STATUS_PEND_SIZE 1 #define CSR_USB_OUT_EV_STATUS_ADDR 0xe0004844L #define CSR_USB_OUT_EV_STATUS_SIZE 1 static inline unsigned char usb_out_ev_status_read(void) { @@ -555,29 +555,18 @@ static inline unsigned char usb_out_ev_enable_read(void) { static inline void usb_out_ev_enable_write(unsigned char value) { csr_writel(value, 0xe000484cL); } -#define CSR_USB_ADDRESS_ADDR 0xe0004850L -#define CSR_USB_ADDRESS_SIZE 1 -static inline unsigned char usb_address_read(void) { +#define CSR_USB_OUT_ENABLE_STATUS_ADDR 0xe0004850L +#define CSR_USB_OUT_ENABLE_STATUS_SIZE 1 +static inline unsigned char usb_out_enable_status_read(void) { unsigned char r = csr_readl(0xe0004850L); return r; } -static inline void usb_address_write(unsigned char value) { - csr_writel(value, 0xe0004850L); -} -#define CSR_USB_ADDRESS_ADDR_OFFSET 0 -#define CSR_USB_ADDRESS_ADDR_SIZE 7 -#define CSR_USB_STAGE_NUM_ADDR 0xe0004854L -#define CSR_USB_STAGE_NUM_SIZE 1 -static inline unsigned char usb_stage_num_read(void) { +#define CSR_USB_OUT_STALL_STATUS_ADDR 0xe0004854L +#define CSR_USB_OUT_STALL_STATUS_SIZE 1 +static inline unsigned char usb_out_stall_status_read(void) { unsigned char r = csr_readl(0xe0004854L); return r; } -#define CSR_USB_LAST_STAGE_NUM_ADDR 0xe0004858L -#define CSR_USB_LAST_STAGE_NUM_SIZE 1 -static inline unsigned char usb_last_stage_num_read(void) { - unsigned char r = csr_readl(0xe0004858L); - return r; -} /* version */ #define CSR_VERSION_BASE 0xe0007000L From 835a72c59599e83183e623972fe85e779ed01383 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Oct 2019 08:35:04 +0800 Subject: [PATCH 13/27] fomu: semi-working dcd file Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 133 ++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 40 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index 8b2212c16..07efcce7a 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -26,6 +26,10 @@ #include "tusb_option.h" +#ifndef DEBUG +#define DEBUG 0 +#endif + // #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) #if 1 @@ -48,16 +52,17 @@ uint8_t volatile * rx_buffer[16]; uint16_t volatile rx_buffer_max[16]; volatile uint8_t tx_ep; +volatile bool tx_active; volatile uint16_t tx_buffer_offset[16]; uint8_t volatile * tx_buffer[16]; volatile uint16_t tx_buffer_max[16]; volatile uint8_t reset_count; +#ifdef DEBUG __attribute__((used)) uint8_t volatile * last_tx_buffer; __attribute__((used)) volatile uint8_t last_tx_ep; - +#endif uint8_t setup_packet_bfr[10]; - //--------------------------------------------------------------------+ // PIPE HELPER //--------------------------------------------------------------------+ @@ -86,27 +91,35 @@ static void tx_more_data(void) { } static void process_tx(bool in_isr) { - // If the buffer is now empty, search for the next buffer to fill. - if (!tx_buffer[tx_ep]) { - if (advance_tx_ep()) - tx_more_data(); - return; - } - +#if DEBUG // If the system isn't idle, then something is very wrong. uint8_t in_status = usb_in_status_read(); if (!(in_status & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) fomu_error(__LINE__); +#endif + + // If the buffer is now empty, search for the next buffer to fill. + if (!tx_buffer[tx_ep]) { + if (advance_tx_ep()) + tx_more_data(); + else + tx_active = false; + return; + } tx_buffer_offset[tx_ep] += EP_SIZE; if (tx_buffer_offset[tx_ep] >= tx_buffer_max[tx_ep]) { +#if DEBUG last_tx_buffer = tx_buffer[tx_ep]; last_tx_ep = tx_ep; +#endif tx_buffer[tx_ep] = NULL; - dcd_event_xfer_complete(0, tu_edpt_addr(tx_ep, TUSB_DIR_IN), tx_buffer_max[tx_ep], XFER_RESULT_SUCCESS, in_isr); if (!advance_tx_ep()) + tx_active = false; + dcd_event_xfer_complete(0, tu_edpt_addr(tx_ep, TUSB_DIR_IN), tx_buffer_max[tx_ep], XFER_RESULT_SUCCESS, in_isr); + if (!tx_active) return; } @@ -115,61 +128,85 @@ static void process_tx(bool in_isr) { } static void process_rx(bool in_isr) { - // If the OUT handler is still waiting to send, don't do anything. uint8_t out_status = usb_out_status_read(); +#if DEBUG + // If the OUT handler is still waiting to send, don't do anything. if (!(out_status & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET))) fomu_error(__LINE__); // return; - +#endif uint8_t rx_ep = (out_status >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf; // If the destination buffer doesn't exist, don't drain the hardware // fifo. Note that this can cause deadlocks if the host is waiting // on some other endpoint's data! +#if DEBUG if (rx_buffer[rx_ep] == NULL) { fomu_error(__LINE__); return; } +#endif + // Drain the FIFO into the destination buffer uint32_t total_read = 0; uint32_t current_offset = rx_buffer_offset[rx_ep]; +#if DEBUG if (current_offset > rx_buffer_max[rx_ep]) fomu_error(__LINE__); +#endif while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) { uint8_t c = usb_out_data_read(); total_read++; if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) rx_buffer[rx_ep][current_offset++] = c; } +#if DEBUG if (total_read > 66) fomu_error(__LINE__); + if (total_read < 2) + fomu_error(__LINE__); +#endif // Strip off the CRC16 rx_buffer_offset[rx_ep] += (total_read - 2); if (rx_buffer_offset[rx_ep] > rx_buffer_max[rx_ep]) rx_buffer_offset[rx_ep] = rx_buffer_max[rx_ep]; + // If there's no more data, complete the transfer to tinyusb if (rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep]) { +#if DEBUG if (rx_buffer[rx_ep] == NULL) fomu_error(__LINE__); +#endif - // Disable this endpoint (causing it to respond NAK) until we have - // a buffer to place the data into. + // Free up this buffer. rx_buffer[rx_ep] = NULL; uint16_t len = rx_buffer_offset[rx_ep]; - // uint16_t ep_en_mask = usb_out_enable_status_read(); - // int i; - // for (i = 0; i < 16; i++) { - // if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) - // fomu_error(__LINE__); - // } +#if DEBUG + // Validate that all enabled endpoints have buffers, + // and no disabled endpoints have buffers. + uint16_t ep_en_mask = usb_out_enable_status_read(); + int i; + for (i = 0; i < 16; i++) { + if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { + uint8_t new_status = usb_out_status_read(); + // Another IRQ came in while we were processing, so ignore this endpoint. + if ((new_status & 0x20) && ((new_status & 0xf) == i)) + continue; + fomu_error(__LINE__); + } + } +#endif dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr); - return; + } + else { + // If there's more data, re-enable data reception on this endpoint + usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | rx_ep); } - // If there's more data, re-enable data reception - usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | rx_ep); + // Now that the buffer is drained, clear the pending IRQ. + usb_out_ev_pending_write(usb_out_ev_pending_read()); } //--------------------------------------------------------------------+ @@ -198,6 +235,7 @@ static void dcd_reset(void) memset((void *)tx_buffer_max, 0, sizeof(tx_buffer_max)); memset((void *)tx_buffer_offset, 0, sizeof(tx_buffer_offset)); tx_ep = 0; + tx_active = false; // Enable all event handlers and clear their contents usb_setup_ev_pending_write(-1); @@ -251,7 +289,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); // Wait for the response packet to get sent - while (tx_buffer[0] != NULL) + while (tx_active) ; // Activate the new address @@ -305,8 +343,12 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) if (tu_edpt_number(ep_addr) == 2) fomu_error(__LINE__); - if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) - usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_STALL_OFFSET) | (1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | tu_edpt_number(ep_addr)); + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { + uint8_t enable = 0; + if (rx_buffer[ep_addr]) + enable = 1; + usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_STALL_OFFSET) | (enable << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | tu_edpt_number(ep_addr)); + } else usb_in_ctrl_write((1 << CSR_USB_IN_CTRL_STALL_OFFSET) | tu_edpt_number(ep_addr)); } @@ -359,32 +401,36 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t // Update the tx_ep to point to our endpoint number and queue the data. // Otherwise, let it be and it'll get picked up after the next transfer // finishes. - if ((tx_buffer[tx_ep] == NULL) || (tx_ep == ep_num)) { + if (!tx_active) { tx_ep = ep_num; + tx_active = true; tx_more_data(); } dcd_int_enable(0); } + else if (ep_dir == TUSB_DIR_OUT) { while (rx_buffer[ep_num] != NULL) ; + dcd_int_disable(0); + TU_ASSERT(rx_buffer[ep_num] == NULL); + rx_buffer[ep_num] = buffer; rx_buffer_offset[ep_num] = 0; rx_buffer_max[ep_num] = total_bytes; - dcd_int_disable(0); - rx_buffer[ep_num] = buffer; usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | ep_num); - - // uint16_t ep_en_mask = usb_out_enable_status_read(); - // int i; - // for (i = 0; i < 16; i++) { - // if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { - // if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i) - // continue; - // fomu_error(__LINE__); - // } - // } +#if DEBUG + uint16_t ep_en_mask = usb_out_enable_status_read(); + int i; + for (i = 0; i < 16; i++) { + if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { + if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i) + continue; + fomu_error(__LINE__); + } + } +#endif dcd_int_enable(0); } return true; @@ -412,9 +458,10 @@ void hal_dcd_isr(uint8_t rhport) // (But only if we can accept the data) // if (out_pending) { if (out_pending) { +#if DEBUG if (!usb_out_ev_enable_read()) fomu_error(__LINE__); - usb_out_ev_pending_write(out_pending); +#endif process_rx(true); } @@ -426,8 +473,10 @@ void hal_dcd_isr(uint8_t rhport) // to begin with, then make a subsequent request. If we don't handle // the IN packets first, then the second request will be truncated. if (in_pending) { +#if DEBUG if (!usb_in_ev_enable_read()) fomu_error(__LINE__); +#endif usb_in_ev_pending_write(in_pending); process_tx(true); } @@ -438,8 +487,10 @@ void hal_dcd_isr(uint8_t rhport) // Setup packets are always 8 bytes, plus two bytes of crc16. uint32_t setup_length = 0; +#if DEBUG if (!(usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET))) fomu_error(__LINE__); +#endif while (usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)) { uint8_t c = usb_setup_data_read(); @@ -458,9 +509,11 @@ void hal_dcd_isr(uint8_t rhport) // if (!((setup_packet_bfr[0] == 0x00) && (setup_packet_bfr[1] == 0x05))) usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_ACK_OFFSET); } +#if DEBUG else { fomu_error(__LINE__); } +#endif } } From 913032ae1d1d4a28e295d150bfa636f296be7bb9 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Oct 2019 11:14:07 +0800 Subject: [PATCH 14/27] dcd_fomu: nearly there Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 101 ++++++++++++++++------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index 07efcce7a..12add4c85 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -24,11 +24,11 @@ * This file is part of the TinyUSB stack. */ +#ifndef DEBUG +#define DEBUG 1 +#endif #include "tusb_option.h" -#ifndef DEBUG -#define DEBUG 0 -#endif // #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) #if 1 @@ -41,6 +41,8 @@ void fomu_error(uint32_t line); void mputs(const char *str); void mputln(const char *str); +static uint8_t last_address; + //--------------------------------------------------------------------+ // SIE Command //--------------------------------------------------------------------+ @@ -58,11 +60,11 @@ uint8_t volatile * tx_buffer[16]; volatile uint16_t tx_buffer_max[16]; volatile uint8_t reset_count; -#ifdef DEBUG +#if DEBUG __attribute__((used)) uint8_t volatile * last_tx_buffer; __attribute__((used)) volatile uint8_t last_tx_ep; -#endif uint8_t setup_packet_bfr[10]; +#endif //--------------------------------------------------------------------+ // PIPE HELPER //--------------------------------------------------------------------+ @@ -82,15 +84,15 @@ static bool advance_tx_ep(void) { static void tx_more_data(void) { // Send more data uint8_t added_bytes; - for (added_bytes = 0; (added_bytes < EP_SIZE) && (added_bytes + tx_buffer_offset[tx_ep] < tx_buffer_max[tx_ep]); added_bytes++) { - usb_in_data_write(tx_buffer[tx_ep][added_bytes + tx_buffer_offset[tx_ep]]); + for (added_bytes = 0; (added_bytes < EP_SIZE) && (tx_buffer_offset[tx_ep] < tx_buffer_max[tx_ep]); added_bytes++) { + usb_in_data_write(tx_buffer[tx_ep][tx_buffer_offset[tx_ep]++]); } // Updating the epno queues the data usb_in_ctrl_write(tx_ep & 0xf); } -static void process_tx(bool in_isr) { +static void process_tx(void) { #if DEBUG // If the system isn't idle, then something is very wrong. uint8_t in_status = usb_in_status_read(); @@ -107,18 +109,20 @@ static void process_tx(bool in_isr) { return; } - tx_buffer_offset[tx_ep] += EP_SIZE; - if (tx_buffer_offset[tx_ep] >= tx_buffer_max[tx_ep]) { #if DEBUG last_tx_buffer = tx_buffer[tx_ep]; last_tx_ep = tx_ep; #endif tx_buffer[tx_ep] = NULL; + uint16_t xferred_bytes = tx_buffer_max[tx_ep]; + uint8_t xferred_ep = tx_ep; if (!advance_tx_ep()) tx_active = false; - dcd_event_xfer_complete(0, tu_edpt_addr(tx_ep, TUSB_DIR_IN), tx_buffer_max[tx_ep], XFER_RESULT_SUCCESS, in_isr); + if ((xferred_bytes == 13) && (tx_buffer_max[tx_ep] == 512)) + fomu_error(__LINE__); + dcd_event_xfer_complete(0, tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes, XFER_RESULT_SUCCESS, true); if (!tx_active) return; } @@ -127,7 +131,7 @@ static void process_tx(bool in_isr) { return; } -static void process_rx(bool in_isr) { +static void process_rx(void) { uint8_t out_status = usb_out_status_read(); #if DEBUG // If the OUT handler is still waiting to send, don't do anything. @@ -190,15 +194,15 @@ static void process_rx(bool in_isr) { int i; for (i = 0; i < 16; i++) { if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { - uint8_t new_status = usb_out_status_read(); - // Another IRQ came in while we were processing, so ignore this endpoint. - if ((new_status & 0x20) && ((new_status & 0xf) == i)) - continue; + // uint8_t new_status = usb_out_status_read(); + // // Another IRQ came in while we were processing, so ignore this endpoint. + // if ((new_status & 0x20) && ((new_status & 0xf) == i)) + // continue; fomu_error(__LINE__); } } #endif - dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr); + dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, true); } else { // If there's more data, re-enable data reception on this endpoint @@ -220,6 +224,8 @@ static void dcd_reset(void) usb_in_ev_enable_write(0); usb_out_ev_enable_write(0); + if (last_address) + asm("ebreak"); usb_address_write(0); // Reset all three FIFO handlers @@ -294,6 +300,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) // Activate the new address usb_address_write(dev_addr); + last_address = dev_addr; } // Called when the device received SET_CONFIG request, you can leave this @@ -387,11 +394,13 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t while (tx_buffer[ep_num] != NULL) ; + dcd_int_disable(0); + if (total_bytes == 499) + asm("ebreak"); // If a reset happens while we're waiting, abort the transfer if (previous_reset_count != reset_count) return true; - dcd_int_disable(0); TU_ASSERT(tx_buffer[ep_num] == NULL); tx_buffer_offset[ep_num] = 0; tx_buffer_max[ep_num] = total_bytes; @@ -419,18 +428,19 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t rx_buffer_offset[ep_num] = 0; rx_buffer_max[ep_num] = total_bytes; + // Enable receiving on this particular endpoint usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | ep_num); -#if DEBUG - uint16_t ep_en_mask = usb_out_enable_status_read(); - int i; - for (i = 0; i < 16; i++) { - if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { - if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i) - continue; - fomu_error(__LINE__); - } - } -#endif +// #if DEBUG +// uint16_t ep_en_mask = usb_out_enable_status_read(); +// int i; +// for (i = 0; i < 16; i++) { +// if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { +// if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i) +// continue; +// fomu_error(__LINE__); +// } +// } +// #endif dcd_int_enable(0); } return true; @@ -442,9 +452,12 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t void hal_dcd_isr(uint8_t rhport) { - uint8_t setup_pending = usb_setup_ev_pending_read(); - uint8_t in_pending = usb_in_ev_pending_read(); - uint8_t out_pending = usb_out_ev_pending_read(); + uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); + uint8_t in_pending = usb_in_ev_pending_read() & usb_in_ev_enable_read(); + uint8_t out_pending = usb_out_ev_pending_read() & usb_out_ev_enable_read(); +#if !DEBUG + uint8_t setup_packet_bfr[10]; +#endif usb_setup_ev_pending_write(setup_pending); // This event means a bus reset occurred. Reset everything, and @@ -454,17 +467,6 @@ void hal_dcd_isr(uint8_t rhport) return; } - // An "OUT" transaction just completed so we have new data. - // (But only if we can accept the data) - // if (out_pending) { - if (out_pending) { -#if DEBUG - if (!usb_out_ev_enable_read()) - fomu_error(__LINE__); -#endif - process_rx(true); - } - // An "IN" transaction just completed. // Note that due to the way tinyusb's callback system is implemented, // we must handle IN and OUT packets before we handle SETUP packets. @@ -478,9 +480,20 @@ void hal_dcd_isr(uint8_t rhport) fomu_error(__LINE__); #endif usb_in_ev_pending_write(in_pending); - process_tx(true); + process_tx(); } + // An "OUT" transaction just completed so we have new data. + // (But only if we can accept the data) + // if (out_pending) { + if (out_pending) { +#if DEBUG + if (!usb_out_ev_enable_read()) + fomu_error(__LINE__); +#endif + process_rx(); + } + // We got a SETUP packet. Copy it to the setup buffer and clear // the "pending" bit. if (setup_pending & 1) { From 77cf0b5bfdba4aa97da4e75f0217048106bec151 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 1 Nov 2019 12:31:01 +0800 Subject: [PATCH 15/27] fomu: csr: add version with next_ev register The Fomu bitstream now includes a `USB_NEXT_EV` register to indicate which is the next logical event to process. Add this register to the CSR definition. Signed-off-by: Sean Cross --- hw/bsp/fomu/include/csr.h | 168 +++++++++++++++++++++----------------- 1 file changed, 91 insertions(+), 77 deletions(-) diff --git a/hw/bsp/fomu/include/csr.h b/hw/bsp/fomu/include/csr.h index bcd48eb42..01ef754b2 100644 --- a/hw/bsp/fomu/include/csr.h +++ b/hw/bsp/fomu/include/csr.h @@ -1,5 +1,5 @@ //-------------------------------------------------------------------------------- -// Auto-generated by Migen (f4fcd10) & LiteX (1425a68d) on 2019-10-30 21:48:57 +// Auto-generated by Migen (f4fcd10) & LiteX (1425a68d) on 2019-11-01 12:04:21 //-------------------------------------------------------------------------------- #ifndef __GENERATED_CSR_H #define __GENERATED_CSR_H @@ -362,31 +362,45 @@ static inline void usb_address_write(unsigned char value) { } #define CSR_USB_ADDRESS_ADDR_OFFSET 0 #define CSR_USB_ADDRESS_ADDR_SIZE 7 -#define CSR_USB_SETUP_DATA_ADDR 0xe0004808L +#define CSR_USB_NEXT_EV_ADDR 0xe0004808L +#define CSR_USB_NEXT_EV_SIZE 1 +static inline unsigned char usb_next_ev_read(void) { + unsigned char r = csr_readl(0xe0004808L); + return r; +} +#define CSR_USB_NEXT_EV_IN_OFFSET 0 +#define CSR_USB_NEXT_EV_IN_SIZE 1 +#define CSR_USB_NEXT_EV_OUT_OFFSET 1 +#define CSR_USB_NEXT_EV_OUT_SIZE 1 +#define CSR_USB_NEXT_EV_SETUP_OFFSET 2 +#define CSR_USB_NEXT_EV_SETUP_SIZE 1 +#define CSR_USB_NEXT_EV_RESET_OFFSET 3 +#define CSR_USB_NEXT_EV_RESET_SIZE 1 +#define CSR_USB_SETUP_DATA_ADDR 0xe000480cL #define CSR_USB_SETUP_DATA_SIZE 1 static inline unsigned char usb_setup_data_read(void) { - unsigned char r = csr_readl(0xe0004808L); + unsigned char r = csr_readl(0xe000480cL); return r; } #define CSR_USB_SETUP_DATA_DATA_OFFSET 0 #define CSR_USB_SETUP_DATA_DATA_SIZE 8 -#define CSR_USB_SETUP_CTRL_ADDR 0xe000480cL +#define CSR_USB_SETUP_CTRL_ADDR 0xe0004810L #define CSR_USB_SETUP_CTRL_SIZE 1 static inline unsigned char usb_setup_ctrl_read(void) { - unsigned char r = csr_readl(0xe000480cL); + unsigned char r = csr_readl(0xe0004810L); return r; } static inline void usb_setup_ctrl_write(unsigned char value) { - csr_writel(value, 0xe000480cL); + csr_writel(value, 0xe0004810L); } #define CSR_USB_SETUP_CTRL_ACK_OFFSET 1 #define CSR_USB_SETUP_CTRL_ACK_SIZE 1 #define CSR_USB_SETUP_CTRL_RESET_OFFSET 5 #define CSR_USB_SETUP_CTRL_RESET_SIZE 1 -#define CSR_USB_SETUP_STATUS_ADDR 0xe0004810L +#define CSR_USB_SETUP_STATUS_ADDR 0xe0004814L #define CSR_USB_SETUP_STATUS_SIZE 1 static inline unsigned char usb_setup_status_read(void) { - unsigned char r = csr_readl(0xe0004810L); + unsigned char r = csr_readl(0xe0004814L); return r; } #define CSR_USB_SETUP_STATUS_EPNO_OFFSET 0 @@ -399,63 +413,63 @@ static inline unsigned char usb_setup_status_read(void) { #define CSR_USB_SETUP_STATUS_IS_IN_SIZE 1 #define CSR_USB_SETUP_STATUS_DATA_OFFSET 7 #define CSR_USB_SETUP_STATUS_DATA_SIZE 1 -#define CSR_USB_SETUP_EV_STATUS_ADDR 0xe0004814L +#define CSR_USB_SETUP_EV_STATUS_ADDR 0xe0004818L #define CSR_USB_SETUP_EV_STATUS_SIZE 1 static inline unsigned char usb_setup_ev_status_read(void) { - unsigned char r = csr_readl(0xe0004814L); - return r; -} -static inline void usb_setup_ev_status_write(unsigned char value) { - csr_writel(value, 0xe0004814L); -} -#define CSR_USB_SETUP_EV_PENDING_ADDR 0xe0004818L -#define CSR_USB_SETUP_EV_PENDING_SIZE 1 -static inline unsigned char usb_setup_ev_pending_read(void) { unsigned char r = csr_readl(0xe0004818L); return r; } -static inline void usb_setup_ev_pending_write(unsigned char value) { +static inline void usb_setup_ev_status_write(unsigned char value) { csr_writel(value, 0xe0004818L); } -#define CSR_USB_SETUP_EV_ENABLE_ADDR 0xe000481cL -#define CSR_USB_SETUP_EV_ENABLE_SIZE 1 -static inline unsigned char usb_setup_ev_enable_read(void) { +#define CSR_USB_SETUP_EV_PENDING_ADDR 0xe000481cL +#define CSR_USB_SETUP_EV_PENDING_SIZE 1 +static inline unsigned char usb_setup_ev_pending_read(void) { unsigned char r = csr_readl(0xe000481cL); return r; } -static inline void usb_setup_ev_enable_write(unsigned char value) { +static inline void usb_setup_ev_pending_write(unsigned char value) { csr_writel(value, 0xe000481cL); } -#define CSR_USB_IN_DATA_ADDR 0xe0004820L -#define CSR_USB_IN_DATA_SIZE 1 -static inline unsigned char usb_in_data_read(void) { +#define CSR_USB_SETUP_EV_ENABLE_ADDR 0xe0004820L +#define CSR_USB_SETUP_EV_ENABLE_SIZE 1 +static inline unsigned char usb_setup_ev_enable_read(void) { unsigned char r = csr_readl(0xe0004820L); return r; } -static inline void usb_in_data_write(unsigned char value) { +static inline void usb_setup_ev_enable_write(unsigned char value) { csr_writel(value, 0xe0004820L); } -#define CSR_USB_IN_DATA_DATA_OFFSET 0 -#define CSR_USB_IN_DATA_DATA_SIZE 8 -#define CSR_USB_IN_CTRL_ADDR 0xe0004824L -#define CSR_USB_IN_CTRL_SIZE 1 -static inline unsigned char usb_in_ctrl_read(void) { +#define CSR_USB_IN_DATA_ADDR 0xe0004824L +#define CSR_USB_IN_DATA_SIZE 1 +static inline unsigned char usb_in_data_read(void) { unsigned char r = csr_readl(0xe0004824L); return r; } -static inline void usb_in_ctrl_write(unsigned char value) { +static inline void usb_in_data_write(unsigned char value) { csr_writel(value, 0xe0004824L); } +#define CSR_USB_IN_DATA_DATA_OFFSET 0 +#define CSR_USB_IN_DATA_DATA_SIZE 8 +#define CSR_USB_IN_CTRL_ADDR 0xe0004828L +#define CSR_USB_IN_CTRL_SIZE 1 +static inline unsigned char usb_in_ctrl_read(void) { + unsigned char r = csr_readl(0xe0004828L); + return r; +} +static inline void usb_in_ctrl_write(unsigned char value) { + csr_writel(value, 0xe0004828L); +} #define CSR_USB_IN_CTRL_EPNO_OFFSET 0 #define CSR_USB_IN_CTRL_EPNO_SIZE 4 #define CSR_USB_IN_CTRL_RESET_OFFSET 5 #define CSR_USB_IN_CTRL_RESET_SIZE 1 #define CSR_USB_IN_CTRL_STALL_OFFSET 6 #define CSR_USB_IN_CTRL_STALL_SIZE 1 -#define CSR_USB_IN_STATUS_ADDR 0xe0004828L +#define CSR_USB_IN_STATUS_ADDR 0xe000482cL #define CSR_USB_IN_STATUS_SIZE 1 static inline unsigned char usb_in_status_read(void) { - unsigned char r = csr_readl(0xe0004828L); + unsigned char r = csr_readl(0xe000482cL); return r; } #define CSR_USB_IN_STATUS_IDLE_OFFSET 0 @@ -464,49 +478,49 @@ static inline unsigned char usb_in_status_read(void) { #define CSR_USB_IN_STATUS_HAVE_SIZE 1 #define CSR_USB_IN_STATUS_PEND_OFFSET 5 #define CSR_USB_IN_STATUS_PEND_SIZE 1 -#define CSR_USB_IN_EV_STATUS_ADDR 0xe000482cL +#define CSR_USB_IN_EV_STATUS_ADDR 0xe0004830L #define CSR_USB_IN_EV_STATUS_SIZE 1 static inline unsigned char usb_in_ev_status_read(void) { - unsigned char r = csr_readl(0xe000482cL); - return r; -} -static inline void usb_in_ev_status_write(unsigned char value) { - csr_writel(value, 0xe000482cL); -} -#define CSR_USB_IN_EV_PENDING_ADDR 0xe0004830L -#define CSR_USB_IN_EV_PENDING_SIZE 1 -static inline unsigned char usb_in_ev_pending_read(void) { unsigned char r = csr_readl(0xe0004830L); return r; } -static inline void usb_in_ev_pending_write(unsigned char value) { +static inline void usb_in_ev_status_write(unsigned char value) { csr_writel(value, 0xe0004830L); } -#define CSR_USB_IN_EV_ENABLE_ADDR 0xe0004834L -#define CSR_USB_IN_EV_ENABLE_SIZE 1 -static inline unsigned char usb_in_ev_enable_read(void) { +#define CSR_USB_IN_EV_PENDING_ADDR 0xe0004834L +#define CSR_USB_IN_EV_PENDING_SIZE 1 +static inline unsigned char usb_in_ev_pending_read(void) { unsigned char r = csr_readl(0xe0004834L); return r; } -static inline void usb_in_ev_enable_write(unsigned char value) { +static inline void usb_in_ev_pending_write(unsigned char value) { csr_writel(value, 0xe0004834L); } -#define CSR_USB_OUT_DATA_ADDR 0xe0004838L +#define CSR_USB_IN_EV_ENABLE_ADDR 0xe0004838L +#define CSR_USB_IN_EV_ENABLE_SIZE 1 +static inline unsigned char usb_in_ev_enable_read(void) { + unsigned char r = csr_readl(0xe0004838L); + return r; +} +static inline void usb_in_ev_enable_write(unsigned char value) { + csr_writel(value, 0xe0004838L); +} +#define CSR_USB_OUT_DATA_ADDR 0xe000483cL #define CSR_USB_OUT_DATA_SIZE 1 static inline unsigned char usb_out_data_read(void) { - unsigned char r = csr_readl(0xe0004838L); + unsigned char r = csr_readl(0xe000483cL); return r; } #define CSR_USB_OUT_DATA_DATA_OFFSET 0 #define CSR_USB_OUT_DATA_DATA_SIZE 8 -#define CSR_USB_OUT_CTRL_ADDR 0xe000483cL +#define CSR_USB_OUT_CTRL_ADDR 0xe0004840L #define CSR_USB_OUT_CTRL_SIZE 1 static inline unsigned char usb_out_ctrl_read(void) { - unsigned char r = csr_readl(0xe000483cL); + unsigned char r = csr_readl(0xe0004840L); return r; } static inline void usb_out_ctrl_write(unsigned char value) { - csr_writel(value, 0xe000483cL); + csr_writel(value, 0xe0004840L); } #define CSR_USB_OUT_CTRL_EPNO_OFFSET 0 #define CSR_USB_OUT_CTRL_EPNO_SIZE 4 @@ -516,10 +530,10 @@ static inline void usb_out_ctrl_write(unsigned char value) { #define CSR_USB_OUT_CTRL_RESET_SIZE 1 #define CSR_USB_OUT_CTRL_STALL_OFFSET 6 #define CSR_USB_OUT_CTRL_STALL_SIZE 1 -#define CSR_USB_OUT_STATUS_ADDR 0xe0004840L +#define CSR_USB_OUT_STATUS_ADDR 0xe0004844L #define CSR_USB_OUT_STATUS_SIZE 1 static inline unsigned char usb_out_status_read(void) { - unsigned char r = csr_readl(0xe0004840L); + unsigned char r = csr_readl(0xe0004844L); return r; } #define CSR_USB_OUT_STATUS_EPNO_OFFSET 0 @@ -528,43 +542,43 @@ static inline unsigned char usb_out_status_read(void) { #define CSR_USB_OUT_STATUS_HAVE_SIZE 1 #define CSR_USB_OUT_STATUS_PEND_OFFSET 5 #define CSR_USB_OUT_STATUS_PEND_SIZE 1 -#define CSR_USB_OUT_EV_STATUS_ADDR 0xe0004844L +#define CSR_USB_OUT_EV_STATUS_ADDR 0xe0004848L #define CSR_USB_OUT_EV_STATUS_SIZE 1 static inline unsigned char usb_out_ev_status_read(void) { - unsigned char r = csr_readl(0xe0004844L); - return r; -} -static inline void usb_out_ev_status_write(unsigned char value) { - csr_writel(value, 0xe0004844L); -} -#define CSR_USB_OUT_EV_PENDING_ADDR 0xe0004848L -#define CSR_USB_OUT_EV_PENDING_SIZE 1 -static inline unsigned char usb_out_ev_pending_read(void) { unsigned char r = csr_readl(0xe0004848L); return r; } -static inline void usb_out_ev_pending_write(unsigned char value) { +static inline void usb_out_ev_status_write(unsigned char value) { csr_writel(value, 0xe0004848L); } -#define CSR_USB_OUT_EV_ENABLE_ADDR 0xe000484cL -#define CSR_USB_OUT_EV_ENABLE_SIZE 1 -static inline unsigned char usb_out_ev_enable_read(void) { +#define CSR_USB_OUT_EV_PENDING_ADDR 0xe000484cL +#define CSR_USB_OUT_EV_PENDING_SIZE 1 +static inline unsigned char usb_out_ev_pending_read(void) { unsigned char r = csr_readl(0xe000484cL); return r; } -static inline void usb_out_ev_enable_write(unsigned char value) { +static inline void usb_out_ev_pending_write(unsigned char value) { csr_writel(value, 0xe000484cL); } -#define CSR_USB_OUT_ENABLE_STATUS_ADDR 0xe0004850L -#define CSR_USB_OUT_ENABLE_STATUS_SIZE 1 -static inline unsigned char usb_out_enable_status_read(void) { +#define CSR_USB_OUT_EV_ENABLE_ADDR 0xe0004850L +#define CSR_USB_OUT_EV_ENABLE_SIZE 1 +static inline unsigned char usb_out_ev_enable_read(void) { unsigned char r = csr_readl(0xe0004850L); return r; } -#define CSR_USB_OUT_STALL_STATUS_ADDR 0xe0004854L +static inline void usb_out_ev_enable_write(unsigned char value) { + csr_writel(value, 0xe0004850L); +} +#define CSR_USB_OUT_ENABLE_STATUS_ADDR 0xe0004854L +#define CSR_USB_OUT_ENABLE_STATUS_SIZE 1 +static inline unsigned char usb_out_enable_status_read(void) { + unsigned char r = csr_readl(0xe0004854L); + return r; +} +#define CSR_USB_OUT_STALL_STATUS_ADDR 0xe0004858L #define CSR_USB_OUT_STALL_STATUS_SIZE 1 static inline unsigned char usb_out_stall_status_read(void) { - unsigned char r = csr_readl(0xe0004854L); + unsigned char r = csr_readl(0xe0004858L); return r; } From 729c8d073ce9df2bdf5d1c94a5ff63b2ffc2f48b Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 1 Nov 2019 12:31:17 +0800 Subject: [PATCH 16/27] fomu: dcd_fomu: add next_ev support Now that we have the `USB_NEXT_EV` register, take advantage of it to work around issue #207. Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 206 ++++++++++++++++++++--------- 1 file changed, 144 insertions(+), 62 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index 12add4c85..29bd7d485 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -29,7 +29,6 @@ #endif #include "tusb_option.h" - // #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) #if 1 @@ -41,6 +40,30 @@ void fomu_error(uint32_t line); void mputs(const char *str); void mputln(const char *str); +struct usb_log { + uint8_t ep_num; + uint8_t size; + uint8_t data[66]; +}; +__attribute__((used)) +struct usb_log usb_log[128]; +__attribute__((used)) +uint8_t usb_log_offset; + +struct xfer_log { + uint8_t ep_num; + uint16_t size; +}; +__attribute__((used)) +struct xfer_log xfer_log[64]; +__attribute__((used)) +uint8_t xfer_log_offset; + +__attribute__((used)) +struct xfer_log queue_log[64]; +__attribute__((used)) +uint8_t queue_log_offset; + static uint8_t last_address; //--------------------------------------------------------------------+ @@ -65,6 +88,7 @@ __attribute__((used)) uint8_t volatile * last_tx_buffer; __attribute__((used)) volatile uint8_t last_tx_ep; uint8_t setup_packet_bfr[10]; #endif + //--------------------------------------------------------------------+ // PIPE HELPER //--------------------------------------------------------------------+ @@ -81,13 +105,36 @@ static bool advance_tx_ep(void) { return true; } +void xfer_log_append(uint8_t ep_num, uint16_t sz) { + xfer_log[xfer_log_offset].ep_num = ep_num; + xfer_log[xfer_log_offset].size = sz; + xfer_log_offset++; + if (xfer_log_offset > sizeof(xfer_log)/sizeof(*xfer_log)) + xfer_log_offset = 0; +} + +void queue_log_append(uint8_t ep_num, uint16_t sz) { + queue_log[queue_log_offset].ep_num = ep_num; + queue_log[queue_log_offset].size = sz; + queue_log_offset++; + if (queue_log_offset > sizeof(queue_log)/sizeof(*queue_log)) + queue_log_offset = 0; +} + static void tx_more_data(void) { // Send more data uint8_t added_bytes; for (added_bytes = 0; (added_bytes < EP_SIZE) && (tx_buffer_offset[tx_ep] < tx_buffer_max[tx_ep]); added_bytes++) { + usb_log[usb_log_offset].data[added_bytes] = tx_buffer[tx_ep][tx_buffer_offset[tx_ep]]; usb_in_data_write(tx_buffer[tx_ep][tx_buffer_offset[tx_ep]++]); } + usb_log[usb_log_offset].ep_num = tu_edpt_addr(tx_ep, TUSB_DIR_IN); + usb_log[usb_log_offset].size = added_bytes; + usb_log_offset++; + if (usb_log_offset > sizeof(usb_log)/sizeof(*usb_log)) + usb_log_offset = 0; + // Updating the epno queues the data usb_in_ctrl_write(tx_ep & 0xf); } @@ -122,6 +169,7 @@ static void process_tx(void) { tx_active = false; if ((xferred_bytes == 13) && (tx_buffer_max[tx_ep] == 512)) fomu_error(__LINE__); + xfer_log_append(tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes); dcd_event_xfer_complete(0, tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes, XFER_RESULT_SUCCESS, true); if (!tx_active) return; @@ -158,12 +206,19 @@ static void process_rx(void) { if (current_offset > rx_buffer_max[rx_ep]) fomu_error(__LINE__); #endif + usb_log[usb_log_offset].ep_num = tu_edpt_addr(rx_ep, TUSB_DIR_OUT); + usb_log[usb_log_offset].size = 0; while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) { uint8_t c = usb_out_data_read(); total_read++; - if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) + if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) { + usb_log[usb_log_offset].data[usb_log[usb_log_offset].size++] = c; rx_buffer[rx_ep][current_offset++] = c; + } } + usb_log_offset++; + if (usb_log_offset > sizeof(usb_log)/sizeof(*usb_log)) + usb_log_offset = 0; #if DEBUG if (total_read > 66) fomu_error(__LINE__); @@ -202,6 +257,7 @@ static void process_rx(void) { } } #endif + xfer_log_append(tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len); dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, true); } else { @@ -395,6 +451,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t ; dcd_int_disable(0); + queue_log_append(ep_addr, total_bytes); if (total_bytes == 499) asm("ebreak"); // If a reset happens while we're waiting, abort the transfer @@ -422,8 +479,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t while (rx_buffer[ep_num] != NULL) ; - dcd_int_disable(0); TU_ASSERT(rx_buffer[ep_num] == NULL); + dcd_int_disable(0); + queue_log_append(ep_addr, total_bytes); rx_buffer[ep_num] = buffer; rx_buffer_offset[ep_num] = 0; rx_buffer_max[ep_num] = total_bytes; @@ -450,83 +508,107 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t // ISR //--------------------------------------------------------------------+ -void hal_dcd_isr(uint8_t rhport) +static void handle_out(void) +{ + // An "OUT" transaction just completed so we have new data. + // (But only if we can accept the data) +#if DEBUG + if (!usb_out_ev_pending_read()) + fomu_error(__LINE__); + if (!usb_out_ev_enable_read()) + fomu_error(__LINE__); +#endif + process_rx(); +} + +static void handle_in(void) +{ +#if DEBUG + if (!usb_in_ev_pending_read()) + fomu_error(__LINE__); + if (!usb_in_ev_enable_read()) + fomu_error(__LINE__); +#endif + usb_in_ev_pending_write(usb_in_ev_pending_read()); + process_tx(); +} + +static void handle_reset(void) { uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); - uint8_t in_pending = usb_in_ev_pending_read() & usb_in_ev_enable_read(); - uint8_t out_pending = usb_out_ev_pending_read() & usb_out_ev_enable_read(); -#if !DEBUG - uint8_t setup_packet_bfr[10]; -#endif - usb_setup_ev_pending_write(setup_pending); + if (!(setup_pending & 2)) + fomu_error(__LINE__); + usb_setup_ev_pending_write(2); // This event means a bus reset occurred. Reset everything, and // abandon any further processing. - if (setup_pending & 2) { - dcd_reset(); - return; - } + dcd_reset(); +} - // An "IN" transaction just completed. - // Note that due to the way tinyusb's callback system is implemented, - // we must handle IN and OUT packets before we handle SETUP packets. - // This ensures that any responses to SETUP packets aren't overwritten. - // For example, oftentimes a host will request part of a descriptor - // to begin with, then make a subsequent request. If we don't handle - // the IN packets first, then the second request will be truncated. - if (in_pending) { -#if DEBUG - if (!usb_in_ev_enable_read()) - fomu_error(__LINE__); +static void handle_setup(void) +{ +#if !DEBUG + uint8_t setup_packet_bfr[10]; #endif - usb_in_ev_pending_write(in_pending); - process_tx(); - } - // An "OUT" transaction just completed so we have new data. - // (But only if we can accept the data) - // if (out_pending) { - if (out_pending) { -#if DEBUG - if (!usb_out_ev_enable_read()) - fomu_error(__LINE__); -#endif - process_rx(); - } + uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); + if (!(setup_pending & 1)) + fomu_error(__LINE__); // We got a SETUP packet. Copy it to the setup buffer and clear // the "pending" bit. - if (setup_pending & 1) { - // Setup packets are always 8 bytes, plus two bytes of crc16. - uint32_t setup_length = 0; + // Setup packets are always 8 bytes, plus two bytes of crc16. + uint32_t setup_length = 0; #if DEBUG - if (!(usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET))) - fomu_error(__LINE__); + if (!(usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET))) + fomu_error(__LINE__); #endif - while (usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)) { - uint8_t c = usb_setup_data_read(); - if (setup_length < sizeof(setup_packet_bfr)) - setup_packet_bfr[setup_length] = c; - setup_length++; - } + while (usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)) { + uint8_t c = usb_setup_data_read(); + if (setup_length < sizeof(setup_packet_bfr)) + setup_packet_bfr[setup_length] = c; + setup_length++; + } - // If we have 10 bytes, that's a full SETUP packet plus CRC16. - // Otherwise, it was an RX error. - if (setup_length == 10) { - dcd_event_setup_received(rhport, setup_packet_bfr, true); - // Acknowledge the packet, so long as it isn't a SET_ADDRESS - // packet. If it is, leave it unacknowledged and we'll do this - // in the `dcd_set_address` function instead. - // if (!((setup_packet_bfr[0] == 0x00) && (setup_packet_bfr[1] == 0x05))) - usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_ACK_OFFSET); - } + // If we have 10 bytes, that's a full SETUP packet plus CRC16. + // Otherwise, it was an RX error. + if (setup_length == 10) { + dcd_event_setup_received(0, setup_packet_bfr, true); + // Acknowledge the packet, so long as it isn't a SET_ADDRESS + // packet. If it is, leave it unacknowledged and we'll do this + // in the `dcd_set_address` function instead. + // if (!((setup_packet_bfr[0] == 0x00) && (setup_packet_bfr[1] == 0x05))) + usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_ACK_OFFSET); + } #if DEBUG - else { - fomu_error(__LINE__); - } + else { + fomu_error(__LINE__); + } #endif + + usb_setup_ev_pending_write(1); +} +void hal_dcd_isr(uint8_t rhport) +{ + (void)rhport; + uint8_t next_ev; + while ((next_ev = usb_next_ev_read())) { + switch (next_ev) { + case 1 << CSR_USB_NEXT_EV_IN_OFFSET: + handle_in(); + break; + case 1 << CSR_USB_NEXT_EV_OUT_OFFSET: + handle_out(); + break; + case 1 << CSR_USB_NEXT_EV_SETUP_OFFSET: + handle_setup(); + break; + case 1 << CSR_USB_NEXT_EV_RESET_OFFSET: + handle_reset(); + break; + } } } From 1882a87212859e352502bddaccf973d2fd08ad09 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 1 Nov 2019 16:57:39 +0800 Subject: [PATCH 17/27] fomu: remove reference to SETUP_CTRL.ACK THis bit isn't used anymore, so remove it. Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index 29bd7d485..a77f548c5 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -576,11 +576,6 @@ static void handle_setup(void) // Otherwise, it was an RX error. if (setup_length == 10) { dcd_event_setup_received(0, setup_packet_bfr, true); - // Acknowledge the packet, so long as it isn't a SET_ADDRESS - // packet. If it is, leave it unacknowledged and we'll do this - // in the `dcd_set_address` function instead. - // if (!((setup_packet_bfr[0] == 0x00) && (setup_packet_bfr[1] == 0x05))) - usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_ACK_OFFSET); } #if DEBUG else { From f087cb1580d7167da54698a9c5d5d4d978084dac Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 12 Nov 2019 20:21:06 -0800 Subject: [PATCH 18/27] fomu: crt0: minor text refactor Signed-off-by: Sean Cross --- hw/bsp/fomu/crt0-vexriscv.S | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/hw/bsp/fomu/crt0-vexriscv.S b/hw/bsp/fomu/crt0-vexriscv.S index 46dca5577..d80a29e06 100644 --- a/hw/bsp/fomu/crt0-vexriscv.S +++ b/hw/bsp/fomu/crt0-vexriscv.S @@ -6,13 +6,6 @@ _start: j crt_init - nop - nop - nop - nop - nop - nop - nop .section .text .global trap_entry @@ -53,9 +46,8 @@ trap_entry: lw x31, 0*4(sp) addi sp,sp,16*4 mret - .text - +.text crt_init: la sp, _estack - 4 la a0, trap_entry @@ -87,5 +79,5 @@ bss_done: csrw mie,a0 call main -infinit_loop: - j infinit_loop +infinite_loop: + j infinite_loop From 25d5628063846d5e4601607afc72e7ef3cbbd1a9 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 12 Nov 2019 20:21:17 -0800 Subject: [PATCH 19/27] fomu: csr: sync csr Signed-off-by: Sean Cross --- hw/bsp/fomu/include/csr.h | 130 ++++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 46 deletions(-) diff --git a/hw/bsp/fomu/include/csr.h b/hw/bsp/fomu/include/csr.h index 01ef754b2..a2f60ecf6 100644 --- a/hw/bsp/fomu/include/csr.h +++ b/hw/bsp/fomu/include/csr.h @@ -1,5 +1,5 @@ //-------------------------------------------------------------------------------- -// Auto-generated by Migen (f4fcd10) & LiteX (1425a68d) on 2019-11-01 12:04:21 +// Auto-generated by Migen (f4fcd10) & LiteX (1425a68d) on 2019-11-12 19:41:49 //-------------------------------------------------------------------------------- #ifndef __GENERATED_CSR_H #define __GENERATED_CSR_H @@ -57,41 +57,6 @@ static inline unsigned int ctrl_bus_errors_read(void) { return r; } -/* lxspi */ -#define CSR_LXSPI_BASE 0xe0007800L -#define CSR_LXSPI_BITBANG_ADDR 0xe0007800L -#define CSR_LXSPI_BITBANG_SIZE 1 -static inline unsigned char lxspi_bitbang_read(void) { - unsigned char r = csr_readl(0xe0007800L); - return r; -} -static inline void lxspi_bitbang_write(unsigned char value) { - csr_writel(value, 0xe0007800L); -} -#define CSR_LXSPI_BITBANG_MOSI_OFFSET 0 -#define CSR_LXSPI_BITBANG_MOSI_SIZE 1 -#define CSR_LXSPI_BITBANG_CLK_OFFSET 1 -#define CSR_LXSPI_BITBANG_CLK_SIZE 1 -#define CSR_LXSPI_BITBANG_CS_N_OFFSET 2 -#define CSR_LXSPI_BITBANG_CS_N_SIZE 1 -#define CSR_LXSPI_BITBANG_DIR_OFFSET 3 -#define CSR_LXSPI_BITBANG_DIR_SIZE 1 -#define CSR_LXSPI_MISO_ADDR 0xe0007804L -#define CSR_LXSPI_MISO_SIZE 1 -static inline unsigned char lxspi_miso_read(void) { - unsigned char r = csr_readl(0xe0007804L); - return r; -} -#define CSR_LXSPI_BITBANG_EN_ADDR 0xe0007808L -#define CSR_LXSPI_BITBANG_EN_SIZE 1 -static inline unsigned char lxspi_bitbang_en_read(void) { - unsigned char r = csr_readl(0xe0007808L); - return r; -} -static inline void lxspi_bitbang_en_write(unsigned char value) { - csr_writel(value, 0xe0007808L); -} - /* messible */ #define CSR_MESSIBLE_BASE 0xe0008000L #define CSR_MESSIBLE_IN_ADDR 0xe0008000L @@ -120,6 +85,89 @@ static inline unsigned char messible_status_read(void) { #define CSR_MESSIBLE_STATUS_HAVE_OFFSET 1 #define CSR_MESSIBLE_STATUS_HAVE_SIZE 1 +/* picorvspi */ +#define CSR_PICORVSPI_BASE 0xe0005000L +#define CSR_PICORVSPI_CFG1_ADDR 0xe0005000L +#define CSR_PICORVSPI_CFG1_SIZE 1 +static inline unsigned char picorvspi_cfg1_read(void) { + unsigned char r = csr_readl(0xe0005000L); + return r; +} +static inline void picorvspi_cfg1_write(unsigned char value) { + csr_writel(value, 0xe0005000L); +} +#define CSR_PICORVSPI_CFG1_BB_OUT_OFFSET 0 +#define CSR_PICORVSPI_CFG1_BB_OUT_SIZE 4 +#define CSR_PICORVSPI_CFG1_BB_CLK_OFFSET 4 +#define CSR_PICORVSPI_CFG1_BB_CLK_SIZE 1 +#define CSR_PICORVSPI_CFG1_BB_CS_OFFSET 5 +#define CSR_PICORVSPI_CFG1_BB_CS_SIZE 1 +#define CSR_PICORVSPI_CFG2_ADDR 0xe0005004L +#define CSR_PICORVSPI_CFG2_SIZE 1 +static inline unsigned char picorvspi_cfg2_read(void) { + unsigned char r = csr_readl(0xe0005004L); + return r; +} +static inline void picorvspi_cfg2_write(unsigned char value) { + csr_writel(value, 0xe0005004L); +} +#define CSR_PICORVSPI_CFG2_BB_OE_OFFSET 0 +#define CSR_PICORVSPI_CFG2_BB_OE_SIZE 4 +#define CSR_PICORVSPI_CFG3_ADDR 0xe0005008L +#define CSR_PICORVSPI_CFG3_SIZE 1 +static inline unsigned char picorvspi_cfg3_read(void) { + unsigned char r = csr_readl(0xe0005008L); + return r; +} +static inline void picorvspi_cfg3_write(unsigned char value) { + csr_writel(value, 0xe0005008L); +} +#define CSR_PICORVSPI_CFG3_RLAT_OFFSET 0 +#define CSR_PICORVSPI_CFG3_RLAT_SIZE 4 +#define CSR_PICORVSPI_CFG3_CRM_OFFSET 4 +#define CSR_PICORVSPI_CFG3_CRM_SIZE 1 +#define CSR_PICORVSPI_CFG3_QSPI_OFFSET 5 +#define CSR_PICORVSPI_CFG3_QSPI_SIZE 1 +#define CSR_PICORVSPI_CFG3_DDR_OFFSET 6 +#define CSR_PICORVSPI_CFG3_DDR_SIZE 1 +#define CSR_PICORVSPI_CFG4_ADDR 0xe000500cL +#define CSR_PICORVSPI_CFG4_SIZE 1 +static inline unsigned char picorvspi_cfg4_read(void) { + unsigned char r = csr_readl(0xe000500cL); + return r; +} +static inline void picorvspi_cfg4_write(unsigned char value) { + csr_writel(value, 0xe000500cL); +} +#define CSR_PICORVSPI_CFG4_MEMIO_OFFSET 7 +#define CSR_PICORVSPI_CFG4_MEMIO_SIZE 1 +#define CSR_PICORVSPI_STAT1_ADDR 0xe0005010L +#define CSR_PICORVSPI_STAT1_SIZE 1 +static inline unsigned char picorvspi_stat1_read(void) { + unsigned char r = csr_readl(0xe0005010L); + return r; +} +#define CSR_PICORVSPI_STAT1_BB_IN_OFFSET 0 +#define CSR_PICORVSPI_STAT1_BB_IN_SIZE 4 +#define CSR_PICORVSPI_STAT2_ADDR 0xe0005014L +#define CSR_PICORVSPI_STAT2_SIZE 1 +static inline unsigned char picorvspi_stat2_read(void) { + unsigned char r = csr_readl(0xe0005014L); + return r; +} +#define CSR_PICORVSPI_STAT3_ADDR 0xe0005018L +#define CSR_PICORVSPI_STAT3_SIZE 1 +static inline unsigned char picorvspi_stat3_read(void) { + unsigned char r = csr_readl(0xe0005018L); + return r; +} +#define CSR_PICORVSPI_STAT4_ADDR 0xe000501cL +#define CSR_PICORVSPI_STAT4_SIZE 1 +static inline unsigned char picorvspi_stat4_read(void) { + unsigned char r = csr_readl(0xe000501cL); + return r; +} + /* reboot */ #define CSR_REBOOT_BASE 0xe0006000L #define CSR_REBOOT_CTRL_ADDR 0xe0006000L @@ -393,8 +441,6 @@ static inline unsigned char usb_setup_ctrl_read(void) { static inline void usb_setup_ctrl_write(unsigned char value) { csr_writel(value, 0xe0004810L); } -#define CSR_USB_SETUP_CTRL_ACK_OFFSET 1 -#define CSR_USB_SETUP_CTRL_ACK_SIZE 1 #define CSR_USB_SETUP_CTRL_RESET_OFFSET 5 #define CSR_USB_SETUP_CTRL_RESET_SIZE 1 #define CSR_USB_SETUP_STATUS_ADDR 0xe0004814L @@ -660,14 +706,6 @@ static inline int timer0_interrupt_read(void) { static inline int usb_interrupt_read(void) { return 3; } -#define SPI_BOOT 1 -static inline int spi_boot_read(void) { - return 1; -} -#define SPI_ENTRYPOINT 536977408 -static inline int spi_entrypoint_read(void) { - return 536977408; -} #define CONFIG_BITSTREAM_SYNC_HEADER1 2123999870 static inline int config_bitstream_sync_header1_read(void) { return 2123999870; From 3292920933a35c98ecaf88062020cceb6a9bd5c2 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 12 Nov 2019 20:22:00 -0800 Subject: [PATCH 20/27] fomu: first stable working commit This appears to be stable, and works well. Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 50 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index a77f548c5..49ad7d4b5 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -109,7 +109,7 @@ void xfer_log_append(uint8_t ep_num, uint16_t sz) { xfer_log[xfer_log_offset].ep_num = ep_num; xfer_log[xfer_log_offset].size = sz; xfer_log_offset++; - if (xfer_log_offset > sizeof(xfer_log)/sizeof(*xfer_log)) + if (xfer_log_offset >= sizeof(xfer_log)/sizeof(*xfer_log)) xfer_log_offset = 0; } @@ -117,7 +117,7 @@ void queue_log_append(uint8_t ep_num, uint16_t sz) { queue_log[queue_log_offset].ep_num = ep_num; queue_log[queue_log_offset].size = sz; queue_log_offset++; - if (queue_log_offset > sizeof(queue_log)/sizeof(*queue_log)) + if (queue_log_offset >= sizeof(queue_log)/sizeof(*queue_log)) queue_log_offset = 0; } @@ -132,7 +132,7 @@ static void tx_more_data(void) { usb_log[usb_log_offset].ep_num = tu_edpt_addr(tx_ep, TUSB_DIR_IN); usb_log[usb_log_offset].size = added_bytes; usb_log_offset++; - if (usb_log_offset > sizeof(usb_log)/sizeof(*usb_log)) + if (usb_log_offset >= sizeof(usb_log)/sizeof(*usb_log)) usb_log_offset = 0; // Updating the epno queues the data @@ -167,8 +167,6 @@ static void process_tx(void) { if (!advance_tx_ep()) tx_active = false; - if ((xferred_bytes == 13) && (tx_buffer_max[tx_ep] == 512)) - fomu_error(__LINE__); xfer_log_append(tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes); dcd_event_xfer_complete(0, tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes, XFER_RESULT_SUCCESS, true); if (!tx_active) @@ -213,17 +211,19 @@ static void process_rx(void) { total_read++; if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) { usb_log[usb_log_offset].data[usb_log[usb_log_offset].size++] = c; - rx_buffer[rx_ep][current_offset++] = c; + if (rx_buffer[rx_ep] != (volatile uint8_t *)0xffffffff) + rx_buffer[rx_ep][current_offset++] = c; } } usb_log_offset++; - if (usb_log_offset > sizeof(usb_log)/sizeof(*usb_log)) + if (usb_log_offset >= sizeof(usb_log)/sizeof(*usb_log)) usb_log_offset = 0; #if DEBUG if (total_read > 66) fomu_error(__LINE__); if (total_read < 2) - fomu_error(__LINE__); + total_read = 2; + // fomu_error(__LINE__); #endif // Strip off the CRC16 @@ -232,7 +232,11 @@ static void process_rx(void) { rx_buffer_offset[rx_ep] = rx_buffer_max[rx_ep]; // If there's no more data, complete the transfer to tinyusb - if (rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep]) { + if ((rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep]) + // ZLP with less than the total amount of data + || ((total_read == 2) && ((rx_buffer_offset[rx_ep] & 63) == 0)) + // Short read, but not a full packet + || (((rx_buffer_offset[rx_ep] & 63) != 0) && (total_read < 66))) { #if DEBUG if (rx_buffer[rx_ep] == NULL) fomu_error(__LINE__); @@ -249,10 +253,10 @@ static void process_rx(void) { int i; for (i = 0; i < 16; i++) { if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { - // uint8_t new_status = usb_out_status_read(); - // // Another IRQ came in while we were processing, so ignore this endpoint. - // if ((new_status & 0x20) && ((new_status & 0xf) == i)) - // continue; + uint8_t new_status = usb_out_status_read(); + // Another IRQ came in while we were processing, so ignore this endpoint. + if ((new_status & 0x20) && ((new_status & 0xf) == i)) + continue; fomu_error(__LINE__); } } @@ -280,8 +284,8 @@ static void dcd_reset(void) usb_in_ev_enable_write(0); usb_out_ev_enable_write(0); - if (last_address) - asm("ebreak"); + // if (last_address) + // asm("ebreak"); usb_address_write(0); // Reset all three FIFO handlers @@ -300,9 +304,9 @@ static void dcd_reset(void) tx_active = false; // Enable all event handlers and clear their contents - usb_setup_ev_pending_write(-1); - usb_in_ev_pending_write(-1); - usb_out_ev_pending_write(-1); + usb_setup_ev_pending_write(0xff); + usb_in_ev_pending_write(0xff); + usb_out_ev_pending_write(0xff); usb_in_ev_enable_write(1); usb_out_ev_enable_write(1); usb_setup_ev_enable_write(3); @@ -535,9 +539,9 @@ static void handle_in(void) static void handle_reset(void) { - uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); - if (!(setup_pending & 2)) - fomu_error(__LINE__); + // uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); + // if (!(setup_pending & 2)) + // fomu_error(__LINE__); usb_setup_ev_pending_write(2); // This event means a bus reset occurred. Reset everything, and @@ -592,8 +596,8 @@ void hal_dcd_isr(uint8_t rhport) while ((next_ev = usb_next_ev_read())) { switch (next_ev) { case 1 << CSR_USB_NEXT_EV_IN_OFFSET: - handle_in(); - break; + handle_in(); + break; case 1 << CSR_USB_NEXT_EV_OUT_OFFSET: handle_out(); break; From e05e9801e46e19bc541c1ca7d6a2cc37902f6b2a Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 12 Nov 2019 20:55:48 -0800 Subject: [PATCH 21/27] fomu: gate debug/logging features This gates the majority of the debug and logging features behind testable macros. Signed-off-by: Sean Cross --- src/portable/foosn/fomu/dcd_fomu.c | 80 +++++++++++++++++++----------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/foosn/fomu/dcd_fomu.c index 49ad7d4b5..ee79366e4 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/foosn/fomu/dcd_fomu.c @@ -25,21 +25,24 @@ */ #ifndef DEBUG -#define DEBUG 1 +#define DEBUG 0 #endif + +#ifndef LOG_USB +#define LOG_USB 0 +#endif + #include "tusb_option.h" -// #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) -#if 1 +#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) #include "device/dcd.h" #include "dcd_fomu.h" #include "csr.h" #include "irq.h" void fomu_error(uint32_t line); -void mputs(const char *str); -void mputln(const char *str); +#if LOG_USB struct usb_log { uint8_t ep_num; uint8_t size; @@ -63,8 +66,7 @@ __attribute__((used)) struct xfer_log queue_log[64]; __attribute__((used)) uint8_t queue_log_offset; - -static uint8_t last_address; +#endif //--------------------------------------------------------------------+ // SIE Command @@ -105,6 +107,7 @@ static bool advance_tx_ep(void) { return true; } +#if LOG_USB void xfer_log_append(uint8_t ep_num, uint16_t sz) { xfer_log[xfer_log_offset].ep_num = ep_num; xfer_log[xfer_log_offset].size = sz; @@ -120,20 +123,25 @@ void queue_log_append(uint8_t ep_num, uint16_t sz) { if (queue_log_offset >= sizeof(queue_log)/sizeof(*queue_log)) queue_log_offset = 0; } +#endif static void tx_more_data(void) { // Send more data uint8_t added_bytes; for (added_bytes = 0; (added_bytes < EP_SIZE) && (tx_buffer_offset[tx_ep] < tx_buffer_max[tx_ep]); added_bytes++) { +#if LOG_USB usb_log[usb_log_offset].data[added_bytes] = tx_buffer[tx_ep][tx_buffer_offset[tx_ep]]; +#endif usb_in_data_write(tx_buffer[tx_ep][tx_buffer_offset[tx_ep]++]); } +#if LOG_USB usb_log[usb_log_offset].ep_num = tu_edpt_addr(tx_ep, TUSB_DIR_IN); usb_log[usb_log_offset].size = added_bytes; usb_log_offset++; if (usb_log_offset >= sizeof(usb_log)/sizeof(*usb_log)) usb_log_offset = 0; +#endif // Updating the epno queues the data usb_in_ctrl_write(tx_ep & 0xf); @@ -167,7 +175,9 @@ static void process_tx(void) { if (!advance_tx_ep()) tx_active = false; +#if LOG_USB xfer_log_append(tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes); +#endif dcd_event_xfer_complete(0, tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes, XFER_RESULT_SUCCESS, true); if (!tx_active) return; @@ -201,23 +211,34 @@ static void process_rx(void) { uint32_t total_read = 0; uint32_t current_offset = rx_buffer_offset[rx_ep]; #if DEBUG + uint8_t test_buffer[256]; + memset(test_buffer, 0, sizeof(test_buffer)); if (current_offset > rx_buffer_max[rx_ep]) fomu_error(__LINE__); #endif +#if LOG_USB usb_log[usb_log_offset].ep_num = tu_edpt_addr(rx_ep, TUSB_DIR_OUT); usb_log[usb_log_offset].size = 0; +#endif while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) { uint8_t c = usb_out_data_read(); +#if DEBUG + test_buffer[total_read] = c; +#endif total_read++; if ((rx_buffer_offset[rx_ep] + current_offset) < rx_buffer_max[rx_ep]) { +#if LOG_USB usb_log[usb_log_offset].data[usb_log[usb_log_offset].size++] = c; +#endif if (rx_buffer[rx_ep] != (volatile uint8_t *)0xffffffff) rx_buffer[rx_ep][current_offset++] = c; } } +#if LOG_USB usb_log_offset++; if (usb_log_offset >= sizeof(usb_log)/sizeof(*usb_log)) usb_log_offset = 0; +#endif #if DEBUG if (total_read > 66) fomu_error(__LINE__); @@ -261,7 +282,9 @@ static void process_rx(void) { } } #endif +#if LOG_USB xfer_log_append(tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len); +#endif dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, true); } else { @@ -284,8 +307,6 @@ static void dcd_reset(void) usb_in_ev_enable_write(0); usb_out_ev_enable_write(0); - // if (last_address) - // asm("ebreak"); usb_address_write(0); // Reset all three FIFO handlers @@ -360,7 +381,6 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) // Activate the new address usb_address_write(dev_addr); - last_address = dev_addr; } // Called when the device received SET_CONFIG request, you can leave this @@ -407,8 +427,6 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; - if (tu_edpt_number(ep_addr) == 2) - fomu_error(__LINE__); if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { uint8_t enable = 0; @@ -455,9 +473,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t ; dcd_int_disable(0); +#if LOG_USB queue_log_append(ep_addr, total_bytes); - if (total_bytes == 499) - asm("ebreak"); +#endif // If a reset happens while we're waiting, abort the transfer if (previous_reset_count != reset_count) return true; @@ -485,24 +503,26 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t TU_ASSERT(rx_buffer[ep_num] == NULL); dcd_int_disable(0); +#if LOG_USB queue_log_append(ep_addr, total_bytes); +#endif rx_buffer[ep_num] = buffer; rx_buffer_offset[ep_num] = 0; rx_buffer_max[ep_num] = total_bytes; // Enable receiving on this particular endpoint usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | ep_num); -// #if DEBUG -// uint16_t ep_en_mask = usb_out_enable_status_read(); -// int i; -// for (i = 0; i < 16; i++) { -// if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { -// if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i) -// continue; -// fomu_error(__LINE__); -// } -// } -// #endif +#if DEBUG + uint16_t ep_en_mask = usb_out_enable_status_read(); + int i; + for (i = 0; i < 16; i++) { + if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) { + if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i) + continue; + fomu_error(__LINE__); + } + } +#endif dcd_int_enable(0); } return true; @@ -539,9 +559,11 @@ static void handle_in(void) static void handle_reset(void) { - // uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); - // if (!(setup_pending & 2)) - // fomu_error(__LINE__); +#if DEBUG + uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); + if (!(setup_pending & 2)) + fomu_error(__LINE__); +#endif usb_setup_ev_pending_write(2); // This event means a bus reset occurred. Reset everything, and @@ -555,9 +577,11 @@ static void handle_setup(void) uint8_t setup_packet_bfr[10]; #endif +#if DEBUG uint8_t setup_pending = usb_setup_ev_pending_read() & usb_setup_ev_enable_read(); if (!(setup_pending & 1)) fomu_error(__LINE__); +#endif // We got a SETUP packet. Copy it to the setup buffer and clear // the "pending" bit. From 8c5f02960b7d41f663b0c6063a0cc268ef8d2270 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 12 Nov 2019 21:11:46 -0800 Subject: [PATCH 22/27] valentyusb: rename from `foosn` While Fomu is produced by Foosn, the actual name of the hardware block is `valentyusb`. Rename the module to match that. Signed-off-by: Sean Cross --- hw/bsp/fomu/board.mk | 6 +- src/portable/foosn/fomu/dcd_fomu.h | 151 ------------------ .../eptri/dcd_eptri.c} | 4 +- src/portable/valentyusb/eptri/dcd_eptri.h | 39 +++++ .../eptri/hal_eptri.c} | 2 +- 5 files changed, 45 insertions(+), 157 deletions(-) delete mode 100644 src/portable/foosn/fomu/dcd_fomu.h rename src/portable/{foosn/fomu/dcd_fomu.c => valentyusb/eptri/dcd_eptri.c} (99%) create mode 100644 src/portable/valentyusb/eptri/dcd_eptri.h rename src/portable/{foosn/fomu/hal_fomu.c => valentyusb/eptri/hal_eptri.c} (96%) diff --git a/hw/bsp/fomu/board.mk b/hw/bsp/fomu/board.mk index 86f8df23f..cdcd63b28 100644 --- a/hw/bsp/fomu/board.mk +++ b/hw/bsp/fomu/board.mk @@ -2,7 +2,7 @@ CFLAGS += \ -march=rv32i \ -mabi=ilp32 \ -nostdlib \ - -DCFG_TUSB_MCU=OPT_MCU_FOMU_EPTRI + -DCFG_TUSB_MCU=OPT_MCU_VALENTYUSB_EPTRI MCU_DIR = hw/mcu/fomu BSP_DIR = hw/bsp/fomu @@ -21,8 +21,8 @@ INC += \ $(TOP)/$(BSP_DIR)/include # For TinyUSB port source -VENDOR = foosn -CHIP_FAMILY = fomu +VENDOR = valentyusb +CHIP_FAMILY = eptri # flash using dfu-util flash: $(BUILD)/$(BOARD)-firmware.dfu diff --git a/src/portable/foosn/fomu/dcd_fomu.h b/src/portable/foosn/fomu/dcd_fomu.h deleted file mode 100644 index 60bc1240f..000000000 --- a/src/portable/foosn/fomu/dcd_fomu.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * 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. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_DCD_FOMU_H_ -#define _TUSB_DCD_FOMU_H_ - -#include "common/tusb_common.h" -#ifdef __cplusplus - extern "C" { -#endif - -// //--------------------------------------------------------------------+ -// // Register Interface -// //--------------------------------------------------------------------+ - -// //------------- USB Interrupt USBIntSt -------------// -// //enum { -// // DCD_USB_REQ_LOW_PRIO_MASK = TU_BIT(0), -// // DCD_USB_REQ_HIGH_PRIO_MASK = TU_BIT(1), -// // DCD_USB_REQ_DMA_MASK = TU_BIT(2), -// // DCD_USB_REQ_NEED_CLOCK_MASK = TU_BIT(8), -// // DCD_USB_REQ_ENABLE_MASK = TU_BIT(31) -// //}; - -// //------------- Device Interrupt USBDevInt -------------// -// enum { -// DEV_INT_FRAME_MASK = TU_BIT(0), -// DEV_INT_ENDPOINT_FAST_MASK = TU_BIT(1), -// DEV_INT_ENDPOINT_SLOW_MASK = TU_BIT(2), -// DEV_INT_DEVICE_STATUS_MASK = TU_BIT(3), -// DEV_INT_COMMAND_CODE_EMPTY_MASK = TU_BIT(4), -// DEV_INT_COMMAND_DATA_FULL_MASK = TU_BIT(5), -// DEV_INT_RX_ENDPOINT_PACKET_MASK = TU_BIT(6), -// DEV_INT_TX_ENDPOINT_PACKET_MASK = TU_BIT(7), -// DEV_INT_ENDPOINT_REALIZED_MASK = TU_BIT(8), -// DEV_INT_ERROR_MASK = TU_BIT(9) -// }; - -// //------------- DMA Interrupt USBDMAInt-------------// -// enum { -// DMA_INT_END_OF_XFER_MASK = TU_BIT(0), -// DMA_INT_NEW_DD_REQUEST_MASK = TU_BIT(1), -// DMA_INT_ERROR_MASK = TU_BIT(2) -// }; - -// //------------- USBCtrl -------------// -// enum { -// USBCTRL_READ_ENABLE_MASK = TU_BIT(0), -// USBCTRL_WRITE_ENABLE_MASK = TU_BIT(1), -// }; - -// //------------- USBRxPLen -------------// -// enum { -// USBRXPLEN_PACKET_LENGTH_MASK = (TU_BIT(10)-1), -// USBRXPLEN_DATA_VALID_MASK = TU_BIT(10), -// USBRXPLEN_PACKET_READY_MASK = TU_BIT(11), -// }; - -// //------------- SIE Command Code -------------// -// typedef enum -// { -// SIE_CMDPHASE_WRITE = 1, -// SIE_CMDPHASE_READ = 2, -// SIE_CMDPHASE_COMMAND = 5 -// } sie_cmdphase_t; - -// enum { -// // device commands -// SIE_CMDCODE_SET_ADDRESS = 0xd0, -// SIE_CMDCODE_CONFIGURE_DEVICE = 0xd8, -// SIE_CMDCODE_SET_MODE = 0xf3, -// SIE_CMDCODE_READ_FRAME_NUMBER = 0xf5, -// SIE_CMDCODE_READ_TEST_REGISTER = 0xfd, -// SIE_CMDCODE_DEVICE_STATUS = 0xfe, -// SIE_CMDCODE_GET_ERROR = 0xff, -// SIE_CMDCODE_READ_ERROR_STATUS = 0xfb, - -// // endpoint commands -// SIE_CMDCODE_ENDPOINT_SELECT = 0x00, // + endpoint index -// SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT = 0x40, // + endpoint index, should use USBEpIntClr instead -// SIE_CMDCODE_ENDPOINT_SET_STATUS = 0x40, // + endpoint index -// SIE_CMDCODE_BUFFER_CLEAR = 0xf2, -// SIE_CMDCODE_BUFFER_VALIDATE = 0xfa -// }; - -// //------------- SIE Device Status (get/set from SIE_CMDCODE_DEVICE_STATUS) -------------// -// enum { -// SIE_DEV_STATUS_CONNECT_STATUS_MASK = TU_BIT(0), -// SIE_DEV_STATUS_CONNECT_CHANGE_MASK = TU_BIT(1), -// SIE_DEV_STATUS_SUSPEND_MASK = TU_BIT(2), -// SIE_DEV_STATUS_SUSPEND_CHANGE_MASK = TU_BIT(3), -// SIE_DEV_STATUS_RESET_MASK = TU_BIT(4) -// }; - -// //------------- SIE Select Endpoint Command -------------// -// enum { -// SIE_SELECT_ENDPOINT_FULL_EMPTY_MASK = TU_BIT(0), // 0: empty, 1 full. IN endpoint checks empty, OUT endpoint check full -// SIE_SELECT_ENDPOINT_STALL_MASK = TU_BIT(1), -// SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK = TU_BIT(2), // clear by SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT -// SIE_SELECT_ENDPOINT_PACKET_OVERWRITTEN_MASK = TU_BIT(3), // previous packet is overwritten by a SETUP packet -// SIE_SELECT_ENDPOINT_NAK_MASK = TU_BIT(4), // last packet response is NAK (auto clear by an ACK) -// SIE_SELECT_ENDPOINT_BUFFER1_FULL_MASK = TU_BIT(5), -// SIE_SELECT_ENDPOINT_BUFFER2_FULL_MASK = TU_BIT(6) -// }; - -// typedef enum -// { -// SIE_SET_ENDPOINT_STALLED_MASK = TU_BIT(0), -// SIE_SET_ENDPOINT_DISABLED_MASK = TU_BIT(5), -// SIE_SET_ENDPOINT_RATE_FEEDBACK_MASK = TU_BIT(6), -// SIE_SET_ENDPOINT_CONDITION_STALLED_MASK = TU_BIT(7), -// }sie_endpoint_set_status_mask_t; - -// //------------- DMA Descriptor Status -------------// -// enum { -// DD_STATUS_NOT_SERVICED = 0, -// DD_STATUS_BEING_SERVICED, -// DD_STATUS_NORMAL, -// DD_STATUS_DATA_UNDERUN, // short packet -// DD_STATUS_DATA_OVERRUN, -// DD_STATUS_SYSTEM_ERROR -// }; - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_DCD_FOMU_H_ */ diff --git a/src/portable/foosn/fomu/dcd_fomu.c b/src/portable/valentyusb/eptri/dcd_eptri.c similarity index 99% rename from src/portable/foosn/fomu/dcd_fomu.c rename to src/portable/valentyusb/eptri/dcd_eptri.c index ee79366e4..d7e1b8a9a 100644 --- a/src/portable/foosn/fomu/dcd_fomu.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -34,10 +34,10 @@ #include "tusb_option.h" -#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) +#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI) #include "device/dcd.h" -#include "dcd_fomu.h" +#include "dcd_eptri.h" #include "csr.h" #include "irq.h" void fomu_error(uint32_t line); diff --git a/src/portable/valentyusb/eptri/dcd_eptri.h b/src/portable/valentyusb/eptri/dcd_eptri.h new file mode 100644 index 000000000..0fa6ecc64 --- /dev/null +++ b/src/portable/valentyusb/eptri/dcd_eptri.h @@ -0,0 +1,39 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DCD_VALENTYUSB_EPTRI_H_ +#define _TUSB_DCD_VALENTYUSB_EPTRI_H_ + +#include "common/tusb_common.h" +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DCD_VALENTYUSB_EPTRI_H_ */ diff --git a/src/portable/foosn/fomu/hal_fomu.c b/src/portable/valentyusb/eptri/hal_eptri.c similarity index 96% rename from src/portable/foosn/fomu/hal_fomu.c rename to src/portable/valentyusb/eptri/hal_eptri.c index ebc0a1d93..72453affa 100644 --- a/src/portable/foosn/fomu/hal_fomu.c +++ b/src/portable/valentyusb/eptri/hal_eptri.c @@ -26,7 +26,7 @@ #include "common/tusb_common.h" -#if (CFG_TUSB_MCU == OPT_MCU_FOMU_EPTRI) +#if (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI) // No HAL-specific stuff here! From cc73990530f3cae083c47d17716edeff2b58ffb3 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 12 Nov 2019 21:12:31 -0800 Subject: [PATCH 23/27] tusb: rename `foosn` to `valentyusb` Use the name `valentyusb` as the vendor for the `valentyusb` project, rather than the manufacturer name of the Fomu device. This is because the `valentyusb` core can be used across multiple vendors, much like how other cores can be used across chip vendors. Signed-off-by: Sean Cross --- src/tusb_option.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tusb_option.h b/src/tusb_option.h index d2a9ad804..53b837f6d 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -70,7 +70,7 @@ #define OPT_MCU_CXD56 400 ///< SONY CXD56 -#define OPT_MCU_FOMU_EPTRI 600 ///< Fomu eptri config +#define OPT_MCU_VALENTYUSB_EPTRI 600 ///< Fomu eptri config /** @} */ From 737d437ab8d8159330cd4e08f639bd2cdac7d2f8 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 13 Nov 2019 09:22:18 -0800 Subject: [PATCH 24/27] travis: fetch xPack risc-v toolchain This toolchain seems popular in the embedded space, and is generally preferred over the upstream SiFive toolchain. It can produce both 32- and 64-bit binaries, so its prefix is riscv-none-embed-. Signed-off-by: Sean Cross --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 6dfc507fc..2413e4225 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,11 @@ install: - gem install ceedling before_script: + - wget -O /tmp/riscv-toolchain.tgz https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/download/v8.3.0-1.1/xpack-riscv-none-embed-gcc-8.3.0-1.1-linux-x64.tgz + - tar -xzf /tmp/riscv-toolchain.tgz + - export PATH=$PWD/xPacks/riscv-none-embed-gcc/8.3.0-1.1/bin:$PATH - arm-none-eabi-gcc --version + - riscv-none-embed-gcc --version script: # Build all examples From dce070ebe0ab95a8a87f5be2a0696ec58a749ab0 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 13 Nov 2019 09:26:00 -0800 Subject: [PATCH 25/27] examples: make: specify CROSS_COMPILE for fomu When BOARD=fomu, use the riscv cross-compiler. Otherwise, use the default arm compiler. This can be overridden by passing CROSS_COMIPLE on the command line. Note that there are now three common risc-v prefixes: - riscv32-unknown-elf- : Common for users who compile their own - riscv64-unknown-elf- : Upstream multiarch toolchain from SiFive - riscv-none-embed- : xPack embedded version of SiFive toolchain Here we assume users are using the `riscv-none-embed-` toolchain from xPack, because it appears to be growing more common. Additionally, there is much confusion surrounding `riscv64-unknown-elf-`, which actually includes both 32- and 64-bit runtimes and can generate software for both. Signed-off-by: Sean Cross --- examples/make.mk | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/make.mk b/examples/make.mk index c2e0559fb..5bb556870 100644 --- a/examples/make.mk +++ b/examples/make.mk @@ -2,8 +2,12 @@ # Common make definition for all examples # -# Compiler +# Compiler +ifeq ($(BOARD), fomu) +CROSS_COMPILE = riscv-none-embed- +else CROSS_COMPILE = arm-none-eabi- +endif CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ OBJCOPY = $(CROSS_COMPILE)objcopy From 67267a93997770a2f59d606b5eb2f2d96b3a1437 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 13 Nov 2019 11:08:56 -0800 Subject: [PATCH 26/27] fomu: bsp: remove unused messible functions These functions are unused in the current implementation. Signed-off-by: Sean Cross --- hw/bsp/fomu/{bsp.c => fomu.c} | 17 ----------------- 1 file changed, 17 deletions(-) rename hw/bsp/fomu/{bsp.c => fomu.c} (90%) diff --git a/hw/bsp/fomu/bsp.c b/hw/bsp/fomu/fomu.c similarity index 90% rename from hw/bsp/fomu/bsp.c rename to hw/bsp/fomu/fomu.c index 3910cff44..3303a0826 100644 --- a/hw/bsp/fomu/bsp.c +++ b/hw/bsp/fomu/fomu.c @@ -36,26 +36,10 @@ void hal_dcd_isr(uint8_t rhport); -void mputs(const char *str) { - (void)str; - while (*str) { - while ( (messible_status_read() & CSR_MESSIBLE_STATUS_FULL_OFFSET)) - ; - messible_in_write(*str); - str++; - } -} - -void mputln(const char *str) { - mputs(str); - mputs("\n"); -} - void fomu_error(uint32_t line) { (void)line; TU_BREAKPOINT(); - // while (1) {} } volatile uint32_t system_ticks = 0; @@ -90,7 +74,6 @@ void isr(void) void board_init(void) { - mputln("Fomu Initializing"); irq_setmask(0); irq_setie(1); timer_init(); From 679821e9174f9410960f974eefd46a94e74cfeda Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 13 Nov 2019 11:10:37 -0800 Subject: [PATCH 27/27] fomu: bsp: don't call usb isr when usb is disabled When compiled without usb support, we don't want to call the USB ISR. Signed-off-by: Sean Cross --- hw/bsp/fomu/fomu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/bsp/fomu/fomu.c b/hw/bsp/fomu/fomu.c index 3303a0826..519c63630 100644 --- a/hw/bsp/fomu/fomu.c +++ b/hw/bsp/fomu/fomu.c @@ -63,9 +63,11 @@ void isr(void) irqs = irq_pending() & irq_getmask(); +#if CFG_TUSB_RHPORT0_MODE == OPT_MODE_DEVICE if (irqs & (1 << USB_INTERRUPT)) { hal_dcd_isr(0); } +#endif if (irqs & (1 << TIMER0_INTERRUPT)) { system_ticks++; timer0_ev_pending_write(1);