Changed fill-column to 80, so more space for comments.

This commit is contained in:
2024-06-28 16:11:01 +01:00
parent 3a09beb582
commit 6014620baa
8 changed files with 92 additions and 112 deletions

View File

@@ -91,8 +91,7 @@ typedef union
} data_t; } data_t;
/** /**
@brief Enum of type tags for the data_t structure to provide @brief Enum of type tags for the data_t structure to provide context.
context.
*/ */
typedef enum typedef enum
{ {
@@ -116,11 +115,10 @@ static const hword_t __i = 0xFFFF0000;
#endif #endif
/** /**
@brief Safely subtract SUB from W, where both are words (64 bit @brief Safely subtract SUB from W, where both are words (64 bit integers).
integers).
@details In case of underflow (i.e. where W - SUB < 0) returns 0 @details In case of underflow (i.e. where W - SUB < 0) returns 0 instead of
instead of the underflowed result. the underflowed result.
*/ */
#define WORD_SAFE_SUB(W, SUB) ((W) > (SUB) ? ((W) - (SUB)) : 0) #define WORD_SAFE_SUB(W, SUB) ((W) > (SUB) ? ((W) - (SUB)) : 0)
@@ -141,17 +139,15 @@ static const hword_t __i = 0xFFFF0000;
/** /**
@brief Return the Nth half word of WORD. @brief Return the Nth half word of WORD.
@details N should range from 0 to 1 as there are 2 half words in a @details N should range from 0 to 1 as there are 2 half words in a word
word
*/ */
#define WORD_NTH_HWORD(WORD, N) (((WORD) >> ((N) * 32)) & 0xFFFFFFFF) #define WORD_NTH_HWORD(WORD, N) (((WORD) >> ((N) * 32)) & 0xFFFFFFFF)
/** /**
@brief Convert a buffer of bytes to a short @brief Convert a buffer of bytes to a short
@details It is assumed that the buffer of bytes are in virtual @details It is assumed that the buffer of bytes are in virtual machine byte
machine byte code format (little endian) and that they are at least code format (little endian) and that they are at least SHORT_SIZE in size.
SHORT_SIZE in size.
*/ */
short_t convert_bytes_to_short(const byte_t *buffer); short_t convert_bytes_to_short(const byte_t *buffer);
@@ -161,17 +157,16 @@ short_t convert_bytes_to_short(const byte_t *buffer);
@param s: Short to convert @param s: Short to convert
@param buffer: Buffer to store into. It is assumed that the buffer @param buffer: Buffer to store into. It is assumed that the buffer has at
has at least SHORT_SIZE space. least SHORT_SIZE space.
*/ */
void convert_short_to_bytes(const short_t s, byte_t *buffer); void convert_short_to_bytes(const short_t s, byte_t *buffer);
/** /**
@brief Convert a buffer of bytes to a half word. @brief Convert a buffer of bytes to a half word.
@details It is assumed that the buffer of bytes are in virtual @details It is assumed that the buffer of bytes are in virtual machine byte
machine byte code format (little endian) and that they are at least code format (little endian) and that they are at least HWORD_SIZE in size.
HWORD_SIZE in size.
*/ */
hword_t convert_bytes_to_hword(const byte_t *buffer); hword_t convert_bytes_to_hword(const byte_t *buffer);
@@ -181,36 +176,34 @@ hword_t convert_bytes_to_hword(const byte_t *buffer);
@param h: Half word to convert @param h: Half word to convert
@param buffer: Buffer to store into. It is assumed that the buffer @param buffer: Buffer to store into. It is assumed that the buffer has at
has at least HWORD_SIZE space. least HWORD_SIZE space.
*/ */
void convert_hword_to_bytes(const hword_t h, byte_t *buffer); void convert_hword_to_bytes(const hword_t h, byte_t *buffer);
/** /**
@brief Convert a buffer of bytes to a word. @brief Convert a buffer of bytes to a word.
@details It is assumed that the buffer of bytes are in virtual @details It is assumed that the buffer of bytes are in virtual machine byte
machine byte code format (little endian) and that they are at least code format (little endian) and that they are at least WORD_SIZE in size.
WORD_SIZE in size.
*/ */
word_t convert_bytes_to_word(const byte_t *); word_t convert_bytes_to_word(const byte_t *);
/** /**
@brief Convert a word into a VM byte code format bytes (little @brief Convert a word into a VM byte code format bytes (little endian)
endian)
@param w: Word to convert @param w: Word to convert
@param buffer: Buffer to store into. It is assumed that the buffer @param buffer: Buffer to store into. It is assumed that the buffer has at
has at least WORD_SIZE space. least WORD_SIZE space.
*/ */
void convert_word_to_bytes(const word_t w, byte_t *buffer); void convert_word_to_bytes(const word_t w, byte_t *buffer);
/** /**
@brief Swap the ordering of bytes within an short @brief Swap the ordering of bytes within an short
@details The ordering of the bytes in the short are reversed (2 @details The ordering of the bytes in the short are reversed (2 bytes in a
bytes in a short). short).
@param s: short to swap @param s: short to swap
*/ */
@@ -219,8 +212,8 @@ short_t short_byteswap(const short_t s);
/** /**
@brief Swap the ordering of bytes within an half word @brief Swap the ordering of bytes within an half word
@details The ordering of the bytes in the half word are reversed (4 @details The ordering of the bytes in the half word are reversed (4 bytes in
bytes in a half word). a half word).
@param h: Half word to swap @param h: Half word to swap
*/ */
@@ -229,8 +222,8 @@ hword_t hword_byteswap(const hword_t h);
/** /**
@brief Swap the ordering of bytes within an word @brief Swap the ordering of bytes within an word
@details The ordering of the bytes in the word are reversed (8 @details The ordering of the bytes in the word are reversed (8 bytes in a
bytes in a word). word).
@param w: Word to swap @param w: Word to swap
*/ */

View File

@@ -42,10 +42,10 @@ typedef struct
/** /**
@brief Get the `IND`th item of type `TYPE` in `DARR_DATA` @brief Get the `IND`th item of type `TYPE` in `DARR_DATA`
@details Cast `DARR_DATA` to `TYPE`, taking the `IND`th item. @details Cast `DARR_DATA` to `TYPE`, taking the `IND`th item. NOTE: This is
NOTE: This is unsafe as bound checks are not done i.e. if unsafe as bound checks are not done i.e. if `DARR_DATA` has at least space
`DARR_DATA` has at least space for `IND` * sizeof(`TYPE`) items. for `IND` * sizeof(`TYPE`) items. It is presumed the caller will check
It is presumed the caller will check themselves. themselves.
@param[TYPE] Type to cast internal byte array @param[TYPE] Type to cast internal byte array
@param[DARR_DATA] Byte array of darr @param[DARR_DATA] Byte array of darr
@@ -58,24 +58,23 @@ typedef struct
/** /**
@brief Initialise a dynamic array `darr` with n bytes of space. @brief Initialise a dynamic array `darr` with n bytes of space.
@details All properties of `darr` are initialised. `darr`.used is @details All properties of `darr` are initialised. `darr`.used is set to 0,
set to 0, `darr`.available is set to `n` and `darr`.data is set to `darr`.available is set to `n` and `darr`.data is set to a pointer of `n`
a pointer of `n` bytes. NOTE: If `n` = 0 then it is set to bytes. NOTE: If `n` = 0 then it is set to DARR_DEFAULT_SIZE
DARR_DEFAULT_SIZE
@param[darr] Pointer to darr_t object to initialise @param[darr] Pointer to darr_t object to initialise
@param[n] Number of bytes to allocate. If equal to 0 then @param[n] Number of bytes to allocate. If equal to 0 then considered treated
considered treated as DARR_DEFAULT_SIZE as DARR_DEFAULT_SIZE
*/ */
void darr_init(darr_t *darr, size_t n); void darr_init(darr_t *darr, size_t n);
/** /**
@brief Ensure a dynamic array has at least n bytes of space free. @brief Ensure a dynamic array has at least n bytes of space free.
@details If `darr` has n or more bytes free, nothing occurs. @details If `darr` has n or more bytes free, nothing occurs. Otherwise, the
Otherwise, the byte array in `darr` is reallocated such that it has byte array in `darr` is reallocated such that it has at least `n` bytes of
at least `n` bytes of free space. NOTE: `darr` has at least `n` free space. NOTE: `darr` has at least `n` bytes free if and only if
bytes free if and only if `darr`.used + `n` <= `darr`.available `darr`.used + `n` <= `darr`.available
@param[darr] Dynamic array to check @param[darr] Dynamic array to check
@param[n] Number of bytes @param[n] Number of bytes
@@ -85,10 +84,9 @@ void darr_ensure_capacity(darr_t *darr, size_t n);
/** /**
@brief Append a byte to a dynamic array. @brief Append a byte to a dynamic array.
@details Append a byte to the end of the byte buffer in a dyamic @details Append a byte to the end of the byte buffer in a dyamic array. If
array. If the dynamic array doesn't have enough free space to fit the dynamic array doesn't have enough free space to fit the byte, it will
the byte, it will reallocate to ensure it can fit it in via reallocate to ensure it can fit it in via darr_ensure_capacity().
darr_ensure_capacity().
@param[darr] Dynamic arrary to append to @param[darr] Dynamic arrary to append to
@param[b] Byte to append @param[b] Byte to append
@@ -98,10 +96,9 @@ void darr_append_byte(darr_t *darr, byte_t b);
/** /**
@brief Append an array of n bytes to a dynamic array. @brief Append an array of n bytes to a dynamic array.
@details Append an array of bytes to the end of a byte buffer. If @details Append an array of bytes to the end of a byte buffer. If the
the dynamic array doesn't have enough free space to fit all n bytes dynamic array doesn't have enough free space to fit all n bytes it will
it will reallocate to ensure it can fit it in via reallocate to ensure it can fit it in via darr_ensure_capacity().
darr_ensure_capacity().
@param[darr] Dynamic array to append to @param[darr] Dynamic array to append to
@param[b] Array of bytes to append @param[b] Array of bytes to append
@@ -112,9 +109,9 @@ void darr_append_bytes(darr_t *darr, byte_t *b, size_t n);
/** /**
@brief Get the nth byte of a dynamic array @brief Get the nth byte of a dynamic array
@details Get the nth byte of the dynamic array. 0 based. NOTE: If @details Get the nth byte of the dynamic array. 0 based. NOTE: If the
the dynamic array has less than n bytes used, it will return 0 as a dynamic array has less than n bytes used, it will return 0 as a default
default value, so this is a safe alternative to DARR_AT(). value, so this is a safe alternative to DARR_AT().
@param[darr] Dynamic array to index @param[darr] Dynamic array to index
@param[n] Index to get byte at @param[n] Index to get byte at
@@ -126,9 +123,9 @@ byte_t *darr_at(darr_t *darr, size_t n);
/** /**
@brief Write the bytes of a dynamic array to a file pointer @brief Write the bytes of a dynamic array to a file pointer
@details Given a dynamic array and a file pointer, write the @details Given a dynamic array and a file pointer, write the internal buffer
internal buffer of bytes to the file pointer. NOTE: The file of bytes to the file pointer. NOTE: The file pointer is assumed to be open
pointer is assumed to be open and suitable for writing. and suitable for writing.
@param[darr] Dynamic array to write @param[darr] Dynamic array to write
@param[fp] File pointer to write on @param[fp] File pointer to write on
@@ -138,14 +135,14 @@ void darr_write_file(darr_t *darr, FILE *fp);
/** /**
@brief Read a file pointer in its entirety into a dynamic array @brief Read a file pointer in its entirety into a dynamic array
@details Read a file pointer as a buffer of bytes then return that @details Read a file pointer as a buffer of bytes then return that buffer
buffer wrapped in a darr_t structure. NOTE: the file pointer is wrapped in a darr_t structure. NOTE: the file pointer is assumed to be open
assumed to be open and suitable for reading. and suitable for reading.
@param[fp]: File pointer to read @param[fp]: File pointer to read
@return Dynamic array structure with available set to the size of @return Dynamic array structure with available set to the size of the
the `buffer` read and `data` set to the buffer of bytes. `buffer` read and `data` set to the buffer of bytes.
*/ */
darr_t darr_read_file(FILE *fp); darr_t darr_read_file(FILE *fp);

View File

@@ -59,8 +59,7 @@ bool heap_free(heap_t *heap, page_t *page)
if (cur == page) if (cur == page)
{ {
page_delete(cur); page_delete(cur);
// TODO: When does this fragmentation become a performance // TODO: When does this fragmentation become a performance issue?
// issue?
DARR_AT(page_t *, heap->page_vec.data, i) = NULL; DARR_AT(page_t *, heap->page_vec.data, i) = NULL;
return true; return true;
} }

View File

@@ -26,8 +26,8 @@
/** /**
@brief Some fixed portion of bytes allocated on the heap. @brief Some fixed portion of bytes allocated on the heap.
@details A fixed allocation of bytes. Cannot be resized nor can it @details A fixed allocation of bytes. Cannot be resized nor can it be stack
be stack allocated (the usual way) due to flexible array attached. allocated (the usual way) due to flexible array attached.
@prop[next] Next page in the linked list @prop[next] Next page in the linked list
@prop[available] Available number of bytes in page @prop[available] Available number of bytes in page
@@ -42,9 +42,8 @@ typedef struct Page
/** /**
@brief Allocate a new page on the heap with the given properties. @brief Allocate a new page on the heap with the given properties.
@details Allocates a new page using malloc with the given size and @details Allocates a new page using malloc with the given size and pointer to
pointer to next page. NOTE: all memory is 0 initialised by next page. NOTE: all memory is 0 initialised by default.
default.
@param[max] Maximum available memory in page @param[max] Maximum available memory in page
*/ */
@@ -53,9 +52,8 @@ page_t *page_create(size_t max);
/** /**
@brief Delete a page, freeing its memory @brief Delete a page, freeing its memory
@details Free's the memory associated with the page via free(). @details Free's the memory associated with the page via free(). NOTE: any
NOTE: any pointers to the page's memory are considered invalid once pointers to the page's memory are considered invalid once this is called.
this is called.
@param[page] Page to delete @param[page] Page to delete
*/ */
@@ -65,8 +63,8 @@ void page_delete(page_t *page);
@brief A collection of pages through which generic allocations can @brief A collection of pages through which generic allocations can
occur. occur.
@details Collection of pages maintained through a vector of @details Collection of pages maintained through a vector of pointers to
pointers to pages. pages.
@prop[page_vec] Vector of pages @prop[page_vec] Vector of pages
*/ */
@@ -80,9 +78,8 @@ typedef struct
/** /**
@brief Instantiate a new heap structure @brief Instantiate a new heap structure
@details Initialises the heap structure given. No heap allocation @details Initialises the heap structure given. No heap allocation occurs
occurs here until a new page is created, so this may be called here until a new page is created, so this may be called safely.
safely.
@param[heap] Pointer to heap to initialise @param[heap] Pointer to heap to initialise
*/ */
@@ -91,8 +88,8 @@ void heap_create(heap_t *heap);
/** /**
@brief Allocate a new page on the heap @brief Allocate a new page on the heap
@details Creates and joins a new page onto the linked list @details Creates and joins a new page onto the linked list maintained by the
maintained by the heap. heap.end is set to this new page. heap. heap.end is set to this new page.
@param[heap] Heap to create a new page on @param[heap] Heap to create a new page on
@param[size] Size of page to allocate @param[size] Size of page to allocate
@@ -104,10 +101,9 @@ page_t *heap_allocate(heap_t *heap, size_t size);
/** /**
@brief Free a page of memory from the heap @brief Free a page of memory from the heap
@details The page given is removed from the linked list of pages @details The page given is removed from the linked list of pages then freed
then freed from the heap via page_delete(). If the page does not from the heap via page_delete(). If the page does not belong to this heap
belong to this heap (O(heap.pages) time) then false is returned, (O(heap.pages) time) then false is returned, otherwise true.
otherwise true.
@param[heap] Heap to free page from @param[heap] Heap to free page from
@param[page] Page to delete @param[page] Page to delete

View File

@@ -210,10 +210,10 @@ typedef struct
/** /**
@brief Serialise an instruction into a byte buffer @brief Serialise an instruction into a byte buffer
@details Given an instruction and a suitably sized byte buffer, @details Given an instruction and a suitably sized byte buffer, write the
write the bytecode for the instruction into the buffer. NOTE: This bytecode for the instruction into the buffer. NOTE: This function does NOT
function does NOT check the bounds of `bytes` i.e. we assume the check the bounds of `bytes` i.e. we assume the caller has created a suitably
caller has created a suitably sized buffer. sized buffer.
@param[inst] Instruction to serialise @param[inst] Instruction to serialise
@param[bytes] Buffer to write on @param[bytes] Buffer to write on
@@ -233,21 +233,19 @@ typedef enum
/** /**
@brief Deserialise an instruction from a bytecode buffer @brief Deserialise an instruction from a bytecode buffer
@details Given a buffer of bytes, deserialise an instruction, @details Given a buffer of bytes, deserialise an instruction, storing the
storing the result in the pointer given. The number of bytes read result in the pointer given. The number of bytes read in the buffer is
in the buffer is returned, which should be opcode_bytecode_size(). returned, which should be opcode_bytecode_size(). NOTE: If bytes is not
NOTE: If bytes is not suitably sized for the instruction expected suitably sized for the instruction expected or it is not well formed i.e. not
or it is not well formed i.e. not the right schema then a negative the right schema then a negative number is returned.
number is returned.
@param[inst] Pointer to instruction which will store result @param[inst] Pointer to instruction which will store result
@param[bytes] Bytecode buffer to deserialise @param[bytes] Bytecode buffer to deserialise
@param[size_bytes] Number of bytes in buffer @param[size_bytes] Number of bytes in buffer
@return[int] Number of bytes read. If negative then an error @return[int] Number of bytes read. If negative then an error occurred in
occurred in deserialisation (either buffer was not suitably sized deserialisation (either buffer was not suitably sized or instruction was not
or instruction was not well formed) so any result must be well formed) so any result must be considered invalid.
considered invalid.
*/ */
int inst_read_bytecode(inst_t *inst, byte_t *bytes, size_t size_bytes); int inst_read_bytecode(inst_t *inst, byte_t *bytes, size_t size_bytes);

View File

@@ -70,8 +70,8 @@ void test_lib_darr_ensure_capacity_expands(void)
{10, 10, 10, 20}, {10, 10, 10, 20},
{50, 100, 300, 350}, {50, 100, 300, 350},
{1 << 20, 2 << 20, 2 << 20, 3 << 20}, {1 << 20, 2 << 20, 2 << 20, 3 << 20},
// When we reallocate we allocate MORE than needed (for // When we reallocate we allocate MORE than needed (for amortized
// amortized constant) // constant)
{1, 5, 5, 10}, {1, 5, 5, 10},
{85, 100, 40, 200}, {85, 100, 40, 200},
{4 << 20, 5 << 20, 1 << 23, 5 << 21}, {4 << 20, 5 << 20, 1 << 23, 5 << 21},

View File

@@ -60,8 +60,7 @@ int main(int argc, char *argv[])
else if (program.count == 0) else if (program.count == 0)
return 0; return 0;
// After reading header, we can allocate the buffer of instrutions // After reading header, we can allocate the buffer of instrutions exactly
// exactly
program.instructions = calloc(program.count, sizeof(*program.instructions)); program.instructions = calloc(program.count, sizeof(*program.instructions));
size_t bytes_read = 0; size_t bytes_read = 0;
read_err_prog_t read_err = read_err_prog_t read_err =

View File

@@ -98,11 +98,10 @@ err_t vm_execute(vm_t *vm)
"Code using OPCODE_DATA_TYPE for quick same type opcode " "Code using OPCODE_DATA_TYPE for quick same type opcode "
"conversion may be out of date."); "conversion may be out of date.");
// NOTE: We always use the first register to hold the result of // NOTE: We always use the first register to hold the result of this pop.
// this pop.
// Here we add OP_MOV_BYTE and the data_type_t of the opcode to // Here we add OP_MOV_BYTE and the data_type_t of the opcode to get the
// get the right typed OP_MOV opcode. // right typed OP_MOV opcode.
opcode_t mov_opcode = opcode_t mov_opcode =
OPCODE_DATA_TYPE(instruction.opcode, OP_POP) + OP_MOV_BYTE; OPCODE_DATA_TYPE(instruction.opcode, OP_POP) + OP_MOV_BYTE;
@@ -152,8 +151,8 @@ err_t vm_execute(vm_t *vm)
"conversion may be out of date."); "conversion may be out of date.");
data_t datum = {0}; data_t datum = {0};
// Here we add OP_POP_BYTE and the data_type_t of the opcode to // Here we add OP_POP_BYTE and the data_type_t of the opcode to get the
// get the right OP_POP opcode. // right OP_POP opcode.
opcode_t pop_opcode = opcode_t pop_opcode =
OPCODE_DATA_TYPE(instruction.opcode, OP_JUMP_IF) + OP_POP_BYTE; OPCODE_DATA_TYPE(instruction.opcode, OP_JUMP_IF) + OP_POP_BYTE;
@@ -228,9 +227,8 @@ err_t vm_execute(vm_t *vm)
// 2) create a format string for each datum type possible // 2) create a format string for each datum type possible
// TODO: Figure out a way to ensure the ordering of OP_PRINT_* is // TODO: Figure out a way to ensure the ordering of OP_PRINT_* is exactly
// exactly BYTE, SBYTE, SHORT, SSHORT, HWORD, SHWORD, WORD, SWORD // BYTE, SBYTE, SHORT, SSHORT, HWORD, SHWORD, WORD, SWORD via static_assert
// via static_assert
// lookup table // lookup table
const char *format_strings[] = { const char *format_strings[] = {