foboot: move software stuff to sw directory
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
114
sw/Makefile
Normal file
114
sw/Makefile
Normal 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
24
sw/include/console.h
Normal 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
15
sw/include/crc.h
Normal 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
11
sw/include/csr-defs.h
Normal 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
413
sw/include/generated/csr.h
Normal 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
|
13
sw/include/generated/mem.h
Normal file
13
sw/include/generated/mem.h
Normal 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
602
sw/include/grainuum.h
Normal 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
52
sw/include/hw/common.h
Normal 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
40
sw/include/hw/flags.h
Normal 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
144
sw/include/irq.h
Normal 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
124
sw/include/printf.h
Normal 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
8
sw/include/spiflash.h
Normal 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
59
sw/include/system.h
Normal 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
15
sw/include/time.h
Normal 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
20
sw/include/uart.h
Normal 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
15
sw/include/usb.h
Normal 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
55
sw/ld/linker.ld
Normal 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
1
sw/ld/output_format.ld
Normal file
@ -0,0 +1 @@
|
||||
OUTPUT_FORMAT("elf32-littleriscv")
|
5
sw/ld/regions.ld
Normal file
5
sw/ld/regions.ld
Normal 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
243
sw/src/grainuum-phy.c
Normal 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
348
sw/src/grainuum-state.c
Normal 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
88
sw/src/main.c
Normal 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
576
sw/src/usb-epfifo.c
Normal 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
116
sw/src/usb-rawfifo.c
Normal 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
61
sw/third_party/libbase/crc16.c
vendored
Normal 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
103
sw/third_party/libbase/crc32.c
vendored
Normal 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
91
sw/third_party/libbase/crt0-vexriscv.S
vendored
Normal 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
117
sw/third_party/libbase/libc.c
vendored
Normal 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
215
sw/third_party/libbase/qsort.c
vendored
Normal 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
33
sw/third_party/libbase/time.c
vendored
Normal 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
110
sw/third_party/libbase/uart.c
vendored
Normal 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
263
sw/third_party/printf.c
vendored
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user