fix compilation, more stuff
This commit is contained in:
parent
3c3795f8cb
commit
36b55483a8
|
@ -110,7 +110,7 @@ target_include_directories(${PROJECT} PUBLIC
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/default/
|
||||
)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type -Werror=maybe-uninitialized")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||
|
||||
add_custom_target(fix_db ALL WORKING_DIRECTORY ${OUTPUT_DIR}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#define CFG_TUD_VENDOR 1
|
||||
|
||||
/* don't access storage for RAM-only builds */
|
||||
#ifndef PICO_NO_FLASH
|
||||
#define BOARD_HAS_STORAGE
|
||||
#if !PICO_NO_FLASH
|
||||
#define DBOARD_HAS_STORAGE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,16 +7,22 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef PICO_NO_FLASH
|
||||
#if !PICO_NO_FLASH
|
||||
|
||||
#include <hardware/addressmap.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hardware/regs/addressmap.h>
|
||||
#include <hardware/regs/xip.h>
|
||||
#include <hardware/structs/xip_ctrl.h>
|
||||
#include <hardware/flash.h>
|
||||
#include <hardware/sync.h>
|
||||
|
||||
#ifndef PICO_FLASH_SIZE_BYTES
|
||||
#warning "PICO_FLASH_SIZE_BYTES not defined, defaulting to 2 megabytes. This WILL break if your flash is smaller!"
|
||||
#define PICO_FLASH_SIZE_BYTES (2*1024*1024)
|
||||
#error "PICO_FLASH_SIZE_BYTES not defined"
|
||||
#endif
|
||||
|
||||
#define STORAGE_RAM_FUNC(x) __no_inline_not_in_flash_func(x)
|
||||
|
||||
static inline size_t storage_get_program_size(void) {
|
||||
extern uint8_t __flash_binary_start, __flash_binary_end;
|
||||
|
||||
|
@ -41,16 +47,68 @@ static inline void storage_read(void* dest, size_t offset, size_t size) {
|
|||
// * SSI DMA: blocking & fast, code needs to run from RAM. a bit unwieldy
|
||||
memcpy(dest, (uint8_t*)(XIP_BASE+offset), size);
|
||||
}
|
||||
static inline bool storage_erasewrite(size_t offset, const void* src, size_t size) {
|
||||
static bool STORAGE_RAM_FUNC(storage_erasewrite)(size_t offset, const void* src, size_t size) {
|
||||
// bad alignment => give an error in advance
|
||||
if (offset & (FLASH_SECTOR_SIZE - 1)) return false;
|
||||
if (size & (FLASH_SECTOR_SIZE - 1)) return false;
|
||||
|
||||
// memcmp pre: if no changes, don't flash
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (*(uint8_t*)(XIP_BASE + offset + i) != ((const uint8_t*)src)[i]) {
|
||||
goto do_flash;
|
||||
}
|
||||
|
||||
asm volatile("":::"memory"); // make sure the compiler won't turn this into a memcmp call
|
||||
}
|
||||
|
||||
return true; // all equal, nothing to do, all is fine
|
||||
|
||||
do_flash:
|
||||
// these functions are RAM-only-safe
|
||||
flash_range_erase(offset, size);
|
||||
// TODO: only program ranges written to?
|
||||
flash_range_program(offset, src, size);
|
||||
|
||||
// maybe not a bad idea either
|
||||
return !memcmp(src, (uint8_t*)(XIP_BASE+offset), size);
|
||||
// now do a memcmp, kinda badly but we can't call newlib memcmp
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (*(uint8_t*)(XIP_BASE + offset + i) != ((const uint8_t*)src)[i]) {
|
||||
return false; // welp
|
||||
}
|
||||
|
||||
asm volatile("":::"memory"); // make sure the compiler won't turn this into a memcmp call
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void* STORAGE_RAM_FUNC(storage_extra_ram_get_base)(void) {
|
||||
return (void*)XIP_SRAM_BASE;
|
||||
}
|
||||
|
||||
typedef uint32_t storage_extra_ram_temp_t;
|
||||
|
||||
static storage_extra_ram_temp_t STORAGE_RAM_FUNC(storage_extra_ram_enable)(void) {
|
||||
uint32_t flags = save_and_disable_interrupts();
|
||||
|
||||
xip_ctrl_hw->flush = 1; // flush XIP stuff
|
||||
// wait until flush is done
|
||||
while (!(xip_ctrl_hw->stat & XIP_STAT_FLUSH_RDY))
|
||||
asm volatile("nop":::"memory");
|
||||
|
||||
xip_ctrl_hw->ctrl &= ~(io_rw_32)XIP_CTRL_EN_BITS; // disable XIP cache -> can now use it as SRAM
|
||||
|
||||
// interrupts may access flash
|
||||
//restore_interrupts(flags);
|
||||
|
||||
return flags;
|
||||
}
|
||||
static void STORAGE_RAM_FUNC(storage_extra_ram_disable)(storage_extra_ram_temp_t flags) {
|
||||
//uint32_t flags = save_and_disable_interrupts();
|
||||
|
||||
xip_ctrl_hw->ctrl |= XIP_CTRL_EN_BITS; // reenable XIP cache
|
||||
|
||||
restore_interrupts(flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,9 +32,9 @@ int main() {
|
|||
vndcfg_thread = co_derive(vndcfg_stack, sizeof vndcfg_stack, vndcfg_thread_fn);
|
||||
thread_enter(vndcfg_thread);
|
||||
|
||||
storage_init(); // sets mode_next_id
|
||||
int startupmode = storage_init();
|
||||
|
||||
modes_init(mode_next_id);
|
||||
modes_init(startupmode);
|
||||
if (mode_current) mode_current->enter();
|
||||
|
||||
tusb_init();
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "mode.h"
|
||||
#include "storage.h"
|
||||
|
||||
#ifndef BOARD_HAS_STORAGE
|
||||
void storage_init(void) { }
|
||||
#ifndef DBOARD_HAS_STORAGE
|
||||
int storage_init(void) { return -1; }
|
||||
void storage_flush_data(void) { }
|
||||
struct mode_info storage_mode_get_size(int _) {
|
||||
(void)_; return (struct mode_info){ .size = 0, .version = 0 };
|
||||
|
@ -16,11 +16,21 @@ void storage_mode_read(int _, void* __) { (void)_; (void)__; }
|
|||
|
||||
#include "storage_internal.h"
|
||||
|
||||
uint32_t str_hash_djb2_digest(uint32_t hash, const void* data, size_t len) {
|
||||
const uint8_t* d = data;
|
||||
|
||||
for (size_t i = 0; i < len; ++i) hash += hash * 33 + d[i];
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool header_valid = false;
|
||||
struct storage_header header_tmp;
|
||||
uint8_t data_tmp[1024 - sizeof(struct storage_header)];
|
||||
uint8_t data_tmp[256];
|
||||
uint16_t mode_bad = 0;
|
||||
|
||||
static int in_init = 0;
|
||||
|
||||
static void storage_init_defaults(void) {
|
||||
memcpy(header_tmp.magic, STORAGE_MAGIC, STORAGE_MAGIC_LEN);
|
||||
header_tmp.fwversion = STORAGE_VER;
|
||||
|
@ -34,8 +44,8 @@ static void storage_init_defaults(void) {
|
|||
header_valid = true;
|
||||
}
|
||||
|
||||
void storage_init(void) {
|
||||
mode_next_id = -1; // by default, boot to default mode
|
||||
int storage_init(void) {
|
||||
++in_init;
|
||||
|
||||
mode_bad = 0;
|
||||
storage_read(&header_tmp, STORAGE_SIZE - sizeof(struct storage_header),
|
||||
|
@ -44,14 +54,16 @@ void storage_init(void) {
|
|||
bool bad = false;
|
||||
if (memcmp(header_tmp.magic, STORAGE_MAGIC, STORAGE_MAGIC_LEN)) {
|
||||
storage_init_defaults();
|
||||
storage_flush_data();
|
||||
return;
|
||||
if (in_init == 1) storage_flush_data();
|
||||
--in_init;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header_tmp.fwversion != STORAGE_VER) {
|
||||
// TODO: migrate... if there were any older versions
|
||||
header_valid = false;
|
||||
return;
|
||||
--in_init;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header_tmp.nmodes >= 16) bad = true;
|
||||
|
@ -64,13 +76,14 @@ void storage_init(void) {
|
|||
|
||||
if (bad) {
|
||||
storage_init_defaults();
|
||||
storage_flush_data();
|
||||
return;
|
||||
if (in_init == 1) storage_flush_data();
|
||||
--in_init;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mode_next_id = header_tmp.curmode;
|
||||
|
||||
header_valid = true;
|
||||
--in_init;
|
||||
return header_tmp.curmode;
|
||||
}
|
||||
|
||||
struct mode_info storage_mode_get_info(int mode) {
|
||||
|
@ -89,7 +102,7 @@ struct mode_info storage_mode_get_info(int mode) {
|
|||
uint32_t mdoffset = md.offsetandmode & ((1<<28)-1);
|
||||
|
||||
if (mdmode != mode) continue;
|
||||
if (~mdsize == 0 || ~md.version == 0 || ~offsetandmode == 0)
|
||||
if (mdsize == 0xffff || md.version == 0xffff || md.offsetandmode == 0xffffffffu)
|
||||
continue; // empty (wut?)
|
||||
|
||||
// found it!
|
||||
|
@ -141,7 +154,7 @@ void storage_mode_read(int mode, void* dst) {
|
|||
uint32_t mdoffset = md.offsetandmode & ((1<<28)-1);
|
||||
|
||||
if (mdmode != mode) continue;
|
||||
if (~mdsize == 0 || ~md.version == 0 || ~offsetandmode == 0)
|
||||
if (mdsize == 0xffff || md.version == 0xffff || md.offsetandmode == 0xffffffffu)
|
||||
continue; // empty (wut?)
|
||||
|
||||
// found it!
|
||||
|
|
|
@ -19,8 +19,8 @@ enum mode_storage_class {
|
|||
// mode callbacks used by the storage subsystem
|
||||
struct mode_storage {
|
||||
enum mode_storage_class stclass;
|
||||
uint32_t (*get_size)(void);
|
||||
void (*get_data)(void* dst);
|
||||
uint16_t (*get_size)(void);
|
||||
void (*get_data)(void* dst, size_t offset, size_t maxsize);
|
||||
bool (*is_dirty)(void); // if data was changed since last mode_read/get_data call
|
||||
};
|
||||
|
||||
|
@ -37,7 +37,7 @@ void storage_mode_read(int mode, void* dst);
|
|||
// global functions
|
||||
|
||||
// reads all data, creates table if needed
|
||||
void storage_init(void);
|
||||
int storage_init(void);
|
||||
|
||||
// flush edits if anything has been edited
|
||||
void storage_flush_data(void);
|
||||
|
|
|
@ -8,7 +8,7 @@ inline static uint32_t str_hash_djb2_init(void) {
|
|||
}
|
||||
uint32_t str_hash_djb2_digest(uint32_t hash, const void* data, size_t len);
|
||||
inline static uint32_t str_hash_djb2(const void* data, size_t len) {
|
||||
return str_hash_djb2_digestt(str_hash_djb2_init(), data, len);
|
||||
return str_hash_djb2_digest(str_hash_djb2_init(), data, len);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -62,7 +62,7 @@ __attribute__((__packed__)) struct storage_header {
|
|||
|
||||
extern bool header_valid;
|
||||
extern struct storage_header header_tmp;
|
||||
extern uint8_t data_tmp[1024 - sizeof(struct storage_header)];
|
||||
extern uint8_t data_tmp[256];
|
||||
extern uint16_t mode_bad;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,22 +5,116 @@
|
|||
#include "mode.h"
|
||||
#include "storage.h"
|
||||
|
||||
#ifdef BOARD_HAS_STORAGE
|
||||
#ifdef DBOARD_HAS_STORAGE
|
||||
|
||||
#include "storage_internal.h"
|
||||
|
||||
static void storage_write_data(void) {
|
||||
static bool storage_mode_has(int i) {
|
||||
if (mode_list[i]->storage.stclass == mode_storage_none) return false;
|
||||
if (mode_list[i]->storage.get_size == NULL) return false;
|
||||
if (mode_list[i]->storage.get_data == NULL) return false;
|
||||
if (mode_list[i]->storage.is_dirty == NULL) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct mode_storage msto[16];
|
||||
|
||||
static size_t storage_allocate_new(void) {
|
||||
static const size_t stclass_sz[] = { 0, 32, 128, 512, 0xffffffff };
|
||||
|
||||
memcpy(header_tmp.magic, STORAGE_MAGIC, STORAGE_MAGIC_LEN);
|
||||
memset(header_tmp.reserved, 0xff, sizeof(header_tmp.reserved));
|
||||
memset(header_tmp.mode_data_table, 0xff, sizeof(header_tmp.mode_data_table));
|
||||
|
||||
header_tmp.fwversion = STORAGE_VER;
|
||||
header_tmp.curmode = mode_current_id;
|
||||
header_tmp.nmodes = 0;
|
||||
|
||||
size_t current_page = STORAGE_SIZE - STORAGE_ERASEWRITE_ALIGN,
|
||||
current_page_end = STORAGE_SIZE - sizeof(struct storage_header);
|
||||
size_t current_wrhead = current_page;
|
||||
size_t npages = 1;
|
||||
|
||||
for (enum mode_storage_class stcls = mode_storage_32b; stcls <= mode_storage_big; ++stcls) {
|
||||
for (int mode = 1; mode < 16; ++mode) {
|
||||
if (mode_list[mode] == NULL || !storage_mode_has(mode)) continue;
|
||||
if (mode_list[mode]->storage.stclass != stcls) continue;
|
||||
|
||||
// too big for the class? don't write the data, then
|
||||
uint16_t dsize = mode_list[mode]->storage.get_size();
|
||||
if (dsize > stclass_sz[stcls]) continue;
|
||||
|
||||
if (current_wrhead + dsize > current_page_end) { // welp
|
||||
current_page_end = current_page;
|
||||
current_page -= STORAGE_ERASEWRITE_ALIGN;
|
||||
current_wrhead = current_page;
|
||||
++npages;
|
||||
|
||||
if (current_page < storage_get_program_offset() + storage_get_program_size())
|
||||
return 0; // welp, out of space
|
||||
}
|
||||
|
||||
struct mode_data* md = &header_tmp.mode_data_table[header_tmp.nmodes];
|
||||
md->version = mode_list[mode]->version;
|
||||
md->datasize = dsize;
|
||||
md->offsetandmode = current_wrhead | ((uint32_t)mode << 28);
|
||||
msto[header_tmp.nmodes] = mode_list[mode]->storage; // copy to RAM because mode_list is in rodata!
|
||||
|
||||
current_wrhead += stclass_sz[stcls];
|
||||
|
||||
uint32_t hash = str_hash_djb2_init();
|
||||
|
||||
for (size_t i = 0; i < dsize; i += sizeof(data_tmp)) {
|
||||
size_t tohash = sizeof(data_tmp);
|
||||
if (dsize - i < tohash) tohash = dsize - i;
|
||||
|
||||
mode_list[mode]->storage.get_data(data_tmp, i, tohash);
|
||||
|
||||
hash = str_hash_djb2_digest(hash, data_tmp, tohash);
|
||||
}
|
||||
|
||||
md->data_djb2 = hash;
|
||||
++header_tmp.nmodes;
|
||||
}
|
||||
}
|
||||
|
||||
header_tmp.table_djb2 = str_hash_djb2(header_tmp.mode_data_table,
|
||||
sizeof(header_tmp.mode_data_table));
|
||||
|
||||
return npages;
|
||||
}
|
||||
|
||||
static void STORAGE_RAM_FUNC(storage_serialize_xip)(size_t pageid,
|
||||
size_t pagestart, size_t pageend, void* dest) {
|
||||
(void)pageid; (void)pagestart; (void)pageend; (void)dest;
|
||||
|
||||
// BIG TODO
|
||||
// * try to allocate every mode data thing, smaller stuff (cf. mode storage
|
||||
// class) at higher addrs, bigger ones at lower ones. can use get_size(),
|
||||
// but maybe keep data aligned
|
||||
// * for each flash page, copy data into a big buffer. maybe use the XIP
|
||||
// cache because the running mode may be already using all data. all
|
||||
// get_data() functions and the bsp write function need to run from RAM,
|
||||
// though
|
||||
// * then write it out
|
||||
// * maybe we could only write pages that changed? or maybe the bsp code
|
||||
// can take care of this
|
||||
}
|
||||
|
||||
static void STORAGE_RAM_FUNC(storage_write_data)(void) {
|
||||
size_t npages = storage_allocate_new();
|
||||
if (npages == 0) {
|
||||
storage_init();
|
||||
return; // TODO: error, somehow
|
||||
}
|
||||
|
||||
storage_extra_ram_temp_t ramtmp = storage_extra_ram_enable();
|
||||
|
||||
size_t current_page = STORAGE_SIZE - STORAGE_ERASEWRITE_ALIGN,
|
||||
current_page_end = STORAGE_SIZE - sizeof(struct storage_header);
|
||||
for (size_t page = 0; page < npages; ++page) {
|
||||
storage_serialize_xip(page, current_page, current_page_end,
|
||||
storage_extra_ram_get_base());
|
||||
|
||||
storage_erasewrite(current_page, storage_extra_ram_get_base(),
|
||||
STORAGE_ERASEWRITE_ALIGN);
|
||||
|
||||
current_page_end = current_page;
|
||||
current_page -= STORAGE_ERASEWRITE_ALIGN;
|
||||
}
|
||||
|
||||
storage_extra_ram_disable(ramtmp);
|
||||
|
||||
// also TODO:
|
||||
// * call storage_flush_data on vnd cfg command
|
||||
|
@ -29,15 +123,6 @@ static void storage_write_data(void) {
|
|||
// * try to save when unplugging???
|
||||
}
|
||||
|
||||
static bool storage_mode_has(int mode) {
|
||||
if (mode_list[i]->storage.stclass == mode_storage_none) return false;
|
||||
if (mode_list[i]->get_size == NULL) return false;
|
||||
if (mode_list[i]->get_data == NULL) return false;
|
||||
if (mode_list[i]->is_dirty == NULL) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void storage_flush_data(void) {
|
||||
if (mode_bad != 0 || mode_current_id != header_tmp.curmode) {
|
||||
storage_write_data();
|
||||
|
@ -45,7 +130,7 @@ void storage_flush_data(void) {
|
|||
if (mode_list[i] == NULL || !storage_mode_has(i)) continue;
|
||||
|
||||
if (mode_list[i]->storage.is_dirty()) {
|
||||
storage_write_data(i);
|
||||
storage_write_data();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue