foboot: move software stuff to sw directory

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
2019-03-05 08:52:47 +08:00
parent 2ac79e45e9
commit 84d4b40897
36 changed files with 0 additions and 2048 deletions

114
sw/Makefile Normal file
View File

@ -0,0 +1,114 @@
PACKAGE = $(notdir $(realpath .))
FOMU_SDK ?= .
ADD_CFLAGS = -I$(FOMU_SDK)/include -D__vexriscv__ -march=rv32im -mabi=ilp32
ADD_LFLAGS =
SRC_DIR = src
GIT_VERSION := $(shell git describe --tags)
TRGT ?= riscv64-unknown-elf-
CC = $(TRGT)gcc
CXX = $(TRGT)g++
OBJCOPY = $(TRGT)objcopy
RM = rm -rf
COPY = cp -a
PATH_SEP = /
ifeq ($(OS),Windows_NT)
COPY = copy
RM = del
PATH_SEP = \\
endif
LDSCRIPT = $(FOMU_SDK)/ld/linker.ld
LDSCRIPTS = $(LDSCRIPT) $(FOMU_SDK)/ld/output_format.ld $(FOMU_SDK)/ld/regions.ld
DBG_CFLAGS = -ggdb -g -DDEBUG -Wall
DBG_LFLAGS = -ggdb -g -Wall
CFLAGS = $(ADD_CFLAGS) \
-Wall -Wextra \
-ffunction-sections -fdata-sections -fno-common \
-fomit-frame-pointer -Os \
-DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11
CXXFLAGS = $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
LFLAGS = $(CFLAGS) $(ADD_LFLAGS) \
-nostartfiles \
-nostdlib \
-Wl,--gc-sections \
-Wl,--no-warn-mismatch \
-Wl,--script=$(LDSCRIPT) \
-Wl,--build-id=none
OBJ_DIR = .obj
CSOURCES = $(wildcard $(SRC_DIR)/*.c) $(wildcard third_party/libbase/*.c) $(wildcard third_party/*.c)
CPPSOURCES = $(wildcard $(SRC_DIR)/*.cpp) $(wildcard third_party/libbase/*.cpp) $(wildcard third_party/*.cpp)
ASOURCES = $(wildcard $(SRC_DIR)/*.S) $(wildcard third_party/libbase/*.S) $(wildcard third_party/*.S)
COBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(CSOURCES:.c=.o)))
CXXOBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(CPPSOURCES:.cpp=.o)))
AOBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(ASOURCES:.S=.o)))
OBJECTS = $(COBJS) $(CXXOBJS) $(AOBJS)
VPATH = $(SRC_DIR) third_party/libbase third_party
QUIET = @
ALL = all
TARGET = $(PACKAGE).elf
CLEAN = clean
$(ALL): $(TARGET) $(PACKAGE).bin $(PACKAGE).ihex
$(OBJECTS): | $(OBJ_DIR)
$(TARGET): $(OBJECTS) $(LDSCRIPTS)
$(QUIET) echo " LD $@"
$(QUIET) $(CC) $(OBJECTS) $(LFLAGS) -o $@
$(PACKAGE).bin: $(TARGET)
$(QUIET) echo " OBJCOPY $@"
$(QUIET) $(OBJCOPY) -O binary $(TARGET) $@
$(PACKAGE).dfu: $(TARGET)
$(QUIET) echo " DFU $@"
$(QUIET) $(COPY) $(PACKAGE).bin $@
$(QUIET) dfu-suffix -v 1209 -p 70b1 -a $@
#$(PACKAGE).bit: $(TARGET)
# $(QUIET) echo " BIT $@"
# # $(QUIET) ice40-repack input/top.bin input/mem_1.init ./foboot.bin ./foboot.bit
$(PACKAGE).ihex: $(TARGET)
$(QUIET) echo " IHEX $(PACKAGE).ihex"
$(QUIET) $(OBJCOPY) -O ihex $(TARGET) $@
$(DEBUG): CFLAGS += $(DBG_CFLAGS)
$(DEBUG): LFLAGS += $(DBG_LFLAGS)
CFLAGS += $(DBG_CFLAGS)
LFLAGS += $(DBG_LFLAGS)
$(DEBUG): $(TARGET)
$(OBJ_DIR):
$(QUIET) mkdir $(OBJ_DIR)
$(COBJS) : $(OBJ_DIR)/%.o : %.c Makefile
$(QUIET) echo " CC $< $(notdir $@)"
$(QUIET) $(CC) -c $< $(CFLAGS) -o $@ -MMD
$(OBJ_DIR)/%.o: %.cpp
$(QUIET) echo " CXX $< $(notdir $@)"
$(QUIET) $(CXX) -c $< $(CXXFLAGS) -o $@ -MMD
$(OBJ_DIR)/%.o: %.S
$(QUIET) echo " AS $< $(notdir $@)"
$(QUIET) $(CC) -x assembler-with-cpp -c $< $(CFLAGS) -o $@ -MMD
.PHONY: clean
clean:
$(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))
$(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.o))
$(QUIET) echo " RM $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu"
-$(QUIET) $(RM) $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu
include $(wildcard $(OBJ_DIR)/*.d)

24
sw/include/console.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef __CONSOLE_H
#define __CONSOLE_H
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*console_write_hook)(char);
typedef char (*console_read_hook)(void);
typedef int (*console_read_nonblock_hook)(void);
void console_set_write_hook(console_write_hook h);
void console_set_read_hook(console_read_hook r, console_read_nonblock_hook rn);
char readchar(void);
int readchar_nonblock(void);
void putsnonl(const char *s);
#ifdef __cplusplus
}
#endif
#endif /* __CONSOLE_H */

15
sw/include/crc.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __CRC_H
#define __CRC_H
#ifdef __cplusplus
extern "C" {
#endif
unsigned short crc16(const unsigned char *buffer, int len);
unsigned int crc32(const unsigned char *buffer, unsigned int len);
#ifdef __cplusplus
}
#endif
#endif

11
sw/include/csr-defs.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef CSR_DEFS__H
#define CSR_DEFS__H
#define CSR_MSTATUS_MIE 0x8
#define CSR_IRQ_MASK 0xBC0
#define CSR_IRQ_PENDING 0xFC0
#define CSR_DCACHE_INFO 0xCC0
#endif /* CSR_DEFS__H */

413
sw/include/generated/csr.h Normal file
View File

@ -0,0 +1,413 @@
#ifndef __GENERATED_CSR_H
#define __GENERATED_CSR_H
#include <stdint.h>
#ifdef CSR_ACCESSORS_DEFINED
extern void csr_writeb(uint8_t value, uint32_t addr);
extern uint8_t csr_readb(uint32_t addr);
extern void csr_writew(uint16_t value, uint32_t addr);
extern uint16_t csr_readw(uint32_t addr);
extern void csr_writel(uint32_t value, uint32_t addr);
extern uint32_t csr_readl(uint32_t addr);
#else /* ! CSR_ACCESSORS_DEFINED */
#include <hw/common.h>
#endif /* ! CSR_ACCESSORS_DEFINED */
/* spiflash */
#define CSR_SPIFLASH_BASE 0xe0004800
#define CSR_SPIFLASH_BITBANG_ADDR 0xe0004800
#define CSR_SPIFLASH_BITBANG_SIZE 1
static inline unsigned char spiflash_bitbang_read(void) {
unsigned char r = csr_readl(0xe0004800);
return r;
}
static inline void spiflash_bitbang_write(unsigned char value) {
csr_writel(value, 0xe0004800);
}
#define CSR_SPIFLASH_MISO_ADDR 0xe0004804
#define CSR_SPIFLASH_MISO_SIZE 1
static inline unsigned char spiflash_miso_read(void) {
unsigned char r = csr_readl(0xe0004804);
return r;
}
#define CSR_SPIFLASH_BITBANG_EN_ADDR 0xe0004808
#define CSR_SPIFLASH_BITBANG_EN_SIZE 1
static inline unsigned char spiflash_bitbang_en_read(void) {
unsigned char r = csr_readl(0xe0004808);
return r;
}
static inline void spiflash_bitbang_en_write(unsigned char value) {
csr_writel(value, 0xe0004808);
}
/* timer0 */
#define CSR_TIMER0_BASE 0xe0002800
#define CSR_TIMER0_LOAD_ADDR 0xe0002800
#define CSR_TIMER0_LOAD_SIZE 4
static inline unsigned int timer0_load_read(void) {
unsigned int r = csr_readl(0xe0002800);
r <<= 8;
r |= csr_readl(0xe0002804);
r <<= 8;
r |= csr_readl(0xe0002808);
r <<= 8;
r |= csr_readl(0xe000280c);
return r;
}
static inline void timer0_load_write(unsigned int value) {
csr_writel(value >> 24, 0xe0002800);
csr_writel(value >> 16, 0xe0002804);
csr_writel(value >> 8, 0xe0002808);
csr_writel(value, 0xe000280c);
}
#define CSR_TIMER0_RELOAD_ADDR 0xe0002810
#define CSR_TIMER0_RELOAD_SIZE 4
static inline unsigned int timer0_reload_read(void) {
unsigned int r = csr_readl(0xe0002810);
r <<= 8;
r |= csr_readl(0xe0002814);
r <<= 8;
r |= csr_readl(0xe0002818);
r <<= 8;
r |= csr_readl(0xe000281c);
return r;
}
static inline void timer0_reload_write(unsigned int value) {
csr_writel(value >> 24, 0xe0002810);
csr_writel(value >> 16, 0xe0002814);
csr_writel(value >> 8, 0xe0002818);
csr_writel(value, 0xe000281c);
}
#define CSR_TIMER0_EN_ADDR 0xe0002820
#define CSR_TIMER0_EN_SIZE 1
static inline unsigned char timer0_en_read(void) {
unsigned char r = csr_readl(0xe0002820);
return r;
}
static inline void timer0_en_write(unsigned char value) {
csr_writel(value, 0xe0002820);
}
#define CSR_TIMER0_UPDATE_VALUE_ADDR 0xe0002824
#define CSR_TIMER0_UPDATE_VALUE_SIZE 1
static inline unsigned char timer0_update_value_read(void) {
unsigned char r = csr_readl(0xe0002824);
return r;
}
static inline void timer0_update_value_write(unsigned char value) {
csr_writel(value, 0xe0002824);
}
#define CSR_TIMER0_VALUE_ADDR 0xe0002828
#define CSR_TIMER0_VALUE_SIZE 4
static inline unsigned int timer0_value_read(void) {
unsigned int r = csr_readl(0xe0002828);
r <<= 8;
r |= csr_readl(0xe000282c);
r <<= 8;
r |= csr_readl(0xe0002830);
r <<= 8;
r |= csr_readl(0xe0002834);
return r;
}
#define CSR_TIMER0_EV_STATUS_ADDR 0xe0002838
#define CSR_TIMER0_EV_STATUS_SIZE 1
static inline unsigned char timer0_ev_status_read(void) {
unsigned char r = csr_readl(0xe0002838);
return r;
}
static inline void timer0_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0002838);
}
#define CSR_TIMER0_EV_PENDING_ADDR 0xe000283c
#define CSR_TIMER0_EV_PENDING_SIZE 1
static inline unsigned char timer0_ev_pending_read(void) {
unsigned char r = csr_readl(0xe000283c);
return r;
}
static inline void timer0_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe000283c);
}
#define CSR_TIMER0_EV_ENABLE_ADDR 0xe0002840
#define CSR_TIMER0_EV_ENABLE_SIZE 1
static inline unsigned char timer0_ev_enable_read(void) {
unsigned char r = csr_readl(0xe0002840);
return r;
}
static inline void timer0_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0002840);
}
/* uart */
#define CSR_UART_BASE 0xe0001800
#define CSR_UART_RXTX_ADDR 0xe0001800
#define CSR_UART_RXTX_SIZE 1
static inline unsigned char uart_rxtx_read(void) {
unsigned char r = csr_readl(0xe0001800);
return r;
}
static inline void uart_rxtx_write(unsigned char value) {
csr_writel(value, 0xe0001800);
}
#define CSR_UART_TXFULL_ADDR 0xe0001804
#define CSR_UART_TXFULL_SIZE 1
static inline unsigned char uart_txfull_read(void) {
unsigned char r = csr_readl(0xe0001804);
return r;
}
#define CSR_UART_RXEMPTY_ADDR 0xe0001808
#define CSR_UART_RXEMPTY_SIZE 1
static inline unsigned char uart_rxempty_read(void) {
unsigned char r = csr_readl(0xe0001808);
return r;
}
#define CSR_UART_EV_STATUS_ADDR 0xe000180c
#define CSR_UART_EV_STATUS_SIZE 1
static inline unsigned char uart_ev_status_read(void) {
unsigned char r = csr_readl(0xe000180c);
return r;
}
static inline void uart_ev_status_write(unsigned char value) {
csr_writel(value, 0xe000180c);
}
#define CSR_UART_EV_PENDING_ADDR 0xe0001810
#define CSR_UART_EV_PENDING_SIZE 1
static inline unsigned char uart_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0001810);
return r;
}
static inline void uart_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0001810);
}
#define CSR_UART_EV_ENABLE_ADDR 0xe0001814
#define CSR_UART_EV_ENABLE_SIZE 1
static inline unsigned char uart_ev_enable_read(void) {
unsigned char r = csr_readl(0xe0001814);
return r;
}
static inline void uart_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0001814);
}
/* uart_phy */
#define CSR_UART_PHY_BASE 0xe0001000
#define CSR_UART_PHY_TUNING_WORD_ADDR 0xe0001000
#define CSR_UART_PHY_TUNING_WORD_SIZE 4
static inline unsigned int uart_phy_tuning_word_read(void) {
unsigned int r = csr_readl(0xe0001000);
r <<= 8;
r |= csr_readl(0xe0001004);
r <<= 8;
r |= csr_readl(0xe0001008);
r <<= 8;
r |= csr_readl(0xe000100c);
return r;
}
static inline void uart_phy_tuning_word_write(unsigned int value) {
csr_writel(value >> 24, 0xe0001000);
csr_writel(value >> 16, 0xe0001004);
csr_writel(value >> 8, 0xe0001008);
csr_writel(value, 0xe000100c);
}
/* usb */
#define CSR_USB_BASE 0xe0005000
#define CSR_USB_PULLUP_OUT_ADDR 0xe0005000
#define CSR_USB_PULLUP_OUT_SIZE 1
static inline unsigned char usb_pullup_out_read(void) {
unsigned char r = csr_readl(0xe0005000);
return r;
}
static inline void usb_pullup_out_write(unsigned char value) {
csr_writel(value, 0xe0005000);
}
#define CSR_USB_EP_0_OUT_EV_STATUS_ADDR 0xe0005004
#define CSR_USB_EP_0_OUT_EV_STATUS_SIZE 1
static inline unsigned char usb_ep_0_out_ev_status_read(void) {
unsigned char r = csr_readl(0xe0005004);
return r;
}
static inline void usb_ep_0_out_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0005004);
}
#define CSR_USB_EP_0_OUT_EV_PENDING_ADDR 0xe0005008
#define CSR_USB_EP_0_OUT_EV_PENDING_SIZE 1
static inline unsigned char usb_ep_0_out_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0005008);
return r;
}
static inline void usb_ep_0_out_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0005008);
}
#define CSR_USB_EP_0_OUT_EV_ENABLE_ADDR 0xe000500c
#define CSR_USB_EP_0_OUT_EV_ENABLE_SIZE 1
static inline unsigned char usb_ep_0_out_ev_enable_read(void) {
unsigned char r = csr_readl(0xe000500c);
return r;
}
static inline void usb_ep_0_out_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe000500c);
}
#define CSR_USB_EP_0_OUT_LAST_TOK_ADDR 0xe0005010
#define CSR_USB_EP_0_OUT_LAST_TOK_SIZE 1
static inline unsigned char usb_ep_0_out_last_tok_read(void) {
unsigned char r = csr_readl(0xe0005010);
return r;
}
#define CSR_USB_EP_0_OUT_RESPOND_ADDR 0xe0005014
#define CSR_USB_EP_0_OUT_RESPOND_SIZE 1
static inline unsigned char usb_ep_0_out_respond_read(void) {
unsigned char r = csr_readl(0xe0005014);
return r;
}
static inline void usb_ep_0_out_respond_write(unsigned char value) {
csr_writel(value, 0xe0005014);
}
#define CSR_USB_EP_0_OUT_DTB_ADDR 0xe0005018
#define CSR_USB_EP_0_OUT_DTB_SIZE 1
static inline unsigned char usb_ep_0_out_dtb_read(void) {
unsigned char r = csr_readl(0xe0005018);
return r;
}
static inline void usb_ep_0_out_dtb_write(unsigned char value) {
csr_writel(value, 0xe0005018);
}
#define CSR_USB_EP_0_OUT_OBUF_HEAD_ADDR 0xe000501c
#define CSR_USB_EP_0_OUT_OBUF_HEAD_SIZE 1
static inline unsigned char usb_ep_0_out_obuf_head_read(void) {
unsigned char r = csr_readl(0xe000501c);
return r;
}
static inline void usb_ep_0_out_obuf_head_write(unsigned char value) {
csr_writel(value, 0xe000501c);
}
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_ADDR 0xe0005020
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_SIZE 1
static inline unsigned char usb_ep_0_out_obuf_empty_read(void) {
unsigned char r = csr_readl(0xe0005020);
return r;
}
#define CSR_USB_EP_0_IN_EV_STATUS_ADDR 0xe0005024
#define CSR_USB_EP_0_IN_EV_STATUS_SIZE 1
static inline unsigned char usb_ep_0_in_ev_status_read(void) {
unsigned char r = csr_readl(0xe0005024);
return r;
}
static inline void usb_ep_0_in_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0005024);
}
#define CSR_USB_EP_0_IN_EV_PENDING_ADDR 0xe0005028
#define CSR_USB_EP_0_IN_EV_PENDING_SIZE 1
static inline unsigned char usb_ep_0_in_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0005028);
return r;
}
static inline void usb_ep_0_in_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0005028);
}
#define CSR_USB_EP_0_IN_EV_ENABLE_ADDR 0xe000502c
#define CSR_USB_EP_0_IN_EV_ENABLE_SIZE 1
static inline unsigned char usb_ep_0_in_ev_enable_read(void) {
unsigned char r = csr_readl(0xe000502c);
return r;
}
static inline void usb_ep_0_in_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe000502c);
}
#define CSR_USB_EP_0_IN_LAST_TOK_ADDR 0xe0005030
#define CSR_USB_EP_0_IN_LAST_TOK_SIZE 1
static inline unsigned char usb_ep_0_in_last_tok_read(void) {
unsigned char r = csr_readl(0xe0005030);
return r;
}
#define CSR_USB_EP_0_IN_RESPOND_ADDR 0xe0005034
#define CSR_USB_EP_0_IN_RESPOND_SIZE 1
static inline unsigned char usb_ep_0_in_respond_read(void) {
unsigned char r = csr_readl(0xe0005034);
return r;
}
static inline void usb_ep_0_in_respond_write(unsigned char value) {
csr_writel(value, 0xe0005034);
}
#define CSR_USB_EP_0_IN_DTB_ADDR 0xe0005038
#define CSR_USB_EP_0_IN_DTB_SIZE 1
static inline unsigned char usb_ep_0_in_dtb_read(void) {
unsigned char r = csr_readl(0xe0005038);
return r;
}
static inline void usb_ep_0_in_dtb_write(unsigned char value) {
csr_writel(value, 0xe0005038);
}
#define CSR_USB_EP_0_IN_IBUF_HEAD_ADDR 0xe000503c
#define CSR_USB_EP_0_IN_IBUF_HEAD_SIZE 1
static inline unsigned char usb_ep_0_in_ibuf_head_read(void) {
unsigned char r = csr_readl(0xe000503c);
return r;
}
static inline void usb_ep_0_in_ibuf_head_write(unsigned char value) {
csr_writel(value, 0xe000503c);
}
#define CSR_USB_EP_0_IN_IBUF_EMPTY_ADDR 0xe0005040
#define CSR_USB_EP_0_IN_IBUF_EMPTY_SIZE 1
static inline unsigned char usb_ep_0_in_ibuf_empty_read(void) {
unsigned char r = csr_readl(0xe0005040);
return r;
}
#define CSR_IDENTIFIER_MEM_BASE 0xe0002000
/* constants */
#define NMI_INTERRUPT 0
static inline int nmi_interrupt_read(void) {
return 0;
}
#define TIMER0_INTERRUPT 1
static inline int timer0_interrupt_read(void) {
return 1;
}
#define UART_INTERRUPT 2
static inline int uart_interrupt_read(void) {
return 2;
}
#define USB_INTERRUPT 3
static inline int usb_interrupt_read(void) {
return 3;
}
#define CSR_DATA_WIDTH 8
static inline int csr_data_width_read(void) {
return 8;
}
#define SYSTEM_CLOCK_FREQUENCY 12000000
static inline int system_clock_frequency_read(void) {
return 12000000;
}
#define SPIFLASH_PAGE_SIZE 256
static inline int spiflash_page_size_read(void) {
return 256;
}
#define SPIFLASH_SECTOR_SIZE 65536
static inline int spiflash_sector_size_read(void) {
return 65536;
}
#define ROM_DISABLE 1
static inline int rom_disable_read(void) {
return 1;
}
#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_VARIANT "VEXRISCV"
static inline const char * config_cpu_variant_read(void) {
return "VEXRISCV";
}
#define CONFIG_CSR_DATA_WIDTH 8
static inline int config_csr_data_width_read(void) {
return 8;
}
#endif

View File

@ -0,0 +1,13 @@
#ifndef __GENERATED_MEM_H
#define __GENERATED_MEM_H
#define SPIFLASH_BASE 0x20000000
#define SPIFLASH_SIZE 0x00200000
#define SRAM_BASE 0x10000000
#define SRAM_SIZE 0x00020000
#define ROM_BASE 0x00000000
#define ROM_SIZE 0x00002000
#endif

602
sw/include/grainuum.h Normal file
View File

@ -0,0 +1,602 @@
/****************************************************************************
* Grainuum Software USB Stack *
* *
* MIT License: *
* Copyright (c) 2016 Sean Cross *
* *
* 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, distribute with modifications, 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 ABOVE 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. *
* *
* Except as contained in this notice, the name(s) of the above copyright *
* holders shall not be used in advertising or otherwise to promote the *
* sale, use or other dealings in this Software without prior written *
* authorization. *
****************************************************************************/
#ifndef _GRAINUUM_H
#define _GRAINUUM_H
#include <stdint.h>
/**
* @brief Extra fields for GrainuumState struct.
* @note You probably can ignore this.
*/
#ifndef GRAINUUM_STATE_EXTRA
#define GRAINUUM_STATE_EXTRA
#endif /* GRAINUUM_STATE_EXTRA */
#define GRAINUUM_PACKET_SIZE_MAX 64
/**
* @brief Extra fields for GrainuumUSB struct.
* @note Use this to store context and thread information.
*/
#ifndef GRAINUUM_EXTRA
#define GRAINUUM_EXTRA
#endif /* GRAINUUM_EXTRA */
#define GET_STATUS 0
#define CLEAR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADDRESS 5
#define GET_DESCRIPTOR 6
#define SET_DESCRIPTOR 7
#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9
#define GET_INTERFACE 10
#define SET_INTERFACE 11
#define SYNC_FRAME 12
#define GET_REPORT 1
#define GET_IDLE 2
#define GET_PROTOCOL 3
#define SET_REPORT 9
#define SET_IDLE 10
#define SET_PROTOCOL 11
enum usb_pids {
USB_PID_RESERVED = 0xf0,
USB_PID_OUT = 0xe1,
USB_PID_ACK = 0xd2,
USB_PID_DATA0 = 0xc3,
USB_PID_PING = 0xb4,
USB_PID_SOF = 0xa5,
USB_PID_NYET = 0x96,
USB_PID_DATA2 = 0x87,
USB_PID_SPLIT = 0x78,
USB_PID_IN = 0x69,
USB_PID_NAK = 0x5a,
USB_PID_DATA1 = 0x4b,
USB_PID_ERR = 0x3c,
USB_PID_SETUP = 0x2d,
USB_PID_STALL = 0x1e,
USB_PID_MDATA = 0x0f,
};
enum valenty_usb_pids {
VUSB_PID_IN = 0x2,
VUSB_PID_OUT = 0x0,
VUSB_PID_SETUP = 0x3,
};
struct GrainuumUSB;
struct GrainuumState;
struct GrainuumConfig;
/* Function callbacks */
/* Each of these functions are called by the USB system to get a buffer.
* On return, *data will point to the buffer, and the number of bytes
* in the buffer will be returned.
*
* If the data does not exist, return 0.
*/
typedef int (*get_usb_descriptor_t)(struct GrainuumUSB *usb,
const void *pkt,
const void **data);
typedef void (*usb_set_config_num_t)(struct GrainuumUSB *usb,
int configNum);
/*
* Called when doing an OUT xfer (data to device) to get a buffer for
* the specified endpoint.
* It is up to the user to ensure the buffer is large enough.
*/
typedef void * (*usb_get_buffer_t)(struct GrainuumUSB *usb,
uint8_t epnum,
int32_t *size);
/*
* When data is received (i.e. OUT EP), this function will be called.
*/
typedef int (*usb_data_in_t)(struct GrainuumUSB *usb,
uint8_t epnum,
uint32_t bytes,
const void *data);
/**
* @brief Called immediately after @p grainuumSendData() has queued data.
* @note This function can be used to e.g. sleep a thread.
* @param[in] usb pointer to the @p GrainuumUSB object
* @param[in] epnum endpoint number of the transfer
* @param[in] data pointer to the data being written
* @param[in] size number of bytes being written
* @api
*/
typedef void (*usb_data_out_start_t)(struct GrainuumUSB *usb,
int epnum,
const void *data,
int size);
/**
* @brief Called once all data has been sent.
* @note This function can be used to e.g. wake up a thread.
* @param[out] usb pointer to the @p GrainuumUSB object
* @param[out] result whether the transfer was successful (0), or had an error.
* @api
*/
typedef int (*usb_data_out_finish_t)(struct GrainuumUSB *usb,
int result);
/* Structure of a USB packet on the wire, plus size field */
struct usb_packet {
union {
struct {
// uint8_t pid;
uint8_t data[GRAINUUM_PACKET_SIZE_MAX + 2]; /* Including CRC */
} __attribute((packed, aligned(4)));
uint8_t raw_data[GRAINUUM_PACKET_SIZE_MAX + 2];
} __attribute((packed, aligned(4)));
uint8_t size; /* Not including pid (so may be 0) */
/* Checksum omitted */
} __attribute__((packed, aligned(4)));
/* USB Descriptors */
#define DT_DEVICE 0x01
#define DT_CONFIGURATION 0x02
#define DT_STRING 0x03
#define DT_INTERFACE 0x04
#define DT_ENDPOINT 0x05
#define DT_DEVICE_QUALIFIER 0x06
#define DT_OTHER_SPEED_CONFIGURATION 0x07
#define DT_INTERFACE_POWER 0x08
#define DT_HID 0x21
#define DT_HID_REPORT 0x22
#define DT_PID 0x23
struct usb_setup_packet {
uint8_t bmRequestType;
uint8_t bRequest;
union {
uint16_t wValue;
struct {
uint8_t wValueL;
uint8_t wValueH;
};
};
uint16_t wIndex;
uint16_t wLength;
} __attribute__((packed, aligned(4)));
struct usb_device_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} __attribute__((packed, aligned(4)));
struct usb_configuration_descriptor {
uint8_t bLength; /* Size of this descriptor, in bytes (9) */
uint8_t bDescriptorType; /* DT_CONFIGURATION (2) */
uint16_t wTotalLength; /* Total length of this, plus sizeof(data) */
uint8_t bNumInterfaces; /* Number of interfaces supported by config */
uint8_t bConfigurationValue; /* Value used by Set Configuration */
uint8_t iConfiguration; /* index of string descriptor for config */
uint8_t bmAttributes; /* Bitmap of attributes. D7 must be 1. */
uint8_t bMaxPower; /* Maximum power, in units of 2mA */
uint8_t data[]; /* Remaining descriptors */
} __attribute__((packed, aligned(4)));
struct usb_string_descriptor {
uint8_t bLength; /* sizeof(usb_string_descriptor) + sizeof(data) */
uint8_t bDescriptorType; /* DT_STRING (3) */
uint8_t data[]; /* UTF-16LE string data or lang data(for string 0 */
} __attribute__((packed, aligned(4)));
struct usb_interface_descriptor {
uint8_t bLength; /* sizeof(usb_interface_descriptor) (9) */
uint8_t bDescriptorType; /* DT_INTERFACE (4) */
uint8_t bInterfaceNumber; /* Which interface this describes. Usually 0. */
uint8_t bAlternateSetting; /* ??? */
uint8_t bNumEndpoints; /* Number of endpoints, minus 1 */
uint8_t bInterfaceClass; /* Class code */
uint8_t bInterfaceSubclass; /* Class sub-code */
uint8_t bInterfaceProtocol; /* Protocol code, assigned by USB */
uint8_t iInterface; /* Index of string for this interface */
} __attribute__((packed, aligned(4)));
struct usb_endpoint_descriptor {
uint8_t bLength; /* sizeof(usb_endpoint_descriptor) (7) */
uint8_t bDescriptorType; /* DT_ENDPOINT (5) */
uint8_t bEndpointAddress; /* High bit 1:IN, 0:OUT. Lower 4-bits are EP# */
uint8_t bmAttributes; /* 0=control, 2=bulk, 3=interrupt */
uint16_t wMaxPacketSize; /* Max packet size for this EP */
uint8_t bInterval; /* Polling rate (in 1ms units) */
} __attribute__((packed, aligned(4)));
struct usb_hid_descriptor {
uint8_t bLength; /* sizeof(usb_hid_descriptor) (9) */
uint8_t bDescriptorType; /* DT_HID (0x21) */
uint16_t bcdHID; /* HID class version number, in BCD */
uint8_t bCountryCode; /* Target country (usually 0) */
uint8_t bNumDescriptors; /* Number of HID class descriptors (usually 1) */
uint8_t bReportDescriptorType; /* Report descriptor type (usually 0x22) */
uint16_t wReportDescriptorLength; /* Length of the HID/PID report descriptor */
} __attribute__((packed, aligned(4)));
#define GRAINUUM_BUFFER_ELEMENT_SIZE 12 /* 1 PID, 8 data, 2 CRC16, 1 size */
/* grainuum_buffer is aligned such that its first byte is on a word boundary.
* This is because the first byte of every packet is a PID, which is
* immediately discarded. This leaves the remainder of the packet
* word-aligned.
*/
#define GRAINUUM_BUFFER(name, sz) \
struct { \
uint8_t head; \
uint8_t tail; \
uint8_t padding; \
union { \
uint8_t buffer[(sz) * GRAINUUM_BUFFER_ELEMENT_SIZE]; \
uint8_t elements[sz][GRAINUUM_BUFFER_ELEMENT_SIZE]; \
}; \
} name __attribute__((aligned(4))); \
uint8_t * name ## _head_ptr;
#define GRAINUUM_BUFFER_INIT(name) \
do { \
(name).head = 0; \
(name).tail = 0; \
name ## _head_ptr = (name).buffer; \
} while(0)
#define GRAINUUM_BUFFER_ADVANCE(name) \
do { \
(name).head += GRAINUUM_BUFFER_ELEMENT_SIZE; \
if ((name).head >= sizeof((name).buffer)) \
(name).head = 0; \
name ## _head_ptr = ((name).buffer + (name).head); \
} while(0)
#define GRAINUUM_BUFFER_TOP(name) \
(&((name).buffer[(name).tail]))
#define GRAINUUM_BUFFER_REMOVE(name) \
do { \
(name).tail += GRAINUUM_BUFFER_ELEMENT_SIZE; \
if ((name).tail >= sizeof((name).buffer)) \
(name).tail = 0; \
} while(0)
#define GRAINUUM_BUFFER_IS_EMPTY(name) \
((name).head == (name).tail)
#define GRAINUUM_BUFFER_ENTRY(name) \
name ## _head_ptr
/* Grainuum Structs */
struct GrainuumConfig {
get_usb_descriptor_t getDescriptor;
usb_set_config_num_t setConfigNum;
usb_get_buffer_t getReceiveBuffer;
usb_data_in_t receiveData;
usb_data_out_start_t sendDataStarted;
usb_data_out_finish_t sendDataFinished;
void *data;
struct GrainuumUSB *usb;
} __attribute__((packed, aligned(4)));
struct GrainuumState {
struct GrainuumUSB *usb;
const void *data_out; /* Pointer to the data that's being sent */
int32_t data_out_left; /* How much data has yet to be sent */
int32_t data_out_max; /* The maximum number of bytes to send */
int32_t data_out_epnum; /* Which endpoint the data is for */
struct usb_packet packet; /* Currently-queued packet */
int packet_queued; /* Whether a packet is queued */
uint32_t tok_pos; /* Position within the current token */
void *tok_buf; /* Buffer storing current token's data */
uint8_t tok_epnum; /* Last token's endpoint */
uint8_t data_buffer; /* Whether we're sending DATA0 or DATA1 */
uint8_t packet_type; /* PACKET_SETUP, PACKET_IN, or PACKET_OUT */
uint8_t address; /* Our configured address */
GRAINUUM_STATE_EXTRA
} __attribute__((packed, aligned(4)));
struct GrainuumUSB {
struct GrainuumConfig *cfg; /* Callbacks */
int initialized;
/* USB D- pin specification */
uint32_t usbdnIAddr;
uint32_t usbdnSAddr;
uint32_t usbdnCAddr;
uint32_t usbdnDAddr;
uint32_t usbdnShift;
/* USB D+ pin specification */
uint32_t usbdpIAddr;
uint32_t usbdpSAddr;
uint32_t usbdpCAddr;
uint32_t usbdpDAddr;
uint32_t usbdpShift;
uint32_t usbdnMask;
uint32_t usbdpMask;
uint32_t queued_size;
uint32_t queued_epnum;
const void *queued_data;
struct GrainuumState state; /* Associated state */
GRAINUUM_EXTRA
} __attribute__((packed, aligned(4)));
#ifdef __cplusplus
extern "C" {
#endif
static inline void grainuumWritel(uint32_t value, uint32_t addr)
{
*((volatile uint32_t *)addr) = value;
}
static inline uint32_t grainuumReadl(uint32_t addr)
{
return *(volatile uint32_t *)addr;
}
/*===========================================================================*/
/* Weak hook functions. */
/*===========================================================================*/
/**
* @brief Called just before the USB device is plugged in.
* @param[in] usb pointer to the @p GrainuumUSB object
* @api
*/
void grainuumConnectPre(struct GrainuumUSB *usb);
/**
* @brief Called just after the USB device is plugged in.
* @param[in] usb pointer to the @p GrainuumUSB object
* @api
*/
void grainuumConnectPost(struct GrainuumUSB *usb);
/**
* @brief Called just before the USB device is unplugged.
* @param[in] usb pointer to the @p GrainuumUSB object
* @api
*/
void grainuumDisconnectPre(struct GrainuumUSB *usb);
/**
* @brief Called just after the USB device is unplugged.
* @param[in] usb pointer to the @p GrainuumUSB object
* @api
*/
void grainuumDisconnectPost(struct GrainuumUSB *usb);
/**
* @brief Called just before the USB device is first initialized.
* @param[in] usb pointer to the @p GrainuumUSB object
* @api
*/
void grainuumInitPre(struct GrainuumUSB *usb);
/**
* @brief Called just before the USB device is first initialized.
* @param[in] usb pointer to the @p GrainuumUSB object
* @api
*/
void grainuumInitPost(struct GrainuumUSB *usb);
/**
* @brief Called immediately after a packet has been received.
* @note This is called from an interrupt context. Data will
* be stored in the buffer that was passed to @p grainuumCaptureI()
* @param[in] usb pointer to the @p GrainuumUSB object
* @iclass
*/
void grainuumReceivePacket(struct GrainuumUSB *usb);
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/**
* @brief Returns nonzero if Grainuum has been initialized.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @return nonzero if @p GrainuumUSB is initialized.
* @retval 0 Object is not initilized.
* @api
*/
int grainuumInitialized(struct GrainuumUSB *usb);
/**
* @brief Queues some data to be sent to the host.
* @note After the first 8 bytes, @p data must remain valid
* until the transfer has completed. This generally
* means you can send const data stored in the text
* section, or small 8-byte packets.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @param[in] epnum endpoint number of the transfer.
* @param[in] data pointer to the data being written.
* @param[in] size number of bytes being written.
* @return 0 if the transfer completed successfully.
* @retval 0 Transfer completed successfully.
* @api
*/
int grainuumSendData(struct GrainuumUSB *usb, int epnum, const void *data, int size);
/**
* @brief Clears the send buffer, if not empty.
* @note If data has already been queued for the PHY, then
* this will not prevent it from being sent.
* This function is intended to be used to prevent
* grainuumSendData() from returning -EAGAIN.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @api
*/
void grainuumDropData(struct GrainuumUSB *usb);
/**
* @brief Determines if data is already queued.
* @note If data has been queued, then this will return
* nonzero. If this returns zero, then you can
* trust grainuumSendData() will succeed.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @return Nonzero if data is already queued.
* @api
*/
int grainuumDataQueued(struct GrainuumUSB *usb);
/**
* @brief Process one received packet through the Grainuum state machine.
* @note This feeds USB packets into the state machine. It should not
* be called as part of an interrupt.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @param[in] packet The USB packet that was most recently received, with byte 12 holding the size.
* @api
*/
void grainuumProcess(struct GrainuumUSB *usb,
uint8_t pid,
const uint8_t packet[12],
uint32_t size);
/**
* @brief Initialize the Grainuum USB system.
* @note This is meant to run as part of an interrupt. Pass
* the storage buffer in as @p samples. The number
* of bytes that were read will be stored in the last
* byte of the array. For best performance, make
* sure that @p sample is on byte 3 of a 4-byte boundary,
* so that samples[1] is on a word boundary. The @p GrainuumUSB
* object will start out disconnected.
* @param[in] usb Pointer to the @p GrainuumUSB object to initialize.
* @param[in] link Pointer to the @p GrainuumConfig object to use.
* @api
*/
void grainuumInit(struct GrainuumUSB *usb, struct GrainuumConfig *link);
/**
* @brief Capture a USB packet from the wire.
* @note This is meant to run as part of an interrupt. Pass
* the storage buffer in as @p samples. The number
* of bytes that were read will be stored in the last
* byte of the array. For best performance, make
* sure that @p sample is on byte 3 of a 4-byte boundary,
* so that samples[1] is on a word boundary.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @param[in] packet Buffer to store the read samples.
* @api
*/
int grainuumCaptureI(struct GrainuumUSB *usb, uint8_t samples[67]);
/**
* @brief Internal function. Queues 8 bytes to be sent by the phy.
* @note This is an internal function, and is not meant to be called.
* It is meant to queue properly-formatted USB packets complete
* with CRC-16 (if required).
* @param[in] usb pointer to the @p GrainuumUSB object.
* @param[in] epnum The endpoint number to queue data for.
* @param[in] buffer The data to queue.
* @param[in] size The number of bytes that are queued.
* @notapi
*/
void grainuumWriteQueue(struct GrainuumUSB *usb, int epnum,
const void *buffer, int size);
/**
* @brief Simulates plugging the device into USB.
* @note All USB Connect hooks will be called.
* The default USB state is "disconnected",
* so @p grainuumConnect() must be called
* to start communications.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @api
*/
void grainuumConnect(struct GrainuumUSB *usb);
/**
* @brief Simulates unplugging the device from USB.
* @note All USB Disconnect hooks will be called.
* @param[in] usb pointer to the @p GrainuumUSB object.
* @api
*/
void grainuumDisconnect(struct GrainuumUSB *usb);
/**
* @brief Reads one packet from the wire.
* @note This must be called from an interrupt context with
* interrupts disabled.
* @param[in] usb Pointer to the @p GrainuumUSB object.
* @param[out] samples Buffer where the samples will be stored.
* @return The number of bytes read, or negative on error
* @retval -1 Timeout while reading.
* @retval -2 Read too many bits.
* @retval -3 Unable to find sync end.
* @retval -4 Probably a keepalive packet.
* @notapi
*/
int usbPhyReadI(const struct GrainuumUSB *usb, uint8_t samples[11]);
/**
* @brief Writes one packet from the wire.
* @note This must be called from an interrupt context with
* interrupts disabled.
* @param[in] usb Pointer to the @p GrainuumUSB object.
* @param[in] samples Buffer where the samples will be stored.
* @param[in] size Number of bytes to write.
* @notapi
*/
void usbPhyWriteI(const struct GrainuumUSB *usb, const void *buffer, uint32_t size);
#ifdef __cplusplus
};
#endif
#endif /* _GRAINUUM_H */

52
sw/include/hw/common.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef __HW_COMMON_H
#define __HW_COMMON_H
#include <stdint.h>
/* To overwrite CSR accessors, define extern, non-inlined versions
* of csr_read[bwl]() and csr_write[bwl](), and define
* CSR_ACCESSORS_DEFINED.
*/
#ifndef CSR_ACCESSORS_DEFINED
#define CSR_ACCESSORS_DEFINED
#ifdef __ASSEMBLER__
#define MMPTR(x) x
#else /* ! __ASSEMBLER__ */
#define MMPTR(x) (*((volatile unsigned int *)(x)))
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 /* ! __ASSEMBLER__ */
#endif /* ! CSR_ACCESSORS_DEFINED */
#endif /* __HW_COMMON_H */

40
sw/include/hw/flags.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef __HW_FLAGS_H
#define __HW_FLAGS_H
#define UART_EV_TX 0x1
#define UART_EV_RX 0x2
#define DFII_CONTROL_SEL 0x01
#define DFII_CONTROL_CKE 0x02
#define DFII_CONTROL_ODT 0x04
#define DFII_CONTROL_RESET_N 0x08
#define DFII_COMMAND_CS 0x01
#define DFII_COMMAND_WE 0x02
#define DFII_COMMAND_CAS 0x04
#define DFII_COMMAND_RAS 0x08
#define DFII_COMMAND_WRDATA 0x10
#define DFII_COMMAND_RDDATA 0x20
#define ETHMAC_EV_SRAM_WRITER 0x1
#define ETHMAC_EV_SRAM_READER 0x1
#define CLKGEN_STATUS_BUSY 0x1
#define CLKGEN_STATUS_PROGDONE 0x2
#define CLKGEN_STATUS_LOCKED 0x4
#define DVISAMPLER_TOO_LATE 0x1
#define DVISAMPLER_TOO_EARLY 0x2
#define DVISAMPLER_DELAY_MASTER_CAL 0x01
#define DVISAMPLER_DELAY_MASTER_RST 0x02
#define DVISAMPLER_DELAY_SLAVE_CAL 0x04
#define DVISAMPLER_DELAY_SLAVE_RST 0x08
#define DVISAMPLER_DELAY_INC 0x10
#define DVISAMPLER_DELAY_DEC 0x20
#define DVISAMPLER_SLOT_EMPTY 0
#define DVISAMPLER_SLOT_LOADED 1
#define DVISAMPLER_SLOT_PENDING 2
#endif /* __HW_FLAGS_H */

144
sw/include/irq.h Normal file
View File

@ -0,0 +1,144 @@
#ifndef __IRQ_H
#define __IRQ_H
#ifdef __cplusplus
extern "C" {
#endif
#include <system.h>
#ifdef __picorv32__
// PicoRV32 has a very limited interrupt support, implemented via custom
// instructions. It also doesn't have a global interrupt enable/disable, so
// we have to emulate it via saving and restoring a mask and using 0/~1 as a
// hardware mask.
// Due to all this somewhat low-level mess, all of the glue is implemented in
// the RiscV crt0, and this header is kept as a thin wrapper. Since interrupts
// managed by this layer, do not call interrupt instructions directly, as the
// state will go out of sync with the hardware.
// Read only.
extern unsigned int _irq_pending;
// Read only.
extern unsigned int _irq_mask;
// Read only.
extern unsigned int _irq_enabled;
extern void _irq_enable(void);
extern void _irq_disable(void);
extern void _irq_setmask(unsigned int);
#endif
static inline unsigned int irq_getie(void)
{
#if defined (__lm32__)
unsigned int ie;
__asm__ __volatile__("rcsr %0, IE" : "=r" (ie));
return ie;
#elif defined (__or1k__)
return !!(mfspr(SPR_SR) & SPR_SR_IEE);
#elif defined (__picorv32__)
return _irq_enabled != 0;
#elif defined (__vexriscv__)
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
#elif defined (__minerva__)
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
#else
#error Unsupported architecture
#endif
}
static inline void irq_setie(unsigned int ie)
{
#if defined (__lm32__)
__asm__ __volatile__("wcsr IE, %0" : : "r" (ie));
#elif defined (__or1k__)
if (ie & 0x1)
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
else
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_IEE);
#elif defined (__picorv32__)
if (ie & 0x1)
_irq_enable();
else
_irq_disable();
#elif defined (__vexriscv__)
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
#elif defined (__minerva__)
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
#else
#error Unsupported architecture
#endif
}
static inline unsigned int irq_getmask(void)
{
#if defined (__lm32__)
unsigned int mask;
__asm__ __volatile__("rcsr %0, IM" : "=r" (mask));
return mask;
#elif defined (__or1k__)
return mfspr(SPR_PICMR);
#elif defined (__picorv32__)
// PicoRV32 interrupt mask bits are high-disabled. This is the inverse of how
// LiteX sees things.
return ~_irq_mask;
#elif defined (__vexriscv__)
unsigned int mask;
asm volatile ("csrr %0, %1" : "=r"(mask) : "i"(CSR_IRQ_MASK));
return mask;
#elif defined (__minerva__)
unsigned int mask;
asm volatile ("csrr %0, %1" : "=r"(mask) : "i"(CSR_IRQ_MASK));
return mask;
#else
#error Unsupported architecture
#endif
}
static inline void irq_setmask(unsigned int mask)
{
#if defined (__lm32__)
__asm__ __volatile__("wcsr IM, %0" : : "r" (mask));
#elif defined (__or1k__)
mtspr(SPR_PICMR, mask);
#elif defined (__picorv32__)
// PicoRV32 interrupt mask bits are high-disabled. This is the inverse of how
// LiteX sees things.
_irq_setmask(~mask);
#elif defined (__vexriscv__)
asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask));
#elif defined (__minerva__)
asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask));
#else
#error Unsupported architecture
#endif
}
static inline unsigned int irq_pending(void)
{
#if defined (__lm32__)
unsigned int pending;
__asm__ __volatile__("rcsr %0, IP" : "=r" (pending));
return pending;
#elif defined (__or1k__)
return mfspr(SPR_PICSR);
#elif defined (__picorv32__)
return _irq_pending;
#elif defined (__vexriscv__)
unsigned int pending;
asm volatile ("csrr %0, %1" : "=r"(pending) : "i"(CSR_IRQ_PENDING));
return pending;
#elif defined (__minerva__)
unsigned int pending;
asm volatile ("csrr %0, %1" : "=r"(pending) : "i"(CSR_IRQ_PENDING));
return pending;
#else
#error Unsupported architecture
#endif
}
#ifdef __cplusplus
}
#endif
#endif /* __IRQ_H */

124
sw/include/printf.h Normal file
View File

@ -0,0 +1,124 @@
/*
File: printf.h
Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
contributors may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
----------------------------------------------------------------------
This library is realy just two files: 'printf.h' and 'printf.c'.
They provide a simple and small (+200 loc) printf functionality to
be used in embedded systems.
I've found them so usefull in debugging that I do not bother with a
debugger at all.
They are distributed in source form, so to use them, just compile them
into your project.
Two printf variants are provided: printf and sprintf.
The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
Zero padding and field width are also supported.
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
long specifier is also
supported. Note that this will pull in some long math routines (pun intended!)
and thus make your executable noticably longer.
The memory foot print of course depends on the target cpu, compiler and
compiler options, but a rough guestimate (based on a H8S target) is about
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
Not too bad. Your milage may vary. By hacking the source code you can
get rid of some hunred bytes, I'm sure, but personally I feel the balance of
functionality and flexibility versus code size is close to optimal for
many embedded systems.
To use the printf you need to supply your own character output function,
something like :
void putc ( void* p, char c)
{
while (!SERIAL_PORT_EMPTY) ;
SERIAL_PORT_TX_REGISTER = c;
}
Before you can call printf you need to initialize it to use your
character output function with something like:
init_printf(NULL,putc);
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
the NULL (or any pointer) you pass into the 'init_printf' will eventually be
passed to your 'putc' routine. This allows you to pass some storage space (or
anything realy) to the character output function, if necessary.
This is not often needed but it was implemented like that because it made
implementing the sprintf function so neat (look at the source code).
The code is re-entrant, except for the 'init_printf' function, so it
is safe to call it from interupts too, although this may result in mixed output.
If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
The printf and sprintf functions are actually macros that translate to
'tfp_printf' and 'tfp_sprintf'. This makes it possible
to use them along with 'stdio.h' printf's in a single source file.
You just need to undef the names before you include the 'stdio.h'.
Note that these are not function like macros, so if you have variables
or struct members with these names, things will explode in your face.
Without variadic macros this is the best we can do to wrap these
fucnction. If it is a problem just give up the macros and use the
functions directly or rename them.
For further details see source code.
regs Kusti, 23.10.2004
*/
#ifndef __TFP_PRINTF__
#define __TFP_PRINTF__
#include <stdarg.h>
void init_printf(void* putp,void (*putf) (void*,char));
void tfp_printf(char *fmt, ...);
void tfp_sprintf(char* s,char *fmt, ...);
void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
#define printf tfp_printf
#define sprintf tfp_sprintf
#endif

8
sw/include/spiflash.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __SPIFLASH_H
#define __SPIFLASH_H
void write_to_flash_page(unsigned int addr, const unsigned char *c, unsigned int len);
void erase_flash_sector(unsigned int addr);
void write_to_flash(unsigned int addr, const unsigned char *c, unsigned int len);
#endif /* __SPIFLASH_H */

59
sw/include/system.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef __SYSTEM_H
#define __SYSTEM_H
#ifdef __cplusplus
extern "C" {
#endif
void flush_cpu_icache(void);
void flush_cpu_dcache(void);
void flush_l2_cache(void);
#ifdef __or1k__
#include <spr-defs.h>
static inline unsigned long mfspr(unsigned long add)
{
unsigned long ret;
__asm__ __volatile__ ("l.mfspr %0,%1,0" : "=r" (ret) : "r" (add));
return ret;
}
static inline void mtspr(unsigned long add, unsigned long val)
{
__asm__ __volatile__ ("l.mtspr %0,%1,0" : : "r" (add), "r" (val));
}
#endif
#if defined(__vexriscv__) || defined(__minerva__)
#include <csr-defs.h>
#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)); })
#endif
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_H */

15
sw/include/time.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __TIME_H
#define __TIME_H
#ifdef __cplusplus
extern "C" {
#endif
void time_init(void);
int elapsed(int *last_event, int period);
#ifdef __cplusplus
}
#endif
#endif /* __TIME_H */

20
sw/include/uart.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef __UART_H
#define __UART_H
#ifdef __cplusplus
extern "C" {
#endif
void uart_init(void);
void uart_isr(void);
void uart_sync(void);
void uart_write(char c);
char uart_read(void);
int uart_read_nonblock(void);
#ifdef __cplusplus
}
#endif
#endif

15
sw/include/usb.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __USB_H
#define __USB_H
#ifdef __cplusplus
extern "C" {
#endif
void usb_isr(void);
void usb_init(void);
#ifdef __cplusplus
}
#endif
#endif

55
sw/ld/linker.ld Normal file
View File

@ -0,0 +1,55 @@
INCLUDE ld/output_format.ld
ENTRY(_start)
__DYNAMIC = 0;
INCLUDE ld/regions.ld
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 = .;
} > sram
}
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);

1
sw/ld/output_format.ld Normal file
View File

@ -0,0 +1 @@
OUTPUT_FORMAT("elf32-littleriscv")

5
sw/ld/regions.ld Normal file
View File

@ -0,0 +1,5 @@
MEMORY {
spiflash : ORIGIN = 0x20000000, LENGTH = 0x00200000
sram : ORIGIN = 0x10000000, LENGTH = 0x00020000
rom : ORIGIN = 0x00000000, LENGTH = 0x00002000
}

243
sw/src/grainuum-phy.c Normal file
View File

@ -0,0 +1,243 @@
/****************************************************************************
* Grainuum Software USB Stack *
* *
* MIT License: *
* Copyright (c) 2016 Sean Cross *
* *
* 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, distribute with modifications, 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 ABOVE 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. *
* *
* Except as contained in this notice, the name(s) of the above copyright *
* holders shall not be used in advertising or otherwise to promote the *
* sale, use or other dealings in this Software without prior written *
* authorization. *
****************************************************************************/
#include <generated/csr.h>
#include <grainuum.h>
#include <printf.h>
__attribute__((weak)) void grainuumConnectPre(struct GrainuumUSB *usb)
{
(void)usb;
}
__attribute__((weak)) void grainuumConnectPost(struct GrainuumUSB *usb)
{
(void)usb;
}
__attribute__((weak)) void grainuumDisconnectPre(struct GrainuumUSB *usb)
{
(void)usb;
}
__attribute__((weak)) void grainuumDisconnectPost(struct GrainuumUSB *usb)
{
(void)usb;
}
__attribute__((weak)) void grainuumReceivePacket(struct GrainuumUSB *usb)
{
(void)usb;
}
__attribute__((weak)) void grainuumInitPre(struct GrainuumUSB *usb)
{
(void)usb;
}
__attribute__((weak)) void grainuumInitPost(struct GrainuumUSB *usb)
{
(void)usb;
}
/* --- */
void grainuum_receive_packet(struct GrainuumUSB *usb)
{
grainuumReceivePacket(usb);
}
int grainuumCaptureI(struct GrainuumUSB *usb, uint8_t samples[67])
{
#if 0
int ret;
const uint8_t nak_pkt[] = {USB_PID_NAK};
const uint8_t ack_pkt[] = {USB_PID_ACK};
ret = usbPhyReadI(usb, samples);
if (ret <= 0) {
if (ret != -1)
usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt));
return 0;
}
/* Save the byte counter for later inspection */
samples[11] = ret;
switch (samples[0]) {
case USB_PID_IN:
/* Make sure we have queued data, and that it's for this particular EP */
if ((!usb->queued_size)
|| (((((const uint16_t *)(samples+1))[0] >> 7) & 0xf) != usb->queued_epnum))
{
usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt));
break;
}
usbPhyWriteI(usb, usb->queued_data, usb->queued_size);
break;
case USB_PID_SETUP:
grainuum_receive_packet(usb);
break;
case USB_PID_OUT:
grainuum_receive_packet(usb);
break;
case USB_PID_ACK:
/* Allow the next byte to be sent */
usb->queued_size = 0;
grainuum_receive_packet(usb);
break;
case USB_PID_DATA0:
case USB_PID_DATA1:
usbPhyWriteI(usb, ack_pkt, sizeof(ack_pkt));
grainuum_receive_packet(usb);
break;
default:
usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt));
break;
}
return ret;
#endif
uint8_t obufbuf[128];
uint32_t obufbuf_cnt = 0;
while (!usb_ep_0_out_obuf_empty_read())
{
uint32_t obh = usb_ep_0_out_obuf_head_read();
obufbuf[obufbuf_cnt++] = obh;
usb_ep_0_out_obuf_head_write(1);
}
int i;
static int loops;
uint8_t last_tok = usb_ep_0_out_last_tok_read();
printf("i: %d b: %d olt: %02x --", loops, obufbuf_cnt, last_tok); //obe: %d obh: %02x\n", i, obe, obh);
for (i = 0; i < obufbuf_cnt; i++)
{
printf(" %02x", obufbuf[i]);
}
printf("\n");
usb_ep_0_out_ev_pending_write((1 << 1));
// Response
if (!usb_ep_0_in_ibuf_empty_read())
{
printf("USB ibuf still has data\n");
return 0;
}
uint32_t usb_in_pending = usb_ep_0_out_ev_pending_read();
if (usb_in_pending)
{
printf("USB EP0 in pending is: %02x\n", usb_in_pending);
return 0;
}
grainuumProcess(usb, last_tok, obufbuf, obufbuf_cnt);
return 0;
}
int grainuumInitialized(struct GrainuumUSB *usb)
{
if (!usb)
return 0;
return usb->initialized;
}
enum usb_responses {
USB_STALL = 0b11,
USB_ACK = 0b00,
USB_NAK = 0b01,
USB_NONE = 0b10,
};
void grainuumWriteQueue(struct GrainuumUSB *usb, int epnum,
const void *buffer, int size)
{
usb->queued_data = buffer;
usb->queued_epnum = epnum;
usb->queued_size = size;
int i;
const uint8_t *buffer_u8 = buffer;
for (i = 0; i < size; i++)
{
usb_ep_0_in_ibuf_head_write(buffer_u8[i]);
}
// Indicate that we respond with an ACK
usb_ep_0_in_respond_write(USB_ACK);
usb_ep_0_in_ev_pending_write(0xff);
}
void grainuumInit(struct GrainuumUSB *usb,
struct GrainuumConfig *cfg)
{
if (usb->initialized)
return;
printf("Initializing USB to %08x, cfg to 0x%08x 0x%08x\n", usb, cfg, cfg->getDescriptor);
grainuumInitPre(usb);
usb->cfg = cfg;
usb->state.usb = usb;
cfg->usb = usb;
usb->initialized = 1;
grainuumInitPost(usb);
}
void grainuumDisconnect(struct GrainuumUSB *usb)
{
grainuumDisconnectPre(usb);
usb_pullup_out_write(0);
grainuumDisconnectPost(usb);
}
void grainuumConnect(struct GrainuumUSB *usb)
{
grainuumConnectPre(usb);
usb_pullup_out_write(1);
grainuumConnectPost(usb);
}

348
sw/src/grainuum-state.c Normal file
View File

@ -0,0 +1,348 @@
/****************************************************************************
* Grainuum Software USB Stack *
* *
* MIT License: *
* Copyright (c) 2016 Sean Cross *
* *
* 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, distribute with modifications, 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 ABOVE 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. *
* *
* Except as contained in this notice, the name(s) of the above copyright *
* holders shall not be used in advertising or otherwise to promote the *
* sale, use or other dealings in this Software without prior written *
* authorization. *
****************************************************************************/
#include "grainuum.h"
#include <printf.h>
#include <generated/csr.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
void *memcpy(void *dest, const void *src, unsigned int n);
enum usb_state_packet_type {
packet_type_none,
packet_type_setup,
packet_type_setup_in,
packet_type_setup_out,
packet_type_in,
packet_type_out,
};
__attribute__((weak))
void grainuumSendWait(struct GrainuumUSB *usb, int epnum,
const void *data, int size)
{
(void)usb;
(void)epnum;
(void)data;
(void)size;
}
static uint16_t crc16_add(uint16_t crc, uint8_t c, uint16_t poly)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if ((crc ^ c) & 1)
crc = (crc >> 1) ^ poly;
else
crc >>= 1;
c >>= 1;
}
return crc;
}
static uint16_t crc16(const uint8_t *data, uint32_t size,
uint16_t init, uint32_t poly)
{
while (size--)
init = crc16_add(init, *data++, poly);
return init;
}
static void grainuum_state_clear_tx(struct GrainuumState *state, int result)
{
struct GrainuumUSB *usb = state->usb;
/* If a thread is blocking, wake it up with a failure */
if (usb->cfg->sendDataFinished && state->packet_queued)
usb->cfg->sendDataFinished(usb, result);
state->data_out_left = 0;
state->data_out_max = 0;
state->data_out = NULL;
state->packet_queued = 0;
}
static void grainuum_state_process_tx(struct GrainuumState *state)
{
uint16_t crc;
struct GrainuumUSB *usb = state->usb;
/* Don't allow us to re-prepare data */
if (state->packet_queued) {
return;
}
state->packet_queued = 1;
/* If there's no data to send, then don't send any */
if (!state->data_out) {
state->packet_queued = 0;
return;
}
/* If we've sent all of our data, then there's nothing else to send */
if ((state->data_out_left < 0) || (state->data_out_max < 0)) {
grainuum_state_clear_tx(state, 0);
return;
}
/* Pick the correct PID, DATA0 or DATA1 */
// if (state->data_buffer & (1 << state->tok_epnum))
// state->packet.pid = USB_PID_DATA1;
// else
// state->packet.pid = USB_PID_DATA0;
/* If there's no data, prepare a special NULL packet */
if ((state->data_out_left == 0) || (state->data_out_max == 0)) {
/* The special-null thing only happens for EP0 */
if (state->data_out_epnum != 0) {
grainuum_state_clear_tx(state, 0);
return;
}
state->packet.data[0] = 0; /* CRC16 for empty packets is 0 */
state->packet.data[1] = 0;
state->packet.size = 2;
grainuumWriteQueue(usb, state->data_out_epnum,
&state->packet, state->packet.size + 1);
return;
}
/* Keep the packet size to 8 bytes max */
if (state->data_out_left > GRAINUUM_PACKET_SIZE_MAX)
state->packet.size = GRAINUUM_PACKET_SIZE_MAX;
else
state->packet.size = state->data_out_left;
/* Limit the amount of data transferred to data_out_max */
if (state->packet.size > state->data_out_max)
state->packet.size = state->data_out_max;
/* Copy over data bytes */
memcpy(state->packet.data, state->data_out, state->packet.size);
/* Calculate and copy the crc16 */
crc = ~crc16(state->packet.data, state->packet.size, 0xffff, 0xa001);
state->packet.data[state->packet.size++] = crc;
state->packet.data[state->packet.size++] = crc >> 8;
/* Prepare the packet, including the PID at the end */
grainuumWriteQueue(usb, state->data_out_epnum,
&state->packet, state->packet.size + 1);
}
/* Called when a packet is ACKed.
* Updates the outgoing packet buffer.
*/
static void usbStateTransferSuccess(struct GrainuumState *state)
{
/* Reduce the amount of data left.
* If the packet is divisible by 8, this will cause one more call
* to this function with state->data_out_left == 0. This will send
* a NULL packet, which indicates end-of-transfer.
*/
state->data_out_left -= GRAINUUM_PACKET_SIZE_MAX;
state->data_out_max -= GRAINUUM_PACKET_SIZE_MAX;
state->data_out += GRAINUUM_PACKET_SIZE_MAX;
if ((state->data_out_left < 0) || (state->data_out_max < 0)) {
grainuum_state_clear_tx(state, 0);
/* End of a State setup packet */
if (state->packet_type == packet_type_setup_out)
state->packet_type = packet_type_none;
if (state->packet_type == packet_type_setup_in)
state->packet_type = packet_type_none;
if (state->packet_type == packet_type_out)
state->packet_type = packet_type_none;
}
state->packet_queued = 0;
}
/* Send data down the wire, interrupting any existing
* data that may be queued.
*/
static int grainuum_state_send_data(struct GrainuumState *state,
int epnum,
const void *data,
int size,
int max)
{
/* De-queue any data that may already be queued. */
grainuum_state_clear_tx(state, 1);
state->data_out_epnum = epnum;
state->data_out_left = size;
state->data_out_max = max;
state->data_out = data;
grainuum_state_process_tx(state);
return 0;
}
void grainuumDropData(struct GrainuumUSB *usb)
{
usb->state.packet_queued = 0;
usb->state.data_out = 0;
grainuumWriteQueue(usb, 0, NULL, 0);
}
int grainuumDataQueued(struct GrainuumUSB *usb)
{
return (usb->state.data_out || usb->state.packet_queued);
}
int grainuumSendData(struct GrainuumUSB *usb, int epnum,
const void *data, int size)
{
struct GrainuumState *state = &usb->state;
int ret;
if (state->data_out || !state->address || state->packet_queued) {
return -11; /* EAGAIN */
}
ret = grainuum_state_send_data(state, epnum, data, size, size);
if (ret)
return ret;
grainuum_state_process_tx(state);
if (usb->cfg->sendDataStarted)
usb->cfg->sendDataStarted(usb, epnum, data, size);
return 0;
}
static int grainuum_state_process_setup(struct GrainuumState *state, const uint8_t packet[10])
{
const struct usb_setup_packet *setup;
const void *response = (void *)-1;
uint32_t response_len = 0;
struct GrainuumUSB *usb = state->usb;
struct GrainuumConfig *cfg = usb->cfg;
setup = (const struct usb_setup_packet *)packet;
if ((setup->bmRequestType == 0x00) && (setup->bRequest == SET_ADDRESS)) {
state->address = setup->wValue;
}
else if ((setup->bmRequestType == 0x00) && (setup->bRequest == SET_CONFIGURATION)) {
if (cfg->setConfigNum)
cfg->setConfigNum(usb, setup->wValue);
}
else {
printf("Going to get descriptor @ 0x%08x\n", cfg->getDescriptor);
response_len = cfg->getDescriptor(usb, setup, &response);
}
grainuum_state_send_data(state, state->tok_epnum, response, response_len, setup->wLength);
return 0;
}
static void grainuum_state_parse_data(struct GrainuumState *state,
const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 2],
uint32_t size)
{
(void)size;
struct GrainuumUSB *usb = state->usb;
switch (state->packet_type) {
case packet_type_setup:
grainuum_state_process_setup(state, packet);
grainuum_state_process_tx(state);
state->packet_type = packet_type_none;
break;
case packet_type_out:
// XXX HACK: An OUT packet gets generated (on Windows at least) when
// terminating a SETUP sequence. This seems odd.
if (state->tok_epnum == 0)
break;
// Copy over the packet, minus the CRC16
memcpy(state->tok_buf + state->tok_pos, packet, size - 2);
state->tok_pos += (size - 2);
if (!usb->cfg->receiveData(usb, state->tok_epnum, size - 2, packet))
state->packet_type = packet_type_none;
break;
case packet_type_in:
case packet_type_none:
default:
break;
}
}
void grainuumProcess(struct GrainuumUSB *usb,
uint8_t pid,
const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 3],
uint32_t size)
{
// uint32_t size = packet[GRAINUUM_PACKET_SIZE_MAX + 3];
struct GrainuumState *state = &usb->state;
printf("Processing %d byte packet %x %08x (%02x)\n", size, pid, packet, packet[0]);
switch(pid) {
case VUSB_PID_SETUP:
printf("Setup packet!\n");
state->packet_type = packet_type_setup;
grainuum_state_clear_tx(state, 1);
break;
case USB_PID_OUT:
state->packet_type = packet_type_out;
state->tok_pos = 0;
state->tok_buf = usb->cfg->getReceiveBuffer(usb, state->tok_epnum, NULL);
break;
default:
printf("Unrecognized PID: %02x\n", pid);
break;
}
if (size == 0) {
usb_ep_0_in_respond_write(0);
usb_ep_0_in_ev_pending_write(0xff);
}
//state->data_buffer |= (1 << state->tok_epnum);
grainuum_state_parse_data(state, packet, size);
}

88
sw/src/main.c Normal file
View File

@ -0,0 +1,88 @@
#include <stdio.h>
#include <irq.h>
#include <printf.h>
#include <uart.h>
#include <usb.h>
#include <time.h>
#include <generated/csr.h>
void isr(void)
{
unsigned int irqs;
irqs = irq_pending() & irq_getmask();
if (irqs & (1 << USB_INTERRUPT))
usb_isr();
if (irqs & (1 << UART_INTERRUPT))
uart_isr();
}
static void rv_putchar(void *ignored, char c)
{
(void)ignored;
if (c == '\n')
uart_write('\r');
if (c == '\r')
return;
uart_write(c);
// uart_sync();
}
static void init(void)
{
init_printf(NULL, rv_putchar);
irq_setmask(0);
irq_setie(1);
uart_init();
usb_init();
time_init();
}
static const char *usb_hw_api(void) {
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
return "epfifo";
#else
#ifdef CSR_USB_OBUF_EMPTY_ADDR
return "rawfifo";
#else
#ifdef CSR_USB_WHATEVER
return "whatever";
#else
return "unrecognized hw api";
#endif /* CSR_USB_WHATEVER */
#endif /* CSR_USB_OBUF_EMPTY_ADDR */
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
}
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
init();
printf("\n\nUSB API: %s\n", usb_hw_api());
// printf("Press any key to enable USB...\n");
usb_print_status();
// uart_read();
printf("Enabling USB\n");
usb_connect();
printf("USB enabled, waiting for packet...\n");
// usb_wait();
usb_print_status();
int last = 0;
while (1)
{
if (usb_irq_happened() != last) {
last = usb_irq_happened();
printf("USB %d IRQ happened\n", last);
}
// printf("x");
usb_print_status();
}
return 0;
}

576
sw/src/usb-epfifo.c Normal file
View File

@ -0,0 +1,576 @@
#include <grainuum.h>
#include <usb.h>
#include <irq.h>
#include <generated/csr.h>
#include <string.h>
#include <printf.h>
#include <uart.h>
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
#define NUM_BUFFERS 4
#define BUFFER_SIZE 64
#define EP_INTERVAL_MS 6
//static struct GrainuumUSB usb;
//static uint8_t usb_buf[67];
static const uint8_t hid_report_descriptor[] = {
0x06, 0x00, 0xFF, // (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined
0x09, 0x00, // (LOCAL) USAGE 0xFF000000
0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0xFF000000: Page=Vendor-defined, Usage=, Type=)
0x26, 0xFF, 0x00, // (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255)
0x75, 0x08, // (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
0x95, 0x08, // (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
0x06, 0xFF, 0xFF, // (GLOBAL) USAGE_PAGE 0xFFFF Vendor-defined
0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001
0x81, 0x02, // (MAIN) INPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001
0x91, 0x02, // (MAIN) OUTPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
0xC0, // (MAIN) END_COLLECTION Application
};
static const struct usb_device_descriptor device_descriptor = {
.bLength = 18, //sizeof(struct usb_device_descriptor),
.bDescriptorType = DT_DEVICE, /* DEVICE */
.bcdUSB = 0x0200, /* USB 2.0 */
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = 0x08, /* 8-byte packets max */
.idVendor = 0x1209,
.idProduct = 0x9317,
.bcdDevice = 0x0114, /* Device release 1.14 */
.iManufacturer = 0x02, /* No manufacturer string */
.iProduct = 0x01, /* Product name in string #2 */
.iSerialNumber = 0x03, /* No serial number */
.bNumConfigurations = 0x01,
};
static const struct usb_configuration_descriptor configuration_descriptor = {
.bLength = 9, //sizeof(struct usb_configuration_descriptor),
.bDescriptorType = DT_CONFIGURATION,
.wTotalLength = (9 + /*9 + 9 + 7 +*/ 9 + 9 + 7 + 7) /*
(sizeof(struct usb_configuration_descriptor)
+ sizeof(struct usb_interface_descriptor)
+ sizeof(struct usb_hid_descriptor)
+ sizeof(struct usb_endpoint_descriptor)*/,
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 5,
.bmAttributes = 0x80, /* Remote wakeup not supported */
.bMaxPower = 100 / 2, /* 100 mA (in 2-mA units) */
.data = {
/* struct usb_interface_descriptor { */
/* uint8_t bLength; */ 9,
/* uint8_t bDescriptorType; */ DT_INTERFACE,
/* uint8_t bInterfaceNumber; */ 0,
/* uint8_t bAlternateSetting; */ 0,
/* uint8_t bNumEndpoints; */ 2, /* Two extra EPs */
/* uint8_t bInterfaceClass; */ 3, /* HID class */
/* uint8_t bInterfaceSubclass; */ 0, /* Boot Device subclass */
/* uint8_t bInterfaceProtocol; */ 0, /* 1 == keyboard, 2 == mouse */
/* uint8_t iInterface; */ 4, /* String index #4 */
/* }*/
/* struct usb_hid_descriptor { */
/* uint8_t bLength; */ 9,
/* uint8_t bDescriptorType; */ DT_HID,
/* uint16_t bcdHID; */ 0x11, 0x01,
/* uint8_t bCountryCode; */ 0,
/* uint8_t bNumDescriptors; */ 1, /* We have only one REPORT */
/* uint8_t bReportDescriptorType; */ DT_HID_REPORT,
/* uint16_t wReportDescriptorLength; */ sizeof(hid_report_descriptor),
sizeof(hid_report_descriptor) >> 8,
/* } */
/* struct usb_endpoint_descriptor { */
/* uint8_t bLength; */ 7,
/* uint8_t bDescriptorType; */ DT_ENDPOINT,
/* uint8_t bEndpointAddress; */ 0x81, /* EP1 (IN) */
/* uint8_t bmAttributes; */ 3, /* Interrupt */
/* uint16_t wMaxPacketSize; */ 0x08, 0x00,
/* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */
/* } */
/* struct usb_endpoint_descriptor { */
/* uint8_t bLength; */ 7,
/* uint8_t bDescriptorType; */ DT_ENDPOINT,
/* uint8_t bEndpointAddress; */ 0x01, /* EP1 (OUT) */
/* uint8_t bmAttributes; */ 3, /* Interrupt */
/* uint16_t wMaxPacketSize; */ 0x08, 0x00,
/* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */
/* } */
},
};
enum epfifo_response {
EPF_ACK = 0,
EPF_NAK = 1,
EPF_NONE = 2,
EPF_STALL = 3,
};
#define USB_EV_ERROR 1
#define USB_EV_PACKET 2
void usb_connect(void) {
usb_pullup_out_write(1);
// By default, it wants to respond with NAK.
usb_ep_0_out_respond_write(EPF_ACK);
usb_ep_0_in_respond_write(EPF_NAK);
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read());
usb_ep_0_out_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
usb_ep_0_in_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
}
void usb_init(void) {
return;
}
volatile int irq_count = 0;
#define EP0OUT_BUFFERS 64
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128];
uint8_t usb_ep0out_wr_ptr;
uint8_t usb_ep0out_rd_ptr;
int descriptor_ptr;
int max_byte_length = 8;
static const uint8_t *current_data;
static int current_length;
static int current_offset;
static int current_to_send;
static int maybe_send_more_data(int epnum) {
(void)epnum;
// Don't allow requeueing
if (usb_ep_0_in_respond_read() != EPF_NAK)
return -1;
// if (!usb_ep_0_in_ibuf_empty_read())
// return -2;
int this_offset;
current_to_send = current_length - current_offset;
if (current_to_send > max_byte_length)
current_to_send = max_byte_length;
for (this_offset = current_offset; this_offset < current_offset + current_to_send; this_offset++) {
usb_ep_0_in_ibuf_head_write(current_data[this_offset]);
}
usb_ep_0_in_respond_write(EPF_ACK);
return 0;
}
static int send_data(int epnum, const void *data, int total_count) {
// Don't allow requeueing
if (usb_ep_0_in_respond_read() != EPF_NAK)
return -1;
current_data = (uint8_t *)data;
current_length = total_count;
current_offset = 0;
maybe_send_more_data(epnum);
return 0;
}
void usb_isr(void) {
irq_count++;
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
if (ep0o_pending) {
int byte_count = 0;
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
while (1) {
if (usb_ep_0_out_obuf_empty_read())
break;
obuf[++byte_count] = usb_ep_0_out_obuf_head_read();
usb_ep_0_out_obuf_head_write(0);
}
usb_ep_0_out_ev_pending_write(ep0o_pending);
if (byte_count) {
obuf[0] = byte_count;
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
// usb_ep_0_in_dtb_write(1);
send_data(0, &device_descriptor, sizeof(device_descriptor));
}
else {
usb_ep_0_out_respond_write(EPF_ACK);
}
}
if (ep0i_pending) {
/*
uint8_t *descriptor = (uint8_t *)&device_descriptor;
if (descriptor_ptr < 0) {
usb_ep_0_in_respond_write(EPF_NAK);
}
else if (descriptor_ptr >= sizeof(device_descriptor)) {
descriptor_ptr = -1;
usb_ep_0_in_respond_write(EPF_ACK);
}
else {
usb_ep_0_in_respond_write(EPF_NAK);
for (descriptor_ptr; descriptor_ptr < sizeof(device_descriptor); descriptor_ptr++) {
usb_ep_0_in_ibuf_head_write(descriptor[descriptor_ptr]);
}
usb_ep_0_in_respond_write(EPF_ACK);
}
*/
usb_ep_0_in_respond_write(EPF_NAK);
current_offset += current_to_send;
maybe_send_more_data(0);
usb_ep_0_in_ev_pending_write(ep0i_pending);
}
return;
}
void usb_wait(void) {
while (!irq_count)
;
}
int usb_irq_happened(void) {
return irq_count;
}
static const char hex[] = "0123456789abcdef";
void usb_print_status(void) {
/*
printf("EP0_OUT Status: %02x\n", usb_ep_0_out_ev_status_read());
printf("EP0_OUT Pending: %02x\n", usb_ep_0_out_ev_pending_read());
printf("EP0_OUT Enable: %02x\n", usb_ep_0_out_ev_enable_read());
printf("EP0_OUT Last Tok: %02x\n", usb_ep_0_out_last_tok_read());
printf("EP0_OUT Respond: %02x\n", usb_ep_0_out_respond_read());
printf("EP0_OUT DTB: %02x\n", usb_ep_0_out_dtb_read());
printf("EP0_OUT OBUF Head: %02x\n", usb_ep_0_out_obuf_head_read());
printf("EP0_OUT OBUF Empty: %02x\n", usb_ep_0_out_obuf_empty_read());
printf("EP0_IN Status: %02x\n", usb_ep_0_in_ev_status_read());
printf("EP0_IN Pending: %02x\n", usb_ep_0_in_ev_pending_read());
printf("EP0_IN Enable: %02x\n", usb_ep_0_in_ev_enable_read());
printf("EP0_IN Last Tok: %02x\n", usb_ep_0_in_last_tok_read());
printf("EP0_IN Respond: %02x\n", usb_ep_0_in_respond_read());
printf("EP0_IN DTB: %02x\n", usb_ep_0_in_dtb_read());
printf("EP0_IN IBUF Head: %02x\n", usb_ep_0_in_ibuf_head_read());
printf("EP0_IN IBUF Empty: %02x\n", usb_ep_0_in_ibuf_empty_read());
*/
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
// printf("for (this_offset = current_offset; this_offset < this_offset + current_to_send; this_offset++) {\n");
// printf("for (this_offset = %d; this_offset < %d; %d++) {\n", current_offset, this_offset, this_offset + current_to_send, this_offset);
printf("current_data: 0x%08x\n", current_data);
printf("current_length: %d\n", current_length);
printf("current_offset: %d\n", current_offset);
printf("current_to_send: %d\n", current_to_send);
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr];
uint8_t cnt = obuf[0];
unsigned int i;
if (cnt) {
for (i = 0; i < cnt; i++) {
uart_write(' ');
uart_write(hex[(obuf[i+1] >> 4) & 0xf]);
uart_write(hex[obuf[i+1] & (0xf)]);
// printf(" %02x", obufbuf[i]);
}
uart_write('\r');
uart_write('\n');
}
// printf("\n");
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
}
}
// static inline unsigned char usb_pullup_out_read(void);
// static inline void usb_pullup_out_write(unsigned char value);
// static inline unsigned char usb_ep_0_out_ev_status_read(void);
// static inline void usb_ep_0_out_ev_status_write(unsigned char value);
// static inline unsigned char usb_ep_0_out_ev_pending_read(void);
// static inline void usb_ep_0_out_ev_pending_write(unsigned char value);
// static inline unsigned char usb_ep_0_out_ev_enable_read(void);
// static inline void usb_ep_0_out_ev_enable_write(unsigned char value);
// static inline unsigned char usb_ep_0_out_last_tok_read(void);
// static inline unsigned char usb_ep_0_out_respond_read(void);
// static inline void usb_ep_0_out_respond_write(unsigned char value);
// static inline unsigned char usb_ep_0_out_dtb_read(void);
// static inline void usb_ep_0_out_dtb_write(unsigned char value);
// static inline unsigned char usb_ep_0_out_obuf_head_read(void);
// static inline void usb_ep_0_out_obuf_head_write(unsigned char value);
// static inline unsigned char usb_ep_0_out_obuf_empty_read(void);
// static inline unsigned char usb_ep_0_in_ev_status_read(void);
// static inline void usb_ep_0_in_ev_status_write(unsigned char value);
// static inline unsigned char usb_ep_0_in_ev_pending_read(void);
// static inline void usb_ep_0_in_ev_pending_write(unsigned char value);
// static inline unsigned char usb_ep_0_in_ev_enable_read(void);
// static inline void usb_ep_0_in_ev_enable_write(unsigned char value);
// static inline unsigned char usb_ep_0_in_last_tok_read(void);
// static inline unsigned char usb_ep_0_in_respond_read(void);
// static inline void usb_ep_0_in_respond_write(unsigned char value);
// static inline unsigned char usb_ep_0_in_dtb_read(void);
// static inline void usb_ep_0_in_dtb_write(unsigned char value);
// static inline unsigned char usb_ep_0_in_ibuf_head_read(void);
// static inline void usb_ep_0_in_ibuf_head_write(unsigned char value);
// static inline unsigned char usb_ep_0_in_ibuf_empty_read(void);
#if 0
static uint32_t rx_buffer[NUM_BUFFERS][BUFFER_SIZE / sizeof(uint32_t)];
static uint8_t rx_buffer_head;
static uint8_t rx_buffer_tail;
static uint32_t rx_buffer_queries = 0;
static void set_usb_config_num(struct GrainuumUSB *usb, int configNum)
{
(void)usb;
(void)configNum;
;
}
#define USB_STR_BUF_LEN 64
static uint32_t str_buf_storage[USB_STR_BUF_LEN / sizeof(uint32_t)];
static int send_string_descriptor(const char *str, const void **data)
{
int len;
int max_len;
uint8_t *str_buf = (uint8_t *)str_buf_storage;
uint8_t *str_offset = str_buf;
len = strlen(str);
max_len = (USB_STR_BUF_LEN / 2) - 2;
if (len > max_len)
len = max_len;
*str_offset++ = (len * 2) + 2; // Two bytes for length count
*str_offset++ = DT_STRING; // Sending a string descriptor
while (len--)
{
*str_offset++ = *str++;
*str_offset++ = 0;
}
*data = str_buf;
// Return the size, which is stored in the first byte of the output data.
return str_buf[0];
}
static int get_string_descriptor(struct GrainuumUSB *usb,
uint32_t num,
const void **data)
{
static const uint8_t en_us[] = {0x04, DT_STRING, 0x09, 0x04};
(void)usb;
if (num == 0)
{
*data = en_us;
return sizeof(en_us);
}
// Product
if (num == 1)
return send_string_descriptor("Palawan Bootloader", data);
if (num == 2)
return send_string_descriptor("21", data);
if (num == 3)
return send_string_descriptor("1236", data);
if (num == 4)
return send_string_descriptor("12345", data);
if (num == 5)
return send_string_descriptor("54", data);
if (num == 6)
return send_string_descriptor("12345678901234", data);
return 0;
}
static int get_device_descriptor(struct GrainuumUSB *usb,
uint32_t num,
const void **data)
{
(void)usb;
if (num == 0)
{
*data = &device_descriptor;
return sizeof(device_descriptor);
}
return 0;
}
static int get_hid_report_descriptor(struct GrainuumUSB *usb,
uint32_t num,
const void **data)
{
(void)usb;
if (num == 0)
{
*data = &hid_report_descriptor;
return sizeof(hid_report_descriptor);
}
return 0;
}
static int get_configuration_descriptor(struct GrainuumUSB *usb,
uint32_t num,
const void **data)
{
(void)usb;
if (num == 0)
{
*data = &configuration_descriptor;
return configuration_descriptor.wTotalLength;
}
return 0;
}
static int get_descriptor(struct GrainuumUSB *usb,
const void *packet,
const void **response)
{
const struct usb_setup_packet *setup = packet;
printf("In get_Descriptor()\n");
switch (setup->wValueH)
{
case DT_DEVICE:
printf("Returning device descriptor %d\n", setup->wValueL);
return get_device_descriptor(usb, setup->wValueL, response);
case DT_STRING:
printf("Returning string descriptor %d\n", setup->wValueL);
return get_string_descriptor(usb, setup->wValueL, response);
case DT_CONFIGURATION:
printf("Returning configuration descriptor %d\n", setup->wValueL);
return get_configuration_descriptor(usb, setup->wValueL, response);
case DT_HID_REPORT:
printf("Returning HID descriptor %d\n", setup->wValueL);
return get_hid_report_descriptor(usb, setup->wValueL, response);
}
printf("Returning no descriptor %d\n", setup->wValueL);
return 0;
}
static void *get_usb_rx_buffer(struct GrainuumUSB *usb,
uint8_t epNum,
int32_t *size)
{
(void)usb;
(void)epNum;
if (size)
*size = sizeof(rx_buffer[0]);
rx_buffer_queries++;
return rx_buffer[rx_buffer_head];
}
static int received_data(struct GrainuumUSB *usb,
uint8_t epNum,
uint32_t bytes,
const void *data)
{
(void)usb;
(void)epNum;
(void)bytes;
(void)data;
if (epNum == 1)
{
rx_buffer_head = (rx_buffer_head + 1) & (NUM_BUFFERS - 1);
}
/* Return 0, indicating this packet is complete. */
return 0;
}
static int send_data_finished(struct GrainuumUSB *usb, int result)
{
(void)usb;
(void)result;
return 0;
}
static struct GrainuumConfig cfg = {
.getDescriptor = get_descriptor,
.getReceiveBuffer = get_usb_rx_buffer,
.receiveData = received_data,
.sendDataFinished = send_data_finished,
.setConfigNum = set_usb_config_num,
};
// void usb_isr(void) {
// // grainuumCaptureI(&usb, usb_buf);
// return;
// }
// void usb_init(void) {
// // grainuumInit(&usb, &cfg);
// // grainuumConnect(&usb);
// return;
// }
void usbPhyWriteI(const struct GrainuumUSB *usb, const void *buffer, uint32_t size) {
// (void)usb;
// const uint8_t *ubuffer = (const uint8_t *)buffer;
// uint32_t i = 0;
// while (i < size)
// usb_obuf_head_write(ubuffer[i]);
}
int usbPhyReadI(const struct GrainuumUSB *usb, uint8_t *samples) {
(void)usb;
int count = 0;
// while (!usb_ibuf_empty_read()) {
// samples[count++] = usb_ibuf_head_read();
// }
return count;
}
#endif
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */

116
sw/src/usb-rawfifo.c Normal file
View File

@ -0,0 +1,116 @@
#include <usb.h>
#include <irq.h>
#include <generated/csr.h>
#include <string.h>
#include <printf.h>
#include <uart.h>
#ifdef CSR_USB_OBUF_EMPTY_ADDR
static inline unsigned char usb_obuf_head_read(void);
static inline void usb_obuf_head_write(unsigned char value);
static inline unsigned char usb_obuf_empty_read(void);
static inline unsigned char usb_arm_read(void);
static inline void usb_arm_write(unsigned char value);
static inline unsigned char usb_ibuf_head_read(void);
static inline void usb_ibuf_head_write(unsigned char value);
static inline unsigned char usb_ibuf_empty_read(void);
static inline unsigned char usb_pullup_out_read(void);
static inline void usb_pullup_out_write(unsigned char value);
static inline unsigned char usb_ev_status_read(void);
static inline void usb_ev_status_write(unsigned char value);
static inline unsigned char usb_ev_pending_read(void);
static inline void usb_ev_pending_write(unsigned char value);
static inline unsigned char usb_ev_enable_read(void);
static inline void usb_ev_enable_write(unsigned char value);
static const char hex[] = "0123456789abcdef";
uint8_t usb_ep0out_wr_ptr;
uint8_t usb_ep0out_rd_ptr;
#define EP0OUT_BUFFERS 64
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128];
void usb_print_status(void)
{
static int loops;
loops++;
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr];
uint8_t cnt = obuf[0];
unsigned int i;
if (cnt) {
for (i = 0; i < cnt; i++) {
uart_write(' ');
uart_write(hex[(obuf[i+1] >> 4) & 0xf]);
uart_write(hex[obuf[i+1] & (0xf)]);
// printf(" %02x", obufbuf[i]);
}
uart_write('\r');
uart_write('\n');
}
// printf("\n");
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
}
// if (!obe) {
// uint32_t obh = usb_obuf_head_read();
// usb_obuf_head_write(1);
// if (i < 300)
// printf("i: %8d obe: %d obh: %02x\n", i, obe, obh);
// }
}
int irq_happened;
void usb_init(void) {
return;
}
void usb_isr(void) {
uint8_t pending = usb_ev_pending_read();
// Advance the obuf head, which will reset the obuf_empty bit
if (pending & 1) {
int byte_count = 0;
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
while (1) {
if (usb_obuf_empty_read())
break;
obuf[++byte_count] = usb_obuf_head_read();
usb_obuf_head_write(0);
}
usb_ev_pending_write(1);
obuf[0] = byte_count;
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
}
return;
}
void usb_connect(void) {
usb_pullup_out_write(1);
usb_ev_pending_write(usb_ev_pending_read());
usb_ev_enable_write(0xff);
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
}
void usb_wait(void) {
while (!irq_happened)
;
}
int usb_irq_happened(void) {
return irq_happened;
}
#endif /* CSR_USB_OBUF_EMPTY_ADDR */

61
sw/third_party/libbase/crc16.c vendored Normal file
View File

@ -0,0 +1,61 @@
#include <crc.h>
#ifdef CRC16_FAST
static const unsigned int crc16_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
unsigned short crc16(const unsigned char *buffer, int len)
{
return 0;
unsigned short crc;
crc = 0;
while(len-- > 0)
crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8);
return crc;
}
#else
unsigned short crc16(const unsigned char* data_p, int length) {
unsigned char x;
unsigned short crc = 0;
while (length--){
x = crc >> 8 ^ *data_p++;
x ^= x>>4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x <<5)) ^ ((unsigned short)x);
}
return crc;
}
#endif

103
sw/third_party/libbase/crc32.c vendored Normal file
View File

@ -0,0 +1,103 @@
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include <crc.h>
#ifdef CRC32_FAST
static const unsigned int crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
unsigned int crc32(const unsigned char *buffer, unsigned int len)
{
return 0;
unsigned int crc;
crc = 0;
crc = crc ^ 0xffffffffL;
while(len >= 8) {
DO8(buffer);
len -= 8;
}
if(len) do {
DO1(buffer);
} while(--len);
return crc ^ 0xffffffffL;
}
#else
unsigned int crc32(const unsigned char *message, unsigned int len) {
int j;
unsigned int i;
unsigned int byte, crc, mask;
i = 0;
crc = 0xFFFFFFFF;
while (i < len) {
byte = message[i]; // Get next byte.
crc = crc ^ byte;
for (j = 7; j >= 0; j--) { // Do eight times.
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
i = i + 1;
}
return ~crc;
}
#endif

91
sw/third_party/libbase/crt0-vexriscv.S vendored Normal file
View File

@ -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

117
sw/third_party/libbase/libc.c vendored Normal file
View File

@ -0,0 +1,117 @@
/* $OpenBSD: strlen.c,v 1.8 2014/06/10 04:17:37 deraadt Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <string.h>
size_t
strlen(const char *str)
{
const char *s;
for (s = str; *s; ++s)
;
return (s - str);
}
/**
* memcpy - Copies one area of memory to another
* @dest: Destination
* @src: Source
* @n: The size to copy.
*/
void *memcpy(void *to, const void *from, size_t n)
{
void *xto = to;
size_t temp;
if(!n)
return xto;
if((long)to & 1) {
char *cto = to;
const char *cfrom = from;
*cto++ = *cfrom++;
to = cto;
from = cfrom;
n--;
}
if((long)from & 1) {
char *cto = to;
const char *cfrom = from;
for (; n; n--)
*cto++ = *cfrom++;
return xto;
}
if(n > 2 && (long)to & 2) {
short *sto = to;
const short *sfrom = from;
*sto++ = *sfrom++;
to = sto;
from = sfrom;
n -= 2;
}
if((long)from & 2) {
short *sto = to;
const short *sfrom = from;
temp = n >> 1;
for (; temp; temp--)
*sto++ = *sfrom++;
to = sto;
from = sfrom;
if(n & 1) {
char *cto = to;
const char *cfrom = from;
*cto = *cfrom;
}
return xto;
}
temp = n >> 2;
if(temp) {
long *lto = to;
const long *lfrom = from;
for(; temp; temp--)
*lto++ = *lfrom++;
to = lto;
from = lfrom;
}
if(n & 2) {
short *sto = to;
const short *sfrom = from;
*sto++ = *sfrom++;
to = sto;
from = sfrom;
}
if(n & 1) {
char *cto = to;
const char *cfrom = from;
*cto = *cfrom;
}
return xto;
}

215
sw/third_party/libbase/qsort.c vendored Normal file
View File

@ -0,0 +1,215 @@
/****************************************************************************
* lib/stdlib/lib_qsort.c
*
* Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Leveraged from:
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
****************************************************************************/
#include <stdlib.h>
#define min(a, b) ((unsigned)(a)) < (((unsigned)(b))) ? ((unsigned)(a)) : ((unsigned)(b))
#define swapcode(TYPE, parmi, parmj, n) \
{ \
long i = (n) / sizeof (TYPE); \
register TYPE *pi = (TYPE *) (parmi); \
register TYPE *pj = (TYPE *) (parmj); \
do { \
register TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
#define SWAPINIT(a, size) \
swaptype = ((char *)a - (char *)0) % sizeof(long) || \
size % sizeof(long) ? 2 : size == sizeof(long)? 0 : 1;
#define swap(a, b) \
if (swaptype == 0) \
{ \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} \
else \
{ \
swapfunc(a, b, size, swaptype); \
}
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static inline void swapfunc(char *a, char *b, int n, int swaptype);
static inline char *med3(char *a, char *b, char *c,
int (*compar)(const void *, const void *));
static inline void swapfunc(char *a, char *b, int n, int swaptype)
{
if(swaptype <= 1)
{
swapcode(long, a, b, n)
}
else
{
swapcode(char, a, b, n)
}
}
static inline char *med3(char *a, char *b, char *c,
int (*compar)(const void *, const void *))
{
return compar(a, b) < 0 ?
(compar(b, c) < 0 ? b : (compar(a, c) < 0 ? c : a ))
:(compar(b, c) > 0 ? b : (compar(a, c) < 0 ? a : c ));
}
/****************************************************************************
* Name: qsort
*
* Description:
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*
****************************************************************************/
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *))
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
loop:
SWAPINIT(base, size);
swap_cnt = 0;
if (nmemb < 7)
{
for (pm = (char *) base + size; pm < (char *) base + nmemb * size; pm += size)
{
for (pl = pm; pl > (char *) base && compar(pl - size, pl) > 0; pl -= size)
{
swap(pl, pl - size);
}
}
return;
}
pm = (char *) base + (nmemb / 2) * size;
if (nmemb > 7)
{
pl = base;
pn = (char *) base + (nmemb - 1) * size;
if (nmemb > 40)
{
d = (nmemb / 8) * size;
pl = med3(pl, pl + d, pl + 2 * d, compar);
pm = med3(pm - d, pm, pm + d, compar);
pn = med3(pn - 2 * d, pn - d, pn, compar);
}
pm = med3(pl, pm, pn, compar);
}
swap(base, pm);
pa = pb = (char *) base + size;
pc = pd = (char *) base + (nmemb - 1) * size;
for (;;)
{
while (pb <= pc && (r = compar(pb, base)) <= 0)
{
if (r == 0)
{
swap_cnt = 1;
swap(pa, pb);
pa += size;
}
pb += size;
}
while (pb <= pc && (r = compar(pc, base)) >= 0)
{
if (r == 0)
{
swap_cnt = 1;
swap(pc, pd);
pd -= size;
}
pc -= size;
}
if (pb > pc)
{
break;
}
swap(pb, pc);
swap_cnt = 1;
pb += size;
pc -= size;
}
if (swap_cnt == 0)
{
/* Switch to insertion sort */
for (pm = (char *) base + size; pm < (char *) base + nmemb * size; pm += size)
{
for (pl = pm; pl > (char *) base && compar(pl - size, pl) > 0; pl -= size)
{
swap(pl, pl - size);
}
}
return;
}
pn = (char *) base + nmemb * size;
r = min(pa - (char *)base, pb - pa);
vecswap(base, pb - r, r);
r = min(pd - pc, pn - pd - size);
vecswap(pb, pn - r, r);
if ((r = pb - pa) > (int)size)
{
qsort(base, r / size, size, compar);
}
if ((r = pd - pc) > (int)size)
{
/* Iterate rather than recurse to save stack space */
base = pn - r;
nmemb = r / size;
goto loop;
}
}

33
sw/third_party/libbase/time.c vendored Normal file
View File

@ -0,0 +1,33 @@
#include <generated/csr.h>
#include <time.h>
void time_init(void)
{
int t;
timer0_en_write(0);
t = 2*SYSTEM_CLOCK_FREQUENCY;
timer0_reload_write(t);
timer0_load_write(t);
timer0_en_write(1);
}
int elapsed(int *last_event, int period)
{
int t, dt;
timer0_update_value_write(1);
t = timer0_reload_read() - timer0_value_read();
if(period < 0) {
*last_event = t;
return 1;
}
dt = t - *last_event;
if(dt < 0)
dt += timer0_reload_read();
if((dt > period) || (dt < 0)) {
*last_event = t;
return 1;
} else
return 0;
}

110
sw/third_party/libbase/uart.c vendored Normal file
View File

@ -0,0 +1,110 @@
#include <uart.h>
#include <irq.h>
#include <generated/csr.h>
#include <hw/flags.h>
/*
* Buffer sizes must be a power of 2 so that modulos can be computed
* with logical AND.
*/
#define UART_RINGBUFFER_SIZE_RX 128
#define UART_RINGBUFFER_MASK_RX (UART_RINGBUFFER_SIZE_RX-1)
static char rx_buf[UART_RINGBUFFER_SIZE_RX];
static volatile unsigned int rx_produce;
static unsigned int rx_consume;
#define UART_RINGBUFFER_SIZE_TX 128
#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)
static char tx_buf[UART_RINGBUFFER_SIZE_TX];
static unsigned int tx_produce;
static volatile unsigned int tx_consume;
void uart_isr(void)
{
unsigned int stat, rx_produce_next;
stat = uart_ev_pending_read();
if(stat & UART_EV_RX) {
while(!uart_rxempty_read()) {
rx_produce_next = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
if(rx_produce_next != rx_consume) {
rx_buf[rx_produce] = uart_rxtx_read();
rx_produce = rx_produce_next;
}
uart_ev_pending_write(UART_EV_RX);
}
}
if(stat & UART_EV_TX) {
uart_ev_pending_write(UART_EV_TX);
while((tx_consume != tx_produce) && !uart_txfull_read()) {
uart_rxtx_write(tx_buf[tx_consume]);
tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
}
}
}
/* Do not use in interrupt handlers! */
char uart_read(void)
{
char c;
if (irq_getie()) {
while (rx_consume == rx_produce);
} else if (rx_consume == rx_produce) {
return 0;
}
c = rx_buf[rx_consume];
rx_consume = (rx_consume + 1) & UART_RINGBUFFER_MASK_RX;
return c;
}
int uart_read_nonblock(void)
{
return (rx_consume != rx_produce);
}
void uart_write(char c)
{
unsigned int oldmask;
unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
if (irq_getie()) {
while(tx_produce_next == tx_consume);
} else if(tx_produce_next == tx_consume) {
return;
}
oldmask = irq_getmask();
irq_setmask(oldmask & ~(1 << UART_INTERRUPT));
if ((tx_consume != tx_produce) || uart_txfull_read()) {
tx_buf[tx_produce] = c;
tx_produce = tx_produce_next;
} else {
uart_rxtx_write(c);
}
irq_setmask(oldmask);
}
void uart_init(void)
{
rx_produce = 0;
rx_consume = 0;
tx_produce = 0;
tx_consume = 0;
uart_ev_pending_write(uart_ev_pending_read());
uart_ev_enable_write(UART_EV_TX | UART_EV_RX);
irq_setmask(irq_getmask() | (1 << UART_INTERRUPT));
}
void uart_sync(void)
{
while(tx_consume != tx_produce);
}

263
sw/third_party/printf.c vendored Normal file
View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "printf.h"
typedef void (*putcf)(void *, char);
static putcf stdout_putf;
static void *stdout_putp;
#ifdef PRINTF_LONG_SUPPORT
static void uli2a(unsigned long int num, unsigned int base, int uc, char *bf)
{
int n = 0;
unsigned int d = 1;
while (num / d >= base)
d *= base;
while (d != 0)
{
int dgt = num / d;
num %= d;
d /= base;
if (n || dgt > 0 || d == 0)
{
*bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
++n;
}
}
*bf = 0;
}
static void li2a(long num, char *bf)
{
if (num < 0)
{
num = -num;
*bf++ = '-';
}
uli2a(num, 10, 0, bf);
}
#endif
static void ui2a(unsigned int num, unsigned int base, int uc, char *bf)
{
int n = 0;
unsigned int d = 1;
while (num / d >= base)
d *= base;
while (d != 0)
{
int dgt = num / d;
num %= d;
d /= base;
if (n || dgt > 0 || d == 0)
{
*bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
++n;
}
}
*bf = 0;
}
static void i2a(int num, char *bf)
{
if (num < 0)
{
num = -num;
*bf++ = '-';
}
ui2a(num, 10, 0, bf);
}
static int a2d(char ch)
{
if (ch >= '0' && ch <= '9')
return ch - '0';
else if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
else if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
else
return -1;
}
static char a2i(char ch, char **src, int base, int *nump)
{
char *p = *src;
int num = 0;
int digit;
while ((digit = a2d(ch)) >= 0)
{
if (digit > base)
break;
num = num * base + digit;
ch = *p++;
}
*src = p;
*nump = num;
return ch;
}
static void putchw(void *putp, putcf putf, int n, char z, char *bf)
{
char fc = z ? '0' : ' ';
char ch;
char *p = bf;
while (*p++ && n > 0)
n--;
while (n-- > 0)
putf(putp, fc);
while ((ch = *bf++))
putf(putp, ch);
}
void tfp_format(void *putp, putcf putf, char *fmt, va_list va)
{
char bf[12];
char ch;
while ((ch = *(fmt++)))
{
if (ch != '%')
putf(putp, ch);
else
{
char lz = 0;
#ifdef PRINTF_LONG_SUPPORT
char lng = 0;
#endif
int w = 0;
ch = *(fmt++);
if (ch == '0')
{
ch = *(fmt++);
lz = 1;
}
if (ch >= '0' && ch <= '9')
{
ch = a2i(ch, &fmt, 10, &w);
}
#ifdef PRINTF_LONG_SUPPORT
if (ch == 'l')
{
ch = *(fmt++);
lng = 1;
}
#endif
switch (ch)
{
case 0:
goto abort;
case 'u':
{
#ifdef PRINTF_LONG_SUPPORT
if (lng)
uli2a(va_arg(va, unsigned long int), 10, 0, bf);
else
#endif
ui2a(va_arg(va, unsigned int), 10, 0, bf);
putchw(putp, putf, w, lz, bf);
break;
}
case 'd':
{
#ifdef PRINTF_LONG_SUPPORT
if (lng)
li2a(va_arg(va, unsigned long int), bf);
else
#endif
i2a(va_arg(va, int), bf);
putchw(putp, putf, w, lz, bf);
break;
}
case 'x':
case 'X':
#ifdef PRINTF_LONG_SUPPORT
if (lng)
uli2a(va_arg(va, unsigned long int), 16, (ch == 'X'), bf);
else
#endif
ui2a(va_arg(va, unsigned int), 16, (ch == 'X'), bf);
putchw(putp, putf, w, lz, bf);
break;
case 'c':
putf(putp, (char)(va_arg(va, int)));
break;
case 's':
putchw(putp, putf, w, 0, va_arg(va, char *));
break;
case '%':
putf(putp, ch);
default:
break;
}
}
}
abort:;
}
void init_printf(void *putp, void (*putf)(void *, char))
{
stdout_putf = putf;
stdout_putp = putp;
}
void tfp_printf(char *fmt, ...)
{
va_list va;
va_start(va, fmt);
tfp_format(stdout_putp, stdout_putf, fmt, va);
va_end(va);
}
static void putcp(void *p, char c)
{
*(*((char **)p))++ = c;
}
void tfp_sprintf(char *s, char *fmt, ...)
{
va_list va;
va_start(va, fmt);
tfp_format(&s, putcp, fmt, va);
putcp(&s, 0);
va_end(va);
}
int puts(const char *s) {
while (*s++)
stdout_putf(stdout_putp, *s);
stdout_putf(stdout_putp, '\n');
return 1;
}