From fd85393b54fcd7d0c2ac995f87ea1ca52155c3e6 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 21 Feb 2024 00:59:43 -0600 Subject: [PATCH] Dropped mode field from lfsr_data_t Now that in-block fields are limited to 28-bits, we have a few more bits in our lfsr_data_t size field to encoding things. This commit uses the top 2-bits to encode one of our 4 different lfsr_data_t encodings: - 00--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => buffer poiner - 01--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => inlined data - 10--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => on-disk reference - 11--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => concatenated data pointer .--|-------|-------|-------' | | .-|-------' | | | '------. | '-----|--------|--------. v v v v 1nnnnnnn 1nnnnnnn 1nnnnnnn 0nnnnnnn <= leb128 Note this still works with a hypothetical 12-bit/10-bit littlefs variant, where we'd only have 2 spare bits: - 00nnnnnn nnnnnnnn => buffer poiner - 01nnnnnn nnnnnnnn => inlined data - 10nnnnnn nnnnnnnn => on-disk reference - 11nnnnnn nnnnnnnn => concatenated data pointer .|-------' |'-------. v v 1nnnnnnn 0nnnnnnn <= leb128 We don't really care about 8-bit/7-bit, can we even fit an rbyd in a 127-byte block? The main benefit of this encoding is that lfsr_data_t's pointer fields get the same space as the two words used to encode on-disk block+off. This may be useful on systems where ptr=2-word, such as some 16-bit word/32-bit address devices, and some 2-word CHERI pointer devices. One interesting thing to note: This encoding is only possible thanks to the observation that total data size is sufficent information to write out concatendated datas. We don't really need to know the exact number until prog time, and during prog we can just iterate over datas until size is exhausted. So the size field turns out to be sufficient enough for indicating how many datas are referenced, saving a data-count field. Code changes are negligible. It should be noted that _most_ machines won't benefit from ptr=2-word optimizations, including Thumb, our benchmark ISA: code stack before: 33948 2872 after: 33912 (-0.1%) 2872 (+0.0%) --- lfs.c | 57 ++++++++++++++++++++++++++------------------------------- lfs.h | 6 +----- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/lfs.c b/lfs.c index 407fc52b..68f92156 100644 --- a/lfs.c +++ b/lfs.c @@ -1100,15 +1100,14 @@ static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs, /// lfsr_data_t stuff /// -// data uses the size's sign bit to indicate on-disk vs in-device +// the top bits of data's size indicates the actual encoding +// 0x0 => buffer pointer +// 0x4 => inlined data +// 0x8 => on-disk reference +// 0xc => concatenated data pointer #define LFSR_DATA_ONDISK 0x80000000 - -// in-device data modes -enum { - LFSR_DATA_BUF = 0, - LFSR_DATA_IMM = 1, - LFSR_DATA_CAT = 2, -}; +#define LFSR_DATA_ISIMM 0x40000000 +#define LFSR_DATA_ISCAT 0xc0000000 // LFSR_DATA_DATA just provides and escape hatch to pass raw datas // through the LFSR_ATTR macro @@ -1117,7 +1116,6 @@ enum { #define LFSR_DATA_NULL() \ ((lfsr_data_t){ \ .u.buf.size=0, \ - .u.buf.mode=LFSR_DATA_BUF, \ .u.buf.buffer=NULL}) #define LFSR_DATA_DISK(_block, _off, _size) \ @@ -1129,7 +1127,6 @@ enum { #define LFSR_DATA_BUF(_buffer, _size) \ ((lfsr_data_t){ \ .u.buf.size=_size, \ - .u.buf.mode=LFSR_DATA_BUF, \ .u.buf.buffer=(const void*)(_buffer)}) #define LFSR_DATA_IMM(_buffer, _size) \ @@ -1171,52 +1168,48 @@ typedef struct lfsr_shrubcommit lfsr_shrubcommit_t; ((lfsr_data_t){.u.buf.buffer=(const void*)(const lfsr_shrub_t*){_shrub}}) static inline bool lfsr_data_ondisk(const lfsr_data_t *data) { - return data->u.size & LFSR_DATA_ONDISK; + return (data->u.size & LFSR_DATA_ISCAT) == LFSR_DATA_ONDISK; } static inline bool lfsr_data_isbuf(const lfsr_data_t *data) { - return !lfsr_data_ondisk(data) && data->u.buf.mode == LFSR_DATA_BUF; + return (data->u.size & LFSR_DATA_ISCAT) == 0; } static inline bool lfsr_data_isimm(const lfsr_data_t *data) { - return !lfsr_data_ondisk(data) && data->u.buf.mode == LFSR_DATA_IMM; + return (data->u.size & LFSR_DATA_ISCAT) == LFSR_DATA_ISIMM; } static inline bool lfsr_data_iscat(const lfsr_data_t *data) { - return !lfsr_data_ondisk(data) && data->u.buf.mode == LFSR_DATA_CAT; + return (data->u.size & LFSR_DATA_ISCAT) == LFSR_DATA_ISCAT; } static inline lfs_size_t lfsr_data_size(const lfsr_data_t *data) { - return data->u.size & ~LFSR_DATA_ONDISK; + return data->u.size & ~LFSR_DATA_ISCAT; } // some data initializers just can't be macros, we at least make these inline // so most of the internal logic is hopefully elided static inline lfsr_data_t lfsr_data_fromimm( const void *buffer, lfs_size_t size) { - LFS_ASSERT(size <= 5); + LFS_ASSERT(size <= 8); lfsr_data_t data; memcpy(data.u.imm.buf, buffer, size); - data.u.imm.size = size; - data.u.imm.mode = LFSR_DATA_IMM; + data.u.imm.size = LFSR_DATA_ISIMM | size; return data; } static inline lfsr_data_t lfsr_data_fromleb128(uint32_t word) { lfsr_data_t data; lfs_ssize_t size = lfs_toleb128(word, data.u.imm.buf, 5); - LFS_ASSERT(size >= 0); + LFS_ASSERT(size > 0); LFS_ASSERT(size <= 5); - data.u.imm.size = size; - data.u.imm.mode = LFSR_DATA_IMM; + data.u.imm.size = LFSR_DATA_ISIMM | size; return data; } static inline lfsr_data_t lfsr_data_fromcat( const lfsr_data_t *datas, lfs_size_t count) { - LFS_ASSERT(count <= 255); - // find total size lfs_size_t size = 0; for (uint8_t i = 0; i < count; i++) { @@ -1224,9 +1217,7 @@ static inline lfsr_data_t lfsr_data_fromcat( } return (lfsr_data_t){ - .u.cat.size=size, - .u.cat.mode=LFSR_DATA_CAT, - .u.cat.count=count, + .u.cat.size=LFSR_DATA_ISCAT | size, .u.cat.datas=datas}; } @@ -1257,7 +1248,7 @@ static lfsr_data_t lfsr_data_slice(lfsr_data_t data, memmove(data.u.imm.buf, data.u.imm.buf + off_, size_); - data.u.imm.size = size_; + data.u.imm.size = LFSR_DATA_ISIMM | size_; // concatenated? not supported } else { @@ -1469,7 +1460,7 @@ static int lfsr_bd_progdata_(lfs_t *lfs, // inlined? } else if (lfsr_data_isimm(&data)) { int err = lfsr_bd_prog(lfs, block, off, - data.u.imm.buf, data.u.imm.size, + data.u.imm.buf, lfsr_data_size(&data), cksum_, flcksum_); if (err) { return err; @@ -1496,14 +1487,18 @@ static int lfsr_bd_progdata(lfs_t *lfs, // concatenated data? handle specially to avoid recursion } else { - for (uint8_t i = 0; i < data.u.cat.count; i++) { - int err = lfsr_bd_progdata_(lfs, block, off, data.u.cat.datas[i], + lfs_size_t size = lfsr_data_size(&data); + const lfsr_data_t *datas = data.u.cat.datas; + while (size > 0) { + int err = lfsr_bd_progdata_(lfs, block, off, *datas, cksum_, flcksum_); if (err) { return err; } - off += lfsr_data_size(&data.u.cat.datas[i]); + off += lfsr_data_size(datas); + size -= lfsr_data_size(datas); + datas += 1; } } diff --git a/lfs.h b/lfs.h index e6d5d676..867e20b3 100644 --- a/lfs.h +++ b/lfs.h @@ -424,18 +424,14 @@ typedef struct lfsr_data { } disk; struct { lfs_ssize_t size; - uint8_t mode; const uint8_t *buffer; } buf; struct { lfs_ssize_t size; - uint8_t mode; - uint8_t buf[5]; + uint8_t buf[8]; } imm; struct { lfs_ssize_t size; - uint8_t mode; - uint8_t count; const struct lfsr_data *datas; } cat; } u;