mirror of
https://github.com/im-tomu/foboot.git
synced 2024-09-20 02:40:09 +00:00
foboot-main: remove unused project
The `foboot-main` project was never completed, and probably should never have been merged to the main branch. Move it onto a side branch in case anyone wants to work on it. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
d9a72a8fde
commit
46556c1edf
@ -1,131 +0,0 @@
|
||||
GIT_VERSION := $(shell git describe --tags)
|
||||
|
||||
# There is no 64-bit gcc on Raspberry Pi, so use the 32-bit version
|
||||
ifneq (,$(wildcard /etc/rpi-issue))
|
||||
TRGT ?= riscv32-unknown-elf-
|
||||
else
|
||||
TRGT ?= riscv64-unknown-elf-
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
ifeq ($(LITEX),1)
|
||||
BASE_DIR := ../../../../sw
|
||||
LDSCRIPT := $(BASE_DIR)/ld/linker.ld
|
||||
LD_DIR := ../include/generated
|
||||
ADD_CFLAGS := -I../include -I$(BASE_DIR)/include
|
||||
ADD_LFLAGS :=
|
||||
PACKAGE := bios
|
||||
else
|
||||
BASE_DIR := .
|
||||
LD_DIR := $(BASE_DIR)/ld
|
||||
LDSCRIPT := $(BASE_DIR)/ld/linker.ld
|
||||
ADD_CFLAGS := -I$(BASE_DIR)/include
|
||||
ADD_LFLAGS :=
|
||||
PACKAGE := foboot-main
|
||||
endif
|
||||
|
||||
LDSCRIPTS := $(LDSCRIPT) $(LD_DIR)/output_format.ld $(LD_DIR)/regions.ld
|
||||
SRC_DIR := $(BASE_DIR)/src
|
||||
THIRD_PARTY := $(BASE_DIR)/third_party
|
||||
DBG_CFLAGS := -ggdb -g -DDEBUG -Wall
|
||||
DBG_LFLAGS := -ggdb -g -Wall
|
||||
CFLAGS := $(ADD_CFLAGS) \
|
||||
-D__vexriscv__ -march=rv32i -mabi=ilp32 \
|
||||
-Wall -Wextra \
|
||||
-flto \
|
||||
-ffunction-sections -fdata-sections -fno-common \
|
||||
-fomit-frame-pointer -Os \
|
||||
-march=rv32i \
|
||||
-DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11
|
||||
CXXFLAGS := $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
|
||||
LFLAGS := $(CFLAGS) $(ADD_LFLAGS) -L$(LD_DIR) \
|
||||
-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) $(THIRD_PARTY)/libbase
|
||||
|
||||
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).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 $(BASE_DIR)/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)
|
@ -1,24 +0,0 @@
|
||||
#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 */
|
@ -1,15 +0,0 @@
|
||||
#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
|
@ -1,11 +0,0 @@
|
||||
#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 */
|
@ -1,742 +0,0 @@
|
||||
#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 */
|
||||
|
||||
/* ctrl */
|
||||
#define CSR_CTRL_BASE 0xe0000000
|
||||
#define CSR_CTRL_RESET_ADDR 0xe0000000
|
||||
#define CSR_CTRL_RESET_SIZE 1
|
||||
static inline unsigned char ctrl_reset_read(void) {
|
||||
unsigned char r = csr_readl(0xe0000000);
|
||||
return r;
|
||||
}
|
||||
static inline void ctrl_reset_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0000000);
|
||||
}
|
||||
#define CSR_CTRL_SCRATCH_ADDR 0xe0000004
|
||||
#define CSR_CTRL_SCRATCH_SIZE 4
|
||||
static inline unsigned int ctrl_scratch_read(void) {
|
||||
unsigned int r = csr_readl(0xe0000004);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000008);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000000c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000010);
|
||||
return r;
|
||||
}
|
||||
static inline void ctrl_scratch_write(unsigned int value) {
|
||||
csr_writel(value >> 24, 0xe0000004);
|
||||
csr_writel(value >> 16, 0xe0000008);
|
||||
csr_writel(value >> 8, 0xe000000c);
|
||||
csr_writel(value, 0xe0000010);
|
||||
}
|
||||
#define CSR_CTRL_BUS_ERRORS_ADDR 0xe0000014
|
||||
#define CSR_CTRL_BUS_ERRORS_SIZE 4
|
||||
static inline unsigned int ctrl_bus_errors_read(void) {
|
||||
unsigned int r = csr_readl(0xe0000014);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000018);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000001c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000020);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* picorvspi */
|
||||
#define CSR_PICORVSPI_BASE 0xe0005000
|
||||
#define CSR_PICORVSPI_CFG1_ADDR 0xe0005000
|
||||
#define CSR_PICORVSPI_CFG1_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg1_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005000);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg1_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0005000);
|
||||
}
|
||||
#define CSR_PICORVSPI_CFG2_ADDR 0xe0005004
|
||||
#define CSR_PICORVSPI_CFG2_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg2_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005004);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg2_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0005004);
|
||||
}
|
||||
#define CSR_PICORVSPI_CFG3_ADDR 0xe0005008
|
||||
#define CSR_PICORVSPI_CFG3_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg3_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005008);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg3_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0005008);
|
||||
}
|
||||
#define CSR_PICORVSPI_CFG4_ADDR 0xe000500c
|
||||
#define CSR_PICORVSPI_CFG4_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg4_read(void) {
|
||||
unsigned char r = csr_readl(0xe000500c);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg4_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000500c);
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT1_ADDR 0xe0005010
|
||||
#define CSR_PICORVSPI_STAT1_SIZE 1
|
||||
static inline unsigned char picorvspi_stat1_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005010);
|
||||
return r;
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT2_ADDR 0xe0005014
|
||||
#define CSR_PICORVSPI_STAT2_SIZE 1
|
||||
static inline unsigned char picorvspi_stat2_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005014);
|
||||
return r;
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT3_ADDR 0xe0005018
|
||||
#define CSR_PICORVSPI_STAT3_SIZE 1
|
||||
static inline unsigned char picorvspi_stat3_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005018);
|
||||
return r;
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT4_ADDR 0xe000501c
|
||||
#define CSR_PICORVSPI_STAT4_SIZE 1
|
||||
static inline unsigned char picorvspi_stat4_read(void) {
|
||||
unsigned char r = csr_readl(0xe000501c);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* reboot */
|
||||
#define CSR_REBOOT_BASE 0xe0006000
|
||||
#define CSR_REBOOT_CTRL_ADDR 0xe0006000
|
||||
#define CSR_REBOOT_CTRL_SIZE 1
|
||||
static inline unsigned char reboot_ctrl_read(void) {
|
||||
unsigned char r = csr_readl(0xe0006000);
|
||||
return r;
|
||||
}
|
||||
static inline void reboot_ctrl_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0006000);
|
||||
}
|
||||
#define CSR_REBOOT_ADDR_ADDR 0xe0006004
|
||||
#define CSR_REBOOT_ADDR_SIZE 4
|
||||
static inline unsigned int reboot_addr_read(void) {
|
||||
unsigned int r = csr_readl(0xe0006004);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0006008);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000600c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0006010);
|
||||
return r;
|
||||
}
|
||||
static inline void reboot_addr_write(unsigned int value) {
|
||||
csr_writel(value >> 24, 0xe0006004);
|
||||
csr_writel(value >> 16, 0xe0006008);
|
||||
csr_writel(value >> 8, 0xe000600c);
|
||||
csr_writel(value, 0xe0006010);
|
||||
}
|
||||
|
||||
/* rgb */
|
||||
#define CSR_RGB_BASE 0xe0006800
|
||||
#define CSR_RGB_DAT_ADDR 0xe0006800
|
||||
#define CSR_RGB_DAT_SIZE 1
|
||||
static inline unsigned char rgb_dat_read(void) {
|
||||
unsigned char r = csr_readl(0xe0006800);
|
||||
return r;
|
||||
}
|
||||
static inline void rgb_dat_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0006800);
|
||||
}
|
||||
#define CSR_RGB_ADDR_ADDR 0xe0006804
|
||||
#define CSR_RGB_ADDR_SIZE 1
|
||||
static inline unsigned char rgb_addr_read(void) {
|
||||
unsigned char r = csr_readl(0xe0006804);
|
||||
return r;
|
||||
}
|
||||
static inline void rgb_addr_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0006804);
|
||||
}
|
||||
#define CSR_RGB_CTRL_ADDR 0xe0006808
|
||||
#define CSR_RGB_CTRL_SIZE 1
|
||||
static inline unsigned char rgb_ctrl_read(void) {
|
||||
unsigned char r = csr_readl(0xe0006808);
|
||||
return r;
|
||||
}
|
||||
static inline void rgb_ctrl_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0006808);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* touch */
|
||||
#define CSR_TOUCH_BASE 0xe0005800
|
||||
#define CSR_TOUCH_O_ADDR 0xe0005800
|
||||
#define CSR_TOUCH_O_SIZE 1
|
||||
static inline unsigned char touch_o_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005800);
|
||||
return r;
|
||||
}
|
||||
static inline void touch_o_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0005800);
|
||||
}
|
||||
#define CSR_TOUCH_OE_ADDR 0xe0005804
|
||||
#define CSR_TOUCH_OE_SIZE 1
|
||||
static inline unsigned char touch_oe_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005804);
|
||||
return r;
|
||||
}
|
||||
static inline void touch_oe_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0005804);
|
||||
}
|
||||
#define CSR_TOUCH_I_ADDR 0xe0005808
|
||||
#define CSR_TOUCH_I_SIZE 1
|
||||
static inline unsigned char touch_i_read(void) {
|
||||
unsigned char r = csr_readl(0xe0005808);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* usb */
|
||||
#define CSR_USB_BASE 0xe0004800
|
||||
#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800
|
||||
#define CSR_USB_PULLUP_OUT_SIZE 1
|
||||
static inline unsigned char usb_pullup_out_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004800);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_pullup_out_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004800);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_EV_STATUS_ADDR 0xe0004804
|
||||
#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(0xe0004804);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004804);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_EV_PENDING_ADDR 0xe0004808
|
||||
#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(0xe0004808);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004808);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_EV_ENABLE_ADDR 0xe000480c
|
||||
#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(0xe000480c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000480c);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_LAST_TOK_ADDR 0xe0004810
|
||||
#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(0xe0004810);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_RESPOND_ADDR 0xe0004814
|
||||
#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(0xe0004814);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_respond_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004814);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_DTB_ADDR 0xe0004818
|
||||
#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(0xe0004818);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_dtb_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004818);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_OBUF_HEAD_ADDR 0xe000481c
|
||||
#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(0xe000481c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_obuf_head_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000481c);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_ADDR 0xe0004820
|
||||
#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(0xe0004820);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_EV_STATUS_ADDR 0xe0004824
|
||||
#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(0xe0004824);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004824);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_EV_PENDING_ADDR 0xe0004828
|
||||
#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(0xe0004828);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004828);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_EV_ENABLE_ADDR 0xe000482c
|
||||
#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(0xe000482c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000482c);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_LAST_TOK_ADDR 0xe0004830
|
||||
#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(0xe0004830);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_RESPOND_ADDR 0xe0004834
|
||||
#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(0xe0004834);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_respond_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004834);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_DTB_ADDR 0xe0004838
|
||||
#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(0xe0004838);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_dtb_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004838);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_IBUF_HEAD_ADDR 0xe000483c
|
||||
#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(0xe000483c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ibuf_head_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000483c);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_IBUF_EMPTY_ADDR 0xe0004840
|
||||
#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(0xe0004840);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_EV_STATUS_ADDR 0xe0004844
|
||||
#define CSR_USB_EP_1_IN_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ev_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004844);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004844);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_EV_PENDING_ADDR 0xe0004848
|
||||
#define CSR_USB_EP_1_IN_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ev_pending_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004848);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004848);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_EV_ENABLE_ADDR 0xe000484c
|
||||
#define CSR_USB_EP_1_IN_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ev_enable_read(void) {
|
||||
unsigned char r = csr_readl(0xe000484c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000484c);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_LAST_TOK_ADDR 0xe0004850
|
||||
#define CSR_USB_EP_1_IN_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_last_tok_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004850);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_RESPOND_ADDR 0xe0004854
|
||||
#define CSR_USB_EP_1_IN_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_respond_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004854);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_respond_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004854);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_DTB_ADDR 0xe0004858
|
||||
#define CSR_USB_EP_1_IN_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_dtb_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004858);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_dtb_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004858);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_IBUF_HEAD_ADDR 0xe000485c
|
||||
#define CSR_USB_EP_1_IN_IBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ibuf_head_read(void) {
|
||||
unsigned char r = csr_readl(0xe000485c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ibuf_head_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000485c);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_IBUF_EMPTY_ADDR 0xe0004860
|
||||
#define CSR_USB_EP_1_IN_IBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ibuf_empty_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004860);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_EV_STATUS_ADDR 0xe0004864
|
||||
#define CSR_USB_EP_2_OUT_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_ev_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004864);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004864);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_EV_PENDING_ADDR 0xe0004868
|
||||
#define CSR_USB_EP_2_OUT_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_ev_pending_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004868);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004868);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_EV_ENABLE_ADDR 0xe000486c
|
||||
#define CSR_USB_EP_2_OUT_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_ev_enable_read(void) {
|
||||
unsigned char r = csr_readl(0xe000486c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000486c);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_LAST_TOK_ADDR 0xe0004870
|
||||
#define CSR_USB_EP_2_OUT_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_last_tok_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004870);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_RESPOND_ADDR 0xe0004874
|
||||
#define CSR_USB_EP_2_OUT_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_respond_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004874);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_respond_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004874);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_DTB_ADDR 0xe0004878
|
||||
#define CSR_USB_EP_2_OUT_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_dtb_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004878);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_dtb_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004878);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_OBUF_HEAD_ADDR 0xe000487c
|
||||
#define CSR_USB_EP_2_OUT_OBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_obuf_head_read(void) {
|
||||
unsigned char r = csr_readl(0xe000487c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_obuf_head_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000487c);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_ADDR 0xe0004880
|
||||
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_obuf_empty_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004880);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_EV_STATUS_ADDR 0xe0004884
|
||||
#define CSR_USB_EP_2_IN_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ev_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004884);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004884);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_EV_PENDING_ADDR 0xe0004888
|
||||
#define CSR_USB_EP_2_IN_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ev_pending_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004888);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004888);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_EV_ENABLE_ADDR 0xe000488c
|
||||
#define CSR_USB_EP_2_IN_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ev_enable_read(void) {
|
||||
unsigned char r = csr_readl(0xe000488c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000488c);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_LAST_TOK_ADDR 0xe0004890
|
||||
#define CSR_USB_EP_2_IN_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_last_tok_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004890);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_RESPOND_ADDR 0xe0004894
|
||||
#define CSR_USB_EP_2_IN_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_respond_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004894);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_respond_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004894);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_DTB_ADDR 0xe0004898
|
||||
#define CSR_USB_EP_2_IN_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_dtb_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004898);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_dtb_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004898);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_IBUF_HEAD_ADDR 0xe000489c
|
||||
#define CSR_USB_EP_2_IN_IBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ibuf_head_read(void) {
|
||||
unsigned char r = csr_readl(0xe000489c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ibuf_head_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000489c);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_IBUF_EMPTY_ADDR 0xe00048a0
|
||||
#define CSR_USB_EP_2_IN_IBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ibuf_empty_read(void) {
|
||||
unsigned char r = csr_readl(0xe00048a0);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* version */
|
||||
#define CSR_VERSION_BASE 0xe0007000
|
||||
#define CSR_VERSION_MAJOR_ADDR 0xe0007000
|
||||
#define CSR_VERSION_MAJOR_SIZE 1
|
||||
static inline unsigned char version_major_read(void) {
|
||||
unsigned char r = csr_readl(0xe0007000);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_MINOR_ADDR 0xe0007004
|
||||
#define CSR_VERSION_MINOR_SIZE 1
|
||||
static inline unsigned char version_minor_read(void) {
|
||||
unsigned char r = csr_readl(0xe0007004);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_REVISION_ADDR 0xe0007008
|
||||
#define CSR_VERSION_REVISION_SIZE 1
|
||||
static inline unsigned char version_revision_read(void) {
|
||||
unsigned char r = csr_readl(0xe0007008);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_GITREV_ADDR 0xe000700c
|
||||
#define CSR_VERSION_GITREV_SIZE 4
|
||||
static inline unsigned int version_gitrev_read(void) {
|
||||
unsigned int r = csr_readl(0xe000700c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007010);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007014);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007018);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_GITEXTRA_ADDR 0xe000701c
|
||||
#define CSR_VERSION_GITEXTRA_SIZE 2
|
||||
static inline unsigned short int version_gitextra_read(void) {
|
||||
unsigned short int r = csr_readl(0xe000701c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007020);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_DIRTY_ADDR 0xe0007024
|
||||
#define CSR_VERSION_DIRTY_SIZE 1
|
||||
static inline unsigned char version_dirty_read(void) {
|
||||
unsigned char r = csr_readl(0xe0007024);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* 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 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
|
@ -1,16 +0,0 @@
|
||||
#ifndef __GENERATED_MEM_H
|
||||
#define __GENERATED_MEM_H
|
||||
|
||||
#define VEXRISCV_DEBUG_BASE 0xf00f0000
|
||||
#define VEXRISCV_DEBUG_SIZE 0x00000010
|
||||
|
||||
#define SRAM_BASE 0x10000000
|
||||
#define SRAM_SIZE 0x00020000
|
||||
|
||||
#define ROM_BASE 0x00000000
|
||||
#define ROM_SIZE 0x00002000
|
||||
|
||||
#define SPIFLASH_BASE 0x20000000
|
||||
#define SPIFLASH_SIZE 0x00200000
|
||||
|
||||
#endif
|
@ -1,52 +0,0 @@
|
||||
#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 */
|
@ -1,40 +0,0 @@
|
||||
#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 */
|
@ -1,144 +0,0 @@
|
||||
#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 */
|
@ -1,10 +0,0 @@
|
||||
#ifndef _RGB_H_
|
||||
#define _RGB_H_
|
||||
|
||||
void rgb_init(void);
|
||||
void rgb_mode_idle(void);
|
||||
void rgb_mode_done(void);
|
||||
void rgb_mode_writing(void);
|
||||
void rgb_mode_error(void);
|
||||
|
||||
#endif /* _RGB_H_ */
|
@ -1,94 +0,0 @@
|
||||
#ifndef BB_SPI_H_
|
||||
#define BB_SPI_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum spi_state {
|
||||
SS_UNCONFIGURED = 0,
|
||||
SS_SINGLE,
|
||||
SS_DUAL_RX,
|
||||
SS_DUAL_TX,
|
||||
SS_QUAD_RX,
|
||||
SS_QUAD_TX,
|
||||
SS_HARDWARE,
|
||||
};
|
||||
|
||||
enum spi_type {
|
||||
ST_UNCONFIGURED,
|
||||
ST_SINGLE,
|
||||
ST_DUAL,
|
||||
ST_QUAD,
|
||||
ST_QPI,
|
||||
};
|
||||
|
||||
enum spi_pin {
|
||||
SP_MOSI,
|
||||
SP_MISO,
|
||||
SP_HOLD,
|
||||
SP_WP,
|
||||
SP_CS,
|
||||
SP_CLK,
|
||||
SP_D0,
|
||||
SP_D1,
|
||||
SP_D2,
|
||||
SP_D3,
|
||||
};
|
||||
|
||||
struct spi_id {
|
||||
uint8_t manufacturer_id; // Result from 0x90
|
||||
uint8_t device_id; // Result from 0x90
|
||||
uint8_t _manufacturer_id; // Result from 0x9f
|
||||
uint8_t memory_type; // Result from 0x9f
|
||||
uint8_t memory_size; // Result from 0x9f
|
||||
uint8_t signature; // Result from 0xab
|
||||
uint8_t serial[4]; // Result from 0x4b
|
||||
int bytes; // -1 if unknown
|
||||
const char *manufacturer;
|
||||
const char *model;
|
||||
const char *capacity;
|
||||
};
|
||||
|
||||
struct ff_spi;
|
||||
|
||||
void spiPause(struct ff_spi *spi);
|
||||
void spiBegin(struct ff_spi *spi);
|
||||
void spiEnd(struct ff_spi *spi);
|
||||
|
||||
//void spiSingleTx(struct ff_spi *spi, uint8_t out);
|
||||
//uint8_t spiSingleRx(struct ff_spi *spi);
|
||||
//void spiDualTx(struct ff_spi *spi, uint8_t out);
|
||||
//void spiQuadTx(struct ff_spi *spi, uint8_t out);
|
||||
void spiCommand(struct ff_spi *spi, uint8_t cmd);
|
||||
//uint8_t spiDualRx(struct ff_spi *spi);
|
||||
//uint8_t spiQuadRx(struct ff_spi *spi);
|
||||
int spiTx(struct ff_spi *spi, uint8_t word);
|
||||
uint8_t spiRx(struct ff_spi *spi);
|
||||
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr);
|
||||
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val);
|
||||
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
|
||||
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
|
||||
int spiSetType(struct ff_spi *spi, enum spi_type type);
|
||||
int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count);
|
||||
int spiIsBusy(struct ff_spi *spi);
|
||||
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr);
|
||||
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr);
|
||||
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *data, unsigned int count);
|
||||
void spiEnableQuad(void);
|
||||
|
||||
struct spi_id spiId(struct ff_spi *spi);
|
||||
void spiOverrideSize(struct ff_spi *spi, uint32_t new_size);
|
||||
|
||||
//int spi_wait_for_not_busy(struct ff_spi *spi);
|
||||
int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count);
|
||||
uint8_t spiReset(struct ff_spi *spi);
|
||||
int spiInit(struct ff_spi *spi);
|
||||
|
||||
void spiHold(struct ff_spi *spi);
|
||||
void spiUnhold(struct ff_spi *spi);
|
||||
void spiSwapTxRx(struct ff_spi *spi);
|
||||
|
||||
struct ff_spi *spiAlloc(void);
|
||||
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val);
|
||||
void spiFree(void);
|
||||
|
||||
#endif /* BB_SPI_H_ */
|
@ -1,8 +0,0 @@
|
||||
#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 */
|
@ -1,67 +0,0 @@
|
||||
#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
|
||||
|
||||
#include <generated/csr.h>
|
||||
|
||||
__attribute__((noreturn)) void reboot(void);
|
||||
|
||||
__attribute__((noreturn)) static inline void warmboot_to_image(uint8_t image_index) {
|
||||
reboot_ctrl_write(0xac | (image_index & 3) << 0);
|
||||
while (1);
|
||||
}
|
||||
#endif /* __SYSTEM_H */
|
@ -1,16 +0,0 @@
|
||||
#ifndef __TIME_H
|
||||
#define __TIME_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void time_init(void);
|
||||
int elapsed(int *last_event, int period);
|
||||
void msleep(int ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TIME_H */
|
@ -1,20 +0,0 @@
|
||||
#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
|
@ -1,99 +0,0 @@
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2013 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _usb_desc_h_
|
||||
#define _usb_desc_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <webusb-defs.h>
|
||||
|
||||
struct usb_setup_request {
|
||||
union {
|
||||
struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
};
|
||||
uint16_t wRequestAndType;
|
||||
};
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
};
|
||||
|
||||
struct usb_string_descriptor_struct {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t wString[];
|
||||
};
|
||||
|
||||
#define NUM_USB_BUFFERS 8
|
||||
#define VENDOR_ID 0x1209 // pid.codes
|
||||
#define PRODUCT_ID 0x70b1 // Assigned to Tomu project
|
||||
#define DEVICE_VER 0x0101 // Bootloader version
|
||||
#define MANUFACTURER_NAME u"Foosn"
|
||||
#define MANUFACTURER_NAME_LEN sizeof(MANUFACTURER_NAME)
|
||||
#define PRODUCT_NAME u"Fomu Bootloader " GIT_VERSION
|
||||
#define PRODUCT_NAME_LEN sizeof(PRODUCT_NAME)
|
||||
#define SERIAL_NUMBER u"000000000000"
|
||||
#define SERIAL_NUMBER_LEN sizeof(SERIAL_NUMBER)
|
||||
#define EP0_SIZE 64
|
||||
#define NUM_INTERFACE 1
|
||||
|
||||
// Microsoft Compatible ID Feature Descriptor
|
||||
#define MSFT_VENDOR_CODE '~' // Arbitrary, but should be printable ASCII
|
||||
#define MSFT_WCID_LEN 40
|
||||
extern const uint8_t usb_microsoft_wcid[MSFT_WCID_LEN];
|
||||
|
||||
#define USB_DT_ENDPOINT 5
|
||||
#define USB_DT_ENDPOINT_SIZE 7
|
||||
#define USB_ENDPOINT_ATTR_BULK 0x02
|
||||
|
||||
typedef struct {
|
||||
uint16_t wValue;
|
||||
uint16_t length;
|
||||
const uint8_t *addr;
|
||||
} usb_descriptor_list_t;
|
||||
|
||||
extern const usb_descriptor_list_t usb_descriptor_list[];
|
||||
|
||||
// WebUSB Landing page URL descriptor
|
||||
#define WEBUSB_VENDOR_CODE 2
|
||||
|
||||
#ifndef LANDING_PAGE_URL
|
||||
#define LANDING_PAGE_URL "dfu.fomu.im"
|
||||
#endif
|
||||
|
||||
#define LANDING_PAGE_DESCRIPTOR_SIZE (WEBUSB_DT_URL_DESCRIPTOR_SIZE \
|
||||
+ sizeof(LANDING_PAGE_URL) - 1)
|
||||
|
||||
const uint8_t *get_landing_url_descriptor(uint32_t *datalen);
|
||||
|
||||
#endif
|
@ -1,129 +0,0 @@
|
||||
#ifndef USB_MSC_H
|
||||
#define USB_MSC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* The sense codes */
|
||||
enum sbc_sense_key {
|
||||
SBC_SENSE_KEY_NO_SENSE = 0x00,
|
||||
SBC_SENSE_KEY_RECOVERED_ERROR = 0x01,
|
||||
SBC_SENSE_KEY_NOT_READY = 0x02,
|
||||
SBC_SENSE_KEY_MEDIUM_ERROR = 0x03,
|
||||
SBC_SENSE_KEY_HARDWARE_ERROR = 0x04,
|
||||
SBC_SENSE_KEY_ILLEGAL_REQUEST = 0x05,
|
||||
SBC_SENSE_KEY_UNIT_ATTENTION = 0x06,
|
||||
SBC_SENSE_KEY_DATA_PROTECT = 0x07,
|
||||
SBC_SENSE_KEY_BLANK_CHECK = 0x08,
|
||||
SBC_SENSE_KEY_VENDOR_SPECIFIC = 0x09,
|
||||
SBC_SENSE_KEY_COPY_ABORTED = 0x0A,
|
||||
SBC_SENSE_KEY_ABORTED_COMMAND = 0x0B,
|
||||
SBC_SENSE_KEY_VOLUME_OVERFLOW = 0x0D,
|
||||
SBC_SENSE_KEY_MISCOMPARE = 0x0E
|
||||
};
|
||||
|
||||
enum sbc_asc {
|
||||
SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
|
||||
SBC_ASC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x03,
|
||||
SBC_ASC_LOGICAL_UNIT_NOT_READY = 0x04,
|
||||
SBC_ASC_UNRECOVERED_READ_ERROR = 0x11,
|
||||
SBC_ASC_INVALID_COMMAND_OPERATION_CODE = 0x20,
|
||||
SBC_ASC_LBA_OUT_OF_RANGE = 0x21,
|
||||
SBC_ASC_INVALID_FIELD_IN_CDB = 0x24,
|
||||
SBC_ASC_WRITE_PROTECTED = 0x27,
|
||||
SBC_ASC_NOT_READY_TO_READY_CHANGE = 0x28,
|
||||
SBC_ASC_FORMAT_ERROR = 0x31,
|
||||
SBC_ASC_MEDIUM_NOT_PRESENT = 0x3A
|
||||
};
|
||||
|
||||
enum sbc_ascq {
|
||||
SBC_ASCQ_NA = 0x00,
|
||||
SBC_ASCQ_FORMAT_COMMAND_FAILED = 0x01,
|
||||
SBC_ASCQ_INITIALIZING_COMMAND_REQUIRED = 0x02,
|
||||
SBC_ASCQ_OPERATION_IN_PROGRESS = 0x07
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief SCSI Standard Inquiry data structure
|
||||
*/
|
||||
struct scsi_inquiry_data {
|
||||
uint8_t pq_pdt; /**< Peripheral Qual / Peripheral Dev Type */
|
||||
#define SCSI_INQ_PQ_CONNECTED 0x00 /**< Peripheral connected */
|
||||
#define SCSI_INQ_PQ_NOT_CONN 0x20 /**< Peripheral not connected */
|
||||
#define SCSI_INQ_PQ_NOT_SUPP 0x60 /**< Peripheral not supported */
|
||||
#define SCSI_INQ_DT_DIR_ACCESS 0x00 /**< Direct Access (SBC) */
|
||||
#define SCSI_INQ_DT_SEQ_ACCESS 0x01 /**< Sequential Access */
|
||||
#define SCSI_INQ_DT_PRINTER 0x02 /**< Printer */
|
||||
#define SCSI_INQ_DT_PROCESSOR 0x03 /**< Processor device */
|
||||
#define SCSI_INQ_DT_WRITE_ONCE 0x04 /**< Write-once device */
|
||||
#define SCSI_INQ_DT_CD_DVD 0x05 /**< CD/DVD device */
|
||||
#define SCSI_INQ_DT_OPTICAL 0x07 /**< Optical Memory */
|
||||
#define SCSI_INQ_DT_MC 0x08 /**< Medium Changer */
|
||||
#define SCSI_INQ_DT_ARRAY 0x0c /**< Storage Array Controller */
|
||||
#define SCSI_INQ_DT_ENCLOSURE 0x0d /**< Enclosure Services */
|
||||
#define SCSI_INQ_DT_RBC 0x0e /**< Simplified Direct Access */
|
||||
#define SCSI_INQ_DT_OCRW 0x0f /**< Optical card reader/writer */
|
||||
#define SCSI_INQ_DT_BCC 0x10 /**< Bridge Controller Commands */
|
||||
#define SCSI_INQ_DT_OSD 0x11 /**< Object-based Storage */
|
||||
#define SCSI_INQ_DT_NONE 0x1f /**< No Peripheral */
|
||||
uint8_t flags1; /**< Flags (byte 1) */
|
||||
#define SCSI_INQ_RMB 0x80 /**< Removable Medium */
|
||||
uint8_t version; /**< Version */
|
||||
#define SCSI_INQ_VER_NONE 0x00 /**< No standards conformance */
|
||||
#define SCSI_INQ_VER_SPC 0x03 /**< SCSI Primary Commands (link to SBC) */
|
||||
#define SCSI_INQ_VER_SPC2 0x04 /**< SCSI Primary Commands - 2 (link to SBC-2) */
|
||||
#define SCSI_INQ_VER_SPC3 0x05 /**< SCSI Primary Commands - 3 (link to SBC-2) */
|
||||
#define SCSI_INQ_VER_SPC4 0x06 /**< SCSI Primary Commands - 4 (link to SBC-3) */
|
||||
uint8_t flags3; /**< Flags (byte 3) */
|
||||
#define SCSI_INQ_NORMACA 0x20 /**< Normal ACA Supported */
|
||||
#define SCSI_INQ_HISUP 0x10 /**< Hierarchal LUN addressing */
|
||||
#define SCSI_INQ_RSP_SPC2 0x02 /**< SPC-2 / SPC-3 response format */
|
||||
uint8_t addl_len; /**< Additional Length (n-4) */
|
||||
#define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) /**< Total length is \a tot */
|
||||
uint8_t flags5; /**< Flags (byte 5) */
|
||||
#define SCSI_INQ_SCCS 0x80
|
||||
uint8_t flags6; /**< Flags (byte 6) */
|
||||
#define SCSI_INQ_BQUE 0x80
|
||||
#define SCSI_INQ_ENCSERV 0x40
|
||||
#define SCSI_INQ_MULTIP 0x10
|
||||
#define SCSI_INQ_MCHGR 0x08
|
||||
#define SCSI_INQ_ADDR16 0x01
|
||||
uint8_t flags7; /**< Flags (byte 7) */
|
||||
#define SCSI_INQ_WBUS16 0x20
|
||||
#define SCSI_INQ_SYNC 0x10
|
||||
#define SCSI_INQ_LINKED 0x08
|
||||
#define SCSI_INQ_CMDQUE 0x02
|
||||
uint8_t vendor_id[8]; /**< T10 Vendor Identification */
|
||||
uint8_t product_id[16]; /**< Product Identification */
|
||||
uint8_t product_rev[4]; /**< Product Revision Level */
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* Command Status Wrapper */
|
||||
#define CSW_SIGNATURE 0x53425355
|
||||
#define CSW_STATUS_SUCCESS 0
|
||||
#define CSW_STATUS_FAILED 1
|
||||
#define CSW_STATUS_PHASE_ERROR 2
|
||||
|
||||
struct usb_msc_csw {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cbw {
|
||||
// 'USBC'
|
||||
uint8_t signature[4];
|
||||
uint32_t tag;
|
||||
uint32_t length;
|
||||
uint8_t flags;
|
||||
uint8_t lun;
|
||||
uint8_t cbLength;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
int usb_msc_setup(const struct usb_setup_request *setup);
|
||||
void usb_msc_in(void);
|
||||
void usb_msc_out(const void *data, size_t len);
|
||||
|
||||
#endif // USB_MSC_H
|
@ -1,33 +0,0 @@
|
||||
#ifndef __USB_H
|
||||
#define __USB_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct usb_setup_request;
|
||||
|
||||
void usb_isr(void);
|
||||
void usb_init(void);
|
||||
void usb_connect(void);
|
||||
void usb_idle(void);
|
||||
void usb_disconnect(void);
|
||||
|
||||
int usb_irq_happened(void);
|
||||
void usb_setup(const struct usb_setup_request *setup);
|
||||
void usb_send(int epnum, const void *data, size_t total_count);
|
||||
void usb_send_cb(int epnum, int (*cb)(uint8_t *, size_t, void *), void *ptr);
|
||||
void usb_ack(int epnum);
|
||||
void usb_stall(int epnum);
|
||||
int usb_recv(void *buffer, size_t buffer_len);
|
||||
void usb_poll(void);
|
||||
void usb_wait_for_send_done(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Devan Lai
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software
|
||||
* for any purpose with or without fee is hereby granted, provided
|
||||
* that the above copyright notice and this permission notice
|
||||
* appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef WEBUSB_DEFS_H_INCLUDED
|
||||
#define WEBUSB_DEFS_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define WEBUSB_REQ_GET_URL 0x02
|
||||
|
||||
#define WEBUSB_DT_URL 3
|
||||
|
||||
#define WEBUSB_URL_SCHEME_HTTP 0
|
||||
#define WEBUSB_URL_SCHEME_HTTPS 1
|
||||
|
||||
struct webusb_platform_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDevCapabilityType;
|
||||
uint8_t bReserved;
|
||||
uint8_t platformCapabilityUUID[16];
|
||||
uint16_t bcdVersion;
|
||||
uint8_t bVendorCode;
|
||||
uint8_t iLandingPage;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor)
|
||||
|
||||
#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65}
|
||||
|
||||
struct webusb_url_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bScheme;
|
||||
char URL[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3
|
||||
|
||||
#endif
|
@ -1,912 +0,0 @@
|
||||
/*
|
||||
* xxHash - Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* OWNER 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.
|
||||
*
|
||||
* You can contact the author at :
|
||||
* - xxHash homepage: http://www.xxhash.com
|
||||
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
/*!XXH_FORCE_MEMORY_ACCESS :
|
||||
* By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
|
||||
* Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
|
||||
* The below switch allow to select different access method for improved performance.
|
||||
* Method 0 (default) : use `memcpy()`. Safe and portable.
|
||||
* Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
|
||||
* This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
|
||||
* Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
|
||||
* It can generate buggy code on targets which do not support unaligned memory accesses.
|
||||
* But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
|
||||
* See http://stackoverflow.com/a/32095106/646947 for details.
|
||||
* Prefer these methods in priority order (0 > 1 > 2)
|
||||
*/
|
||||
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
|
||||
# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|
||||
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
|
||||
# define XXH_FORCE_MEMORY_ACCESS 2
|
||||
# elif defined(__INTEL_COMPILER) || \
|
||||
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|
||||
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|
||||
|| defined(__ARM_ARCH_7S__) ))
|
||||
# define XXH_FORCE_MEMORY_ACCESS 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*!XXH_ACCEPT_NULL_INPUT_POINTER :
|
||||
* If input pointer is NULL, xxHash default behavior is to dereference it, triggering a segfault.
|
||||
* When this macro is enabled, xxHash actively checks input for null pointer.
|
||||
* It it is, result for null input pointers is the same as a null-length input.
|
||||
*/
|
||||
#ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */
|
||||
# define XXH_ACCEPT_NULL_INPUT_POINTER 0
|
||||
#endif
|
||||
|
||||
/*!XXH_FORCE_NATIVE_FORMAT :
|
||||
* By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
|
||||
* Results are therefore identical for little-endian and big-endian CPU.
|
||||
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
|
||||
* Should endian-independence be of no importance for your application, you may set the #define below to 1,
|
||||
* to improve speed for Big-endian CPU.
|
||||
* This option has no impact on Little_Endian CPU.
|
||||
*/
|
||||
#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
|
||||
# define XXH_FORCE_NATIVE_FORMAT 0
|
||||
#endif
|
||||
|
||||
/*!XXH_FORCE_ALIGN_CHECK :
|
||||
* This is a minor performance trick, only useful with lots of very small keys.
|
||||
* It means : check for aligned/unaligned input.
|
||||
* The check costs one initial branch per hash;
|
||||
* set it to 0 when the input is guaranteed to be aligned,
|
||||
* or when alignment doesn't matter for performance.
|
||||
*/
|
||||
#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
|
||||
# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
|
||||
# define XXH_FORCE_ALIGN_CHECK 0
|
||||
# else
|
||||
# define XXH_FORCE_ALIGN_CHECK 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Includes & Memory related functions
|
||||
***************************************/
|
||||
/*! Modify the local functions below should you wish to use some other memory routines
|
||||
* for malloc(), free() */
|
||||
#include <stdlib.h>
|
||||
static void* XXH_malloc(size_t s) { return malloc(s); }
|
||||
static void XXH_free (void* p) { free(p); }
|
||||
/*! and for memcpy() */
|
||||
#include <string.h>
|
||||
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
|
||||
|
||||
#define XXH_STATIC_LINKING_ONLY
|
||||
#include "xxhash.h"
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Compiler Specific Options
|
||||
***************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
# define FORCE_INLINE static __forceinline
|
||||
#else
|
||||
# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# ifdef __GNUC__
|
||||
# define FORCE_INLINE static inline __attribute__((always_inline))
|
||||
# else
|
||||
# define FORCE_INLINE static inline
|
||||
# endif
|
||||
# else
|
||||
# define FORCE_INLINE static
|
||||
# endif /* __STDC_VERSION__ */
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Basic Types
|
||||
***************************************/
|
||||
#ifndef MEM_MODULE
|
||||
# if !defined (__VMS) \
|
||||
&& (defined (__cplusplus) \
|
||||
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
# else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
|
||||
|
||||
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
|
||||
static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
|
||||
|
||||
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
|
||||
|
||||
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
|
||||
/* currently only defined for gcc and icc */
|
||||
typedef union { U32 u32; } __attribute__((packed)) unalign;
|
||||
static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
|
||||
|
||||
#else
|
||||
|
||||
/* portable and safe solution. Generally efficient.
|
||||
* see : http://stackoverflow.com/a/32095106/646947
|
||||
*/
|
||||
static U32 XXH_read32(const void* memPtr)
|
||||
{
|
||||
U32 val;
|
||||
memcpy(&val, memPtr, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
|
||||
|
||||
|
||||
/* ****************************************
|
||||
* Compiler-specific Functions and Macros
|
||||
******************************************/
|
||||
#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
|
||||
/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
|
||||
#if defined(_MSC_VER)
|
||||
# define XXH_rotl32(x,r) _rotl(x,r)
|
||||
# define XXH_rotl64(x,r) _rotl64(x,r)
|
||||
#else
|
||||
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) /* Visual Studio */
|
||||
# define XXH_swap32 _byteswap_ulong
|
||||
#elif XXH_GCC_VERSION >= 403
|
||||
# define XXH_swap32 __builtin_bswap32
|
||||
#else
|
||||
static U32 XXH_swap32 (U32 x)
|
||||
{
|
||||
return ((x << 24) & 0xff000000 ) |
|
||||
((x << 8) & 0x00ff0000 ) |
|
||||
((x >> 8) & 0x0000ff00 ) |
|
||||
((x >> 24) & 0x000000ff );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Architecture Macros
|
||||
***************************************/
|
||||
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
|
||||
|
||||
/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
|
||||
#ifndef XXH_CPU_LITTLE_ENDIAN
|
||||
static const int g_one = 1;
|
||||
# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
|
||||
#endif
|
||||
|
||||
|
||||
/* ***************************
|
||||
* Memory reads
|
||||
*****************************/
|
||||
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
static U32 XXH_readBE32(const void* ptr)
|
||||
{
|
||||
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
|
||||
}
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define XXH_STATIC_ASSERT(c) { enum { XXH_sa = 1/(int)(!!(c)) }; } /* use after variable declarations */
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
|
||||
|
||||
|
||||
/* *******************************************************************
|
||||
* 32-bit hash functions
|
||||
*********************************************************************/
|
||||
static const U32 PRIME32_1 = 2654435761U;
|
||||
static const U32 PRIME32_2 = 2246822519U;
|
||||
static const U32 PRIME32_3 = 3266489917U;
|
||||
static const U32 PRIME32_4 = 668265263U;
|
||||
static const U32 PRIME32_5 = 374761393U;
|
||||
|
||||
static U32 XXH32_round(U32 seed, U32 input)
|
||||
{
|
||||
seed += input * PRIME32_2;
|
||||
seed = XXH_rotl32(seed, 13);
|
||||
seed *= PRIME32_1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U32 h32;
|
||||
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
|
||||
|
||||
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
|
||||
if (p==NULL) {
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)16;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=16) {
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
U32 v2 = seed + PRIME32_2;
|
||||
U32 v3 = seed + 0;
|
||||
U32 v4 = seed - PRIME32_1;
|
||||
|
||||
do {
|
||||
v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
|
||||
v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
|
||||
v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
|
||||
v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
|
||||
} while (p<=limit);
|
||||
|
||||
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
|
||||
} else {
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (U32) len;
|
||||
|
||||
while (p+4<=bEnd) {
|
||||
h32 += XXH_get32bits(p) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH32_state_t state;
|
||||
XXH32_reset(&state, seed);
|
||||
XXH32_update(&state, input, len);
|
||||
return XXH32_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if (XXH_FORCE_ALIGN_CHECK) {
|
||||
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
} }
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*====== Hash streaming ======*/
|
||||
|
||||
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
|
||||
{
|
||||
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
|
||||
}
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
|
||||
{
|
||||
memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
|
||||
{
|
||||
XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state.v2 = seed + PRIME32_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME32_1;
|
||||
/* do not write into reserved, planned to be removed in a future version */
|
||||
memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE
|
||||
XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
if (input==NULL)
|
||||
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
|
||||
return XXH_OK;
|
||||
#else
|
||||
return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len_32 += (unsigned)len;
|
||||
state->large_len |= (len>=16) | (state->total_len_32>=16);
|
||||
|
||||
if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (unsigned)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* some data left from previous update */
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
|
||||
{ const unsigned* p32 = state->mem32;
|
||||
state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian));
|
||||
}
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= bEnd-16) {
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = state->v1;
|
||||
U32 v2 = state->v2;
|
||||
U32 v3 = state->v3;
|
||||
U32 v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
|
||||
v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
|
||||
v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
|
||||
v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
|
||||
} while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd) {
|
||||
XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
|
||||
state->memsize = (unsigned)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
|
||||
{
|
||||
const BYTE * p = (const BYTE*)state->mem32;
|
||||
const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
|
||||
U32 h32;
|
||||
|
||||
if (state->large_len) {
|
||||
h32 = XXH_rotl32(state->v1, 1)
|
||||
+ XXH_rotl32(state->v2, 7)
|
||||
+ XXH_rotl32(state->v3, 12)
|
||||
+ XXH_rotl32(state->v4, 18);
|
||||
} else {
|
||||
h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += state->total_len_32;
|
||||
|
||||
while (p+4<=bEnd) {
|
||||
h32 += XXH_readLE32(p, endian) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
|
||||
/*! Default XXH result types are basic unsigned 32 and 64 bits.
|
||||
* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
|
||||
* These functions allow transformation of hash result into and from its canonical format.
|
||||
* This way, hash values can be written into a file or buffer, remaining comparable across different systems.
|
||||
*/
|
||||
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
|
||||
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
|
||||
memcpy(dst, &hash, sizeof(*dst));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE32(src);
|
||||
}
|
||||
|
||||
|
||||
#ifndef XXH_NO_LONG_LONG
|
||||
|
||||
/* *******************************************************************
|
||||
* 64-bit hash functions
|
||||
*********************************************************************/
|
||||
|
||||
/*====== Memory access ======*/
|
||||
|
||||
#ifndef MEM_MODULE
|
||||
# define MEM_MODULE
|
||||
# if !defined (__VMS) \
|
||||
&& (defined (__cplusplus) \
|
||||
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
|
||||
# include <stdint.h>
|
||||
typedef uint64_t U64;
|
||||
# else
|
||||
/* if compiler doesn't support unsigned long long, replace by another 64-bit type */
|
||||
typedef unsigned long long U64;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
|
||||
|
||||
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
|
||||
static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
|
||||
|
||||
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
|
||||
|
||||
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
|
||||
/* currently only defined for gcc and icc */
|
||||
typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;
|
||||
static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }
|
||||
|
||||
#else
|
||||
|
||||
/* portable and safe solution. Generally efficient.
|
||||
* see : http://stackoverflow.com/a/32095106/646947
|
||||
*/
|
||||
|
||||
static U64 XXH_read64(const void* memPtr)
|
||||
{
|
||||
U64 val;
|
||||
memcpy(&val, memPtr, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
|
||||
|
||||
#if defined(_MSC_VER) /* Visual Studio */
|
||||
# define XXH_swap64 _byteswap_uint64
|
||||
#elif XXH_GCC_VERSION >= 403
|
||||
# define XXH_swap64 __builtin_bswap64
|
||||
#else
|
||||
static U64 XXH_swap64 (U64 x)
|
||||
{
|
||||
return ((x << 56) & 0xff00000000000000ULL) |
|
||||
((x << 40) & 0x00ff000000000000ULL) |
|
||||
((x << 24) & 0x0000ff0000000000ULL) |
|
||||
((x << 8) & 0x000000ff00000000ULL) |
|
||||
((x >> 8) & 0x00000000ff000000ULL) |
|
||||
((x >> 24) & 0x0000000000ff0000ULL) |
|
||||
((x >> 40) & 0x000000000000ff00ULL) |
|
||||
((x >> 56) & 0x00000000000000ffULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
static U64 XXH_readBE64(const void* ptr)
|
||||
{
|
||||
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
|
||||
}
|
||||
|
||||
|
||||
/*====== xxh64 ======*/
|
||||
|
||||
static const U64 PRIME64_1 = 11400714785074694791ULL;
|
||||
static const U64 PRIME64_2 = 14029467366897019727ULL;
|
||||
static const U64 PRIME64_3 = 1609587929392839161ULL;
|
||||
static const U64 PRIME64_4 = 9650029242287828579ULL;
|
||||
static const U64 PRIME64_5 = 2870177450012600261ULL;
|
||||
|
||||
static U64 XXH64_round(U64 acc, U64 input)
|
||||
{
|
||||
acc += input * PRIME64_2;
|
||||
acc = XXH_rotl64(acc, 31);
|
||||
acc *= PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static U64 XXH64_mergeRound(U64 acc, U64 val)
|
||||
{
|
||||
val = XXH64_round(0, val);
|
||||
acc ^= val;
|
||||
acc = acc * PRIME64_1 + PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U64 h64;
|
||||
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
|
||||
|
||||
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
|
||||
if (p==NULL) {
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)32;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=32) {
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
U64 v2 = seed + PRIME64_2;
|
||||
U64 v3 = seed + 0;
|
||||
U64 v4 = seed - PRIME64_1;
|
||||
|
||||
do {
|
||||
v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
|
||||
v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
|
||||
v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
|
||||
v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
|
||||
} while (p<=limit);
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
h64 = XXH64_mergeRound(h64, v1);
|
||||
h64 = XXH64_mergeRound(h64, v2);
|
||||
h64 = XXH64_mergeRound(h64, v3);
|
||||
h64 = XXH64_mergeRound(h64, v4);
|
||||
|
||||
} else {
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) len;
|
||||
|
||||
while (p+8<=bEnd) {
|
||||
U64 const k1 = XXH64_round(0, XXH_get64bits(p));
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd) {
|
||||
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH64_state_t state;
|
||||
XXH64_reset(&state, seed);
|
||||
XXH64_update(&state, input, len);
|
||||
return XXH64_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if (XXH_FORCE_ALIGN_CHECK) {
|
||||
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
} }
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*====== Hash Streaming ======*/
|
||||
|
||||
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
|
||||
{
|
||||
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
|
||||
}
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
|
||||
{
|
||||
memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
|
||||
{
|
||||
XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state.v2 = seed + PRIME64_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME64_1;
|
||||
/* do not write into reserved, planned to be removed in a future version */
|
||||
memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
FORCE_INLINE
|
||||
XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
if (input==NULL)
|
||||
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
|
||||
return XXH_OK;
|
||||
#else
|
||||
return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* tmp buffer is full */
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
|
||||
state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
|
||||
state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
|
||||
state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
|
||||
state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
|
||||
p += 32-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p+32 <= bEnd) {
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = state->v1;
|
||||
U64 v2 = state->v2;
|
||||
U64 v3 = state->v3;
|
||||
U64 v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
|
||||
v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
|
||||
v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
|
||||
v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
|
||||
} while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd) {
|
||||
XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
|
||||
state->memsize = (unsigned)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
|
||||
{
|
||||
const BYTE * p = (const BYTE*)state->mem64;
|
||||
const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
|
||||
U64 h64;
|
||||
|
||||
if (state->total_len >= 32) {
|
||||
U64 const v1 = state->v1;
|
||||
U64 const v2 = state->v2;
|
||||
U64 const v3 = state->v3;
|
||||
U64 const v4 = state->v4;
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
h64 = XXH64_mergeRound(h64, v1);
|
||||
h64 = XXH64_mergeRound(h64, v2);
|
||||
h64 = XXH64_mergeRound(h64, v3);
|
||||
h64 = XXH64_mergeRound(h64, v4);
|
||||
} else {
|
||||
h64 = state->v3 + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) state->total_len;
|
||||
|
||||
while (p+8<=bEnd) {
|
||||
U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd) {
|
||||
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
|
||||
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
|
||||
memcpy(dst, &hash, sizeof(*dst));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE64(src);
|
||||
}
|
||||
|
||||
#endif /* XXH_NO_LONG_LONG */
|
@ -1,294 +0,0 @@
|
||||
/*
|
||||
xxHash - Extremely Fast Hash algorithm
|
||||
Header File
|
||||
Copyright (C) 2012-2016, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
OWNER 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.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/* Notice extracted from xxHash homepage :
|
||||
|
||||
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
It also successfully passes all tests from the SMHasher suite.
|
||||
|
||||
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||
|
||||
Name Speed Q.Score Author
|
||||
xxHash 5.4 GB/s 10
|
||||
CrapWow 3.2 GB/s 2 Andrew
|
||||
MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
SBox 1.4 GB/s 9 Bret Mulvey
|
||||
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
CRC32 0.43 GB/s 9
|
||||
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
SHA1-32 0.28 GB/s 10
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
|
||||
A 64-bit version, named XXH64, is available since r35.
|
||||
It offers much better speed, but for 64-bit applications only.
|
||||
Name Speed on 64 bits Speed on 32 bits
|
||||
XXH64 13.8 GB/s 1.9 GB/s
|
||||
XXH32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#ifndef XXHASH_H_5627135585666179
|
||||
#define XXHASH_H_5627135585666179 1
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* ****************************
|
||||
* Definitions
|
||||
******************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||
|
||||
|
||||
/* ****************************
|
||||
* API modifier
|
||||
******************************/
|
||||
/** XXH_PRIVATE_API
|
||||
* This is useful to include xxhash functions in `static` mode
|
||||
* in order to inline them, and remove their symbol from the public list.
|
||||
* Methodology :
|
||||
* #define XXH_PRIVATE_API
|
||||
* #include "xxhash.h"
|
||||
* `xxhash.c` is automatically included.
|
||||
* It's not useful to compile and link it as a separate module.
|
||||
*/
|
||||
#ifdef XXH_PRIVATE_API
|
||||
# ifndef XXH_STATIC_LINKING_ONLY
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# endif
|
||||
# if defined(__GNUC__)
|
||||
# define XXH_PUBLIC_API static __inline __attribute__((unused))
|
||||
# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# define XXH_PUBLIC_API static inline
|
||||
# elif defined(_MSC_VER)
|
||||
# define XXH_PUBLIC_API static __inline
|
||||
# else
|
||||
/* this version may generate warnings for unused static functions */
|
||||
# define XXH_PUBLIC_API static
|
||||
# endif
|
||||
#else
|
||||
# define XXH_PUBLIC_API /* do nothing */
|
||||
#endif /* XXH_PRIVATE_API */
|
||||
|
||||
/*!XXH_NAMESPACE, aka Namespace Emulation :
|
||||
|
||||
If you want to include _and expose_ xxHash functions from within your own library,
|
||||
but also want to avoid symbol collisions with other libraries which may also include xxHash,
|
||||
|
||||
you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
|
||||
with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).
|
||||
|
||||
Note that no change is required within the calling program as long as it includes `xxhash.h` :
|
||||
regular symbol name will be automatically translated by this header.
|
||||
*/
|
||||
#ifdef XXH_NAMESPACE
|
||||
# define XXH_CAT(A,B) A##B
|
||||
# define XXH_NAME2(A,B) XXH_CAT(A,B)
|
||||
# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
|
||||
# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
|
||||
# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
|
||||
# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
|
||||
# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
|
||||
# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
|
||||
# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
|
||||
# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
|
||||
# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
|
||||
# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
|
||||
# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
|
||||
# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
|
||||
# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
|
||||
# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
|
||||
# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
|
||||
# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
|
||||
# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
|
||||
# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
|
||||
# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Version
|
||||
***************************************/
|
||||
#define XXH_VERSION_MAJOR 0
|
||||
#define XXH_VERSION_MINOR 6
|
||||
#define XXH_VERSION_RELEASE 4
|
||||
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||
|
||||
|
||||
/*-**********************************************************************
|
||||
* 32-bit hash
|
||||
************************************************************************/
|
||||
typedef unsigned int XXH32_hash_t;
|
||||
|
||||
/*! XXH32() :
|
||||
Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input".
|
||||
The memory between input & input+length must be valid (allocated and read-accessible).
|
||||
"seed" can be used to alter the result predictably.
|
||||
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
|
||||
|
||||
/*====== Streaming ======*/
|
||||
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
|
||||
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
|
||||
|
||||
/*
|
||||
These functions generate the xxHash of an input provided in multiple segments.
|
||||
Note that, for small input, they are slower than single-call functions, due to state management.
|
||||
For small input, prefer `XXH32()` and `XXH64()` .
|
||||
|
||||
XXH state must first be allocated, using XXH*_createState() .
|
||||
|
||||
Start a new hash by initializing state with a seed, using XXH*_reset().
|
||||
|
||||
Then, feed the hash state by calling XXH*_update() as many times as necessary.
|
||||
Obviously, input must be allocated and read accessible.
|
||||
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
||||
|
||||
Finally, a hash value can be produced anytime, by using XXH*_digest().
|
||||
This function returns the nn-bits hash as an int or long long.
|
||||
|
||||
It's still possible to continue inserting input into the hash state after a digest,
|
||||
and generate some new hashes later on, by calling again XXH*_digest().
|
||||
|
||||
When done, free XXH state space if it was allocated dynamically.
|
||||
*/
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
|
||||
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
|
||||
|
||||
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
|
||||
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
|
||||
* These functions allow transformation of hash result into and from its canonical format.
|
||||
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef XXH_NO_LONG_LONG
|
||||
/*-**********************************************************************
|
||||
* 64-bit hash
|
||||
************************************************************************/
|
||||
typedef unsigned long long XXH64_hash_t;
|
||||
|
||||
/*! XXH64() :
|
||||
Calculate the 64-bit hash of sequence of length "len" stored at memory address "input".
|
||||
"seed" can be used to alter the result predictably.
|
||||
This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark).
|
||||
*/
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
|
||||
|
||||
/*====== Streaming ======*/
|
||||
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
|
||||
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
|
||||
#endif /* XXH_NO_LONG_LONG */
|
||||
|
||||
|
||||
#ifdef XXH_STATIC_LINKING_ONLY
|
||||
|
||||
/* ================================================================================================
|
||||
This section contains declarations which are not guaranteed to remain stable.
|
||||
They may change in future versions, becoming incompatible with a different version of the library.
|
||||
These declarations should only be used with static linking.
|
||||
Never use them in association with dynamic linking !
|
||||
=================================================================================================== */
|
||||
|
||||
/* These definitions are only meant to make possible
|
||||
static allocation of XXH state, on stack or in a struct for example.
|
||||
Never use members directly. */
|
||||
|
||||
struct XXH32_state_s {
|
||||
unsigned total_len_32;
|
||||
unsigned large_len;
|
||||
unsigned v1;
|
||||
unsigned v2;
|
||||
unsigned v3;
|
||||
unsigned v4;
|
||||
unsigned mem32[4]; /* buffer defined as U32 for alignment */
|
||||
unsigned memsize;
|
||||
unsigned reserved; /* never read nor write, will be removed in a future version */
|
||||
}; /* typedef'd to XXH32_state_t */
|
||||
|
||||
#ifndef XXH_NO_LONG_LONG /* remove 64-bit support */
|
||||
struct XXH64_state_s {
|
||||
unsigned long long total_len;
|
||||
unsigned long long v1;
|
||||
unsigned long long v2;
|
||||
unsigned long long v3;
|
||||
unsigned long long v4;
|
||||
unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
|
||||
unsigned memsize;
|
||||
unsigned reserved[2]; /* never read nor write, will be removed in a future version */
|
||||
}; /* typedef'd to XXH64_state_t */
|
||||
#endif
|
||||
|
||||
#ifdef XXH_PRIVATE_API
|
||||
# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */
|
||||
#endif
|
||||
|
||||
#endif /* XXH_STATIC_LINKING_ONLY */
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XXHASH_H_5627135585666179 */
|
@ -1,56 +0,0 @@
|
||||
INCLUDE output_format.ld
|
||||
ENTRY(_start)
|
||||
|
||||
__DYNAMIC = 0;
|
||||
|
||||
INCLUDE 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)
|
||||
*(.ramtext .ramtext.*)
|
||||
_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 +0,0 @@
|
||||
OUTPUT_FORMAT("elf32-littleriscv")
|
@ -1,4 +0,0 @@
|
||||
MEMORY {
|
||||
sram : ORIGIN = 0x10000000, LENGTH = 128k
|
||||
rom : ORIGIN = 0x20000000 + 0x1a00, LENGTH = 0xc000
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
#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
|
@ -1,103 +0,0 @@
|
||||
/* 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
|
@ -1,83 +0,0 @@
|
||||
.global main
|
||||
.global isr
|
||||
|
||||
.section .text.start
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
j crt_init
|
||||
.word 0x032bd37d // Magic number indicating this is a valid FBM
|
||||
|
||||
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 section
|
||||
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
|
||||
|
||||
// 880 enable timer + external interrupt sources.
|
||||
// Until mstatus.MIE is set, they will never trigger an interrupt.
|
||||
li a0, 0x880
|
||||
csrw mie,a0
|
||||
|
||||
call main
|
||||
|
||||
.section .ramtext
|
||||
.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
|
@ -1,121 +0,0 @@
|
||||
.text
|
||||
.align 2
|
||||
|
||||
#ifndef __riscv64
|
||||
/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines. */
|
||||
# define __udivdi3 __udivsi3
|
||||
# define __umoddi3 __umodsi3
|
||||
# define __divdi3 __divsi3
|
||||
# define __moddi3 __modsi3
|
||||
#else
|
||||
.globl __udivsi3
|
||||
__udivsi3:
|
||||
/* Compute __udivdi3(a0 << 32, a1 << 32); cast result to uint32_t. */
|
||||
sll a0, a0, 32
|
||||
sll a1, a1, 32
|
||||
move t0, ra
|
||||
jal __udivdi3
|
||||
sext.w a0, a0
|
||||
jr t0
|
||||
|
||||
.globl __umodsi3
|
||||
__umodsi3:
|
||||
/* Compute __udivdi3((uint32_t)a0, (uint32_t)a1); cast a1 to uint32_t. */
|
||||
sll a0, a0, 32
|
||||
sll a1, a1, 32
|
||||
srl a0, a0, 32
|
||||
srl a1, a1, 32
|
||||
move t0, ra
|
||||
jal __udivdi3
|
||||
sext.w a0, a1
|
||||
jr t0
|
||||
|
||||
.globl __modsi3
|
||||
__modsi3 = __moddi3
|
||||
|
||||
.globl __divsi3
|
||||
__divsi3:
|
||||
/* Check for special case of INT_MIN/-1. Otherwise, fall into __divdi3. */
|
||||
li t0, -1
|
||||
beq a1, t0, .L20
|
||||
#endif
|
||||
|
||||
.globl __divdi3
|
||||
__divdi3:
|
||||
bltz a0, .L10
|
||||
bltz a1, .L11
|
||||
/* Since the quotient is positive, fall into __udivdi3. */
|
||||
|
||||
.globl __udivdi3
|
||||
__udivdi3:
|
||||
mv a2, a1
|
||||
mv a1, a0
|
||||
li a0, -1
|
||||
beqz a2, .L5
|
||||
li a3, 1
|
||||
bgeu a2, a1, .L2
|
||||
.L1:
|
||||
blez a2, .L2
|
||||
slli a2, a2, 1
|
||||
slli a3, a3, 1
|
||||
bgtu a1, a2, .L1
|
||||
.L2:
|
||||
li a0, 0
|
||||
.L3:
|
||||
bltu a1, a2, .L4
|
||||
sub a1, a1, a2
|
||||
or a0, a0, a3
|
||||
.L4:
|
||||
srli a3, a3, 1
|
||||
srli a2, a2, 1
|
||||
bnez a3, .L3
|
||||
.L5:
|
||||
ret
|
||||
|
||||
.globl __umoddi3
|
||||
__umoddi3:
|
||||
/* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */
|
||||
move t0, ra
|
||||
jal __udivdi3
|
||||
move a0, a1
|
||||
jr t0
|
||||
|
||||
/* Handle negative arguments to __divdi3. */
|
||||
.L10:
|
||||
neg a0, a0
|
||||
bgez a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */
|
||||
neg a1, a1
|
||||
j __divdi3 /* Compute __udivdi3(-a0, -a1). */
|
||||
.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */
|
||||
neg a1, a1
|
||||
.L12:
|
||||
move t0, ra
|
||||
jal __divdi3
|
||||
neg a0, a0
|
||||
jr t0
|
||||
|
||||
.globl __moddi3
|
||||
__moddi3:
|
||||
move t0, ra
|
||||
bltz a1, .L31
|
||||
bltz a0, .L32
|
||||
.L30:
|
||||
jal __udivdi3 /* The dividend is not negative. */
|
||||
move a0, a1
|
||||
jr t0
|
||||
.L31:
|
||||
neg a1, a1
|
||||
bgez a0, .L30
|
||||
.L32:
|
||||
neg a0, a0
|
||||
jal __udivdi3 /* The dividend is hella negative. */
|
||||
neg a0, a1
|
||||
jr t0
|
||||
|
||||
#ifdef __riscv64
|
||||
/* continuation of __divsi3 */
|
||||
.L20:
|
||||
sll t0, t0, 31
|
||||
bne a0, t0, __divdi3
|
||||
ret
|
||||
#endif
|
@ -1,117 +0,0 @@
|
||||
/* $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;
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <irq.h>
|
||||
#include <uart.h>
|
||||
#include <usb.h>
|
||||
#include <time.h>
|
||||
#include <rgb.h>
|
||||
#include <spi.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
struct ff_spi *spi;
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
void isr(void)
|
||||
{
|
||||
unsigned int irqs;
|
||||
|
||||
irqs = irq_pending() & irq_getmask();
|
||||
|
||||
if (irqs & (1 << USB_INTERRUPT))
|
||||
usb_isr();
|
||||
}
|
||||
|
||||
void reboot(void) {
|
||||
irq_setie(0);
|
||||
irq_setmask(0);
|
||||
|
||||
uint32_t reboot_addr = 262144;
|
||||
uint32_t boot_config = 0;
|
||||
|
||||
// Free the SPI controller, which returns it to memory-mapped mode.
|
||||
spiFree();
|
||||
|
||||
// Scan for configuration data.
|
||||
int i;
|
||||
int riscv_boot = 1;
|
||||
uint32_t *destination_array = (uint32_t *)reboot_addr;
|
||||
reboot_addr_write(reboot_addr);
|
||||
for (i = 0; i < 32; i++) {
|
||||
// Look for FPGA sync pulse.
|
||||
if ((destination_array[i] == 0x7e99aa7e)
|
||||
|| (destination_array[i] == 0x7eaa997e)) {
|
||||
riscv_boot = 0;
|
||||
break;
|
||||
}
|
||||
// Look for "boot config" word
|
||||
else if (destination_array[i] == 0xb469075a) {
|
||||
boot_config = destination_array[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// If requested, just let USB be idle. Otherwise, reset it.
|
||||
if (boot_config & 0x00000020) // NO_USB_RESET
|
||||
usb_idle();
|
||||
else
|
||||
usb_disconnect();
|
||||
|
||||
// Figure out what mode to put SPI flash into.
|
||||
if (boot_config & 0x00000001) { // QPI_EN
|
||||
spiEnableQuad();
|
||||
picorvspi_cfg3_write(picorvspi_cfg3_read() | 0x20);
|
||||
}
|
||||
if (boot_config & 0x00000002) // DDR_EN
|
||||
picorvspi_cfg3_write(picorvspi_cfg3_read() | 0x40);
|
||||
if (boot_config & 0x00000002) // CFM_EN
|
||||
picorvspi_cfg3_write(picorvspi_cfg3_read() | 0x10);
|
||||
rgb_mode_error();
|
||||
|
||||
// Vexriscv requires three extra nop cycles to flush the cache.
|
||||
if (boot_config & 0x00000010) { // FLUSH_CACHE
|
||||
asm("fence.i");
|
||||
asm("nop");
|
||||
asm("nop");
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
if (riscv_boot) {
|
||||
// Reset the Return Address, zero out some registers, and return.
|
||||
asm volatile(
|
||||
"mv ra,%0\n\t" /* x1 */
|
||||
"mv sp,zero\n\t" /* x2 */
|
||||
"mv gp,zero\n\t" /* x3 */
|
||||
"mv tp,zero\n\t" /* x4 */
|
||||
"mv t0,zero\n\t" /* x5 */
|
||||
"mv t1,zero\n\t" /* x6 */
|
||||
"mv t2,zero\n\t" /* x7 */
|
||||
"mv x8,zero\n\t" /* x8 */
|
||||
"mv s1,zero\n\t" /* x9 */
|
||||
"mv a0,zero\n\t" /* x10 */
|
||||
"mv a1,zero\n\t" /* x11 */
|
||||
"ret\n\t"
|
||||
|
||||
:
|
||||
: "r"(reboot_addr)
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Issue a reboot
|
||||
warmboot_to_image(2);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
#ifdef CSR_UART_BASE
|
||||
init_printf(NULL, rv_putchar);
|
||||
#endif
|
||||
irq_setmask(0);
|
||||
irq_setie(1);
|
||||
uart_init();
|
||||
usb_init();
|
||||
time_init();
|
||||
rgb_init();
|
||||
}
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
init();
|
||||
|
||||
usb_connect();
|
||||
while (1)
|
||||
{
|
||||
usb_poll();
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
.text
|
||||
.align 2
|
||||
|
||||
#ifdef __riscv64
|
||||
#define _RISCV_SZPTR 64
|
||||
#define _RISCV_SZINT 64
|
||||
#else
|
||||
/* Our RV64 64-bit routine is equivalent to our RV32 32-bit routine. */
|
||||
# define __muldi3 __mulsi3
|
||||
#define _RISCV_SZPTR 32
|
||||
#define _RISCV_SZINT 32
|
||||
#endif
|
||||
|
||||
.globl __muldi3
|
||||
__muldi3:
|
||||
mv a2, a0
|
||||
li a0, 0
|
||||
.L1:
|
||||
slli a3, a1, _RISCV_SZPTR-1
|
||||
bgez a3, .L2
|
||||
add a0, a0, a2
|
||||
.L2:
|
||||
srli a1, a1, 1
|
||||
slli a2, a2, 1
|
||||
bnez a1, .L1
|
||||
ret
|
@ -1,215 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +0,0 @@
|
||||
#include <rgb.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
enum led_registers {
|
||||
LEDDCR0 = 8,
|
||||
LEDDBR = 9,
|
||||
LEDDONR = 10,
|
||||
LEDDOFR = 11,
|
||||
LEDDBCRR = 5,
|
||||
LEDDBCFR = 6,
|
||||
LEDDPWRR = 1,
|
||||
LEDDPWRG = 2,
|
||||
LEDDPWRB = 3,
|
||||
};
|
||||
|
||||
#define BREATHE_ENABLE (1 << 7)
|
||||
#define BREATHE_EDGE_ON (0 << 6)
|
||||
#define BREATHE_EDGE_BOTH (1 << 6)
|
||||
#define BREATHE_MODE_MODULATE (1 << 5)
|
||||
#define BREATHE_RATE(x) ((x & 7) << 0)
|
||||
|
||||
#define RGB_SWITCH_MODE(x) do { \
|
||||
if (rgb_mode == x) \
|
||||
return; \
|
||||
rgb_mode = x; \
|
||||
/* Toggle LEDD_EXE to force the mode to switch */ \
|
||||
rgb_ctrl_write( (1 << 1) | (1 << 2)); \
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2)); \
|
||||
} while(0)
|
||||
|
||||
static enum {
|
||||
INVALID = 0,
|
||||
IDLE,
|
||||
WRITING,
|
||||
ERROR,
|
||||
DONE,
|
||||
} rgb_mode;
|
||||
|
||||
static void rgb_write(uint8_t value, uint8_t addr) {
|
||||
rgb_addr_write(addr);
|
||||
rgb_dat_write(value);
|
||||
}
|
||||
|
||||
void rgb_init(void) {
|
||||
// Turn on the RGB block and current enable, as well as enabling led control
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2));
|
||||
|
||||
// Enable the LED driver, and set 250 Hz mode.
|
||||
// Also set quick stop, which we'll use to switch patterns quickly.
|
||||
rgb_write((1 << 7) | (1 << 6) | (1 << 3), LEDDCR0);
|
||||
|
||||
// Set clock register to 12 MHz / 64 kHz - 1
|
||||
rgb_write((12000000/64000)-1, LEDDBR);
|
||||
|
||||
rgb_mode_idle();
|
||||
}
|
||||
|
||||
static void rgb_switch_mode(uint8_t mode,
|
||||
uint8_t onr, uint8_t ofr,
|
||||
uint8_t onrate, uint8_t offrate,
|
||||
uint8_t r, uint8_t g, uint8_t b) {
|
||||
RGB_SWITCH_MODE(mode);
|
||||
rgb_write(onr, LEDDONR);
|
||||
rgb_write(ofr, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(onrate), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(offrate), LEDDBCFR);
|
||||
|
||||
rgb_write(r, LEDDPWRG); // Red
|
||||
rgb_write(g, LEDDPWRB); // Green
|
||||
rgb_write(b, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_idle(void) {
|
||||
rgb_switch_mode(IDLE, 18, 5, 20, 3, 0x00/4, 0x7a/4, 0x31/4);
|
||||
}
|
||||
|
||||
void rgb_mode_writing(void) {
|
||||
rgb_switch_mode(WRITING, 1, 2, 1, 3, 0x00/4, 0x7a/4, 0x51/4);
|
||||
}
|
||||
|
||||
void rgb_mode_error(void) {
|
||||
rgb_switch_mode(ERROR, 3, 3, 2, 3, 0xf0/4, 0x0a/4, 0x01/4);
|
||||
}
|
||||
|
||||
void rgb_mode_done(void) {
|
||||
rgb_switch_mode(DONE, 8, 8, 2, 3, 0x14/4, 0xff/4, 0x44/4);
|
||||
}
|
@ -1,824 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
#define fprintf(...) do {} while(0)
|
||||
|
||||
static uint8_t do_mirror;
|
||||
static uint8_t oe_mirror;
|
||||
|
||||
#define PI_OUTPUT 1
|
||||
#define PI_INPUT 0
|
||||
#define PI_ALT0 PI_INPUT
|
||||
static void gpioSetMode(int pin, int mode) {
|
||||
if (mode)
|
||||
oe_mirror |= 1 << pin;
|
||||
else
|
||||
oe_mirror &= ~(1 << pin);
|
||||
picorvspi_cfg2_write(oe_mirror);
|
||||
}
|
||||
|
||||
static void gpioWrite(int pin, int val) {
|
||||
if (val)
|
||||
do_mirror |= 1 << pin;
|
||||
else
|
||||
do_mirror &= ~(1 << pin);
|
||||
picorvspi_cfg1_write(do_mirror);
|
||||
}
|
||||
|
||||
static int gpioRead(int pin) {
|
||||
return !!(picorvspi_stat1_read() & (1 << pin));
|
||||
}
|
||||
|
||||
static void gpioSync(void) {
|
||||
// bbspi_do_write(do_mirror);
|
||||
}
|
||||
|
||||
#define SPI_ONLY_SINGLE
|
||||
|
||||
enum ff_spi_quirks {
|
||||
// There is no separate "Write SR 2" command. Instead,
|
||||
// you must write SR2 after writing SR1
|
||||
SQ_SR2_FROM_SR1 = (1 << 0),
|
||||
|
||||
// Don't issue a "Write Enable" command prior to writing
|
||||
// a status register
|
||||
SQ_SKIP_SR_WEL = (1 << 1),
|
||||
|
||||
// Security registers are shifted up by 4 bits
|
||||
SQ_SECURITY_NYBBLE_SHIFT = (1 << 2),
|
||||
};
|
||||
|
||||
struct ff_spi {
|
||||
enum spi_state state;
|
||||
enum spi_type type;
|
||||
enum spi_type desired_type;
|
||||
struct spi_id id;
|
||||
enum ff_spi_quirks quirks;
|
||||
int size_override;
|
||||
|
||||
struct {
|
||||
int clk;
|
||||
int d0;
|
||||
int d1;
|
||||
int d2;
|
||||
int d3;
|
||||
int wp;
|
||||
int hold;
|
||||
int cs;
|
||||
int miso;
|
||||
int mosi;
|
||||
} pins;
|
||||
};
|
||||
|
||||
static void spi_get_id(struct ff_spi *spi);
|
||||
|
||||
static void spi_set_state(struct ff_spi *spi, enum spi_state state) {
|
||||
return;
|
||||
if (spi->state == state)
|
||||
return;
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
switch (state) {
|
||||
case SS_SINGLE:
|
||||
#endif
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
break;
|
||||
|
||||
case SS_DUAL_RX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
case SS_DUAL_TX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
case SS_QUAD_RX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_INPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_INPUT);
|
||||
break;
|
||||
|
||||
case SS_QUAD_TX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
case SS_HARDWARE:
|
||||
gpioSetMode(spi->pins.clk, PI_ALT0); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_ALT0); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_ALT0); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_ALT0); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized spi state\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
spi->state = state;
|
||||
}
|
||||
|
||||
void spiPause(struct ff_spi *spi) {
|
||||
(void)spi;
|
||||
gpioSync();
|
||||
// usleep(1);
|
||||
return;
|
||||
}
|
||||
|
||||
void spiBegin(struct ff_spi *spi) {
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
if ((spi->type == ST_SINGLE) || (spi->type == ST_DUAL)) {
|
||||
gpioWrite(spi->pins.wp, 1);
|
||||
gpioWrite(spi->pins.hold, 1);
|
||||
}
|
||||
gpioWrite(spi->pins.cs, 0);
|
||||
}
|
||||
|
||||
void spiEnd(struct ff_spi *spi) {
|
||||
(void)spi;
|
||||
gpioWrite(spi->pins.cs, 1);
|
||||
}
|
||||
|
||||
static uint8_t spiXfer(struct ff_spi *spi, uint8_t out) {
|
||||
int bit;
|
||||
uint8_t in = 0;
|
||||
|
||||
for (bit = 7; bit >= 0; bit--) {
|
||||
if (out & (1 << bit)) {
|
||||
gpioWrite(spi->pins.mosi, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.mosi, 0);
|
||||
}
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
in |= ((!!gpioRead(spi->pins.miso)) << bit);
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
static void spiSingleTx(struct ff_spi *spi, uint8_t out) {
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
spiXfer(spi, out);
|
||||
}
|
||||
|
||||
static uint8_t spiSingleRx(struct ff_spi *spi) {
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
return spiXfer(spi, 0xff);
|
||||
}
|
||||
|
||||
static void spiDualTx(struct ff_spi *spi, uint8_t out) {
|
||||
|
||||
int bit;
|
||||
spi_set_state(spi, SS_DUAL_TX);
|
||||
for (bit = 7; bit >= 0; bit -= 2) {
|
||||
if (out & (1 << (bit - 1))) {
|
||||
gpioWrite(spi->pins.d0, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d0, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 0))) {
|
||||
gpioWrite(spi->pins.d1, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d1, 0);
|
||||
}
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
}
|
||||
|
||||
static void spiQuadTx(struct ff_spi *spi, uint8_t out) {
|
||||
int bit;
|
||||
spi_set_state(spi, SS_QUAD_TX);
|
||||
for (bit = 7; bit >= 0; bit -= 4) {
|
||||
if (out & (1 << (bit - 3))) {
|
||||
gpioWrite(spi->pins.d0, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d0, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 2))) {
|
||||
gpioWrite(spi->pins.d1, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d1, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 1))) {
|
||||
gpioWrite(spi->pins.d2, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d2, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 0))) {
|
||||
gpioWrite(spi->pins.d3, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d3, 0);
|
||||
}
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t spiDualRx(struct ff_spi *spi) {
|
||||
int bit;
|
||||
uint8_t in = 0;
|
||||
|
||||
spi_set_state(spi, SS_QUAD_RX);
|
||||
for (bit = 7; bit >= 0; bit -= 2) {
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
in |= ((!!gpioRead(spi->pins.d0)) << (bit - 1));
|
||||
in |= ((!!gpioRead(spi->pins.d1)) << (bit - 0));
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
static uint8_t spiQuadRx(struct ff_spi *spi) {
|
||||
int bit;
|
||||
uint8_t in = 0;
|
||||
|
||||
spi_set_state(spi, SS_QUAD_RX);
|
||||
for (bit = 7; bit >= 0; bit -= 4) {
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
in |= ((!!gpioRead(spi->pins.d0)) << (bit - 3));
|
||||
in |= ((!!gpioRead(spi->pins.d1)) << (bit - 2));
|
||||
in |= ((!!gpioRead(spi->pins.d2)) << (bit - 1));
|
||||
in |= ((!!gpioRead(spi->pins.d3)) << (bit - 0));
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
int spiTx(struct ff_spi *spi, uint8_t word) {
|
||||
switch (spi->type) {
|
||||
case ST_SINGLE:
|
||||
spiSingleTx(spi, word);
|
||||
break;
|
||||
case ST_DUAL:
|
||||
spiDualTx(spi, word);
|
||||
break;
|
||||
case ST_QUAD:
|
||||
case ST_QPI:
|
||||
spiQuadTx(spi, word);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t spiRx(struct ff_spi *spi) {
|
||||
switch (spi->type) {
|
||||
case ST_SINGLE:
|
||||
return spiSingleRx(spi);
|
||||
case ST_DUAL:
|
||||
return spiDualRx(spi);
|
||||
case ST_QUAD:
|
||||
case ST_QPI:
|
||||
return spiQuadRx(spi);
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void spiCommand(struct ff_spi *spi, uint8_t cmd) {
|
||||
if (spi->type == ST_QPI)
|
||||
spiQuadTx(spi, cmd);
|
||||
else
|
||||
spiSingleTx(spi, cmd);
|
||||
}
|
||||
|
||||
uint8_t spiCommandRx(struct ff_spi *spi) {
|
||||
if (spi->type == ST_QPI)
|
||||
return spiQuadRx(spi);
|
||||
else
|
||||
return spiSingleRx(spi);
|
||||
}
|
||||
|
||||
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr) {
|
||||
uint8_t val = 0xff;
|
||||
(void)sr;
|
||||
|
||||
#if 0
|
||||
switch (sr) {
|
||||
case 1:
|
||||
#endif
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x05);
|
||||
val = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
#if 0
|
||||
break;
|
||||
|
||||
case 2:
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x35);
|
||||
val = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x15);
|
||||
val = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unrecognized status register: %d\n", sr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
|
||||
|
||||
if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
|
||||
sr <<= 4;
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
// erase the register
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x44);
|
||||
spiCommand(spi, 0x00); // A23-16
|
||||
spiCommand(spi, sr); // A15-8
|
||||
spiCommand(spi, 0x00); // A0-7
|
||||
spiEnd(spi);
|
||||
|
||||
spi_get_id(spi);
|
||||
sleep(1);
|
||||
|
||||
// write enable
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x42);
|
||||
spiCommand(spi, 0x00); // A23-16
|
||||
spiCommand(spi, sr); // A15-8
|
||||
spiCommand(spi, 0x00); // A0-7
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
spiCommand(spi, security[i]);
|
||||
spiEnd(spi);
|
||||
|
||||
spi_get_id(spi);
|
||||
}
|
||||
|
||||
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
|
||||
if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
|
||||
sr <<= 4;
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x48); // Read security registers
|
||||
spiCommand(spi, 0x00); // A23-16
|
||||
spiCommand(spi, sr); // A15-8
|
||||
spiCommand(spi, 0x00); // A0-7
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
security[i] = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val) {
|
||||
|
||||
switch (sr) {
|
||||
case 1:
|
||||
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x50);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x01);
|
||||
spiCommand(spi, val);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
case 2: {
|
||||
uint8_t sr1 = 0x00;
|
||||
if (spi->quirks & SQ_SR2_FROM_SR1)
|
||||
sr1 = spiReadStatus(spi, 1);
|
||||
|
||||
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x50);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
if (spi->quirks & SQ_SR2_FROM_SR1) {
|
||||
spiCommand(spi, 0x01);
|
||||
spiCommand(spi, sr1);
|
||||
spiCommand(spi, val);
|
||||
}
|
||||
else {
|
||||
spiCommand(spi, 0x31);
|
||||
spiCommand(spi, val);
|
||||
}
|
||||
spiEnd(spi);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x50);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x11);
|
||||
spiCommand(spi, val);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unrecognized status register: %d\n", sr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct spi_id spiId(struct ff_spi *spi) {
|
||||
return spi->id;
|
||||
}
|
||||
|
||||
static void spi_decode_id(struct ff_spi *spi) {
|
||||
spi->id.bytes = -1; // unknown
|
||||
|
||||
if (spi->id.manufacturer_id == 0xef) {
|
||||
// spi->id.manufacturer = "Winbond";
|
||||
if ((spi->id.memory_type == 0x70)
|
||||
&& (spi->id.memory_size == 0x18)) {
|
||||
// spi->id.model = "W25Q128JV";
|
||||
// spi->id.capacity = "128 Mbit";
|
||||
spi->id.bytes = 16 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
if (spi->id.manufacturer_id == 0x1f) {
|
||||
// spi->id.manufacturer = "Adesto";
|
||||
if ((spi->id.memory_type == 0x86)
|
||||
&& (spi->id.memory_size == 0x01)) {
|
||||
// spi->id.model = "AT25SF161";
|
||||
// spi->id.capacity = "16 Mbit";
|
||||
spi->id.bytes = 1 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
static void spi_get_id(struct ff_spi *spi) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x90); // Read manufacturer ID
|
||||
spiCommand(spi, 0x00); // Dummy byte 1
|
||||
spiCommand(spi, 0x00); // Dummy byte 2
|
||||
spiCommand(spi, 0x00); // Dummy byte 3
|
||||
spi->id.manufacturer_id = spiCommandRx(spi);
|
||||
spi->id.device_id = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
return;
|
||||
#if 0
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x9f); // Read device id
|
||||
spi->id._manufacturer_id = spiCommandRx(spi);
|
||||
spi->id.memory_type = spiCommandRx(spi);
|
||||
spi->id.memory_size = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xab); // Read electronic signature
|
||||
spiCommand(spi, 0x00); // Dummy byte 1
|
||||
spiCommand(spi, 0x00); // Dummy byte 2
|
||||
spiCommand(spi, 0x00); // Dummy byte 3
|
||||
spi->id.signature = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x4b); // Read unique ID
|
||||
spiCommand(spi, 0x00); // Dummy byte 1
|
||||
spiCommand(spi, 0x00); // Dummy byte 2
|
||||
spiCommand(spi, 0x00); // Dummy byte 3
|
||||
spiCommand(spi, 0x00); // Dummy byte 4
|
||||
spi->id.serial[0] = spiCommandRx(spi);
|
||||
spi->id.serial[1] = spiCommandRx(spi);
|
||||
spi->id.serial[2] = spiCommandRx(spi);
|
||||
spi->id.serial[3] = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
|
||||
spi_decode_id(spi);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
void spiOverrideSize(struct ff_spi *spi, uint32_t size) {
|
||||
spi->size_override = size;
|
||||
|
||||
// If size is 0, re-read the capacity
|
||||
if (!size)
|
||||
spi_decode_id(spi);
|
||||
else
|
||||
spi->id.bytes = size;
|
||||
}
|
||||
#endif
|
||||
|
||||
int spiSetType(struct ff_spi *spi, enum spi_type type) {
|
||||
|
||||
if (spi->type == type)
|
||||
return 0;
|
||||
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
switch (type) {
|
||||
|
||||
case ST_SINGLE:
|
||||
#endif
|
||||
if (spi->type == ST_QPI) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xff); // Exit QPI Mode
|
||||
spiEnd(spi);
|
||||
}
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
break;
|
||||
|
||||
case ST_DUAL:
|
||||
if (spi->type == ST_QPI) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xff); // Exit QPI Mode
|
||||
spiEnd(spi);
|
||||
}
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_DUAL_TX);
|
||||
break;
|
||||
|
||||
case ST_QUAD:
|
||||
if (spi->type == ST_QPI) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xff); // Exit QPI Mode
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
// Enable QE bit
|
||||
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
|
||||
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_QUAD_TX);
|
||||
break;
|
||||
|
||||
case ST_QPI:
|
||||
// Enable QE bit
|
||||
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x38); // Enter QPI Mode
|
||||
spiEnd(spi);
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_QUAD_TX);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized SPI type: %d\n", type);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiIsBusy(struct ff_spi *spi) {
|
||||
return spiReadStatus(spi, 1) & (1 << 0);
|
||||
}
|
||||
|
||||
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr) {
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x52);
|
||||
spiCommand(spi, erase_addr >> 16);
|
||||
spiCommand(spi, erase_addr >> 8);
|
||||
spiCommand(spi, erase_addr >> 0);
|
||||
spiEnd(spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr) {
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xD8);
|
||||
spiCommand(spi, erase_addr >> 16);
|
||||
spiCommand(spi, erase_addr >> 8);
|
||||
spiCommand(spi, erase_addr >> 0);
|
||||
spiEnd(spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *v_data, unsigned int count) {
|
||||
const uint8_t write_cmd = 0x02;
|
||||
const uint8_t *data = v_data;
|
||||
unsigned int i;
|
||||
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
// uint8_t sr1 = spiReadStatus(spi, 1);
|
||||
// if (!(sr1 & (1 << 1)))
|
||||
// fprintf(stderr, "error: write-enable latch (WEL) not set, write will probably fail\n");
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, write_cmd);
|
||||
spiCommand(spi, addr >> 16);
|
||||
spiCommand(spi, addr >> 8);
|
||||
spiCommand(spi, addr >> 0);
|
||||
for (i = 0; (i < count) && (i < 256); i++)
|
||||
spiTx(spi, *data++);
|
||||
spiEnd(spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t spiReset(struct ff_spi *spi) {
|
||||
// XXX You should check the "Ready" bit before doing this!
|
||||
|
||||
// Shift to QPI mode, then back to Single mode, to ensure
|
||||
// we're actually in Single mode.
|
||||
spiSetType(spi, ST_QPI);
|
||||
spiSetType(spi, ST_SINGLE);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x66); // "Enable Reset" command
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x99); // "Reset Device" command
|
||||
spiEnd(spi);
|
||||
|
||||
// msleep(30);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xab); // "Resume from Deep Power-Down" command
|
||||
spiEnd(spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiInit(struct ff_spi *spi) {
|
||||
spi->state = SS_UNCONFIGURED;
|
||||
spi->type = ST_UNCONFIGURED;
|
||||
|
||||
// Disable memory-mapped mode and enable bit-bang mode
|
||||
picorvspi_cfg4_write(0);
|
||||
|
||||
// Reset the SPI flash, which will return it to SPI mode even
|
||||
// if it's in QPI mode.
|
||||
spiReset(spi);
|
||||
|
||||
spiSetType(spi, ST_SINGLE);
|
||||
|
||||
// Have the SPI flash pay attention to us
|
||||
gpioWrite(spi->pins.hold, 1);
|
||||
|
||||
// Disable WP
|
||||
gpioWrite(spi->pins.wp, 1);
|
||||
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
|
||||
spi_get_id(spi);
|
||||
|
||||
spi->quirks |= SQ_SR2_FROM_SR1;
|
||||
if (spi->id.manufacturer_id == 0xef)
|
||||
spi->quirks |= SQ_SKIP_SR_WEL | SQ_SECURITY_NYBBLE_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spiEnableQuad(void) {
|
||||
struct ff_spi *spi = spiAlloc();
|
||||
spiInit(spi);
|
||||
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
|
||||
spiFree();
|
||||
}
|
||||
|
||||
struct ff_spi *spiAlloc(void) {
|
||||
static struct ff_spi spi;
|
||||
return &spi;
|
||||
}
|
||||
|
||||
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val) {
|
||||
switch (pin) {
|
||||
case SP_MOSI: spi->pins.mosi = val; break;
|
||||
case SP_MISO: spi->pins.miso = val; break;
|
||||
case SP_HOLD: spi->pins.hold = val; break;
|
||||
case SP_WP: spi->pins.wp = val; break;
|
||||
case SP_CS: spi->pins.cs = val; break;
|
||||
case SP_CLK: spi->pins.clk = val; break;
|
||||
case SP_D0: spi->pins.d0 = val; break;
|
||||
case SP_D1: spi->pins.d1 = val; break;
|
||||
case SP_D2: spi->pins.d2 = val; break;
|
||||
case SP_D3: spi->pins.d3 = val; break;
|
||||
default: fprintf(stderr, "unrecognized pin: %d\n", pin); break;
|
||||
}
|
||||
}
|
||||
|
||||
void spiHold(struct ff_spi *spi) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xb9);
|
||||
spiEnd(spi);
|
||||
}
|
||||
void spiUnhold(struct ff_spi *spi) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xab);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
void spiFree(void) {
|
||||
// Re-enable memory-mapped mode
|
||||
picorvspi_cfg4_write(0x80);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
void msleep(int ms)
|
||||
{
|
||||
timer0_en_write(0);
|
||||
timer0_reload_write(0);
|
||||
timer0_load_write(SYSTEM_CLOCK_FREQUENCY/1000*ms);
|
||||
timer0_en_write(1);
|
||||
timer0_update_value_write(1);
|
||||
while(timer0_value_read()) timer0_update_value_write(1);
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
#include <uart.h>
|
||||
#include <irq.h>
|
||||
#include <generated/csr.h>
|
||||
#include <hw/flags.h>
|
||||
|
||||
#ifdef CSR_UART_BASE
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
#else /* !CSR_UART_BASE */
|
||||
void uart_init(void) {}
|
||||
void uart_isr(void) {}
|
||||
#endif
|
@ -1,252 +0,0 @@
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2013 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <usb-desc.h>
|
||||
|
||||
// USB Descriptors are binary data which the USB host reads to
|
||||
// automatically detect a USB device's capabilities. The format
|
||||
// and meaning of every field is documented in numerous USB
|
||||
// standards. When working with USB descriptors, despite the
|
||||
// complexity of the standards and poor writing quality in many
|
||||
// of those documents, remember descriptors are nothing more
|
||||
// than constant binary data that tells the USB host what the
|
||||
// device can do. Computers will load drivers based on this data.
|
||||
// Those drivers then communicate on the endpoints specified by
|
||||
// the descriptors.
|
||||
|
||||
// To configure a new combination of interfaces or make minor
|
||||
// changes to existing configuration (eg, change the name or ID
|
||||
// numbers), usually you would edit "usb_desc.h". This file
|
||||
// is meant to be configured by the header, so generally it is
|
||||
// only edited to add completely new USB interfaces or features.
|
||||
|
||||
// **************************************************************
|
||||
// USB Device
|
||||
// **************************************************************
|
||||
|
||||
#define LSB(n) ((n) & 255)
|
||||
#define MSB(n) (((n) >> 8) & 255)
|
||||
|
||||
#define USB_DT_BOS_SIZE 5
|
||||
#define USB_DT_BOS 0xf
|
||||
#define USB_DT_DEVICE_CAPABILITY 0x10
|
||||
#define USB_DC_PLATFORM 5
|
||||
|
||||
struct usb_bos_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t wTotalLength;
|
||||
uint8_t bNumDeviceCaps;
|
||||
} __attribute__((packed));
|
||||
|
||||
// USB Device Descriptor. The USB host reads this first, to learn
|
||||
// what type of device is connected.
|
||||
static const uint8_t device_descriptor[] = {
|
||||
18, // bLength
|
||||
1, // bDescriptorType
|
||||
0x01, 0x02, // bcdUSB
|
||||
0x08, /* MSC */ // bDeviceClass
|
||||
0, // bDeviceSubClass
|
||||
0, // bDeviceProtocol
|
||||
EP0_SIZE, // bMaxPacketSize0
|
||||
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
|
||||
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
|
||||
LSB(DEVICE_VER), MSB(DEVICE_VER), // bcdDevice
|
||||
1, // iManufacturer
|
||||
2, // iProduct
|
||||
3, // iSerialNumber
|
||||
1 // bNumConfigurations
|
||||
};
|
||||
|
||||
// These descriptors must NOT be "const", because the USB DMA
|
||||
// has trouble accessing flash memory with enough bandwidth
|
||||
// while the processor is executing from flash.
|
||||
|
||||
|
||||
// **************************************************************
|
||||
// USB Configuration
|
||||
// **************************************************************
|
||||
|
||||
// USB Configuration Descriptor. This huge descriptor tells all
|
||||
// of the devices capbilities.
|
||||
#define CONFIG_DESC_SIZE (9+9+USB_DT_ENDPOINT_SIZE+USB_DT_ENDPOINT_SIZE)
|
||||
static const uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
|
||||
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
|
||||
9, // bLength;
|
||||
2, // bDescriptorType;
|
||||
LSB(CONFIG_DESC_SIZE), // wTotalLength
|
||||
MSB(CONFIG_DESC_SIZE),
|
||||
1, // bNumInterfaces
|
||||
1, // bConfigurationValue
|
||||
0, // iConfiguration
|
||||
0x80, // bmAttributes
|
||||
50, // bMaxPower
|
||||
|
||||
// interface descriptor, DFU Mode (DFU spec Table 4.4)
|
||||
9, // bLength
|
||||
4, // bDescriptorType
|
||||
0, // bInterfaceNumber
|
||||
0, // bAlternateSetting
|
||||
2, // bNumEndpoints
|
||||
0x08, /* IFACE_CLASS_MASS_STORAGE */ // bInterfaceClass
|
||||
0x06, /* SCSI subclass */ // bInterfaceSubClass
|
||||
0x50, /* BBB interface */ // bInterfaceProtocol
|
||||
0, // iInterface
|
||||
|
||||
// Endpoint descriptor
|
||||
USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType
|
||||
0x82, // bEndpointAddress
|
||||
USB_ENDPOINT_ATTR_BULK, // bmAttributes
|
||||
LSB(64), // wMaxPacketSize
|
||||
MSB(64), // wMaxPacketSize
|
||||
0, // bInterval
|
||||
|
||||
// Endpoint descriptor
|
||||
USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType
|
||||
0x02, // bEndpointAddress
|
||||
USB_ENDPOINT_ATTR_BULK, // bmAttributes
|
||||
LSB(64), // wMaxPacketSize
|
||||
MSB(64), // wMaxPacketSize
|
||||
0, // bInterval
|
||||
};
|
||||
|
||||
|
||||
// **************************************************************
|
||||
// String Descriptors
|
||||
// **************************************************************
|
||||
|
||||
// The descriptors above can provide human readable strings,
|
||||
// referenced by index numbers. These descriptors are the
|
||||
// actual string data
|
||||
|
||||
static const struct usb_string_descriptor_struct string0 = {
|
||||
4,
|
||||
3,
|
||||
{0x0409}
|
||||
};
|
||||
|
||||
// Microsoft OS String Descriptor. See: https://github.com/pbatard/libwdi/wiki/WCID-Devices
|
||||
static const struct usb_string_descriptor_struct usb_string_microsoft = {
|
||||
18, 3,
|
||||
{'M','S','F','T','1','0','0', MSFT_VENDOR_CODE}
|
||||
};
|
||||
|
||||
// Microsoft WCID
|
||||
const uint8_t usb_microsoft_wcid[MSFT_WCID_LEN] = {
|
||||
MSFT_WCID_LEN, 0, 0, 0, // Length
|
||||
0x00, 0x01, // Version
|
||||
0x04, 0x00, // Compatibility ID descriptor index
|
||||
0x01, // Number of sections
|
||||
0, 0, 0, 0, 0, 0, 0, // Reserved (7 bytes)
|
||||
|
||||
0, // Interface number
|
||||
0x01, // Reserved
|
||||
'W','I','N','U','S','B',0,0, // Compatible ID
|
||||
0,0,0,0,0,0,0,0, // Sub-compatible ID (unused)
|
||||
0,0,0,0,0,0, // Reserved
|
||||
};
|
||||
|
||||
static const struct webusb_url_descriptor landing_url_descriptor = {
|
||||
.bLength = LANDING_PAGE_DESCRIPTOR_SIZE,
|
||||
.bDescriptorType = WEBUSB_DT_URL,
|
||||
.bScheme = WEBUSB_URL_SCHEME_HTTPS,
|
||||
.URL = LANDING_PAGE_URL
|
||||
};
|
||||
|
||||
const uint8_t *get_landing_url_descriptor(uint32_t *datalen) {
|
||||
// Return landing page URL descriptor
|
||||
*datalen = LANDING_PAGE_DESCRIPTOR_SIZE;
|
||||
return (const uint8_t*)&landing_url_descriptor;
|
||||
}
|
||||
|
||||
struct full_bos {
|
||||
struct usb_bos_descriptor bos;
|
||||
struct webusb_platform_descriptor webusb;
|
||||
};
|
||||
|
||||
static const struct full_bos full_bos = {
|
||||
.bos = {
|
||||
.bLength = USB_DT_BOS_SIZE,
|
||||
.bDescriptorType = USB_DT_BOS,
|
||||
.wTotalLength = USB_DT_BOS_SIZE + WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
|
||||
.bNumDeviceCaps = 1,
|
||||
},
|
||||
.webusb = {
|
||||
.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE_CAPABILITY,
|
||||
.bDevCapabilityType = USB_DC_PLATFORM,
|
||||
.bReserved = 0,
|
||||
.platformCapabilityUUID = WEBUSB_UUID,
|
||||
.bcdVersion = 0x0100,
|
||||
.bVendorCode = WEBUSB_VENDOR_CODE,
|
||||
.iLandingPage = 1,
|
||||
},
|
||||
};
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static const struct usb_string_descriptor_struct usb_string_manufacturer_name = {
|
||||
2 + MANUFACTURER_NAME_LEN,
|
||||
3,
|
||||
MANUFACTURER_NAME
|
||||
};
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
struct usb_string_descriptor_struct usb_string_product_name = {
|
||||
2 + PRODUCT_NAME_LEN,
|
||||
3,
|
||||
PRODUCT_NAME
|
||||
};
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static const struct usb_string_descriptor_struct usb_string_serial_number = {
|
||||
2 + SERIAL_NUMBER_LEN,
|
||||
3,
|
||||
SERIAL_NUMBER
|
||||
};
|
||||
|
||||
// **************************************************************
|
||||
// Descriptors List
|
||||
// **************************************************************
|
||||
|
||||
// This table provides access to all the descriptor data above.
|
||||
|
||||
const usb_descriptor_list_t usb_descriptor_list[] = {
|
||||
{0x0100, sizeof(device_descriptor), device_descriptor},
|
||||
{0x0200, sizeof(config_descriptor), config_descriptor},
|
||||
{0x0300, 0, (const uint8_t *)&string0},
|
||||
{0x0301, 0, (const uint8_t *)&usb_string_manufacturer_name},
|
||||
{0x0302, 0, (const uint8_t *)&usb_string_product_name},
|
||||
{0x0303, 0, (const uint8_t *)&usb_string_serial_number},
|
||||
{0x03EE, 0, (const uint8_t *)&usb_string_microsoft},
|
||||
{0x0F00, sizeof(full_bos), (const uint8_t *)&full_bos},
|
||||
{0, 0, NULL}
|
||||
};
|
@ -1,155 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <usb.h>
|
||||
#include <system.h>
|
||||
|
||||
#include <usb-desc.h>
|
||||
#include <usb-msc.h>
|
||||
|
||||
static uint8_t reply_buffer[8];
|
||||
static uint8_t usb_configuration = 0;
|
||||
#define USB_MAX_PACKET_SIZE 64
|
||||
static uint32_t rx_buffer[USB_MAX_PACKET_SIZE/4];
|
||||
uint16_t last_request_and_type;
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
void usb_setup(const struct usb_setup_request *setup)
|
||||
{
|
||||
const uint8_t *data = NULL;
|
||||
uint32_t datalen = 0;
|
||||
const usb_descriptor_list_t *list;
|
||||
last_request_and_type = setup->wRequestAndType;
|
||||
|
||||
switch (setup->wRequestAndType)
|
||||
{
|
||||
case 0xfea1: // Get Max LUN
|
||||
if (usb_msc_setup(setup))
|
||||
return;
|
||||
break;
|
||||
|
||||
case 0x0500: // SET_ADDRESS
|
||||
case 0x0b01: // SET_INTERFACE
|
||||
break;
|
||||
|
||||
case 0x0900: // SET_CONFIGURATION
|
||||
usb_configuration = setup->wValue;
|
||||
break;
|
||||
|
||||
case 0x0880: // GET_CONFIGURATION
|
||||
reply_buffer[0] = usb_configuration;
|
||||
datalen = 1;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0080: // GET_STATUS (device)
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
datalen = 2;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0082: // GET_STATUS (endpoint)
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_stall(0x80);
|
||||
return;
|
||||
}
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
|
||||
// XXX handle endpoint stall here
|
||||
// if (USB->DIEP0CTL & USB_DIEP_CTL_STALL)
|
||||
// reply_buffer[0] = 1;
|
||||
data = reply_buffer;
|
||||
datalen = 2;
|
||||
break;
|
||||
|
||||
case 0x0102: // CLEAR_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_stall(0x80);
|
||||
return;
|
||||
}
|
||||
// XXX: Should we clear the stall bit?
|
||||
// USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL;
|
||||
// TODO: do we need to clear the data toggle here?
|
||||
break;
|
||||
|
||||
case 0x0302: // SET_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_stall(0x80);
|
||||
return;
|
||||
}
|
||||
// XXX: Should we set the stall bit?
|
||||
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
|
||||
// TODO: do we need to clear the data toggle here?
|
||||
break;
|
||||
|
||||
case 0x0680: // GET_DESCRIPTOR
|
||||
case 0x0681:
|
||||
for (list = usb_descriptor_list; 1; list++)
|
||||
{
|
||||
if (list->addr == NULL)
|
||||
break;
|
||||
if (setup->wValue == list->wValue)
|
||||
{
|
||||
data = list->addr;
|
||||
if ((setup->wValue >> 8) == 3)
|
||||
{
|
||||
// for string descriptors, use the descriptor's
|
||||
// length field, allowing runtime configured
|
||||
// length.
|
||||
datalen = *(list->addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
datalen = list->length;
|
||||
}
|
||||
goto send;
|
||||
}
|
||||
}
|
||||
usb_stall(0x80);
|
||||
return;
|
||||
|
||||
case (MSFT_VENDOR_CODE << 8) | 0xC0: // Get Microsoft descriptor
|
||||
case (MSFT_VENDOR_CODE << 8) | 0xC1:
|
||||
if (setup->wIndex == 0x0004)
|
||||
{
|
||||
// Return WCID descriptor
|
||||
data = usb_microsoft_wcid;
|
||||
datalen = MSFT_WCID_LEN;
|
||||
break;
|
||||
}
|
||||
usb_stall(0x80);
|
||||
return;
|
||||
|
||||
case (WEBUSB_VENDOR_CODE << 8) | 0xC0: // Get WebUSB descriptor
|
||||
if (setup->wIndex == 0x0002)
|
||||
{
|
||||
if (setup->wValue == 0x0001)
|
||||
{
|
||||
data = get_landing_url_descriptor(&datalen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
usb_stall(0x80);
|
||||
return;
|
||||
|
||||
default:
|
||||
usb_stall(0x80);
|
||||
return;
|
||||
}
|
||||
|
||||
send:
|
||||
if (data && datalen) {
|
||||
if (datalen > setup->wLength)
|
||||
datalen = setup->wLength;
|
||||
usb_send(0, data, datalen);
|
||||
}
|
||||
else
|
||||
usb_ack(0x80);
|
||||
return;
|
||||
}
|
@ -1,465 +0,0 @@
|
||||
#include <usb.h>
|
||||
#include <irq.h>
|
||||
#include <generated/csr.h>
|
||||
#include <string.h>
|
||||
#include <usb.h>
|
||||
#include <usb-msc.h>
|
||||
|
||||
#define EP0OUT_BUFFERS 4
|
||||
#define EP2OUT_BUFFERS 4
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][256];
|
||||
static uint8_t volatile usb_ep0out_last_tok[EP0OUT_BUFFERS];
|
||||
static volatile uint8_t usb_ep0out_wr_ptr;
|
||||
static volatile uint8_t usb_ep0out_rd_ptr;
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t volatile usb_ep2out_buffer_len[EP2OUT_BUFFERS];
|
||||
static uint8_t volatile usb_ep2out_buffer[EP2OUT_BUFFERS][256];
|
||||
static volatile uint8_t usb_ep2out_wr_ptr;
|
||||
static volatile uint8_t usb_ep2out_rd_ptr;
|
||||
|
||||
static const int max_byte_length = 64;
|
||||
|
||||
static const uint8_t * volatile current_data_0;
|
||||
static volatile int current_length_0;
|
||||
static volatile int data_offset_0;
|
||||
static volatile int data_to_send_0;
|
||||
static int next_packet_is_empty_0;
|
||||
|
||||
static const uint8_t * volatile current_data_2;
|
||||
static volatile int current_length_2;
|
||||
static volatile int data_offset_2;
|
||||
static volatile int data_to_send_2;
|
||||
static int next_packet_is_empty_2;
|
||||
|
||||
static void *ep2_more_data_ptr;
|
||||
static volatile uint8_t ep2_more_data_bfr[64];
|
||||
static int (*ep2_more_data)(uint8_t *bfr, size_t len, void *ptr);
|
||||
|
||||
// Note that our PIDs are only bits 2 and 3 of the token,
|
||||
// since all other bits are effectively redundant at this point.
|
||||
enum USB_PID {
|
||||
USB_PID_OUT = 0,
|
||||
USB_PID_SOF = 1,
|
||||
USB_PID_IN = 2,
|
||||
USB_PID_SETUP = 3,
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
static void process_tx(void);
|
||||
|
||||
void usb_idle(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
|
||||
// Reject all incoming data, since there is no handler anymore
|
||||
usb_ep_0_out_respond_write(EPF_NAK);
|
||||
|
||||
// Reject outgoing data, since we don't have any to give.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_disconnect(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
usb_pullup_out_write(0);
|
||||
}
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
void usb_connect(void) {
|
||||
|
||||
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);
|
||||
|
||||
usb_ep_2_out_ev_pending_write(usb_ep_2_out_ev_enable_read());
|
||||
usb_ep_2_in_ev_pending_write(usb_ep_2_in_ev_pending_read());
|
||||
usb_ep_2_out_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
usb_ep_2_in_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
|
||||
// Accept incoming data by default.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
usb_ep_2_out_respond_write(EPF_ACK);
|
||||
|
||||
// Reject outgoing data, since we have none to give yet.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
usb_ep_2_in_respond_write(EPF_NAK);
|
||||
usb_ep_2_in_dtb_write(1);
|
||||
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_init(void) {
|
||||
usb_ep0out_wr_ptr = 0;
|
||||
usb_ep0out_rd_ptr = 0;
|
||||
usb_ep2out_wr_ptr = 0;
|
||||
usb_ep2out_wr_ptr = 0;
|
||||
usb_pullup_out_write(0);
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
void usb_isr(void) {
|
||||
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
||||
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
||||
uint8_t ep2o_pending = usb_ep_2_out_ev_pending_read();
|
||||
uint8_t ep2i_pending = usb_ep_2_in_ev_pending_read();
|
||||
|
||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||
// and clear the "pending" bit.
|
||||
if (ep0o_pending) {
|
||||
uint8_t last_tok = usb_ep_0_out_last_tok_read();
|
||||
|
||||
int byte_count = 0;
|
||||
usb_ep0out_last_tok[usb_ep0out_wr_ptr] = last_tok;
|
||||
volatile uint8_t * obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
|
||||
while (!usb_ep_0_out_obuf_empty_read()) {
|
||||
obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
|
||||
usb_ep_0_out_obuf_head_write(0);
|
||||
}
|
||||
|
||||
/* Strip off CRC16 */
|
||||
if (byte_count >= 2)
|
||||
byte_count -= 2;
|
||||
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count;
|
||||
|
||||
if (byte_count)
|
||||
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
usb_ep_0_in_dtb_write(1);
|
||||
data_offset_0 = 0;
|
||||
current_length_0 = 0;
|
||||
current_data_0 = NULL;
|
||||
}
|
||||
|
||||
usb_ep_0_out_ev_pending_write(ep0o_pending);
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||
// and clear the "pending" bit.
|
||||
if (ep2o_pending) {
|
||||
uint8_t byte_count = 0;
|
||||
volatile uint8_t * obuf = usb_ep2out_buffer[usb_ep2out_wr_ptr];
|
||||
while (!usb_ep_2_out_obuf_empty_read()) {
|
||||
obuf[byte_count++] = usb_ep_2_out_obuf_head_read();
|
||||
usb_ep_2_out_obuf_head_write(0);
|
||||
}
|
||||
|
||||
/* Strip off CRC16 */
|
||||
if (byte_count >= 2)
|
||||
byte_count -= 2;
|
||||
usb_ep2out_buffer_len[usb_ep2out_wr_ptr] = byte_count;
|
||||
|
||||
if (byte_count)
|
||||
usb_ep2out_wr_ptr = (usb_ep2out_wr_ptr + 1) & (EP2OUT_BUFFERS-1);
|
||||
|
||||
usb_ep_2_out_ev_pending_write(ep2o_pending);
|
||||
usb_ep_2_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
// We just got an "IN" token. Send data if we have it.
|
||||
if (ep0i_pending) {
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
||||
}
|
||||
|
||||
// We just got an "IN" token. Send data if we have it.
|
||||
if (ep2i_pending) {
|
||||
usb_ep_2_in_respond_write(EPF_NAK);
|
||||
usb_ep_2_in_ev_pending_write(ep2i_pending);
|
||||
process_tx();
|
||||
}
|
||||
}
|
||||
|
||||
static void process_tx_0(void) {
|
||||
|
||||
// Don't allow requeueing -- only queue more data if we're
|
||||
// currently set up to respond NAK.
|
||||
if (usb_ep_0_in_respond_read() != EPF_NAK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent us from double-filling the buffer.
|
||||
if (!usb_ep_0_in_ibuf_empty_read()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_data_0 || !current_length_0) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_offset_0 += data_to_send_0;
|
||||
|
||||
data_to_send_0 = current_length_0 - data_offset_0;
|
||||
|
||||
// Clamp the data to the maximum packet length
|
||||
if (data_to_send_0 > max_byte_length) {
|
||||
data_to_send_0 = max_byte_length;
|
||||
next_packet_is_empty_0 = 0;
|
||||
}
|
||||
else if (data_to_send_0 == max_byte_length) {
|
||||
next_packet_is_empty_0 = 1;
|
||||
}
|
||||
else if (next_packet_is_empty_0) {
|
||||
next_packet_is_empty_0 = 0;
|
||||
data_to_send_0 = 0;
|
||||
}
|
||||
else if (current_data_0 == NULL || data_to_send_0 <= 0) {
|
||||
next_packet_is_empty_0 = 0;
|
||||
current_data_0 = NULL;
|
||||
current_length_0 = 0;
|
||||
data_offset_0 = 0;
|
||||
data_to_send_0 = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int this_offset_0;
|
||||
for (this_offset_0 = data_offset_0; this_offset_0 < (data_offset_0 + data_to_send_0); this_offset_0++) {
|
||||
usb_ep_0_in_ibuf_head_write(current_data_0[this_offset_0]);
|
||||
}
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
return;
|
||||
}
|
||||
|
||||
static void process_tx_2(void) {
|
||||
|
||||
// Don't allow requeueing -- only queue more data if we're
|
||||
// currently set up to respond NAK.
|
||||
if (usb_ep_2_in_respond_read() != EPF_NAK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent us from double-filling the buffer.
|
||||
if (!usb_ep_2_in_ibuf_empty_read()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a callback, use that.
|
||||
if (ep2_more_data) {
|
||||
uint8_t data_bfr[64];
|
||||
int new_bytes = ep2_more_data(data_bfr, sizeof(data_bfr), ep2_more_data_ptr);
|
||||
if (new_bytes == 0) {
|
||||
usb_ep_2_in_respond_write(EPF_ACK);
|
||||
ep2_more_data_ptr = NULL;
|
||||
ep2_more_data = NULL;
|
||||
}
|
||||
else if (new_bytes == -1) {
|
||||
ep2_more_data_ptr = NULL;
|
||||
ep2_more_data = NULL;
|
||||
}
|
||||
else if (new_bytes < -1) {
|
||||
usb_ep_2_in_respond_write(EPF_STALL);
|
||||
ep2_more_data_ptr = NULL;
|
||||
ep2_more_data = NULL;
|
||||
}
|
||||
else {
|
||||
int off;
|
||||
for (off = 0; off < new_bytes; off++)
|
||||
usb_ep_2_in_ibuf_head_write(data_bfr[off]);
|
||||
usb_ep_2_in_respond_write(EPF_ACK);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_data_2 || !current_length_2) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_offset_2 += data_to_send_2;
|
||||
|
||||
data_to_send_2 = current_length_2 - data_offset_2;
|
||||
|
||||
// Clamp the data to the maximum packet length
|
||||
if (data_to_send_2 > max_byte_length) {
|
||||
data_to_send_2 = max_byte_length;
|
||||
next_packet_is_empty_2 = 0;
|
||||
}
|
||||
else if (data_to_send_2 == max_byte_length) {
|
||||
next_packet_is_empty_2 = 1;
|
||||
}
|
||||
else if (next_packet_is_empty_2) {
|
||||
next_packet_is_empty_2 = 0;
|
||||
data_to_send_2 = 0;
|
||||
}
|
||||
else if (current_data_2 == NULL || data_to_send_2 <= 0) {
|
||||
next_packet_is_empty_2 = 0;
|
||||
current_data_2 = NULL;
|
||||
current_length_2 = 0;
|
||||
data_offset_2 = 0;
|
||||
data_to_send_2 = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int this_offset_2;
|
||||
for (this_offset_2 = data_offset_2; this_offset_2 < (data_offset_2 + data_to_send_2); this_offset_2++) {
|
||||
usb_ep_2_in_ibuf_head_write(current_data_2[this_offset_2]);
|
||||
}
|
||||
usb_ep_2_in_respond_write(EPF_ACK);
|
||||
return;
|
||||
}
|
||||
|
||||
static void process_tx(void) {
|
||||
process_tx_0();
|
||||
process_tx_2();
|
||||
}
|
||||
|
||||
void usb_wait_for_send_done(void) {
|
||||
while (current_data_0 && current_length_0)
|
||||
usb_poll();
|
||||
while ((usb_ep_0_in_dtb_read() & 1) == 1)
|
||||
usb_poll();
|
||||
}
|
||||
|
||||
void usb_ack(int epnum) {
|
||||
switch (epnum) {
|
||||
case 0x00:
|
||||
while (usb_ep_0_out_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
while (usb_ep_0_in_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
while (usb_ep_2_out_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_2_out_respond_write(EPF_ACK);
|
||||
break;
|
||||
|
||||
case 0x82:
|
||||
while (usb_ep_2_in_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_2_in_respond_write(EPF_ACK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_stall(int epnum) {
|
||||
switch (epnum) {
|
||||
case 0x00:
|
||||
usb_ep_0_out_respond_write(EPF_STALL);
|
||||
break;
|
||||
case 0x80:
|
||||
usb_ep_0_in_respond_write(EPF_STALL);
|
||||
break;
|
||||
case 0x02:
|
||||
usb_ep_2_out_respond_write(EPF_STALL);
|
||||
break;
|
||||
case 0x82:
|
||||
usb_ep_2_in_respond_write(EPF_STALL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_send_cb(int epnum, int (*cb)(uint8_t *, size_t, void *), void *ptr) {
|
||||
if (epnum == 2) {
|
||||
ep2_more_data = cb;
|
||||
ep2_more_data_ptr = ptr;
|
||||
process_tx();
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
void usb_send(int epnum, const void *data, size_t total_count) {
|
||||
switch (epnum) {
|
||||
case 0:
|
||||
while ((usb_ep_0_in_respond_read() == EPF_ACK) && (current_length_0 != 0) && (current_data_0 != 0))
|
||||
;
|
||||
current_data_0 = (uint8_t *)data;
|
||||
current_length_0 = total_count;
|
||||
data_offset_0 = 0;
|
||||
data_to_send_0 = 0;
|
||||
if (!total_count)
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
while ((usb_ep_2_in_respond_read() == EPF_ACK) && (current_length_2 != 0) && (current_data_2 != 0))
|
||||
;
|
||||
if (!total_count) {
|
||||
usb_ep_2_in_respond_write(EPF_ACK);
|
||||
}
|
||||
else {
|
||||
current_data_2 = (uint8_t *)data;
|
||||
current_length_2 = total_count;
|
||||
data_offset_2 = 0;
|
||||
data_to_send_2 = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
process_tx();
|
||||
}
|
||||
|
||||
int usb_recv(void *buffer, unsigned int buffer_len) {
|
||||
|
||||
// Set the OUT response to ACK, since we are in a position to receive data now.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
while (1) {
|
||||
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
|
||||
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
if (ep0_buffer_len < buffer_len)
|
||||
buffer_len = ep0_buffer_len;
|
||||
// usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
memcpy(buffer, (void *)&usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
return buffer_len;
|
||||
}
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
void usb_poll(void) {
|
||||
// If some data was received, then process it.
|
||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
||||
// uint8_t len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
|
||||
|
||||
// usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
usb_setup(request);
|
||||
}
|
||||
}
|
||||
|
||||
while (usb_ep2out_rd_ptr != usb_ep2out_wr_ptr) {
|
||||
const uint8_t *data = (const void *)(usb_ep2out_buffer[usb_ep2out_rd_ptr]);
|
||||
uint8_t len = usb_ep2out_buffer_len[usb_ep2out_rd_ptr];
|
||||
|
||||
// usb_send(2, data, len);
|
||||
usb_msc_out(data, len);
|
||||
|
||||
usb_ep2out_buffer_len[usb_ep2out_rd_ptr] = 0;
|
||||
usb_ep2out_rd_ptr = (usb_ep2out_rd_ptr + 1) & (EP2OUT_BUFFERS-1);
|
||||
}
|
||||
|
||||
process_tx();
|
||||
}
|
@ -1,295 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include "usb-desc.h"
|
||||
#include "usb-msc.h"
|
||||
#include "usb.h"
|
||||
|
||||
static const uint8_t max_lun = 0;
|
||||
#define DISK_SIZE 117760 // ~112 kilobytes
|
||||
#define BLOCK_SIZE 512
|
||||
#define BLOCK_COUNT (DISK_SIZE / BLOCK_SIZE)
|
||||
static uint32_t memory_backing[DISK_SIZE/4];
|
||||
|
||||
static uint32_t swap32(uint32_t x) {
|
||||
return ((x << 24) & 0xff000000) |
|
||||
((x << 8) & 0x00ff0000) |
|
||||
((x >> 8) & 0x0000ff00) |
|
||||
((x >> 24) & 0x000000ff);
|
||||
}
|
||||
|
||||
static uint8_t sbc_sense_key;
|
||||
static uint8_t sbc_asc;
|
||||
static uint8_t sbc_ascq;
|
||||
|
||||
static struct usb_msc_csw csw;
|
||||
|
||||
static int (*usb_write_cb)(const uint8_t *data, size_t count, void *ptr);
|
||||
static void *usb_write_cb_ptr = NULL;
|
||||
|
||||
static void set_sbc_status(enum sbc_sense_key key,
|
||||
enum sbc_asc asc,
|
||||
enum sbc_ascq ascq) {
|
||||
sbc_sense_key = (uint8_t) key;
|
||||
sbc_asc = (uint8_t) asc;
|
||||
sbc_ascq = (uint8_t) ascq;
|
||||
}
|
||||
|
||||
static void set_sbc_status_good(void) {
|
||||
set_sbc_status(SBC_SENSE_KEY_NO_SENSE,
|
||||
SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
SBC_ASCQ_NA);
|
||||
}
|
||||
|
||||
static const char *error_reason = NULL;
|
||||
|
||||
static const void *parse_cbw(const void *data, size_t len, struct cbw *cbw_dest) {
|
||||
const struct cbw *cbw_src = data;
|
||||
unsigned int i;
|
||||
|
||||
// Check for the signature
|
||||
uint8_t sig_test[4] = {'U', 'S', 'B', 'C'};
|
||||
for (i = 0; i < sizeof(sig_test); i++) {
|
||||
if (sig_test[i] != cbw_src->signature[i]) {
|
||||
error_reason = "Signature Mismatch";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the size at least makes sense.
|
||||
if (len < sizeof(*cbw_dest)) {
|
||||
error_reason = "Too short";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy over data and un-swap words.
|
||||
cbw_dest->tag = cbw_src->tag; // Don't swap, since we reply with this
|
||||
cbw_dest->length = swap32(cbw_src->length);
|
||||
cbw_dest->flags = cbw_src->flags;
|
||||
cbw_dest->lun = cbw_src->lun;
|
||||
cbw_dest->cbLength = cbw_src->cbLength;
|
||||
|
||||
if (!cbw_src->data) {
|
||||
error_reason = "Data NULL";
|
||||
}
|
||||
return cbw_src->data;
|
||||
}
|
||||
|
||||
static int reply_scsi_inquiry(const void *data) {
|
||||
|
||||
static struct scsi_inquiry_data udi_msc_inquiry_data = {
|
||||
.pq_pdt = SCSI_INQ_PQ_CONNECTED | SCSI_INQ_DT_DIR_ACCESS,
|
||||
.version = 2, // SCSI_INQ_VER_SPC,
|
||||
.flags1 = SCSI_INQ_RMB,
|
||||
.flags3 = SCSI_INQ_RSP_SPC2,
|
||||
.addl_len = 36 - 4, // SCSI_INQ_ADDL_LEN(sizeof(struct scsi_inquiry_data)),
|
||||
// Linux displays this; Windows shows it in Dev Mgr
|
||||
.vendor_id = "VENDOR",
|
||||
.product_id = "SOMETHING",
|
||||
.product_rev = {'1', '.', '0', '0'},
|
||||
};
|
||||
|
||||
set_sbc_status_good();
|
||||
csw.dCSWDataResidue = sizeof(udi_msc_inquiry_data);
|
||||
|
||||
usb_send(2, &udi_msc_inquiry_data, sizeof(udi_msc_inquiry_data));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reply_scsi_read_capacity(const void *payload) {
|
||||
uint8_t bfr[8];
|
||||
bfr[0] = 0xff & (BLOCK_COUNT >> 24);
|
||||
bfr[1] = 0xff & (BLOCK_COUNT >> 16);
|
||||
bfr[2] = 0xff & (BLOCK_COUNT >> 8);
|
||||
bfr[3] = 0xff & (BLOCK_COUNT >> 0);
|
||||
|
||||
bfr[4] = 0xff & (BLOCK_SIZE >> 24);
|
||||
bfr[5] = 0xff & (BLOCK_SIZE >> 16);
|
||||
bfr[6] = 0xff & (BLOCK_SIZE >> 8);
|
||||
bfr[7] = 0xff & (BLOCK_SIZE >> 0);
|
||||
|
||||
usb_send(2, bfr, sizeof(bfr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reply_csw(struct cbw *cbw, const void *payload, int result) {
|
||||
(void)payload;
|
||||
csw.dCSWSignature = CSW_SIGNATURE;
|
||||
csw.bCSWStatus = result;
|
||||
usb_send(2, &csw, sizeof(csw));
|
||||
}
|
||||
|
||||
static int reply_scsi_mode_sense_6(const void *payload) {
|
||||
const uint8_t *p = payload;
|
||||
uint8_t inf_bfr[4];
|
||||
// switch (p[2]) {
|
||||
// case 0x1c: // Informational
|
||||
inf_bfr[0] = 3; /* Num bytes that follow */
|
||||
inf_bfr[1] = 0; /* Medium Type */
|
||||
inf_bfr[2] = 0; /* Device specific param */
|
||||
inf_bfr[3] = 0;
|
||||
csw.dCSWDataResidue = 4;
|
||||
usb_send(2, inf_bfr, sizeof(inf_bfr));
|
||||
// break;
|
||||
|
||||
// case 0x01: // Error recovery
|
||||
// break;
|
||||
|
||||
// case 0x3f:
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// return 1;
|
||||
// }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void memset(uint8_t *data, int val, size_t len) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < len; i++)
|
||||
data[i] = val;
|
||||
}
|
||||
|
||||
static size_t read_remaining;
|
||||
static size_t read_offset;
|
||||
static int csw_sent;
|
||||
static int read_cb(uint8_t *bfr, size_t max, void *ptr) {
|
||||
(void)ptr;
|
||||
if (!read_remaining) {
|
||||
if (!csw_sent) {
|
||||
csw_sent = 1;
|
||||
memcpy(bfr, &csw, sizeof(csw));
|
||||
return sizeof(csw);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
csw_sent = 0;
|
||||
size_t to_read = read_remaining;
|
||||
if (to_read > max)
|
||||
to_read = max;
|
||||
memcpy(bfr, ((void *)memory_backing) + read_offset, to_read);
|
||||
read_remaining -= to_read;
|
||||
read_offset += to_read;
|
||||
return to_read;
|
||||
}
|
||||
|
||||
static int reply_scsi_read_10(const void *payload) {
|
||||
const uint8_t *p = payload;
|
||||
uint32_t lba_start = (p[2] << 24)
|
||||
| (p[3] << 16)
|
||||
| (p[4] << 8)
|
||||
| (p[5] << 0);
|
||||
uint32_t block_count = (p[7] << 8) | p[8];
|
||||
read_remaining = block_count * BLOCK_SIZE;
|
||||
read_offset = lba_start * BLOCK_SIZE;
|
||||
csw.dCSWDataResidue = BLOCK_SIZE * block_count;
|
||||
usb_send_cb(2, read_cb, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t write_remaining;
|
||||
static size_t write_offset;
|
||||
static int write_cb(const uint8_t *bfr, size_t max, void *ptr) {
|
||||
(void)ptr;
|
||||
|
||||
size_t to_write = write_remaining;
|
||||
if (to_write > max)
|
||||
to_write = max;
|
||||
|
||||
memcpy(((void *)memory_backing) + write_offset, bfr, to_write);
|
||||
write_remaining -= to_write;
|
||||
write_offset += to_write;
|
||||
|
||||
if (!write_remaining) {
|
||||
usb_send(2, &csw, sizeof(csw));
|
||||
}
|
||||
return write_remaining;
|
||||
}
|
||||
|
||||
static int reply_scsi_write_10(const void *payload) {
|
||||
const uint8_t *p = payload;
|
||||
uint32_t lba_start = (p[2] << 24)
|
||||
| (p[3] << 16)
|
||||
| (p[4] << 8)
|
||||
| (p[5] << 0);
|
||||
uint32_t block_count = (p[7] << 8) | p[8];
|
||||
write_remaining = block_count * BLOCK_SIZE;
|
||||
write_offset = lba_start * BLOCK_SIZE;
|
||||
usb_write_cb = write_cb;
|
||||
usb_write_cb_ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Receive an OUT packet from the host
|
||||
void usb_msc_out(const void *data, size_t len) {
|
||||
struct cbw cbw;
|
||||
const void *payload;
|
||||
int result;
|
||||
|
||||
if (usb_write_cb) {
|
||||
int res = usb_write_cb(data, len, usb_write_cb_ptr);
|
||||
if (res > 0)
|
||||
return;
|
||||
usb_write_cb = NULL;
|
||||
usb_write_cb_ptr = NULL;
|
||||
if (res == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
payload = parse_cbw(data, len, &cbw);
|
||||
if (!payload) {
|
||||
usb_stall(0x82);
|
||||
return;
|
||||
}
|
||||
|
||||
csw.dCSWDataResidue = 0;
|
||||
csw.dCSWTag = cbw.tag;
|
||||
const uint8_t *char_view = payload;
|
||||
switch (char_view[0]) {
|
||||
case 0x00: // TEST_UNIT_READY
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case 0x12: // SCSI_INQUIRY
|
||||
result = reply_scsi_inquiry(payload);
|
||||
break;
|
||||
|
||||
case 0x25: // READ_CAPACITY
|
||||
result = reply_scsi_read_capacity(payload);
|
||||
break;
|
||||
|
||||
case 0x1a: // MODE_SENSE_6
|
||||
result = reply_scsi_mode_sense_6(payload);
|
||||
break;
|
||||
|
||||
case 0x1e: // PREVENT_ALLOW_MEDIUM_REMOVAL
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case 0x28: // READ_10
|
||||
reply_scsi_read_10(payload);
|
||||
return;
|
||||
|
||||
case 0x2a: // WRITE_10
|
||||
reply_scsi_write_10(payload);
|
||||
return;
|
||||
|
||||
default:
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
reply_csw(&cbw, payload, result);
|
||||
}
|
||||
|
||||
// Receive an IN packet from the host
|
||||
void usb_msc_in(void) {
|
||||
}
|
||||
|
||||
int usb_msc_setup(const struct usb_setup_request *setup) {
|
||||
if (setup->wRequestAndType == 0xfea1) {
|
||||
usb_send(0, &max_lun, sizeof(max_lun));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user