From 44d82c9998e9bb563b0d3301860892115fde479d Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 1 Sep 2024 18:08:56 +0200 Subject: [PATCH 01/35] Update memory block implementation --- cd.c | 4 +- config.h | 3 ++ memory.c | 61 ++++++++++++++--------- memory.h | 53 +++++++++++--------- memorymap.c | 9 ++-- memorymap.h | 2 +- rom.c | 14 +++--- section.h | 87 ++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 55 +++++++++++++-------- test/memory.c | 118 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 326 insertions(+), 80 deletions(-) create mode 100644 test/memory.c diff --git a/cd.c b/cd.c index a10f418..21ea41f 100644 --- a/cd.c +++ b/cd.c @@ -40,7 +40,7 @@ int cd_memmap(memmap_t *map) { int i, ret = 0; /* Allocate CD RAM */ - if(!mem_create(&map->mem[PCE_MEM_CD_RAM], 8 * 8192)) { + if(!memory_create(&map->mem[PCE_MEM_CD_RAM], 8 * 8192)) { ERROR_MSG("Failed to allocate cd memory!\n"); memmap_destroy(map); } else { @@ -49,7 +49,7 @@ int cd_memmap(memmap_t *map) { map->page[0x80 + i] = &map->mem[PCE_MEM_CD_RAM].data[i * 8192]; } /* Allocate System Card RAM */ - if (!mem_create(&map->mem[PCE_MEM_SYSCARD_RAM], 24 * 8192)) { + if (!memory_create(&map->mem[PCE_MEM_SYSCARD_RAM], 24 * 8192)) { ERROR_MSG("Failed to allocate system card memory!\n"); memmap_destroy(map); } else { diff --git a/config.h b/config.h index c210bb4..8a91251 100644 --- a/config.h +++ b/config.h @@ -42,8 +42,11 @@ #include #include #include +#include #include +#include + #include #include diff --git a/memory.c b/memory.c index 2f23933..3b91f89 100644 --- a/memory.c +++ b/memory.c @@ -35,30 +35,47 @@ */ #include "memory.h" #include "message.h" -/* Create memory block. */ -int mem_create(mem_t *mem, size_t len) { - mem->data = (uint8_t*)malloc(len); - if(!mem->data) { - ERROR_MSG("Unable to allocate memory : %s.\n", strerror(errno)); - mem->len = 0; - return 0; - } - mem->len = len; - return 1; -} -/* Destroy memory block. */ -void mem_destroy(mem_t *mem) { - if(mem) { - mem->len = 0; - if(mem->data) { - free(mem->data); - mem->data = NULL; + +// Creates a new memory block. +bool memory_create(Memory *memory, size_t length) { + assert(memory != NULL); + + bool ret = false; + if(length == 0) { + ERROR_MSG("Invalid length"); + } else { + uint8_t *buffer = (uint8_t*)malloc(length); + if(buffer == NULL) { + ERROR_MSG("Unable to allocate %zu bytes: %s.", length, strerror(errno)); + } else { + memory->data = buffer; + memory->length = length; + ret = true; } } + return ret; } -/* Fill memory block bytes with a given byte value. */ -void mem_fill(mem_t *mem, uint8_t c) { - if(mem->data && mem->len) { - memset(mem->data, (int)mem->len, c); + +// Releases memory block resources. +void memory_destroy(Memory *memory) { + assert(memory != NULL); + assert(memory->data != NULL); + + free(memory->data); + memory->data = NULL; + memory->length = 0; +} + +// Fills a memory block with a given byte value. +bool memory_fill(Memory *memory, uint8_t c) { + assert(memory != NULL); + bool ret = false; + if(memory->data != NULL) { + const size_t n = memory->length; + for(size_t i=0; idata[i] = c; + } + ret = true; } + return ret; } diff --git a/memory.h b/memory.h index 56b85cf..75e1011 100644 --- a/memory.h +++ b/memory.h @@ -37,30 +37,35 @@ #define ETRIPATOR_MEMORY_H #include "config.h" -/** - * Memory block. - */ + +/// @defgroup Memory Memory block +///@{ + +/// Memory block. typedef struct { - size_t len; /**< Byte array length. **/ - uint8_t *data; /**< Byte array. **/ -} mem_t; -/** - * Create memory block. - * \param [out] mem Memory block. - * \param [in] len Memory block size (in bytes). - * \return 1 upon success, 0 if an error occured. - */ -int mem_create(mem_t *mem, size_t len); -/** - * Destroy memory block. - * \param [in] mem Memory block. - */ -void mem_destroy(mem_t *mem); -/** - * Fill memory block bytes with a given byte value. - * \param [in] mem Memory block. - * \param [in] c Byte value. - */ -void mem_fill(mem_t *mem, uint8_t c); + size_t length; ///< Byte array length. + uint8_t *data; ///< Byte array. +} Memory; + +/// Creates a new memory block. +/// \param [out] memory Memory block. +/// \param [in] length Memory block size (in bytes). +/// \return true if the memory block was successfully created. +/// \return false if an error occured. +/// @note memory is left untouched if an error occured. +bool memory_create(Memory *memory, size_t length); + +/// Releases memory block resources. +/// \param [in out] mem Memory block. +void memory_destroy(Memory *memory); + +/// Fills a memory block with a given byte value. +/// \param [in out] mem Memory block. +/// \param [in] c Byte value. +/// \return true if the memory block was successfully filled. +/// \return false if the memory block is invalid (0 size or unallocated). +bool memory_fill(Memory *memory, uint8_t c); + +/// @} #endif // ETRIPATOR_MEMORY_H diff --git a/memorymap.c b/memorymap.c index 7a47b0b..d8cabb1 100644 --- a/memorymap.c +++ b/memorymap.c @@ -38,9 +38,12 @@ /* Initializes memory map. */ int memmap_init(memmap_t *map) { int i, ret = 0; - memset(map, 0, sizeof(memmap_t)); + + memset(map, 0, sizeof(memmap_t)); // [todo] function + + /* Allocate main (or work) RAM */ - if(!mem_create(&map->mem[PCE_MEM_BASE_RAM], 8192)) { + if(!memory_create(&map->mem[PCE_MEM_BASE_RAM], 8192)) { ERROR_MSG("Failed to allocate main memory!\n"); } else { /* Main RAM is mapped to pages 0xf8-0xfb (included). */ @@ -64,7 +67,7 @@ int memmap_init(memmap_t *map) { void memmap_destroy(memmap_t *map) { int i; for(i=0; imem[i]); + memory_destroy(&map->mem[i]); } memset(map, 0, sizeof(memmap_t)); } diff --git a/memorymap.h b/memorymap.h index 7b6a3a3..8c2f301 100644 --- a/memorymap.h +++ b/memorymap.h @@ -53,7 +53,7 @@ enum { * PC Engine memory map. */ typedef struct { - mem_t mem[PCE_MEM_COUNT]; + Memory mem[PCE_MEM_COUNT]; uint8_t *page[0x100]; uint8_t mpr[8]; } memmap_t; diff --git a/rom.c b/rom.c index 50d4e48..86ae63a 100644 --- a/rom.c +++ b/rom.c @@ -68,13 +68,13 @@ static int rom_load_data(const char *filename, memmap_t *map) { } if(size) { /* Allocate rom storage */ - if (!mem_create(&map->mem[PCE_MEM_ROM], (size + 0x1fff) & ~0x1fff)) { + if (!memory_create(&map->mem[PCE_MEM_ROM], (size + 0x1fff) & ~0x1fff)) { ERROR_MSG("Failed to allocate ROM storage : %s", strerror(errno)); } else { /* Fill rom with 0xff */ - memset(map->mem[PCE_MEM_ROM].data, 0xff, map->mem[PCE_MEM_ROM].len); + (void)memory_fill(&map->mem[PCE_MEM_ROM], 0xFF); /* Read ROM data */ - size_t count = (size < map->mem[PCE_MEM_ROM].len) ? size : map->mem[PCE_MEM_ROM].len; + size_t count = (size < map->mem[PCE_MEM_ROM].length) ? size : map->mem[PCE_MEM_ROM].length; size_t nread = fread(map->mem[PCE_MEM_ROM].data, 1, count, in); if (nread != count) { ERROR_MSG("Failed to read ROM data from %s : %s", filename, strerror(errno)); @@ -93,18 +93,18 @@ int rom_load(const char *filename, memmap_t *map) { FILE *in; int ret = 0; if(rom_load_data(filename, map) == 0) { - mem_destroy(&map->mem[PCE_MEM_ROM]); + memory_destroy(&map->mem[PCE_MEM_ROM]); } else { unsigned int i; /* Initialize ROM pages. */ - if (map->mem[PCE_MEM_ROM].len == 0x60000) { + if (map->mem[PCE_MEM_ROM].length == 0x60000) { for (i = 0; i < 64; i++) { map->page[i] = &map->mem[PCE_MEM_ROM].data[(i & 0x1f) * 8192]; } for (i = 64; i < 128; i++) { map->page[i] = &map->mem[PCE_MEM_ROM].data[((i & 0x0f) + 32) * 8192]; } - } else if (map->mem[PCE_MEM_ROM].len == 0x80000) { + } else if (map->mem[PCE_MEM_ROM].length == 0x80000) { for (i = 0; i < 64; i++) { map->page[i] = &map->mem[PCE_MEM_ROM].data[(i & 0x3f) * 8192]; } @@ -113,7 +113,7 @@ int rom_load(const char *filename, memmap_t *map) { } } else { for (i = 0; i < 128; i++) { - uint8_t bank = (uint8_t)(i % (map->mem[PCE_MEM_ROM].len / 8192)); + uint8_t bank = (uint8_t)(i % (map->mem[PCE_MEM_ROM].length / 8192)); map->page[i] = &map->mem[PCE_MEM_ROM].data[bank * 8192]; } } diff --git a/section.h b/section.h index 0f1cc09..26980ce 100644 --- a/section.h +++ b/section.h @@ -38,6 +38,93 @@ #include "config.h" +#if 0 + +/// Section types. +typedef enum { + /// Unknown or invalid section type. + UnknownSectionType = -1, + /// Data type. + /// This a "meta" section type. A data section contains either + /// * Raw binary data + /// * Strings + /// * Addresses + /// @see DataType for a more detailed description. + DataSectionType = 0, + /// The section contains executable code. @see CodeSection + CodeSectionType, + /// Number of supported section types. + SectionTypeCount +} SectionType; + +/// Data section types. +typedef enum { + /// Raw binary data. + RawDataType = 0, + /// String data. + StringDataType, + /// Address list (usually jump table) + JumpTableType, + /// Number of supported data section types. + DataTypeCount +} DataType, + +/// Raw binary data +typedef struct { + /// Must be equal to RawDataType. + DataType type; + /// +} RawData; + +typedef struct { + DataType type; + // [todo] +} StringData; + +typedef struct { + DataType type; +} JumpTable; + +typedef struct { + SectionType type; + union { + RawDataSection raw; + StringDataSection string; + JumpTableDataSection jump_table; + }; +} DataSection; + +typedef struct { + SectionType type; + // [todo] +} CodeSection; + +/* +typedef struct { + SectionType type; + MemoryAddress + { + uint16_t page; + uint16_t logical; + } address; + + MemoryConfiguration ???; + + size_t size; +} SectionBase; + +*/ + + + +typedef union { + SectionType type; + CodeSection code; + DataSection data; +} Section; + +#endif + /** * Section type. */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d405b15..2cf4901 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,26 +2,39 @@ if("${CMAKE_C_COMPILER_ID}" IN_LIST "GNU;Clang;AppleClang") add_compile_options(-Wall -Wshadow -Wextra) endif() -add_executable(section_tests section.c) -target_link_libraries(section_tests munit etripator) -target_include_directories(section_tests PRIVATE ${PROJECT_SOURCE_DIR} ${JANSSON_INCLUDE_DIRS} ${EXTRA_INCLUDE}) -add_test(NAME section_tests - COMMAND $ - WORKING_DIRECTORY $) -set_target_properties(section_tests PROPERTIES C_STANDARD 11) -add_custom_command(TARGET section_tests POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data $/data) +function(add_unit_test) + set(options ) + set(oneValueArgs NAME) + set(multiValueArgs SOURCES LIBRARIES INCLUDE_DIRECTORIES) + cmake_parse_arguments(ut "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) -add_executable(label_tests label.c) -target_link_libraries(label_tests munit etripator) -target_include_directories(label_tests PRIVATE ${PROJECT_SOURCE_DIR} ${JANSSON_INCLUDE_DIRS} ${EXTRA_INCLUDE}) -add_test(NAME label_tests - COMMAND $) -set_target_properties(label_tests PROPERTIES C_STANDARD 11) + set(target_name "${ut_NAME}_ut") -add_executable(comment_tests comment.c) -target_link_libraries(comment_tests munit etripator) -target_include_directories(comment_tests PRIVATE ${PROJECT_SOURCE_DIR} ${JANSSON_INCLUDE_DIRS} ${EXTRA_INCLUDE}) -add_test(NAME comment_tests - COMMAND $) -set_target_properties(comment_tests PROPERTIES C_STANDARD 11) + list(REMOVE_DUPLICATES ut_SOURCES) + + add_executable(${target_name} ${ut_SOURCES}) + target_link_libraries(${target_name} PRIVATE ${ut_LIBRARIES} munit) + target_include_directories(${target_name} PRIVATE ${ut_INCLUDE_DIRECTORIES} ${EXTRA_INCLUDE}) + set_target_properties(${target_name} PROPERTIES C_STANDARD 11) + + add_test( + NAME ${target_name} + COMMAND $ + WORKING_DIRECTORY $ + ) + add_custom_command( + TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data $/data + ) +endfunction() + +add_unit_test( + NAME memory + SOURCES + memory.c + ${PROJECT_SOURCE_DIR}/memory.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) diff --git a/test/memory.c b/test/memory.c new file mode 100644 index 0000000..f8d544f --- /dev/null +++ b/test/memory.c @@ -0,0 +1,118 @@ +/* +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + __/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__ + \_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2023 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include + +#include +#include + +#include + +console_msg_printer_t g_msg_printer; + +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + return NULL; +} + +void tear_down(void* fixture __attribute__((unused))) { +} + +MunitResult memory_create_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + Memory mem = {0}; + bool result = false; + + mem.data = NULL; + mem.length = 0xCAFEU; + munit_assert_false(memory_create(&mem, 0U)); + munit_assert_size(mem.length, ==, 0xCAFEU); + munit_assert_ptr_null(mem.data); + + munit_assert_true(memory_create(&mem, 32U)); + munit_assert_size(mem.length, ==, 32U); + munit_assert_ptr_not_null(mem.data); + + memory_destroy(&mem); + munit_assert_size(mem.length, ==, 0U); + munit_assert_ptr_null(mem.data); + + return MUNIT_OK; +} + +MunitResult memory_create_fill(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + Memory mem = {0}; + + munit_assert_false(memory_fill(&mem, 0x7C)); + + munit_assert_true(memory_create(&mem, 256U)); + munit_assert_size(mem.length, ==, 256U); + munit_assert_ptr_not_null(mem.data); + + munit_assert_true(memory_fill(&mem, 0x7C)); + for(size_t i=0; i Date: Sun, 1 Sep 2024 21:26:53 +0200 Subject: [PATCH 02/35] Update log message output --- CMakeLists.txt | 6 +- message.c | 44 ++++++++------ message.h | 151 +++++++++++++++++++++++----------------------- message/console.c | 127 ++++++++++++++++++-------------------- message/console.h | 14 +---- message/file.c | 119 +++++++++++++++++------------------- message/file.h | 22 +++---- test/memory.c | 9 +-- 8 files changed, 239 insertions(+), 253 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a7cf61..f58cbb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ find_package(Jansson) set(CMAKE_C_STANDARDS 11) add_subdirectory(externals) - +#[[ set(etripator_SRC message.c message/file.c @@ -84,7 +84,7 @@ set_target_properties(etripator_cli ) target_include_directories(etripator_cli PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(etripator_cli etripator argparse) - +#]] set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/doxyfile.in) set(DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/doxyfile) @@ -100,4 +100,4 @@ add_custom_target(doc add_subdirectory(test) -install(TARGETS etripator_cli DESTINATION bin) +# install(TARGETS etripator_cli DESTINATION bin) diff --git a/message.c b/message.c index caaed91..86311b7 100644 --- a/message.c +++ b/message.c @@ -38,43 +38,51 @@ #include -static msg_printer_t* g_msg_printer = NULL; +static MessagePrinter* g_message_printer_head = NULL; /* Setup global message printer list. */ -void msg_printer_init() { - g_msg_printer = NULL; +void message_printer_init() { + g_message_printer_head = NULL; // nothing much atm... } + /* Releases the resources used by message printers. */ -void msg_printer_destroy() { - msg_printer_t* printer; - for(printer=g_msg_printer; NULL != printer; printer=printer->next) { - printer->close(printer); +void message_printer_destroy() { + for(MessagePrinter *it = g_message_printer_head; it != NULL; it = it->next) { + if(it->close) { + it->close(it); + } } + g_message_printer_head = NULL; } + /* Adds a new message printer to the global list. */ -int msg_printer_add(msg_printer_t *printer) { - if(printer->open(printer)) { - return 1; +bool message_printer_add(MessagePrinter *printer) { + bool ret = false; + if((printer != NULL) && (printer->open != NULL)) { + ret = printer->open(printer); + printer->next = g_message_printer_head; + g_message_printer_head = printer; + ret = true; } - printer->next = g_msg_printer; - g_msg_printer = printer; - return 0; + return ret; } + /* Dispatch messages to printers. */ -void print_msg(msg_type_t type, const char* file, size_t line, const char* function, const char* format, ...) { - msg_printer_t* printer; +void message_print(MessageType type, const char* file, size_t line, const char* function, const char* format, ...) { + assert(file != NULL); + assert(function != NULL); const char* filename; size_t length; cwk_path_get_basename(file, &filename, &length); if(filename == NULL) { filename = file; } - for(printer=g_msg_printer; NULL != printer; printer=printer->next) { - if(printer->output) { + for(MessagePrinter *it=g_message_printer_head; it != NULL; it = it->next) { + if(it->output != NULL) { va_list args; va_start(args, format); - printer->output(printer, type, filename, line, function, format, args); + (void)it->output(it, type, filename, line, function, format, args); va_end(args); } } diff --git a/message.h b/message.h index 10c0967..5a04384 100644 --- a/message.h +++ b/message.h @@ -38,80 +38,83 @@ #include "config.h" -/** - * \brief Message types - */ +/// @defgroup Message Message printing +///@{ + +// Message types. typedef enum { - MSG_TYPE_ERROR=0, - MSG_TYPE_WARNING, - MSG_TYPE_INFO -} msg_type_t; - -/** - * \brief Initializes and allocates any resources necessary for the message printer. - * \param [in] impl Message printer. - * \return 0 upon success. - */ -typedef int (*msg_printer_open_t)(void* impl); - -/** - * \brief Deletes, clean up resources used by the message printer. - * \param [in] impl Message printer. - * \return 0 upon success. - */ -typedef int (*msg_printer_close_t)(void* impl); - -/** - * \brief Prints message. - * \param [in] impl Message printer. - * \param [in] type Message type. - * \param [in] file Name of the file where the print message command was issued. - * \param [in] line Line number in the file where the print message command was issued. - * \param [in] function Function where the print message command was issued. - * \param [in] format Format string. - * \param [in] args Argument lists. - * \return 0 upon success. - */ -typedef int (*msg_printer_output_t)(void* impl, msg_type_t type, const char* file, size_t line, const char* function, const char* format, va_list args); - -/** - * \brief - */ -typedef struct msg_printer_t_ { - msg_printer_open_t open; - msg_printer_close_t close; - msg_printer_output_t output; - struct msg_printer_t_* next; -} msg_printer_t; - -#define ERROR_MSG(format, ...) print_msg(MSG_TYPE_ERROR, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) - -#define WARNING_MSG(format, ...) print_msg(MSG_TYPE_WARNING, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) - -#define INFO_MSG(format, ...) print_msg(MSG_TYPE_INFO, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) - -/** - * Setup global message printer list. - */ -void msg_printer_init(); -/** - * Releases the resources used by message printers. - */ -void msg_printer_destroy(); -/** - * Adds a new message printer to the global list. - * \param [in] printer Message printer to be added to the list. - * \return 0 upon success. - */ -int msg_printer_add(msg_printer_t *printer); -/** - * Dispatch messages to printers. - * \param type Message type. - * \param file Name of the file where the print message command was issued. - * \param line Line number in the file where the print message command was issued. - * \param function Function where the print message command was issued. - * \param format Format string. - */ -void print_msg(msg_type_t type, const char* file, size_t line, const char* function, const char* format, ...); + MESSAGE_TYPE_ERROR = 0, + MESSAGE_TYPE_WARNING, + MESSAGE_TYPE_INFO, + MESSAGE_TYPE_DEBUG, + MESSAGE_TYPE_COUNT, +} MessageType; + +struct MessagePrinter; + +/// Initializes and allocates any resources necessary for the message printer. +/// \param [in out] printer Message printer. +/// \return true if the message printer was successfully opened. +/// \return false if an error occured. +typedef bool (*MessagePrinterOpen)(struct MessagePrinter* printer); + +/// Releases resources used by the message printer. +/// \param [in] printer Message printer. +/// \return true if the resources used by the message printer were successfully released. +/// \return false if an error occured. +typedef bool (*MessagePrinterClose)(struct MessagePrinter* printer); + +/// \brief Prints message. +/// \param [in] printer Message printer. +/// \param [in] type Message type. +/// \param [in] file Name of the file where the print message command was issued. +/// \param [in] line Line number in the file where the print message command was issued. +/// \param [in] function Function where the print message command was issued. +/// \param [in] format Format string. +/// \param [in] args Argument lists. +/// \return true if the message was successfully formatted and printed. +/// \return false if an error occured. +typedef bool (*MessagePrinterOutput)(struct MessagePrinter* printer, MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args); + +/// Message printer implementation. +typedef struct MessagePrinter { + MessagePrinterOpen open; + MessagePrinterClose close; + MessagePrinterOutput output; + struct MessagePrinter* next; +} MessagePrinter; + +#define ERROR_MSG(format, ...) message_print(MESSAGE_TYPE_ERROR, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) + +#define WARNING_MSG(format, ...) message_print(MESSAGE_TYPE_WARNING, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) + +#define INFO_MSG(format, ...) message_print(MESSAGE_TYPE_INFO, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) + +#if NDEBUG +# define DEBUG_MSG(format, ...) +#else +# define DEBUG_MSG(format, ...) message_print(MESSAGE_TYPE_DEBUG, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) +#endif + +/// Setup global message printer list. +void message_printer_init(); +/// Releases resources used by message printers. +void message_printer_destroy(); + +/// Opens and adds a new message printer to the global list. +/// \param [in] printer Message printer to be added to the list. +/// \return true if the message printer was successfully added to the list. +/// \return false if the message printer failed to open and could not be added to the message printer list. +bool message_printer_add(MessagePrinter *printer); + +/// Dispatch message to printers. +/// \param type Message type. +/// \param file Name of the file where the print message command was issued. +/// \param line Line number in the file where the print message command was issued. +/// \param function Function where the print message command was issued. +/// \param format Format string. +void message_print(MessageType type, const char* file, size_t line, const char* function, const char* format, ...); + +/// @} #endif // ETRIPATOR_MESSAGE_H diff --git a/message/console.c b/message/console.c index cbb50f9..cb926cf 100644 --- a/message/console.c +++ b/message/console.c @@ -36,95 +36,86 @@ #include "../config.h" #include "console.h" -/** - * \brief Tests if the console has support for colors and other things. - * \param [in] impl Console message printer. - * \return 0 upon success. - */ -static int console_msg_printer_open(void* impl) { - console_msg_printer_t* printer = (console_msg_printer_t*)impl; - printer->use_escape_code = isatty(fileno(stdout)) ? 1 : 0; - if(!printer->use_escape_code) { - fprintf(stderr, "Escape code disabled.\n"); - } - return 0; +static bool g_use_escape_code = false; + +/// Tests if the console has support for colors and other things. +/// \param [in] printer Console message printer. +/// \return true always. +static bool console_message_printer_open(MessagePrinter* printer __attribute__((unused))) { + g_use_escape_code = isatty(fileno(stdout)) ? true : false; + return true; } -/** - * \brief Closes console msg printer. - * \param [in] impl Console message printer. - * \return 0 upon success. - */ -static int console_msg_printer_close(void* impl) { - (void)impl; // Unused atm. - return 0; +/// Do nothing. +/// \param [in] printer Message printer. +/// \return true always. +static bool console_message_printer_close(MessagePrinter *printer __attribute__((unused))) { + return true; } -/** - * \brief Prints message to console. - * \param userData User data. - * \param [in] impl Console message printer. - * \param [in] type Message type. - * \param [in] file Name of the file where the print message command was issued. - * \param [in] line Line number in the file where the print message command was issued. - * \param [in] function Function where the print message command was issued. - * \param [in] format Format string. - * \param [in] args Argument lists. - * \return 0 upon success. - */ -static int console_msg_printer_output(void* impl, msg_type_t type, const char* file, size_t line, const char* function, const char* format, va_list args) { - static const char *msg_type_name[] = { +/// Prints message to console. +/// \param [in] printer Console message printer. +/// \param [in] type Message type. +/// \param [in] file Name of the file where the print message command was issued. +/// \param [in] line Line number in the file where the print message command was issued. +/// \param [in] function Function where the print message command was issued. +/// \param [in] format Format string. +/// \param [in] args Argument lists. +/// \return true upon success. +static bool console_message_printer_output(MessagePrinter *printer, MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { + static const char *message_type_name[] = { "[Error]", "[Warning]", "[Info]" }; - static const char *msg_type_prefix[] = { + static const char *message_type_prefix[] = { "\x1b[1;31m", "\x1b[1;33m", "\x1b[1;32m" }; - int ret = 1; - if(!impl) { + bool ret = true; + if(printer == NULL) { fprintf(stderr, "Invalid console logger.\n"); + ret = false; + } else if(g_use_escape_code) { + fprintf(stderr, "%s%s\x1b[0m %s:%zd \x1b[0;33m %s \x1b[1;37m : " + , message_type_prefix[type] + , message_type_name[type] + , file + , line + , function + ); } else { - console_msg_printer_t* printer = (console_msg_printer_t*)impl; - if(printer->use_escape_code) { - fprintf(stderr, "%s%s\x1b[0m %s:%zd \x1b[0;33m %s \x1b[1;37m : " - , msg_type_prefix[type] - , msg_type_name[type] - , file - , line - , function - ); - } else { - fprintf(stderr, "%s %s:%zd %s : " - , msg_type_name[type] - , file - , line - , function - ); - } + fprintf(stderr, "%s %s:%zd %s : " + , message_type_name[type] + , file + , line + , function + ); + } - vfprintf(stderr, format, args); + vfprintf(stderr, format, args); - if(printer->use_escape_code) { - fprintf(stderr, "\x1b[0m\n"); - } else { - fputc('\n', stderr); - } - fflush(stderr); - ret = 0; + if(g_use_escape_code) { + fprintf(stderr, "\x1b[0m\n"); + } else { + fputc('\n', stderr); } + fflush(stderr); return ret; } +static MessagePrinter g_console_message_printer = { + .open = console_message_printer_open, + .close = console_message_printer_close, + .output = console_message_printer_output, + .next = NULL, +}; + /* Setups console message writer. */ -int console_msg_printer_init(console_msg_printer_t *printer) { - printer->super.open = console_msg_printer_open; - printer->super.close = console_msg_printer_close; - printer->super.output = console_msg_printer_output; - printer->use_escape_code = 0; - return 0; +bool console_message_printer_init() { + g_use_escape_code = false; + return message_printer_add(&g_console_message_printer); } diff --git a/message/console.h b/message/console.h index be12d8f..ae2ddfe 100644 --- a/message/console.h +++ b/message/console.h @@ -38,17 +38,9 @@ #include "../message.h" -typedef struct { - msg_printer_t super; - int use_escape_code; -} console_msg_printer_t; - -/** - * \brief Setups console message writer. - * \param [in] printer Console message printer. - * \return 0 upon success. - */ -int console_msg_printer_init(console_msg_printer_t *printer); +/// Setups file message writer. +/// \return true always. +bool console_message_printer_init(); #endif // ETRIPATOR_MESSAGE_FILE_H diff --git a/message/file.c b/message/file.c index 58919d4..0a234db 100644 --- a/message/file.c +++ b/message/file.c @@ -38,88 +38,83 @@ static const char* g_log_filename = "etripator.log"; -/** - * \brief Opens log file. - * \param [in] impl Msg printer implementation. - * \return 0 upon success. - */ -static int file_msg_printer_open(void* impl) { - int ret = 1; - file_msg_printer_t* printer = (file_msg_printer_t*)impl; - if(!printer) { - fprintf(stderr, "Invalid file logger.\n"); +/// Check if the log file can be opened and written to. +/// \param [in] printer Message printer implementation. +/// \return true if the log file was successfully opened. +/// \return false if an error occured. +static bool file_message_printer_open(MessagePrinter* printer) { + bool ret = false; + if(printer == NULL) { + fprintf(stderr, "Invalid file message printer"); } else { - printer->out = fopen(g_log_filename, "ab"); - if(!printer->out) { + int fd = open(g_log_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if(fd < 0) { fprintf(stderr, "Failed to open log file %s: %s\n", g_log_filename, strerror(errno)); + } else if(close(fd) < 0) { + fprintf(stderr, "Failed to close log file %s: %s\n", g_log_filename, strerror(errno)); } else { - ret = 0; - } + ret = true; + } } return ret; } -/** - * \brief Closes log file. - * \param [in] impl Msg printer implementation. - * \return 0 upon success. - */ -static int file_msg_printer_close(void* impl) { - int ret = 1; - file_msg_printer_t* printer = (file_msg_printer_t*)impl; - if((!printer) || (!printer->out)) { - fprintf(stderr, "Invalid file logger.\n"); - } else if(fclose(printer->out)) { - fprintf(stderr, "Failed to close log file %s : %s\n", g_log_filename, strerror(errno)); - } else { - printer->out = NULL; - ret = 0; - } - return ret; +/// Do nothing. +/// \param [in] printer Message printer implementation. +/// \return true always. +static bool file_message_printer_close(MessagePrinter *printer __attribute__((unused))) { + return true; } -/** - * \brief Prints message to file. - * \param [in] impl Msg printer implementation. - * \param [in] type Message type. - * \param [in] file Name of the file where the print message command was issued. - * \param [in] line Line number in the file where the print message command was issued. - * \param [in] function Function where the print message command was issued. - * \param [in] format Format string. - * \param [in] args Argument lists. - * \return 0 upon success. - */ -static int file_msg_printer_output(void* impl, msg_type_t type, const char* file, size_t line, const char* function, const char* format, va_list args) { - static const char *msg_type_name[] = { +/// Prints message to file. +/// \param [in] printer Msg printer implementation. +/// \param [in] type Message type. +/// \param [in] file Name of the file where the print message command was issued. +/// \param [in] line Line number in the file where the print message command was issued. +/// \param [in] function Function where the print message command was issued. +/// \param [in] format Format string. +/// \param [in] args Argument lists. +/// \return true if the message was successfully written to the log file. +/// \return false if an error occured. +static bool file_message_printer_output(MessagePrinter* printer, MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { + static const char *message_type_name[MESSAGE_TYPE_COUNT] = { "[Error]", "[Warning]", - "[Info]" + "[Info]", + "[Debug]" }; - int ret = 1; - if(!impl) { + bool ret = false; + if(printer == NULL) { fprintf(stderr, "Invalid file logger.\n"); } else { - file_msg_printer_t* printer = (file_msg_printer_t*)impl; - - fprintf(printer->out, "%s %s:%zd %s : ", msg_type_name[type], file, line, function); - vfprintf(printer->out, format, args); - fputc('\n', printer->out); - fflush(printer->out); - if(ferror(printer->out)) { - fprintf(stderr, "Failed to output log to %s: %s\n", g_log_filename, strerror(errno)); + FILE *out = fopen(g_log_filename, "a+"); + if(out == NULL) { + fprintf(stderr, "Failed to open log file %s: %s\n", g_log_filename, strerror(errno)); } else { - ret = 0; + fprintf(out, "%s %s:%zd %s : ", message_type_name[type], file, line, function); + vfprintf(out, format, args); + fputc('\n', out); + fflush(out); + if(ferror(out)) { + fprintf(stderr, "Failed to output log to %s: %s\n", g_log_filename, strerror(errno)); + } else { + ret = true; + } + fclose(out); } } return ret; } +static MessagePrinter g_file_message_printer = { + .open = file_message_printer_open, + .close = file_message_printer_close, + .output = file_message_printer_output, + .next = NULL, +}; + /* Setups file message writer. */ -int file_msg_printer_init(file_msg_printer_t *printer) { - printer->super.open = file_msg_printer_open; - printer->super.close = file_msg_printer_close; - printer->super.output = file_msg_printer_output; - printer->out = NULL; - return 0; +bool file_message_printer_init() { + return message_printer_add(&g_file_message_printer); } diff --git a/message/file.h b/message/file.h index d9224a0..cdcd6d6 100644 --- a/message/file.h +++ b/message/file.h @@ -38,17 +38,17 @@ #include "../message.h" -typedef struct { - msg_printer_t super; - FILE *out; -} file_msg_printer_t; - -/** - * \brief Setups file message writer. - * \param [in] impl Msg printer implementation. - * \return 0 upon success. - */ -int file_msg_printer_init(file_msg_printer_t *printer); +/// @addtogroup Message +/// @{ + +/// Setups file message writer. +/// Messages will be appeneded to a file names "etripator.log". +/// This file will be placed in the current working directory. +/// \return true if the log file can be written to. +/// \return false if an error occured. +bool file_message_printer_init(); + +/// @} #endif // ETRIPATOR_MESSAGE_FILE_H diff --git a/test/memory.c b/test/memory.c index f8d544f..c74a683 100644 --- a/test/memory.c +++ b/test/memory.c @@ -40,8 +40,6 @@ #include -console_msg_printer_t g_msg_printer; - void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { return NULL; } @@ -106,13 +104,12 @@ static const MunitSuite memory_suite = { }; int main (int argc, char* const* argv) { - msg_printer_init(); - console_msg_printer_init(&g_msg_printer); - msg_printer_add((msg_printer_t*)&g_msg_printer); + message_printer_init(); + console_message_printer_init(); int ret = munit_suite_main(&memory_suite, NULL, argc, argv); - msg_printer_destroy(); + message_printer_destroy(); return ret; } \ No newline at end of file From 420b3c16c63b6e55d91e97aec1e88f514597331f Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 1 Sep 2024 23:54:20 +0200 Subject: [PATCH 03/35] Update documentation --- README.md | 23 ++++++++++------------- README.nfo | 23 ++++++++++------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c541b40..330b359 100644 --- a/README.md +++ b/README.md @@ -189,27 +189,24 @@ This can be acheived using a package manager (apt, brew, chocolate, pacman, ...) wget https://github.com/akheron/jansson/archive/v2.12.zip unzip v2.12.zip cd jansson-2.12 -mkdir -p build/cmake -mkdir -p build/install -cd build/cmake -cmake ../.. -DJANSSON_BUILD_DOCS=OFF \ - -DJANSSON_WITHOUT_TESTS=ON \ - -DCMAKE_INSTALL_PREFIX=../install -cmake --build . --target install -cd ../../.. +mkdir -p build +cmake -Bbuild/cmake -S . \ + -DJANSSON_BUILD_DOCS=OFF \ + -DJANSSON_WITHOUT_TESTS=ON \ + -DCMAKE_INSTALL_PREFIX=build/install +cmake --build build/cmake --target install ``` Now on to building etripator. ``` cd etripator -mkdir -p build/cmake -cd build/cmake -cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install +mkdir -p build +cmake -Bbuild/cmake -S . -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=cmake/install ``` If you build jansson as shown earlier you may configure the project with ``` -cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install \ +cmake -Bbuild/cmake -S . -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/install \ -DJANSSON_INCLUDE_DIR=../../jansson-2.12/build/install/include \ -DJANSSON_LIBRARY=../../jansson-2.12/build/install/lib/jansson.lib ``` @@ -218,7 +215,7 @@ cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install \ If everything went right, you can now compile the project with: ``` -cmake --build . --config Release --target install +cmake --build build/cmake --target install ``` ## Authors diff --git a/README.nfo b/README.nfo index fbda2f3..68bbcfd 100644 --- a/README.nfo +++ b/README.nfo @@ -246,27 +246,24 @@ or by building it from source. wget https://github.com/akheron/jansson/archive/v2.12.zip unzip v2.12.zip cd jansson-2.12 -mkdir -p build/cmake -mkdir -p build/install -cd build/cmake -cmake ../.. -DJANSSON_BUILD_DOCS=OFF \ - -DJANSSON_WITHOUT_TESTS=ON \ - -DCMAKE_INSTALL_PREFIX=../install -cmake --build . --target install -cd ../../.. +mkdir -p build +cmake -Bbuild/cmake -S . \ + -DJANSSON_BUILD_DOCS=OFF \ + -DJANSSON_WITHOUT_TESTS=ON \ + -DCMAKE_INSTALL_PREFIX=build/install +cmake --build build/cmake --target install Now on to building etripator. cd etripator -mkdir -p build/cmake -cd build/cmake -cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install +mkdir -p build +cmake -Bbuild/cmake -S . -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=cmake/install If you build jansson as shown earlier you may configure the project with -cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install \ +cmake -Bbuild/cmake -S . -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/install \ -DJANSSON_INCLUDE_DIR=../../jansson-2.12/build/install/include \ -DJANSSON_LIBRARY=../../jansson-2.12/build/install/lib/jansson.lib @@ -274,7 +271,7 @@ cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install \ If everything went right, you can now compile the project with: -cmake --build . --config Release --target install +cmake --build build/cmake --target install ¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ From 90ce677d7c846e388539a2a471d8d17067ba8e5a Mon Sep 17 00:00:00 2001 From: MooZ Date: Mon, 2 Sep 2024 23:26:05 +0200 Subject: [PATCH 04/35] Add message printer unit tests --- message.c | 8 +-- test/CMakeLists.txt | 8 +++ test/message.c | 118 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 test/message.c diff --git a/message.c b/message.c index 86311b7..455f7cd 100644 --- a/message.c +++ b/message.c @@ -33,7 +33,6 @@ ¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ */ -#include "config.h" #include "message.h" #include @@ -61,9 +60,10 @@ bool message_printer_add(MessagePrinter *printer) { bool ret = false; if((printer != NULL) && (printer->open != NULL)) { ret = printer->open(printer); - printer->next = g_message_printer_head; - g_message_printer_head = printer; - ret = true; + if(ret) { + printer->next = g_message_printer_head; + g_message_printer_head = printer; + } } return ret; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2cf4901..e925998 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,6 +28,14 @@ function(add_unit_test) ) endfunction() +add_unit_test( + NAME message + SOURCES + message.c + LIBRARIES cwalk + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) + add_unit_test( NAME memory SOURCES diff --git a/test/message.c b/test/message.c new file mode 100644 index 0000000..b5680b9 --- /dev/null +++ b/test/message.c @@ -0,0 +1,118 @@ +/* +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + __/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__ + \_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2023 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include + +#include "../message.c" + +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + return NULL; +} + +void tear_down(void* fixture __attribute__((unused))) { +} + +MunitResult message_init_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + g_message_printer_head = (MessagePrinter*)0xBEEF; + message_printer_init(); + munit_assert_ptr_null(g_message_printer_head); + + return MUNIT_OK; +} + +static unsigned int dummy_open_0_call_count; +static bool dummy_open_0(MessagePrinter *printer) { + dummy_open_0_call_count++; + return true; +} +static bool dummy_open_1(MessagePrinter *printer) { + dummy_open_0_call_count++; + return false; +} + +MunitResult message_add_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + message_printer_init(); + munit_assert_ptr_null(g_message_printer_head); + + MessagePrinter printer[4] = { + [0] = { .open = dummy_open_0 }, + [1] = { .open = dummy_open_0 }, + [2] = { .open = dummy_open_1 }, + [3] = { .open = dummy_open_0 }, + }; + + dummy_open_0_call_count = 0; + munit_assert_true(message_printer_add(&printer[0])); + munit_assert_uint(dummy_open_0_call_count, ==, 1); + munit_assert_ptr_equal(g_message_printer_head, &printer[0]); + munit_assert_null(g_message_printer_head->next); + + munit_assert_true(message_printer_add(&printer[1])); + munit_assert_uint(dummy_open_0_call_count, ==, 2); + munit_assert_ptr_equal(g_message_printer_head, &printer[1]); + munit_assert_ptr_equal(g_message_printer_head->next, &printer[0]); + munit_assert_null(printer[0].next); + + munit_assert_false(message_printer_add(&printer[2])); + munit_assert_uint(dummy_open_0_call_count, ==, 3); + munit_assert_ptr_equal(g_message_printer_head, &printer[1]); + munit_assert_ptr_equal(g_message_printer_head->next, &printer[0]); + munit_assert_null(g_message_printer_head->next->next); + + munit_assert_true(message_printer_add(&printer[3])); + munit_assert_uint(dummy_open_0_call_count, ==, 4); + munit_assert_ptr_equal(g_message_printer_head, &printer[3]); + munit_assert_ptr_equal(g_message_printer_head->next, &printer[1]); + munit_assert_ptr_equal(g_message_printer_head->next->next, &printer[0]); + munit_assert_null(g_message_printer_head->next->next->next); + + return MUNIT_OK; +} + +static MunitTest message_tests[] = { + { "/init", message_init_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/add", message_add_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + // [todo] destroy + // [todo] print + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } +}; + +static const MunitSuite message_suite = { + "message testt suite", message_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE +}; + +int main (int argc, char* const* argv) { + return munit_suite_main(&message_suite, NULL, argc, argv); +} \ No newline at end of file From 513d0e346ee8b3d4457e00e1e2a8b9352b8e240d Mon Sep 17 00:00:00 2001 From: MooZ Date: Tue, 3 Sep 2024 23:18:55 +0200 Subject: [PATCH 05/35] Update message API Add missing unit tests --- message.c | 6 +-- message.h | 9 ++-- message/console.c | 14 ++---- message/file.c | 51 ++++++++------------ test/message.c | 117 +++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 145 insertions(+), 52 deletions(-) diff --git a/message.c b/message.c index 455f7cd..461d465 100644 --- a/message.c +++ b/message.c @@ -49,7 +49,7 @@ void message_printer_init() { void message_printer_destroy() { for(MessagePrinter *it = g_message_printer_head; it != NULL; it = it->next) { if(it->close) { - it->close(it); + it->close(); } } g_message_printer_head = NULL; @@ -59,7 +59,7 @@ void message_printer_destroy() { bool message_printer_add(MessagePrinter *printer) { bool ret = false; if((printer != NULL) && (printer->open != NULL)) { - ret = printer->open(printer); + ret = printer->open(); if(ret) { printer->next = g_message_printer_head; g_message_printer_head = printer; @@ -82,7 +82,7 @@ void message_print(MessageType type, const char* file, size_t line, const char* if(it->output != NULL) { va_list args; va_start(args, format); - (void)it->output(it, type, filename, line, function, format, args); + (void)it->output(type, filename, line, function, format, args); va_end(args); } } diff --git a/message.h b/message.h index 5a04384..4839791 100644 --- a/message.h +++ b/message.h @@ -53,19 +53,16 @@ typedef enum { struct MessagePrinter; /// Initializes and allocates any resources necessary for the message printer. -/// \param [in out] printer Message printer. /// \return true if the message printer was successfully opened. /// \return false if an error occured. -typedef bool (*MessagePrinterOpen)(struct MessagePrinter* printer); +typedef bool (*MessagePrinterOpen)(); /// Releases resources used by the message printer. -/// \param [in] printer Message printer. /// \return true if the resources used by the message printer were successfully released. /// \return false if an error occured. -typedef bool (*MessagePrinterClose)(struct MessagePrinter* printer); +typedef bool (*MessagePrinterClose)(); /// \brief Prints message. -/// \param [in] printer Message printer. /// \param [in] type Message type. /// \param [in] file Name of the file where the print message command was issued. /// \param [in] line Line number in the file where the print message command was issued. @@ -74,7 +71,7 @@ typedef bool (*MessagePrinterClose)(struct MessagePrinter* printer); /// \param [in] args Argument lists. /// \return true if the message was successfully formatted and printed. /// \return false if an error occured. -typedef bool (*MessagePrinterOutput)(struct MessagePrinter* printer, MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args); +typedef bool (*MessagePrinterOutput)(MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args); /// Message printer implementation. typedef struct MessagePrinter { diff --git a/message/console.c b/message/console.c index cb926cf..69f3e73 100644 --- a/message/console.c +++ b/message/console.c @@ -39,22 +39,19 @@ static bool g_use_escape_code = false; /// Tests if the console has support for colors and other things. -/// \param [in] printer Console message printer. /// \return true always. -static bool console_message_printer_open(MessagePrinter* printer __attribute__((unused))) { +static bool console_message_printer_open() { g_use_escape_code = isatty(fileno(stdout)) ? true : false; return true; } /// Do nothing. -/// \param [in] printer Message printer. /// \return true always. -static bool console_message_printer_close(MessagePrinter *printer __attribute__((unused))) { +static bool console_message_printer_close() { return true; } /// Prints message to console. -/// \param [in] printer Console message printer. /// \param [in] type Message type. /// \param [in] file Name of the file where the print message command was issued. /// \param [in] line Line number in the file where the print message command was issued. @@ -62,7 +59,7 @@ static bool console_message_printer_close(MessagePrinter *printer __attribute__( /// \param [in] format Format string. /// \param [in] args Argument lists. /// \return true upon success. -static bool console_message_printer_output(MessagePrinter *printer, MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { +static bool console_message_printer_output(MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { static const char *message_type_name[] = { "[Error]", "[Warning]", @@ -75,10 +72,7 @@ static bool console_message_printer_output(MessagePrinter *printer, MessageType }; bool ret = true; - if(printer == NULL) { - fprintf(stderr, "Invalid console logger.\n"); - ret = false; - } else if(g_use_escape_code) { + if(g_use_escape_code) { fprintf(stderr, "%s%s\x1b[0m %s:%zd \x1b[0;33m %s \x1b[1;37m : " , message_type_prefix[type] , message_type_name[type] diff --git a/message/file.c b/message/file.c index 0a234db..ae8c5e6 100644 --- a/message/file.c +++ b/message/file.c @@ -39,35 +39,28 @@ static const char* g_log_filename = "etripator.log"; /// Check if the log file can be opened and written to. -/// \param [in] printer Message printer implementation. /// \return true if the log file was successfully opened. /// \return false if an error occured. -static bool file_message_printer_open(MessagePrinter* printer) { +static bool file_message_printer_open() { bool ret = false; - if(printer == NULL) { - fprintf(stderr, "Invalid file message printer"); + int fd = open(g_log_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if(fd < 0) { + fprintf(stderr, "Failed to open log file %s: %s\n", g_log_filename, strerror(errno)); + } else if(close(fd) < 0) { + fprintf(stderr, "Failed to close log file %s: %s\n", g_log_filename, strerror(errno)); } else { - int fd = open(g_log_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - if(fd < 0) { - fprintf(stderr, "Failed to open log file %s: %s\n", g_log_filename, strerror(errno)); - } else if(close(fd) < 0) { - fprintf(stderr, "Failed to close log file %s: %s\n", g_log_filename, strerror(errno)); - } else { - ret = true; - } + ret = true; } return ret; } /// Do nothing. -/// \param [in] printer Message printer implementation. /// \return true always. -static bool file_message_printer_close(MessagePrinter *printer __attribute__((unused))) { +static bool file_message_printer_close() { return true; } /// Prints message to file. -/// \param [in] printer Msg printer implementation. /// \param [in] type Message type. /// \param [in] file Name of the file where the print message command was issued. /// \param [in] line Line number in the file where the print message command was issued. @@ -76,7 +69,7 @@ static bool file_message_printer_close(MessagePrinter *printer __attribute__((un /// \param [in] args Argument lists. /// \return true if the message was successfully written to the log file. /// \return false if an error occured. -static bool file_message_printer_output(MessagePrinter* printer, MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { +static bool file_message_printer_output(MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { static const char *message_type_name[MESSAGE_TYPE_COUNT] = { "[Error]", "[Warning]", @@ -84,24 +77,20 @@ static bool file_message_printer_output(MessagePrinter* printer, MessageType typ "[Debug]" }; bool ret = false; - if(printer == NULL) { - fprintf(stderr, "Invalid file logger.\n"); + FILE *out = fopen(g_log_filename, "a+"); + if(out == NULL) { + fprintf(stderr, "Failed to open log file %s: %s\n", g_log_filename, strerror(errno)); } else { - FILE *out = fopen(g_log_filename, "a+"); - if(out == NULL) { - fprintf(stderr, "Failed to open log file %s: %s\n", g_log_filename, strerror(errno)); + fprintf(out, "%s %s:%zd %s : ", message_type_name[type], file, line, function); + vfprintf(out, format, args); + fputc('\n', out); + fflush(out); + if(ferror(out)) { + fprintf(stderr, "Failed to output log to %s: %s\n", g_log_filename, strerror(errno)); } else { - fprintf(out, "%s %s:%zd %s : ", message_type_name[type], file, line, function); - vfprintf(out, format, args); - fputc('\n', out); - fflush(out); - if(ferror(out)) { - fprintf(stderr, "Failed to output log to %s: %s\n", g_log_filename, strerror(errno)); - } else { - ret = true; - } - fclose(out); + ret = true; } + fclose(out); } return ret; } diff --git a/test/message.c b/test/message.c index b5680b9..cf660b6 100644 --- a/test/message.c +++ b/test/message.c @@ -101,11 +101,124 @@ MunitResult message_add_test(const MunitParameter params[] __attribute__((unused return MUNIT_OK; } +static int dummy_close_call_count; + +static bool dummy_close(MessagePrinter *printer __attribute__((unused))) { + dummy_close_call_count++; + return true; +} + +MunitResult message_destroy_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + message_printer_init(); + munit_assert_ptr_null(g_message_printer_head); + + MessagePrinter printer[4] = { + [0] = { .open = dummy_open_0, .close = dummy_close }, + [1] = { .open = dummy_open_0, .close = dummy_close }, + [2] = { .open = dummy_open_0, .close = dummy_close }, + [3] = { .open = dummy_open_0, .close = dummy_close }, + }; + + dummy_open_0_call_count = 0; + dummy_close_call_count = 0; + + message_printer_init(); + munit_assert_true(message_printer_add(&printer[0])); + munit_assert_true(message_printer_add(&printer[1])); + munit_assert_true(message_printer_add(&printer[2])); + munit_assert_true(message_printer_add(&printer[3])); + + munit_assert_ptr_equal(g_message_printer_head, &printer[3]); + + munit_assert_uint(dummy_open_0_call_count, ==, 4); + munit_assert_uint(dummy_close_call_count, ==, 0); + + message_printer_destroy(); + munit_assert_uint(dummy_close_call_count, ==, 4); + munit_assert_null(g_message_printer_head); + + return MUNIT_OK; +} + +static unsigned int dummy_print_index = 0; +static size_t dummy_print_line = 0; +static unsigned int dummy_print_history[4] = {-1}; + +static bool dummy_print_0(MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { + dummy_print_history[dummy_print_index++] = 0; + munit_assert_uint(type, ==, MESSAGE_TYPE_INFO); + munit_assert_size(line, ==, dummy_print_line); + return true; +} +static bool dummy_print_1(MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { + dummy_print_history[dummy_print_index++] = 1; + munit_assert_uint(type, ==, MESSAGE_TYPE_INFO); + munit_assert_size(line, ==, dummy_print_line); + return true; +} +static bool dummy_print_2(MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { + dummy_print_history[dummy_print_index++] = 2; + munit_assert_uint(type, ==, MESSAGE_TYPE_INFO); + munit_assert_size(line, ==, dummy_print_line); + return true; +} +static bool dummy_print_3(MessageType type, const char* file, size_t line, const char* function, const char* format, va_list args) { + dummy_print_history[dummy_print_index++] = 3; + munit_assert_uint(type, ==, MESSAGE_TYPE_INFO); + munit_assert_size(line, ==, dummy_print_line); + return true; +} + +MunitResult message_print_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + message_printer_init(); + munit_assert_ptr_null(g_message_printer_head); + + MessagePrinter printer[4] = { + [0] = { .open = dummy_open_0, .close = dummy_close, .output = dummy_print_0 }, + [1] = { .open = dummy_open_0, .close = dummy_close, .output = dummy_print_1 }, + [2] = { .open = dummy_open_0, .close = dummy_close, .output = dummy_print_2 }, + [3] = { .open = dummy_open_0, .close = dummy_close, .output = dummy_print_3 }, + }; + + dummy_open_0_call_count = 0; + dummy_close_call_count = 0; + dummy_print_index = 0; + + for(unsigned int i=0; i<4; i++) { + dummy_print_history[i] = -1; + } + + message_printer_init(); + munit_assert_true(message_printer_add(&printer[0])); + munit_assert_true(message_printer_add(&printer[1])); + munit_assert_true(message_printer_add(&printer[2])); + munit_assert_true(message_printer_add(&printer[3])); + + munit_assert_ptr_equal(g_message_printer_head, &printer[3]); + + munit_assert_uint(dummy_open_0_call_count, ==, 4); + munit_assert_uint(dummy_close_call_count, ==, 0); + + dummy_print_line = __LINE__; INFO_MSG("test"); + munit_assert_uint(dummy_print_index, ==, 4); + munit_assert_uint(dummy_print_history[0], ==, 3); + munit_assert_uint(dummy_print_history[1], ==, 2); + munit_assert_uint(dummy_print_history[2], ==, 1); + munit_assert_uint(dummy_print_history[3], ==, 0); + + message_printer_destroy(); + munit_assert_uint(dummy_close_call_count, ==, 4); + munit_assert_null(g_message_printer_head); + + return MUNIT_OK; +} + + static MunitTest message_tests[] = { { "/init", message_init_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { "/add", message_add_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, - // [todo] destroy - // [todo] print + { "/destroy", message_destroy_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/print", message_print_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; From e83edfc983654126e654367d1006ce25e147f754 Mon Sep 17 00:00:00 2001 From: MooZ Date: Wed, 4 Sep 2024 22:59:12 +0200 Subject: [PATCH 06/35] Update memory map --- memory.c | 2 - memory_map.c | 116 +++++++++++++++++++++++++++++++ memorymap.h => memory_map.h | 98 +++++++++++++------------- test/CMakeLists.txt | 12 ++++ memorymap.c => test/memory_map.c | 98 +++++++++++++------------- 5 files changed, 228 insertions(+), 98 deletions(-) create mode 100644 memory_map.c rename memorymap.h => memory_map.h (61%) rename memorymap.c => test/memory_map.c (59%) diff --git a/memory.c b/memory.c index 3b91f89..aa0b04a 100644 --- a/memory.c +++ b/memory.c @@ -59,8 +59,6 @@ bool memory_create(Memory *memory, size_t length) { // Releases memory block resources. void memory_destroy(Memory *memory) { assert(memory != NULL); - assert(memory->data != NULL); - free(memory->data); memory->data = NULL; memory->length = 0; diff --git a/memory_map.c b/memory_map.c new file mode 100644 index 0000000..05e2d1c --- /dev/null +++ b/memory_map.c @@ -0,0 +1,116 @@ +/* +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + __/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__ + \_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2023 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include "memory_map.h" +#include "message.h" + +// Resets memory map. +static void memory_map_clear(MemoryMap *map) { + for(unsigned int i=0; imemory[i].length = 0; + map->memory[i].data = NULL; + } + for(unsigned int i=0; impr[i] = 0xFFU; + } + for(unsigned int i=0; ipage[i].id = PCE_MEMORY_NONE; + map->page[i].bank = 0; + } +} + +// Initializes memory map. +bool memory_map_init(MemoryMap *map) { + bool ret = false; + + memory_map_clear(map); + + // Allocate main (or work) RAM. + if(!memory_create(&map->memory[PCE_MEMORY_BASE_RAM], PCE_BANK_SIZE)) { + ERROR_MSG("Failed to allocate main memory!"); + } else { + // Main RAM is mapped to pages 0xF8 to 0xFB (included). + // Pages 0xF9 to 0xFB mirror page 0xF8. */ + for(unsigned int i=0xf8; i<=0xfb; i++) { + map->page[i].id = PCE_MEMORY_BASE_RAM; + map->page[i].bank = 0; + } + + // ROM and syscard RAM will be initialized later. + ret = true; + } + return ret; +} + +// Releases resources used by the memory map. +void memory_map_destroy(MemoryMap *map) { + assert(map != NULL); + for(unsigned i=0; imemory[i]); + } + memory_map_clear(map); +} + +// Get the memory page associated to a logical address. +uint8_t memory_map_page(MemoryMap* map, uint16_t logical) { + assert(map != NULL); + uint8_t id = (logical >> 13) & 0x07U; + return map->mpr[id]; +} + +// Reads a single byte from memory. +uint8_t memory_map_read(MemoryMap *map, size_t logical) { + assert(map != NULL); + const uint8_t id = memory_map_page(map, (uint16_t)logical); + const Page *page = &map->page[id]; + + uint8_t ret = 0xFFU; + if(page->id != PCE_MEMORY_NONE) { + const size_t offset = (logical & 0x1FFFU) + (page->bank * PCE_BANK_SIZE); + const Memory *mem = &map->memory[page->id]; + if(offset < mem->length) { + ret = mem->data[offset]; + } + } + return ret; +} + +// Update mprs. +void memory_map_mpr(MemoryMap *map, const uint8_t mpr[PCE_MPR_COUNT]) { + assert(map != NULL); + for(unsigned int i=0; impr[i] = mpr[i]; + } +} diff --git a/memorymap.h b/memory_map.h similarity index 61% rename from memorymap.h rename to memory_map.h index 8c2f301..42af452 100644 --- a/memorymap.h +++ b/memory_map.h @@ -38,56 +38,60 @@ #include "memory.h" -/** - * PC Engine memory - */ +/// PC Engine memory blocks. enum { - PCE_MEM_ROM = 0, - PCE_MEM_BASE_RAM, - PCE_MEM_CD_RAM, - PCE_MEM_SYSCARD_RAM, - PCE_MEM_COUNT + PCE_MEMORY_NONE = -1, + PCE_MEMORY_ROM = 0, + PCE_MEMORY_BASE_RAM, + PCE_MEMORY_CD_RAM, + PCE_MEMORY_SYSCARD_RAM, + PCE_MEMORY_COUNT }; -/** - * PC Engine memory map. - */ +#define PCE_PAGE_COUNT 0x100U + +#define PCE_MPR_COUNT 8U + +#define PCE_BANK_SIZE 8192U + +/// PC Engine memory page description. +typedef struct { + int id; // name the PCE_MEMORY_* enum ? + size_t bank; +} Page; + +/// PC Engine memory map. typedef struct { - Memory mem[PCE_MEM_COUNT]; - uint8_t *page[0x100]; - uint8_t mpr[8]; -} memmap_t; - -/** - * Initializes memory map. - * \param map Memory map. - * \return 1 upon success, 0 if an error occured. - */ -int memmap_init(memmap_t *map); -/** - * Releases resources used by the memory map. - * \param map Memory map. - */ -void memmap_destroy(memmap_t *map); -/** - * Get the memory page associated to a logical address. - * \param map Memory map. - * \param logical Logical address. - * \return Memory page. - */ -uint8_t memmap_page(memmap_t* map, uint16_t logical); -/** - * Reads a single byte from memory. - * \param [in] map Memory map. - * \param [in] logical Logical address. - * \return Byte read. - */ -uint8_t memmap_read(memmap_t *map, size_t logical); -/** - * Update mprs. - * \param [in][out] map Memory map. - * \param [in] mpr Memory page registers. - */ -void memmap_mpr(memmap_t *map, const uint8_t *mpr); + Memory memory[PCE_MEMORY_COUNT]; + Page page[PCE_PAGE_COUNT]; + uint8_t mpr[PCE_MPR_COUNT]; +} MemoryMap; + +/// Initializes memory map. +/// \param [in out] map Memory map. +/// \return true +/// \return false +bool memory_map_init(MemoryMap *map); + +/// Releases resources used by the memory map. +/// \param [in out] map Memory map. +void memory_map_destroy(MemoryMap *map); + +/// Get the memory page associated to a logical address. +/// \param [in] map Memory map. +/// \param [in] logical Logical address. +/// \return Memory page. +uint8_t memory_map_page(MemoryMap* map, uint16_t logical); + +/// Reads a single byte from memory. +/// \param [in] map Memory map. +/// \param [in] logical Logical address. +/// \return The value stored at the specified logical address. +uint8_t memory_map_read(MemoryMap *map, size_t logical); + +/// Update the whole mprs list +/// \param [in out] map Memory map. +/// \param [in] mpr Memory page registers. +void memory_map_mpr(MemoryMap *map, const uint8_t mpr[PCE_MPR_COUNT]); #endif // ETRIPATOR_MEMORY_MAP_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e925998..45e089e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,3 +46,15 @@ add_unit_test( LIBRARIES cwalk INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) + +add_unit_test( + NAME memory_map + SOURCES + memory_map.c + ${PROJECT_SOURCE_DIR}/memory_map.c + ${PROJECT_SOURCE_DIR}/memory.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) diff --git a/memorymap.c b/test/memory_map.c similarity index 59% rename from memorymap.c rename to test/memory_map.c index d8cabb1..ad348fd 100644 --- a/memorymap.c +++ b/test/memory_map.c @@ -33,56 +33,56 @@ ¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ */ -#include "memorymap.h" -#include "message.h" -/* Initializes memory map. */ -int memmap_init(memmap_t *map) { - int i, ret = 0; - - memset(map, 0, sizeof(memmap_t)); // [todo] function - - - /* Allocate main (or work) RAM */ - if(!memory_create(&map->mem[PCE_MEM_BASE_RAM], 8192)) { - ERROR_MSG("Failed to allocate main memory!\n"); - } else { - /* Main RAM is mapped to pages 0xf8-0xfb (included). */ - /* Pages 0xf9 to 0xfb mirror page 0xf8. */ - for(i=0xf8; i<=0xfb; i++) { - map->page[i] = &(map->mem[PCE_MEM_BASE_RAM].data[0]); - } - - /* ROM and syscard RAM will be initialized later. */ - - /* Clear mprs. */ - memset(map->mpr, 0, 8); - map->mpr[0] = 0xff; - map->mpr[1] = 0xf8; - - ret = 1; - } - return ret; -} -/* Releases resources used by the memory map. */ -void memmap_destroy(memmap_t *map) { - int i; - for(i=0; imem[i]); - } - memset(map, 0, sizeof(memmap_t)); -} -/* Get the memory page associated to a logical address. */ -uint8_t memmap_page(memmap_t* map, uint16_t logical) { - uint8_t id = (logical >> 13) & 0x07; - return map->mpr[id]; +#include + +#include +#include + +#include + +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + return NULL; } -/* Reads a single byte from memory. */ -uint8_t memmap_read(memmap_t *map, size_t logical) { - uint8_t i = memmap_page(map, (uint16_t)logical); - return (map->page[i]) ? map->page[i][logical & 0x1fff] : 0xff; + +void tear_down(void* fixture __attribute__((unused))) { } -/* Update mprs. */ -void memmap_mpr(memmap_t *map, const uint8_t *mpr) { - memcpy(map->mpr, mpr, 8); + +MunitResult memory_map_read_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + MemoryMap map = {0}; + + munit_assert_true(memory_map_init(&map)); + + map.mpr[1] = 0xF8U; + + map.memory[PCE_MEMORY_BASE_RAM].data[0x0000] = 0xC5; + map.memory[PCE_MEMORY_BASE_RAM].data[0x0100] = 0x7E; + map.memory[PCE_MEMORY_BASE_RAM].data[0x1000] = 0xA9; + + munit_assert_uint8(memory_map_read(&map, 0x2000U), ==, 0xC5); + munit_assert_uint8(memory_map_read(&map, 0x2100U), ==, 0x7E); + munit_assert_uint8(memory_map_read(&map, 0x3000U), ==, 0xA9); + + memory_map_destroy(&map); + + return MUNIT_OK; } +static MunitTest memory_map_tests[] = { + { "/read", memory_map_read_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } +}; + +static const MunitSuite memory_map_suite = { + "Memory map test suite", memory_map_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE +}; + +int main (int argc, char* const* argv) { + message_printer_init(); + console_message_printer_init(); + + int ret = munit_suite_main(&memory_map_suite, NULL, argc, argv); + + message_printer_destroy(); + + return ret; +} \ No newline at end of file From 62a2c7fcb178c7d10f8bd06c43675c746bc28435 Mon Sep 17 00:00:00 2001 From: MooZ Date: Wed, 4 Sep 2024 23:41:54 +0200 Subject: [PATCH 07/35] Add Fake Function Framework --- .gitmodules | 3 +++ externals/fff | 1 + 2 files changed, 4 insertions(+) create mode 160000 externals/fff diff --git a/.gitmodules b/.gitmodules index 2b0728d..999665f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "externals/cwalk"] path = externals/cwalk url = https://github.com/likle/cwalk.git +[submodule "externals/fff"] + path = externals/fff + url = https://github.com/meekrosoft/fff.git diff --git a/externals/fff b/externals/fff new file mode 160000 index 0000000..5111c61 --- /dev/null +++ b/externals/fff @@ -0,0 +1 @@ +Subproject commit 5111c61e1ef7848e3afd3550044a8cf4405f4199 From dce0237827d46572f852d6a89a0bb90c47508619 Mon Sep 17 00:00:00 2001 From: MooZ Date: Wed, 4 Sep 2024 23:42:34 +0200 Subject: [PATCH 08/35] Start updating ROM loading --- rom.c | 70 +++++++++++++++++++++++---------------------- rom.h | 15 +++++----- test/CMakeLists.txt | 13 +++++++++ 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/rom.c b/rom.c index 86ae63a..d1a2a51 100644 --- a/rom.c +++ b/rom.c @@ -36,17 +36,15 @@ #include "rom.h" #include "message.h" -static int rom_load_data(const char *filename, memmap_t *map) { - int ret = 0; - size_t size = 0; - FILE *in; +static bool rom_load_data(const char *filename, MemoryMap *map) { + bool ret = false; - /* Open file */ - in = fopen(filename, "rb"); + size_t size = 0; + FILE *in = fopen(filename, "rb"); if (in == NULL) { ERROR_MSG("Unable to open %s : %s", filename, strerror(errno)); } else { - /* Compute file size. */ + // Compute file size. struct stat infos; int fd = fileno(in); if (fd < 0) { @@ -57,29 +55,31 @@ static int rom_load_data(const char *filename, memmap_t *map) { ERROR_MSG("Empty file: %s", filename); } else { size = infos.st_size; - /* Check for possible header */ - if (size & 0x200) { - /* Jump header */ - size &= ~0x200; - if (fseek(in, 0x200, SEEK_SET)) { + // Check for possible header + if (size & 0x200U) { + // Jump header + size &= ~0x200U; + if (fseek(in, 0x200U, SEEK_SET)) { ERROR_MSG("Failed to jump rom header in %s: %s", filename, strerror(errno)); } } } if(size) { - /* Allocate rom storage */ - if (!memory_create(&map->mem[PCE_MEM_ROM], (size + 0x1fff) & ~0x1fff)) { + // Allocate rom storage + Memory *memory = &map->memory[PCE_MEMORY_ROM]; + if (!memory_create(memory, (size + 0x1FFFU) & ~0x1FFFU)) { ERROR_MSG("Failed to allocate ROM storage : %s", strerror(errno)); } else { - /* Fill rom with 0xff */ - (void)memory_fill(&map->mem[PCE_MEM_ROM], 0xFF); - /* Read ROM data */ - size_t count = (size < map->mem[PCE_MEM_ROM].length) ? size : map->mem[PCE_MEM_ROM].length; - size_t nread = fread(map->mem[PCE_MEM_ROM].data, 1, count, in); + // Fill rom with 0xFF + (void)memory_fill(memory, 0xFFU); + // Read ROM data + size_t count = (size < memory->length) ? size : memory->length; + size_t nread = fread(memory->data, 1, count, in); if (nread != count) { ERROR_MSG("Failed to read ROM data from %s : %s", filename, strerror(errno)); + memory_destroy(memory); } else { - ret = 1; + ret = true; } } } @@ -88,33 +88,35 @@ static int rom_load_data(const char *filename, memmap_t *map) { return ret; } -/* Load ROM from file. */ -int rom_load(const char *filename, memmap_t *map) { +// Load ROM from file and update memory map. +bool rom_load(const char* filename, MemoryMap* map) { FILE *in; - int ret = 0; - if(rom_load_data(filename, map) == 0) { - memory_destroy(&map->mem[PCE_MEM_ROM]); - } else { + bool ret = false; + if(rom_load_data(filename, map)) { unsigned int i; /* Initialize ROM pages. */ - if (map->mem[PCE_MEM_ROM].length == 0x60000) { + if (map->memory[PCE_MEMORY_ROM].length == 0x60000U) { for (i = 0; i < 64; i++) { - map->page[i] = &map->mem[PCE_MEM_ROM].data[(i & 0x1f) * 8192]; + map->page[i].id = PCE_MEMORY_ROM; + map->page[i].bank = i & 0x1FU; } for (i = 64; i < 128; i++) { - map->page[i] = &map->mem[PCE_MEM_ROM].data[((i & 0x0f) + 32) * 8192]; + map->page[i].id = PCE_MEMORY_ROM; + map->page[i].bank = (i & 0x0FU) + 32; } - } else if (map->mem[PCE_MEM_ROM].length == 0x80000) { + } else if (map->memory[PCE_MEMORY_ROM].length == 0x80000U) { for (i = 0; i < 64; i++) { - map->page[i] = &map->mem[PCE_MEM_ROM].data[(i & 0x3f) * 8192]; + map->page[i].id = PCE_MEMORY_ROM; + map->page[i].bank = i & 0x3FU; } for (i = 64; i < 128; i++) { - map->page[i] = &map->mem[PCE_MEM_ROM].data[((i & 0x1f) + 32) * 8192]; + map->page[i].id = PCE_MEMORY_ROM; + map->page[i].bank = (i & 0x1FU) + 32; } } else { for (i = 0; i < 128; i++) { - uint8_t bank = (uint8_t)(i % (map->mem[PCE_MEM_ROM].length / 8192)); - map->page[i] = &map->mem[PCE_MEM_ROM].data[bank * 8192]; + map->page[i].id = PCE_MEMORY_ROM; + map->page[i].bank = i % (map->memory[PCE_MEMORY_ROM].length / PCE_BANK_SIZE); } } ret = 1; diff --git a/rom.h b/rom.h index 48832f5..823485c 100644 --- a/rom.h +++ b/rom.h @@ -36,14 +36,13 @@ #ifndef ETRIPATOR_ROM_H #define ETRIPATOR_ROM_H -#include "memorymap.h" +#include "memory_map.h" -/** - * Load ROM from file. - * \param [in] filename ROM filename. - * \param [out] map Memory map. - * \return 1 upon success, 0 if an error occured. - */ -int rom_load(const char* filename, memmap_t* map); +/// Load ROM from file and update memory map. +/// \param [in] filename ROM filename. +/// \param [out] map Memory map. +/// \return true if the ROM was successfully loaded. +/// \return false if an error occured. +bool rom_load(const char* filename, MemoryMap* map); #endif // ETRIPATOR_ROM_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 45e089e..a3589a3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -58,3 +58,16 @@ add_unit_test( LIBRARIES cwalk INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) + +add_unit_test( + NAME rom + SOURCES + rom.c + ${PROJECT_SOURCE_DIR}/rom.c + ${PROJECT_SOURCE_DIR}/memory_map.c + ${PROJECT_SOURCE_DIR}/memory.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) From 7505b0b6dedbf7e472831fd161b08e69854dc7b8 Mon Sep 17 00:00:00 2001 From: MooZ Date: Fri, 6 Sep 2024 20:40:33 +0200 Subject: [PATCH 09/35] Build fff and add symbol wrapping to ut targets --- cd.c | 58 ++++++++++++++----------- cd.h | 46 +++++++++++--------- externals/CMakeLists.txt | 2 + rom.c | 2 +- test/CMakeLists.txt | 20 ++++++++- test/cd.c | 93 ++++++++++++++++++++++++++++++++++++++++ test/rom.c | 91 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 263 insertions(+), 49 deletions(-) create mode 100644 test/cd.c create mode 100644 test/rom.c diff --git a/cd.c b/cd.c index 21ea41f..b0fec39 100644 --- a/cd.c +++ b/cd.c @@ -36,42 +36,47 @@ #include "cd.h" #include "message.h" -/* Adds CD RAM to memory map. */ -int cd_memmap(memmap_t *map) { - int i, ret = 0; - /* Allocate CD RAM */ - if(!memory_create(&map->mem[PCE_MEM_CD_RAM], 8 * 8192)) { - ERROR_MSG("Failed to allocate cd memory!\n"); - memmap_destroy(map); +/// Adds CD RAM to memory map. +bool cd_memory_map(MemoryMap *map) { + int i; + bool ret = false; + // Allocate CD RAM + if(!memory_create(&map->memory[PCE_MEMORY_CD_RAM], PCE_CD_RAM_BANK_COUNT * PCE_BANK_SIZE)) { + ERROR_MSG("Failed to allocate cd memory!"); + // Allocate System Card RAM + } else if (!memory_create(&map->memory[PCE_MEMORY_SYSCARD_RAM], PCE_SYSCARD_RAM_BANK_COUNT * PCE_BANK_SIZE)) { + ERROR_MSG("Failed to allocate system card memory!"); } else { - /* CD RAM is mapped to pages 0x80-0x88 (included). */ - for (i = 0; i <= 8; i++) { - map->page[0x80 + i] = &map->mem[PCE_MEM_CD_RAM].data[i * 8192]; + // CD RAM is mapped to pages 0x80-0x88 (included). + for (i = 0; i <= PCE_CD_RAM_BANK_COUNT; i++) { + map->page[PCE_CD_RAM_FIRST_PAGE + i].id = PCE_MEMORY_CD_RAM; + map->page[PCE_CD_RAM_FIRST_PAGE + i].bank = i; } - /* Allocate System Card RAM */ - if (!memory_create(&map->mem[PCE_MEM_SYSCARD_RAM], 24 * 8192)) { - ERROR_MSG("Failed to allocate system card memory!\n"); - memmap_destroy(map); - } else { - /* System Card RAM is mapped to pages 0x68-0x86. */ - for (i = 0; i < 24; i++) { - map->page[0x68 + i] = &map->mem[PCE_MEM_SYSCARD_RAM].data[i * 8192]; - } - ret = 1; + // System Card RAM is mapped to pages 0x68-0x86. + for (i = 0; i < PCE_SYSCARD_RAM_BANK_COUNT; i++) { + map->page[PCE_SYSCARD_RAM_FIRST_PAGE + i].id = PCE_MEMORY_SYSCARD_RAM; + map->page[PCE_SYSCARD_RAM_FIRST_PAGE + i].bank = i; } + ret = true; + } + + if(ret == false) { + memory_map_destroy(map); } return ret; } -/* Load CDROM data from file. */ -int cd_load(const char* filename, size_t start, size_t len, size_t sector_size, uint8_t page, size_t offset, memmap_t* map) { - int ret = 0; + +#if 0 +/// Load CDROM data from file. +bool cd_load(const char* filename, size_t start, size_t len, size_t sector_size, uint8_t page, size_t offset, MemoryMap* map) { + bool ret = false; FILE *in = fopen(filename, "rb"); if(in == NULL) { ERROR_MSG("Unable to open %s : %s", filename, strerror(errno)); } else { size_t remaining = len; size_t physical = (offset & 0x1FFFU) | (page << 0x0D); - for(ret=1; ret && remaining; ) { + for(ret=true; ret && remaining; ) { size_t count = 2048 - (start % 2048); if(count > remaining) { count = remaining; @@ -85,13 +90,13 @@ int cd_load(const char* filename, size_t start, size_t len, size_t sector_size, size_t current_page = physical >> 0x0D; size_t current_addr = physical & 0x1FFF; - ret = 0; + ret = false; if(fseek(in, (long int)file_offset, SEEK_SET)) { ERROR_MSG("Offset out of bound : %s", strerror(errno)); } else if(fread(map->page[current_page] + current_addr, 1, count, in) != count) { ERROR_MSG("Failed to read %d bytes : %s", count, strerror(errno)); } else { - ret = 1; + ret = true; } start += count; physical += count; @@ -104,3 +109,4 @@ int cd_load(const char* filename, size_t start, size_t len, size_t sector_size, } return ret; } +#endif \ No newline at end of file diff --git a/cd.h b/cd.h index c70b4ab..3769ac1 100644 --- a/cd.h +++ b/cd.h @@ -37,26 +37,30 @@ #define ETRIPATOR_CD_H #include "config.h" -#include "memorymap.h" - -/** - * Adds CD RAM to memory map. - * \param map Memory map. - * \return 1 upon success, 0 if an error occured. - */ -int cd_memmap(memmap_t *map); - -/** - * Load CDROM data from file. - * \param [in] filename CDROM data filename. - * \param [in] start CDROM data offset. - * \param [in] len CDROM data length (in bytes). - * \param [in] sector_size CD sector size. - * \param [in] page Memory page. - * \param [in] offset memory page offset. - * \param [out] memmap Memory map. - * \return 1 upon success, 0 if an error occured. - */ -int cd_load(const char* filename, size_t start, size_t len, size_t sector_size, uint8_t page, size_t offset, memmap_t* map); +#include "memory_map.h" + +#define PCE_CD_RAM_BANK_COUNT 8U +#define PCE_SYSCARD_RAM_BANK_COUNT 24U + +#define PCE_CD_RAM_FIRST_PAGE 0x80U +#define PCE_SYSCARD_RAM_FIRST_PAGE 0x68U + +/// Adds CD RAM to memory map. +/// \param map Memory map. +/// \return true if the CD RAM and SYSCARD RAM memory areas were successfully created. +/// \return false if an error occured. +bool cd_memory_map(MemoryMap *map); + +/// Load CDROM data from file. +/// \param [in] filename CDROM data filename. +/// \param [in] start CDROM data offset. +/// \param [in] len CDROM data length (in bytes). +/// \param [in] sector_size CD sector size. +/// \param [in] page Memory page. +/// \param [in] offset Memory page offset. +/// \param [out] map Memory map. +/// \return true +/// \return false +int cd_load(const char* filename, size_t start, size_t len, size_t sector_size, uint8_t page, size_t offset, MemoryMap* map); #endif // ETRIPATOR_CD_H diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 1fd6b7a..562606c 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -5,3 +5,5 @@ add_subdirectory(cwalk) add_library(munit STATIC ${CMAKE_CURRENT_LIST_DIR}/munit/munit.c) target_include_directories(munit PUBLIC $) set_property(TARGET munit PROPERTY INTERFACE_INCLUDE_DIRECTORIES $) + +add_subdirectory(fff) diff --git a/rom.c b/rom.c index d1a2a51..6e6279e 100644 --- a/rom.c +++ b/rom.c @@ -119,7 +119,7 @@ bool rom_load(const char* filename, MemoryMap* map) { map->page[i].bank = i % (map->memory[PCE_MEMORY_ROM].length / PCE_BANK_SIZE); } } - ret = 1; + ret = true; } return ret; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a3589a3..93494bc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,17 +5,21 @@ endif() function(add_unit_test) set(options ) set(oneValueArgs NAME) - set(multiValueArgs SOURCES LIBRARIES INCLUDE_DIRECTORIES) + set(multiValueArgs SOURCES LIBRARIES INCLUDE_DIRECTORIES WRAP) cmake_parse_arguments(ut "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(target_name "${ut_NAME}_ut") list(REMOVE_DUPLICATES ut_SOURCES) + list(REMOVE_DUPLICATES ut_WRAP) add_executable(${target_name} ${ut_SOURCES}) target_link_libraries(${target_name} PRIVATE ${ut_LIBRARIES} munit) target_include_directories(${target_name} PRIVATE ${ut_INCLUDE_DIRECTORIES} ${EXTRA_INCLUDE}) set_target_properties(${target_name} PROPERTIES C_STANDARD 11) + foreach(_wrap ${ut_WRAP}) + target_link_options(${target_name} PRIVATE LINKER:--wrap=${_wrap}) + endforeach() add_test( NAME ${target_name} @@ -68,6 +72,20 @@ add_unit_test( ${PROJECT_SOURCE_DIR}/memory.c ${PROJECT_SOURCE_DIR}/message.c ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk fff + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} + WRAP fopen fileno fstat fseek fread fclose +) + +add_unit_test( + NAME cd + SOURCES + cd.c + ${PROJECT_SOURCE_DIR}/cd.c + ${PROJECT_SOURCE_DIR}/memory_map.c + ${PROJECT_SOURCE_DIR}/memory.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c LIBRARIES cwalk INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) diff --git a/test/cd.c b/test/cd.c new file mode 100644 index 0000000..2d88c8a --- /dev/null +++ b/test/cd.c @@ -0,0 +1,93 @@ +/* +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + __/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__ + \_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2023 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include + +#include +#include + +#include + +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + return NULL; +} + +void tear_down(void* fixture __attribute__((unused))) { +} + +MunitResult cd_memory_map_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + MemoryMap map = {}; + + munit_assert_true(memory_map_init(&map)); + munit_assert_true(cd_memory_map(&map)); + + munit_assert_not_null(map.memory[PCE_MEMORY_CD_RAM].data); + munit_assert_size(map.memory[PCE_MEMORY_CD_RAM].length, ==, PCE_CD_RAM_BANK_COUNT*PCE_BANK_SIZE); + for(size_t i=0; i ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2023 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include + +#include + +#include +#include + +#include + +DEFINE_FFF_GLOBALS; + +FAKE_VALUE_FUNC(FILE*, __wrap_fopen, const char*, const char*) +FAKE_VALUE_FUNC(int, __wrap_fileno, FILE*) +FAKE_VALUE_FUNC(int, __wrap_fstat, int, struct stat*) +FAKE_VALUE_FUNC(int, __wrap_fseek, FILE*, long, int) +FAKE_VALUE_FUNC(size_t, __wrap_fread, void*, size_t, size_t, FILE*) +FAKE_VALUE_FUNC(int, __wrap_fclose, FILE*) + +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + RESET_FAKE(__wrap_fopen); + RESET_FAKE(__wrap_fileno); + RESET_FAKE(__wrap_fstat); + RESET_FAKE(__wrap_fseek); + RESET_FAKE(__wrap_fread); + RESET_FAKE(__wrap_fclose); + + return NULL; +} + +void tear_down(void* fixture __attribute__((unused))) { +} + +MunitResult rom_load_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + // [todo] + return MUNIT_OK; +} + +static MunitTest rom_tests[] = { + { "/load", rom_load_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } +}; + +static const MunitSuite rom_suite = { + "ROM test suite", rom_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE +}; + +int main (int argc, char* const* argv) { + message_printer_init(); + console_message_printer_init(); + + int ret = munit_suite_main(&rom_suite, NULL, argc, argv); + + message_printer_destroy(); + + return ret; +} \ No newline at end of file From da32f27954221edaf95b865697bfa5ec0990b5ab Mon Sep 17 00:00:00 2001 From: MooZ Date: Fri, 6 Sep 2024 23:39:41 +0200 Subject: [PATCH 10/35] Start working on rom_load unit tests --- cd.c | 10 ++++--- cd.h | 2 +- rom.c | 6 +++-- test/cd.c | 4 ++- test/rom.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 86 insertions(+), 12 deletions(-) diff --git a/cd.c b/cd.c index b0fec39..92560e0 100644 --- a/cd.c +++ b/cd.c @@ -66,7 +66,6 @@ bool cd_memory_map(MemoryMap *map) { return ret; } -#if 0 /// Load CDROM data from file. bool cd_load(const char* filename, size_t start, size_t len, size_t sector_size, uint8_t page, size_t offset, MemoryMap* map) { bool ret = false; @@ -90,10 +89,14 @@ bool cd_load(const char* filename, size_t start, size_t len, size_t sector_size, size_t current_page = physical >> 0x0D; size_t current_addr = physical & 0x1FFF; + size_t bank_offset = current_addr + (map->page[current_page].bank * PCE_BANK_SIZE); + + // [todo] test that map->page[current_page].id != PCE_MEMORY_NONE + ret = false; - if(fseek(in, (long int)file_offset, SEEK_SET)) { + if(fseek(in, (long int)file_offset, SEEK_SET) < 0) { ERROR_MSG("Offset out of bound : %s", strerror(errno)); - } else if(fread(map->page[current_page] + current_addr, 1, count, in) != count) { + } else if(fread(map->memory[map->page[current_page].id].data+bank_offset, 1, count, in) != count) { ERROR_MSG("Failed to read %d bytes : %s", count, strerror(errno)); } else { ret = true; @@ -109,4 +112,3 @@ bool cd_load(const char* filename, size_t start, size_t len, size_t sector_size, } return ret; } -#endif \ No newline at end of file diff --git a/cd.h b/cd.h index 3769ac1..15b4636 100644 --- a/cd.h +++ b/cd.h @@ -61,6 +61,6 @@ bool cd_memory_map(MemoryMap *map); /// \param [out] map Memory map. /// \return true /// \return false -int cd_load(const char* filename, size_t start, size_t len, size_t sector_size, uint8_t page, size_t offset, MemoryMap* map); +bool cd_load(const char* filename, size_t start, size_t len, size_t sector_size, uint8_t page, size_t offset, MemoryMap* map); #endif // ETRIPATOR_CD_H diff --git a/rom.c b/rom.c index 6e6279e..b1c8c8c 100644 --- a/rom.c +++ b/rom.c @@ -59,7 +59,7 @@ static bool rom_load_data(const char *filename, MemoryMap *map) { if (size & 0x200U) { // Jump header size &= ~0x200U; - if (fseek(in, 0x200U, SEEK_SET)) { + if (fseek(in, 0x200U, SEEK_SET) < 0) { ERROR_MSG("Failed to jump rom header in %s: %s", filename, strerror(errno)); } } @@ -76,7 +76,7 @@ static bool rom_load_data(const char *filename, MemoryMap *map) { size_t count = (size < memory->length) ? size : memory->length; size_t nread = fread(memory->data, 1, count, in); if (nread != count) { - ERROR_MSG("Failed to read ROM data from %s : %s", filename, strerror(errno)); + ERROR_MSG("Failed to read ROM data from %s (expected %zu, read %zu): %s", filename, count, nread, strerror(errno)); memory_destroy(memory); } else { ret = true; @@ -90,6 +90,8 @@ static bool rom_load_data(const char *filename, MemoryMap *map) { // Load ROM from file and update memory map. bool rom_load(const char* filename, MemoryMap* map) { + assert(filename != NULL); + assert(map != NULL); FILE *in; bool ret = false; if(rom_load_data(filename, map)) { diff --git a/test/cd.c b/test/cd.c index 2d88c8a..d042fbe 100644 --- a/test/cd.c +++ b/test/cd.c @@ -72,13 +72,15 @@ MunitResult cd_memory_map_test(const MunitParameter params[] __attribute__((unus return MUNIT_OK; } +// [todo] cd_load + static MunitTest cd_tests[] = { { "/memory_map", cd_memory_map_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; static const MunitSuite cd_suite = { - "ROM test suite", cd_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE + "CDROM test suite", cd_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE }; int main (int argc, char* const* argv) { diff --git a/test/rom.c b/test/rom.c index 8670b16..c0ec916 100644 --- a/test/rom.c +++ b/test/rom.c @@ -44,6 +44,8 @@ DEFINE_FFF_GLOBALS; +// [NOTE] munit is using fileno. If a test fails, munit will loop indefinitely :/ + FAKE_VALUE_FUNC(FILE*, __wrap_fopen, const char*, const char*) FAKE_VALUE_FUNC(int, __wrap_fileno, FILE*) FAKE_VALUE_FUNC(int, __wrap_fstat, int, struct stat*) @@ -51,6 +53,32 @@ FAKE_VALUE_FUNC(int, __wrap_fseek, FILE*, long, int) FAKE_VALUE_FUNC(size_t, __wrap_fread, void*, size_t, size_t, FILE*) FAKE_VALUE_FUNC(int, __wrap_fclose, FILE*) +static int fstat_empty_file(int fd __attribute__((unused)), struct stat* infos) { + memset(infos, 0, sizeof(struct stat)); + infos->st_size = 0; + return 0; +} + +static size_t g_dummy_file_size; + +static int fstat_dummy_file(int fd __attribute__((unused)), struct stat* infos) { + infos->st_size = g_dummy_file_size; + return 0; +} + +static size_t fread_dummy(void* out, size_t size, size_t nmemb, FILE* in __attribute__((unused))) { + uint8_t *ptr = (uint8_t*)out; + uint8_t b = 0; + for(size_t j=0; j 8kb + static MunitTest rom_tests[] = { - { "/load", rom_load_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/load/small", rom_load_small_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; From f6df75009d364ef5fd59d953c3b8b2159aa79005 Mon Sep 17 00:00:00 2001 From: MooZ Date: Sat, 7 Sep 2024 00:32:17 +0200 Subject: [PATCH 11/35] Bring back label unit tests --- test/CMakeLists.txt | 11 +++++++++++ test/label.c | 22 +++++++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 93494bc..f706dda 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -89,3 +89,14 @@ add_unit_test( LIBRARIES cwalk INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) + +add_unit_test( + NAME label + SOURCES + label.c + ${PROJECT_SOURCE_DIR}/label.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) diff --git a/test/label.c b/test/label.c index 1c9a306..7250184 100644 --- a/test/label.c +++ b/test/label.c @@ -39,25 +39,17 @@ #include "message/console.h" #include "message/file.h" -void* setup(const MunitParameter params[], void* user_data) { - (void) params; - (void) user_data; - - console_msg_printer_t *printer = (console_msg_printer_t*)malloc(sizeof(console_msg_printer_t)); - - msg_printer_init(); - console_msg_printer_init(printer); - msg_printer_add((msg_printer_t*)printer); - - return (void*)printer; +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + message_printer_init(); + console_message_printer_init(); + return NULL; } -void tear_down(void* fixture) { - msg_printer_destroy(); - free(fixture); +void tear_down(void* fixture __attribute__((unused))) { + message_printer_destroy(); } -MunitResult label_add_test(const MunitParameter params[], void* fixture) { +MunitResult label_add_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { (void)params; (void)fixture; From 388b5cc3c974ce96c8c61541c1bb904a878cd30e Mon Sep 17 00:00:00 2001 From: MooZ Date: Sat, 7 Sep 2024 20:03:52 +0200 Subject: [PATCH 12/35] Revamped label repository --- label.c | 136 +++++++++++++++++++++----------------------- label.h | 155 +++++++++++++++++++++++---------------------------- test/label.c | 128 ++++++++++++++---------------------------- 3 files changed, 175 insertions(+), 244 deletions(-) diff --git a/label.c b/label.c index 418e950..d7d9378 100644 --- a/label.c +++ b/label.c @@ -38,23 +38,20 @@ #define LABEL_ARRAY_INC 16 -/** - * Label repository. - */ -struct label_repository_impl { - size_t size; /**< Size of label repository */ - size_t last; /**< Last element in the repository */ - label_t *labels; /**< Labels */ +/// Label repository. +struct LabelRepositoryImpl { + size_t size; //< Size of label repository. + size_t last; //< Last element in the repository. + Label *labels; //< Labels. }; -/** - * Get label index by its address. - * \param [in] repository Label repository. - * \param [in] logical Logical address. - * \param [in] page Memory page. - * \return label index or -1 if the label was not found. - */ -static int label_repository_index(label_repository_t* repository, uint16_t logical, uint8_t page) { +/// Get label index by its address. +/// \param [in] repository Label repository. +/// \param [in] logical Logical address. +/// \param [in] page Memory page. +/// \return label index. +/// \return -1 if the label was not found. +static int label_repository_index(LabelRepository *repository, uint16_t logical, uint8_t page) { size_t i; for(i=0; ilast; i++) { if( (repository->labels[i].page == page) && @@ -65,53 +62,45 @@ static int label_repository_index(label_repository_t* repository, uint16_t logic return -1; } -/* Create label repository. */ -label_repository_t* label_repository_create() { - label_repository_t *repository; - repository = (label_repository_t*)malloc(sizeof(label_repository_t)); +// Create label repository. +LabelRepository* label_repository_create() { + LabelRepository *repository = (LabelRepository*)malloc(sizeof(LabelRepository)); if(repository == NULL) { ERROR_MSG("Failed to create label repository: %s", strerror(errno)); - return NULL; - } - - repository->last = 0; - - repository->labels = NULL; - - repository->size = LABEL_ARRAY_INC; - repository->labels = (label_t*)malloc(repository->size * sizeof(label_t)); - if(repository->labels == NULL) { - ERROR_MSG("Failed to create label: %s", strerror(errno)); - label_repository_destroy(repository); - free(repository); - return NULL; - } - + } else { + repository->last = 0; + repository->labels = NULL; + repository->size = LABEL_ARRAY_INC; + repository->labels = (Label*)malloc(repository->size * sizeof(Label)); + if(repository->labels == NULL) { + ERROR_MSG("Failed to create label: %s", strerror(errno)); + label_repository_destroy(repository); + free(repository); + repository = NULL; + } + } return repository; } -/* Delete label repository. */ -void label_repository_destroy(label_repository_t* repository) { +// Delete label repository. +void label_repository_destroy(LabelRepository* repository) { repository->size = 0; repository->last = 0; if(repository->labels != NULL) { - for(int i=0; ilast; i++) { - if(repository->labels[i].name) { - free(repository->labels[i].name); - } - if(repository->labels[i].description) { - free(repository->labels[i].description); - } + for(size_t i=0; ilast; i++) { + free(repository->labels[i].name); + free(repository->labels[i].description); } free(repository->labels); repository->labels = NULL; } } -/* Add label to repository. */ -int label_repository_add(label_repository_t* repository, const char* name, uint16_t logical, uint8_t page, const char *description) { - int ret = 1; +// Add label to repository. +bool label_repository_add(LabelRepository* repository, const char* name, uint16_t logical, uint8_t page, const char *description) { + assert(repository != NULL); + bool ret = true; int index = label_repository_index(repository, logical, page); if(index >= 0) { #if 0 @@ -125,12 +114,12 @@ int label_repository_add(label_repository_t* repository, const char* name, uint1 } else { /* Expand arrays if necessary */ if(repository->last >= repository->size) { - label_t *ptr; + Label *ptr; repository->size += LABEL_ARRAY_INC; - ptr = (label_t*)realloc(repository->labels, repository->size * sizeof(label_t)); + ptr = (Label*)realloc(repository->labels, repository->size * sizeof(Label)); if(ptr == NULL) { label_repository_destroy(repository); - ret = 0; + ret = false; } else { repository->labels = ptr; } @@ -150,35 +139,39 @@ int label_repository_add(label_repository_t* repository, const char* name, uint1 return ret; } -/* Find a label by its address. */ -int label_repository_find(label_repository_t* repository, uint16_t logical, uint8_t page, label_t *out) { +// Find a label by its address. +bool label_repository_find(LabelRepository* repository, uint16_t logical, uint8_t page, Label *out) { int index = label_repository_index(repository, logical, page); - if(index < 0) { - memset(out, 0, sizeof(label_t)); - return 0; + bool ret = (index >= 0); + if(ret) { + memcpy(out, &repository->labels[index], sizeof(Label)); + } else { + memset(out, 0, sizeof(Label)); } - memcpy(out, &repository->labels[index], sizeof(label_t)); - return 1; + return ret; } -/* Get the number of labels stored in the repository. */ -int label_repository_size(label_repository_t* repository) { - return repository ? (int)repository->last : 0; +/// Get the number of labels stored in the repository. +int label_repository_size(LabelRepository* repository) { + assert(repository != NULL); + return (int)repository->last; } -/* Retrieve the label at the specified index. */ -int label_repository_get(label_repository_t* repository, int index, label_t *out) { - if((repository != NULL) && ((index >= 0) && (index < (int)repository->last))) { - memcpy(out, &repository->labels[index], sizeof(label_t)); - return 1; +// Retrieve the label at the specified index. +bool label_repository_get(LabelRepository* repository, int index, Label *out) { + bool ret = false; + if((repository != NULL) && ((index >= 0) && (index < (int)repository->last))) { + ret = true; + memcpy(out, &repository->labels[index], sizeof(Label)); } else { - memset(out, 0, sizeof(label_t)); - return 0; + memset(out, 0, sizeof(Label)); } + return ret; } -/* Delete labels */ -int label_repository_delete(label_repository_t* repository, uint16_t first, uint16_t end, uint8_t page) { - size_t i; + +/// Delete labels. +void label_repository_delete(LabelRepository* repository, uint16_t first, uint16_t end, uint8_t page) { + size_t i; for(i=0; ilast; i++) { if( (repository->labels[i].page == page) && (repository->labels[i].logical >= first) && @@ -191,10 +184,9 @@ int label_repository_delete(label_repository_t* repository, uint16_t first, uint if(repository->labels[i].description) { free(repository->labels[i].description); } - memcpy(&repository->labels[i], &repository->labels[repository->last], sizeof(label_t)); + memcpy(&repository->labels[i], &repository->labels[repository->last], sizeof(Label)); i--; } } } - return 1; } diff --git a/label.h b/label.h index 46e77ef..e785df1 100644 --- a/label.h +++ b/label.h @@ -38,91 +38,76 @@ #include "config.h" -/** - * Label. - */ +/// Label. typedef struct { - char* name; /**< Offset in the repository name buffer */ - uint16_t logical; /**< Logical address */ - uint8_t page; /**< Memory page */ - char* description; /**< Description (optional) */ -} label_t; - -typedef struct label_repository_impl label_repository_t; - -/** - * Create label repository. - * \return A pointer to a label repository or NULL if an error occured. - */ -label_repository_t* label_repository_create(); - -/** - * Release label repository resources. - * \param [in,out] repository Label repository. - */ -void label_repository_destroy(label_repository_t* repository); - -/** - * Add label (or inline description) to repository. - * \param [in,out] repository Label repository. - * \param [in] name Name. If the name is NULL, then this label is an inline description. - * \param [in] logical Logical address. - * \param [in] page Memory page. - * \param [in] description Description (optional if name is set, mandatory otherwise). - */ -int label_repository_add(label_repository_t* repository, const char* name, uint16_t logical, uint8_t page, const char *description); - -/** - * Find a label by its address. - * \param [in] repository Label repository. - * \param [in] logical Logical address. - * \param [in] page Memory page. - * \param [out] out Associated label (if any). - * \return 1 if a label was found, 0 otherwise. - */ -int label_repository_find(label_repository_t* repository, uint16_t logical, uint8_t page, label_t *out); - -/** - * Get the number of labels stored in the repository. - * \param [in] repository Label repository. - * \return Label count. - */ -int label_repository_size(label_repository_t* repository); - -/** - * Retrieve the label at the specified index. - * \param [in] repository Label repository. - * \param [in] index Label index. - * \param [out] out Label (if any). - * \return 1 if a label exists for the specified index, 0 otherwise. - */ -int label_repository_get(label_repository_t* repository, int index, label_t *out); - -/** - * Delete labels - * \param [in] repository Label repository. - * \param [in] first Start of the logical address range. - * \param [in] end End of the logical address range. - * \param [in] page Memory page. - */ -int label_repository_delete(label_repository_t* repository, uint16_t first, uint16_t end, uint8_t page); - -/** - * Load labels from file. - * \param [in] filename Input filename. - * \param [out] repository Label repository. - * \return 1 if the labels contained in the file was succesfully added to the repository. - * 0 if an error occured. - */ -int label_repository_load(const char* filename, label_repository_t* repository); - -/** - * Save labels to file. - * \param [in] filename Configuration file. - * \param [in] reposity Label repository. - * \return 1 if the labels in the repository were succesfully written to the file. - * 0 if an error occured. - */ -int label_repository_save(const char* filename, label_repository_t* repository); + char* name; //< Offset in the repository name buffer + uint16_t logical; //< Logical address + uint8_t page; //< Memory page + char* description; //< Description (optional) +} Label; + +typedef struct LabelRepositoryImpl LabelRepository; + +/// Create label repository. +/// \return A pointer to a label repository. +/// \return NULL if an error occured. +LabelRepository* label_repository_create(); + +/// Release label repository resources. +/// \param [in,out] repository Label repository. +void label_repository_destroy(LabelRepository* repository); + +/// Add label (or inline description) to repository. +/// \param [in,out] repository Label repository. +/// \param [in] name Name. If the name is NULL, then this label is an inline description. +/// \param [in] logical Logical address. +/// \param [in] page Memory page. +/// \param [in] description Description (optional if name is set, mandatory otherwise). +/// \return true if the entry was successfully added in the repository. +/// \return false if an error occured. +bool label_repository_add(LabelRepository* repository, const char* name, uint16_t logical, uint8_t page, const char *description); + +/// Find a label by its address. +/// \param [in] repository Label repository. +/// \param [in] logical Logical address. +/// \param [in] page Memory page. +/// \param [out] out Associated label (if any). +/// \return true if a label was found. +/// \return 0 otherwise. +bool label_repository_find(LabelRepository* repository, uint16_t logical, uint8_t page, Label *out); + +/// Get the number of labels stored in the repository. +/// \param [in] repository Label repository. +/// \return Label count. +int label_repository_size(LabelRepository* repository); + +/// Retrieve the label at the specified index. +/// \param [in] repository Label repository. +/// \param [in] index Label index. +/// \param [out] out Label (if any).& +/// \return true if a label exists for the specified index. +/// \return false otherwise. +bool label_repository_get(LabelRepository* repository, int index, Label *out); + +/// Delete labels +/// \param [in] repository Label repository. +/// \param [in] first Start of the logical address range. +/// \param [in] end End of the logical address range. +/// \param [in] page Memory page. +void label_repository_delete(LabelRepository* repository, uint16_t first, uint16_t end, uint8_t page); + +/// Load labels from file. +/// \param [out] repository Label repository. +/// \param [in] filename Input filename. +/// \return true if the labels contained in the file was succesfully added to the repository. +/// \return false if an error occured. +bool label_repository_load(LabelRepository* repository, const char* filename); + +/// Save labels to file. +/// \param [in] reposity Label repository. +/// \param [in] filename Configuration file. +/// \return true if the labels in the repository were succesfully written to the file. +/// \return false if an error occured. +bool label_repository_save(LabelRepository* repository, const char* filename); #endif // ETRIPATOR_LABEL_H diff --git a/test/label.c b/test/label.c index 7250184..1d47d4c 100644 --- a/test/label.c +++ b/test/label.c @@ -50,131 +50,85 @@ void tear_down(void* fixture __attribute__((unused))) { } MunitResult label_add_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { - (void)params; - (void)fixture; - - int ret; - label_t label; - label_repository_t* repository; - - repository = label_repository_create(); + Label label = {}; + LabelRepository* repository = label_repository_create(); munit_assert_not_null(repository); - ret = label_repository_add(repository, "l_0001", 0x0001, 0x00, NULL); - munit_assert_int(ret, !=, 0); - - ret = label_repository_add(repository, "l_0020", 0x0020, 0x00, NULL); - munit_assert_int(ret, !=, 0); - - ret = label_repository_add(repository, "l_000a", 0x000a, 0xb1, NULL); - munit_assert_int(ret, !=, 0); - - ret = label_repository_add(repository, "l_cafe", 0xcafe, 0xf7, NULL); - munit_assert_int(ret, !=, 0); - - ret = label_repository_add(repository, "l_0001", 0x0001, 0x00, NULL); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_add(repository, "l_0001", 0x0001, 0x00, NULL)); + munit_assert_true(label_repository_add(repository, "l_0020", 0x0020, 0x00, NULL)); + munit_assert_true(label_repository_add(repository, "l_000a", 0x000a, 0xb1, NULL)); + munit_assert_true(label_repository_add(repository, "l_cafe", 0xcafe, 0xf7, NULL)); + munit_assert_true(label_repository_add(repository, "l_0001", 0x0001, 0x00, NULL)); - ret = label_repository_size(repository); - munit_assert_int(ret, ==, 4); + munit_assert_int(label_repository_size(repository), ==, 4); - ret = label_repository_find(repository, 0x000a, 0xb1, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0x000a, 0xb1, &label)); munit_assert_string_equal(label.name, "l_000a"); - ret = label_repository_find(repository, 0x0020, 0x00, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0x0020, 0x00, &label)); munit_assert_string_equal(label.name, "l_0020"); - ret = label_repository_find(repository, 0xcafe, 0xf7, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0xcafe, 0xf7, &label)); munit_assert_string_equal(label.name, "l_cafe"); - ret = label_repository_find(repository, 0x0001, 0x00, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0x0001, 0x00, &label)); munit_assert_string_equal(label.name, "l_0001"); - ret = label_repository_find(repository, 0xbeef, 0xac, &label); - munit_assert_int(ret, ==, 0); + munit_assert_false(label_repository_find(repository, 0xbeef, 0xac, &label)); label_repository_destroy(repository); return MUNIT_OK; } -MunitResult label_delete_test(const MunitParameter params[], void* fixture) { - (void)params; - (void)fixture; - - int ret; - label_t label; - label_repository_t* repository; - - repository = label_repository_create(); +MunitResult label_delete_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + Label label = {}; + LabelRepository* repository = label_repository_create(); munit_assert_not_null(repository); - ret = label_repository_add(repository, "label01", 0x0110, 0x1a, NULL); - munit_assert_int(ret, !=, 0); - ret = label_repository_add(repository, "label02", 0x0220, 0x1a, NULL); - munit_assert_int(ret, !=, 0); - ret = label_repository_add(repository, "label03", 0x0330, 0x1b, "description"); - munit_assert_int(ret, !=, 0); - ret = label_repository_add(repository, "label04", 0x0440, 0x1a, NULL); - munit_assert_int(ret, !=, 0); - ret = label_repository_add(repository, "label05", 0x0550, 0x1b, NULL); - munit_assert_int(ret, !=, 0); - ret = label_repository_add(repository, "label06", 0x0553, 0x1b, NULL); - munit_assert_int(ret, !=, 0); - ret = label_repository_add(repository, "label07", 0x0555, 0x1b, NULL); - munit_assert_int(ret, !=, 0); - ret = label_repository_add(repository, "label08", 0x0557, 0x1b, NULL); - munit_assert_int(ret, !=, 0); - - ret = label_repository_size(repository); - munit_assert_int(ret, ==, 8); - - ret = label_repository_delete(repository, 0x04a0, 0x0556, 0x1b); - munit_assert_int(ret, !=, 0); - - ret = label_repository_size(repository); - munit_assert_int(ret, ==, 5); - - ret = label_repository_find(repository, 0x0557, 0x1b, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_add(repository, "label01", 0x0110, 0x1a, NULL)); + munit_assert_true(label_repository_add(repository, "label02", 0x0220, 0x1a, NULL)); + munit_assert_true(label_repository_add(repository, "label03", 0x0330, 0x1b, "description")); + munit_assert_true(label_repository_add(repository, "label04", 0x0440, 0x1a, NULL)); + munit_assert_true(label_repository_add(repository, "label05", 0x0550, 0x1b, NULL)); + munit_assert_true(label_repository_add(repository, "label06", 0x0553, 0x1b, NULL)); + munit_assert_true(label_repository_add(repository, "label07", 0x0555, 0x1b, NULL)); + munit_assert_true(label_repository_add(repository, "label08", 0x0557, 0x1b, NULL)); + + munit_assert_int(label_repository_size(repository), ==, 8); + + label_repository_delete(repository, 0x04a0, 0x0556, 0x1b); + + munit_assert_int(label_repository_size(repository), ==, 5); + + munit_assert_true(label_repository_find(repository, 0x0557, 0x1b, &label)); munit_assert_string_equal(label.name, "label08"); - ret = label_repository_find(repository, 0x0440, 0x1a, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0x0440, 0x1a, &label)); munit_assert_string_equal(label.name, "label04"); - ret = label_repository_find(repository, 0x0330, 0x1b, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0x0330, 0x1b, &label)); munit_assert_string_equal(label.name, "label03"); munit_assert_string_equal(label.description, "description"); - ret = label_repository_find(repository, 0x0220, 0x1a, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0x0220, 0x1a, &label)); munit_assert_string_equal(label.name, "label02"); - ret = label_repository_find(repository, 0x0110, 0x1a, &label); - munit_assert_int(ret, !=, 0); + munit_assert_true(label_repository_find(repository, 0x0110, 0x1a, &label)); munit_assert_string_equal(label.name, "label01"); - ret = label_repository_find(repository, 0x0555, 0x1b, &label); - munit_assert_int(ret, ==, 0); - ret = label_repository_find(repository, 0x0553, 0x1b, &label); - munit_assert_int(ret, ==, 0); - ret = label_repository_find(repository, 0x0550, 0x1b, &label); - munit_assert_int(ret, ==, 0); + munit_assert_false(label_repository_find(repository, 0x0555, 0x1b, &label)); + munit_assert_false(label_repository_find(repository, 0x0553, 0x1b, &label)); + munit_assert_false(label_repository_find(repository, 0x0550, 0x1b, &label)); label_repository_destroy(repository); return MUNIT_OK; } -static MunitTest label_tests[] = { +static MunitTest Labelests[] = { { "/add", label_add_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { "/delete", label_delete_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; static const MunitSuite label_suite = { - "Label test suite", label_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE + "Label test suite", Labelests, NULL, 1, MUNIT_SUITE_OPTION_NONE }; int main (int argc, char* const* argv) { From efec9a315fb0acbcf1d641c7fc0e5bc951dc90fd Mon Sep 17 00:00:00 2001 From: MooZ Date: Sat, 7 Sep 2024 23:24:44 +0200 Subject: [PATCH 13/35] Bring back comments (still have to work on loading) --- comment.c | 152 +++++++++++++++++++++++++------------------- comment.h | 135 ++++++++++++++++++--------------------- label.h | 2 +- test/CMakeLists.txt | 11 ++++ test/comment.c | 121 ++++++++++------------------------- 5 files changed, 194 insertions(+), 227 deletions(-) diff --git a/comment.c b/comment.c index 53dd907..49c8bda 100644 --- a/comment.c +++ b/comment.c @@ -41,23 +41,20 @@ #define COMMENT_ARRAY_INC 16 -/** - * Comment repository. - */ -struct comment_repository_impl { - size_t size; /**< Size of comment repository */ - size_t last; /**< Last element in the repository */ - comment_t *comments; /**< Comments */ +/// Comment repository. +struct CommentRepositoryImpl { + size_t size; //< Size of comment repository. + size_t last; //< Last element in the repository. + Comment *comments; //< Comments. }; -/** - * Get comment index by its address. - * \param [in] repository Coment repository. - * \param [in] logical Logical address. - * \param [in] page Memory page. - * \return comment index or -1 if the label was not found. - */ -static int comment_repository_index(comment_repository_t* repository, uint16_t logical, uint8_t page) { +/// Get comment index by its address. +/// \param [in] repository Coment repository. +/// \param [in] logical Logical address. +/// \param [in] page Memory page. +/// \return comment index. +/// \return -1 if the label was not found. +static int comment_repository_index(CommentRepository* repository, uint16_t logical, uint8_t page) { size_t i; for(i=0; ilast; i++) { if( (repository->comments[i].page == page) && @@ -68,10 +65,10 @@ static int comment_repository_index(comment_repository_t* repository, uint16_t l return -1; } -/* Create comment repository. */ -comment_repository_t* comment_repository_create() { - comment_repository_t *repository; - repository = (comment_repository_t*)malloc(sizeof(comment_repository_t)); +// Create comment repository. +CommentRepository* comment_repository_create() { + CommentRepository *repository; + repository = (CommentRepository*)malloc(sizeof(CommentRepository)); if(repository == NULL) { ERROR_MSG("Failed to create comment repository: %s", strerror(errno)); } else { @@ -79,7 +76,7 @@ comment_repository_t* comment_repository_create() { repository->comments = NULL; repository->size = COMMENT_ARRAY_INC; - repository->comments = (comment_t*)malloc(repository->size * sizeof(comment_t)); + repository->comments = (Comment*)malloc(repository->size * sizeof(Comment)); if(repository->comments == NULL) { ERROR_MSG("Failed to create comments: %s", strerror(errno)); comment_repository_destroy(repository); @@ -90,43 +87,48 @@ comment_repository_t* comment_repository_create() { return repository; } -/* Release comment repository resources. */ -void comment_repository_destroy(comment_repository_t* repository) { +// Release comment repository resources. +void comment_repository_destroy(CommentRepository* repository) { + assert(repository != NULL); + repository->size = 0; repository->last = 0; if(repository->comments != NULL) { - for(int i=0; ilast; i++) { - if(repository->comments[i].text) { - free(repository->comments[i].text); - } + for(size_t i=0; ilast; i++) { + free(repository->comments[i].text); } free(repository->comments); repository->comments = NULL; } } -/* Add comment to repository. */ -int comment_repository_add(comment_repository_t* repository, uint16_t logical, uint8_t page, const char *text) { - int ret = 1; +// Add comment to repository. +bool comment_repository_add(CommentRepository* repository, uint16_t logical, uint8_t page, const char *text) { + assert(repository != NULL); + assert(text != NULL); + + bool ret = true; int index = comment_repository_index(repository, logical, page); if(index >= 0) { WARNING_MSG("Duplicate comment for logical address $%04x in page $%02x", logical, page); } else { - /* Expand arrays if necessary */ + // Expand arrays if necessary. if(repository->last >= repository->size) { - comment_t *ptr; - repository->size += COMMENT_ARRAY_INC; - ptr = (comment_t*)realloc(repository->comments, repository->size * sizeof(comment_t)); + Comment *ptr; + size_t new_size = repository->size + COMMENT_ARRAY_INC; + ptr = (Comment*)realloc(repository->comments, new_size * sizeof(Comment)); if(ptr == NULL) { + ERROR_MSG("Failed to expand comment buffer: %s", strerror(errno)); comment_repository_destroy(repository); - ret = 0; + ret = false; } else { repository->comments = ptr; + repository->size = new_size; } } - if(ret != 0) { - /* Push addresses & text */ + if(ret) { + // Push addresses & text. repository->comments[repository->last].logical = logical; repository->comments[repository->last].page = page; repository->comments[repository->last].text = strdup(text); @@ -137,37 +139,47 @@ int comment_repository_add(comment_repository_t* repository, uint16_t logical, u return ret; } -/* Find a comment by its address. */ -int comment_repository_find(comment_repository_t* repository, uint16_t logical, uint8_t page, comment_t *out) { +// Find a comment by its address. +bool comment_repository_find(CommentRepository* repository, uint16_t logical, uint8_t page, Comment *out) { + assert(repository != NULL); + assert(out != NULL); + int index = comment_repository_index(repository, logical, page); - if(index < 0) { - memset(out, 0, sizeof(comment_t)); - return 0; + bool ret = (index >= 0); + if(ret) { + memcpy(out, &repository->comments[index], sizeof(Comment)); + } else { + memset(out, 0, sizeof(Comment)); } - memcpy(out, &repository->comments[index], sizeof(comment_t)); - return 1; + return ret; } -/* Get the number of comments stored in the repository. */ -int comment_repository_size(comment_repository_t* repository) { - return repository ? (int)repository->last : 0; +// Get the number of comments stored in the repository. +int comment_repository_size(CommentRepository* repository) { + assert(repository != NULL); + return (int)repository->last; } -/* Retrieve the comment at the specified index. */ -int comment_repository_get(comment_repository_t* repository, int index, comment_t *out) { - if((repository != NULL) && ((index >= 0) && (index < (int)repository->last))) { - memcpy(out, &repository->comments[index], sizeof(comment_t)); - return 1; +// Retrieve the comment at the specified index. +bool comment_repository_get(CommentRepository* repository, int index, Comment *out) { + assert(repository != NULL); + assert(out != NULL); + + bool ret = false; + if((index >= 0) && (index < (int)repository->last)) { + memcpy(out, &repository->comments[index], sizeof(Comment)); + ret = true; } else { - memset(out, 0, sizeof(comment_t)); - return 0; - } + memset(out, 0, sizeof(Comment)); + } + return ret; } -/* Delete comments. */ -int comment_repository_delete(comment_repository_t* repository, uint16_t first, uint16_t end, uint8_t page) { - size_t i; - for(i=0; ilast; i++) { +// Delete comments. +void comment_repository_delete(CommentRepository* repository, uint16_t first, uint16_t end, uint8_t page) { + assert(repository != NULL); + + for(size_t i=0; ilast; i++) { if( (repository->comments[i].page == page) && (repository->comments[i].logical >= first) && (repository->comments[i].logical < end) ) { @@ -176,27 +188,34 @@ int comment_repository_delete(comment_repository_t* repository, uint16_t first, if(repository->comments[i].text) { free(repository->comments[i].text); } - memcpy(&repository->comments[i], &repository->comments[repository->last], sizeof(comment_t)); + memcpy(&repository->comments[i], &repository->comments[repository->last], sizeof(Comment)); i--; } } } - return 1;} +} + +#if 0 +// [todo] move to comment/load +// Load comments from file. +bool comment_repository_load(CommentRepository* repository, const char* filename) { + assert(filename != NULL); + assert(repository != NULL); + + bool ret = false; -/* Load comments from file. */ -int comment_repository_load(const char* filename, comment_repository_t* repository) { json_t* root; json_error_t err; json_t* value; - int ret = 0, index = 0; + int index = 0; root = json_load_file(filename, 0, &err); if(!root) { ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); } else { if(!json_is_array(root)) { ERROR_MSG("Array expected."); - } else for (index = 0, ret = 1; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) { - ret = 0; + } else for (index = 0, ret = true; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) { + ret = false; if(!json_is_object(value)) { ERROR_MSG("Expected object."); } else { @@ -221,7 +240,7 @@ int comment_repository_load(const char* filename, comment_repository_t* reposito } else if((num < 0) || (num > 0xff)) { ERROR_MSG("Page value out of range."); } else if(comment_repository_add(repository, logical, (uint8_t)num, text)) { - ret = 1; + ret = true; } free(text); } @@ -232,3 +251,4 @@ int comment_repository_load(const char* filename, comment_repository_t* reposito } return ret; } +#endif \ No newline at end of file diff --git a/comment.h b/comment.h index 45e15e9..1087f52 100644 --- a/comment.h +++ b/comment.h @@ -38,80 +38,67 @@ #include "config.h" -/** - * Comment. - */ +/// Comment. typedef struct { - uint16_t logical; /**< Logical address */ - uint8_t page; /**< Memory page */ - char* text; /**< Comment text */ -} comment_t; - -typedef struct comment_repository_impl comment_repository_t; - -/** - * Create comment repository. - * \return A pointer to a comment repository or NULL if an error occured. - */ -comment_repository_t* comment_repository_create(); - -/** - * Release comment repository resources. - * \param [in,out] repository Comment repository. - */ -void comment_repository_destroy(comment_repository_t* repository); - -/** - * Add comment to repository. - * \param [in,out] repository Comment repository. - * \param [in] logical Logical address. - * \param [in] page Memory page. - * \param [in] text Comment text. - */ -int comment_repository_add(comment_repository_t* repository, uint16_t logical, uint8_t page, const char *text); - -/** - * Find a comment by its address. - * \param [in] repository Comment repository. - * \param [in] logical Logical address. - * \param [in] page Memory page. - * \param [out] out Associated comment (if any). - * \return 1 if a comment was found, 0 otherwise. - */ -int comment_repository_find(comment_repository_t* repository, uint16_t logical, uint8_t page, comment_t *out); - -/** - * Get the number of comments stored in the repository. - * \param [in] repository Comment repository. - * \return Comment count. - */ -int comment_repository_size(comment_repository_t* repository); - -/** - * Retrieve the comment at the specified index. - * \param [in] repository Comment repository. - * \param [in] index Comment index. - * \param [out] out Comment (if any). - * \return 1 if a comment exists for the specified index, 0 otherwise. - */ -int comment_repository_get(comment_repository_t* repository, int index, comment_t *out); - -/** - * Delete comments. - * \param [in] repository Comment repository. - * \param [in] first Start of the logical address range. - * \param [in] end End of the logical address range. - * \param [in] page Memory page. - */ -int comment_repository_delete(comment_repository_t* repository, uint16_t first, uint16_t end, uint8_t page); - -/** - * Load comments from file. - * \param [in] filename Input filename. - * \param [out] repository Comment repository. - * \return 1 if the comments contained in the file was succesfully added to the repository. - * 0 if an error occured. - */ -int comment_repository_load(const char* filename, comment_repository_t* repository); + uint16_t logical; //< Logical address. + uint8_t page; //< Memory page. + char* text; //< Comment text. +} Comment; + +typedef struct CommentRepositoryImpl CommentRepository; + +/// Create comment repository. +/// \return A pointer to a comment repository. +/// \return NULL if an error occured. +CommentRepository* comment_repository_create(); + +/// Release comment repository resources. +/// \param [in,out] repository Comment repository. +void comment_repository_destroy(CommentRepository* repository); + +/// Add comment to repository. +/// \param [in,out] repository Comment repository. +/// \param [in] logical Logical address. +/// \param [in] page Memory page. +/// \param [in] text Comment text. +/// \return true if the comment was successfully added to the repository. +/// \return false if an error occured. +bool comment_repository_add(CommentRepository* repository, uint16_t logical, uint8_t page, const char *text); + +/// Find a comment by its address. +/// \param [in] repository Comment repository. +/// \param [in] logical Logical address. +/// \param [in] page Memory page. +/// \param [out] out Associated comment (if any). +/// \return true if a comment was found. +/// \return 0 otherwise. +bool comment_repository_find(CommentRepository* repository, uint16_t logical, uint8_t page, Comment *out); + +/// Get the number of comments stored in the repository. +/// \param [in] repository Comment repository. +/// \return Comment count. +int comment_repository_size(CommentRepository* repository); + +/// Retrieve the comment at the specified index. +/// \param [in] repository Comment repository. +/// \param [in] index Comment index. +/// \param [out] out Comment (if any). +/// \return true if a comment exists for the specified index. +/// \return false otherwise. +bool comment_repository_get(CommentRepository* repository, int index, Comment *out); + +/// Delete comments. +/// \param [in] repository Comment repository. +/// \param [in] first Start of the logical address range. +/// \param [in] end End of the logical address range. +/// \param [in] page Memory page. +void comment_repository_delete(CommentRepository* repository, uint16_t first, uint16_t end, uint8_t page); + +/// Load comments from file. +/// \param [in] filename Input filename. +/// \param [out] repository Comment repository. +/// \return true if the comments contained in the file was succesfully added to the repository. +/// \return false if an error occured. +bool comment_repository_load(CommentRepository* repository, const char* filename); #endif // ETRIPATOR_COMMENT_H \ No newline at end of file diff --git a/label.h b/label.h index e785df1..86824cf 100644 --- a/label.h +++ b/label.h @@ -63,7 +63,7 @@ void label_repository_destroy(LabelRepository* repository); /// \param [in] logical Logical address. /// \param [in] page Memory page. /// \param [in] description Description (optional if name is set, mandatory otherwise). -/// \return true if the entry was successfully added in the repository. +/// \return true if the entry was successfully added to the repository. /// \return false if an error occured. bool label_repository_add(LabelRepository* repository, const char* name, uint16_t logical, uint8_t page, const char *description); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f706dda..64e40c6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -100,3 +100,14 @@ add_unit_test( LIBRARIES cwalk INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) + +add_unit_test( + NAME comment + SOURCES + comment.c + ${PROJECT_SOURCE_DIR}/comment.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) diff --git a/test/comment.c b/test/comment.c index 0c39627..550ca80 100644 --- a/test/comment.c +++ b/test/comment.c @@ -37,118 +37,67 @@ #include "comment.h" #include "message.h" #include "message/console.h" -#include "message/file.h" -void* setup(const MunitParameter params[], void* user_data) { - (void) params; - (void) user_data; - - console_msg_printer_t *printer = (console_msg_printer_t*)malloc(sizeof(console_msg_printer_t)); - - msg_printer_init(); - console_msg_printer_init(printer); - msg_printer_add((msg_printer_t*)printer); - - return (void*)printer; +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + message_printer_init(); + console_message_printer_init(); + return NULL; } -void tear_down(void* fixture) { - msg_printer_destroy(); - free(fixture); +void tear_down(void* fixture __attribute__((unused))) { + message_printer_destroy(); } -MunitResult comment_add_test(const MunitParameter params[], void* fixture) { - (void)params; - (void)fixture; - - int ret; - comment_t comment; - comment_repository_t *repository; - - repository = comment_repository_create(); +MunitResult comment_add_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + Comment comment = {0}; + CommentRepository *repository = comment_repository_create(); munit_assert_not_null(repository); - ret = comment_repository_add(repository, 0x0002, 0x00, "comment #0"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0001, 0x00, "comment #1"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0003, 0x00, "comment #3"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0001, 0x01, "comment #2"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_find(repository, 0x0001, 0x01, &comment); - munit_assert_int(ret, !=, 0); + munit_assert_true(comment_repository_add(repository, 0x0002, 0x00, "comment #0")); + munit_assert_true(comment_repository_add(repository, 0x0001, 0x00, "comment #1")); + munit_assert_true(comment_repository_add(repository, 0x0003, 0x00, "comment #3")); + munit_assert_true(comment_repository_add(repository, 0x0001, 0x01, "comment #2")); + + munit_assert_true(comment_repository_find(repository, 0x0001, 0x01, &comment)); munit_assert_int(comment.logical, ==, 0x0001); - munit_assert_int(comment.page, ==, 0x01); + munit_assert_int(comment.page, ==, 0x01); munit_assert_string_equal(comment.text, "comment #2"); - ret = comment_repository_find(repository, 0x0001, 0x00, &comment); - munit_assert_int(ret, !=, 0); + munit_assert_true(comment_repository_find(repository, 0x0001, 0x00, &comment)); munit_assert_int(comment.logical, ==, 0x0001); - munit_assert_int(comment.page, ==, 0x00); + munit_assert_int(comment.page, ==, 0x00); munit_assert_string_equal(comment.text, "comment #1"); - ret = comment_repository_find(repository, 0x0003, 0x00, &comment); - munit_assert_int(ret, !=, 0); + munit_assert_true(comment_repository_find(repository, 0x0003, 0x00, &comment)); munit_assert_int(comment.logical, ==, 0x0003); - munit_assert_int(comment.page, ==, 0x00); + munit_assert_int(comment.page, ==, 0x00); munit_assert_string_equal(comment.text, "comment #3"); - ret = comment_repository_size(repository); - munit_assert_int(ret, ==, 4); + munit_assert_int(comment_repository_size(repository), ==, 4); comment_repository_destroy(repository); return MUNIT_OK; } -MunitResult comment_delete_test(const MunitParameter params[], void* fixture) { - (void)params; - (void)fixture; - - int ret; - comment_t comment; - comment_repository_t *repository; - - repository = comment_repository_create(); +MunitResult comment_delete_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + Comment comment = {0}; + CommentRepository *repository = comment_repository_create(); munit_assert_not_null(repository); - ret = comment_repository_add(repository, 0x0002, 0x03, "comment #7"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0002, 0x01, "comment #6"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0002, 0x02, "comment #5"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x000a, 0x00, "comment #4"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0008, 0x00, "comment #3"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0004, 0x00, "comment #2"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0002, 0x00, "comment #1"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_add(repository, 0x0000, 0x00, "comment #0"); - munit_assert_int(ret, !=, 0); - - ret = comment_repository_size(repository); - munit_assert_int(ret, ==, 8); + munit_assert_true(comment_repository_add(repository, 0x0002, 0x03, "comment #7")); + munit_assert_true(comment_repository_add(repository, 0x0002, 0x01, "comment #6")); + munit_assert_true(comment_repository_add(repository, 0x0002, 0x02, "comment #5")); + munit_assert_true(comment_repository_add(repository, 0x000a, 0x00, "comment #4")); + munit_assert_true(comment_repository_add(repository, 0x0008, 0x00, "comment #3")); + munit_assert_true(comment_repository_add(repository, 0x0004, 0x00, "comment #2")); + munit_assert_true(comment_repository_add(repository, 0x0002, 0x00, "comment #1")); + munit_assert_true(comment_repository_add(repository, 0x0000, 0x00, "comment #0")); + munit_assert_int(comment_repository_size(repository), ==, 8); - ret = comment_repository_delete(repository, 0x0001, 0x0009, 0x00); - munit_assert_int(ret, !=, 0); + comment_repository_delete(repository, 0x0001, 0x0009, 0x00); - ret = comment_repository_size(repository); - munit_assert_int(ret, ==, 5); + munit_assert_int(comment_repository_size(repository), ==, 5); comment_repository_destroy(repository); From 37b7ba1c0878afb7615d8a4ce87647eec8082cf5 Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 8 Sep 2024 14:44:38 +0200 Subject: [PATCH 14/35] Add comment repository load & save --- comment.c | 58 ------------------------- comment.h | 9 +++- comment/load.c | 94 ++++++++++++++++++++++++++++++++++++++++ comment/save.c | 91 ++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 5 ++- test/comment.c | 41 +++++++++++++++--- test/data/comment_0.json | 9 ++++ test/data/comment_1.json | 4 ++ 8 files changed, 245 insertions(+), 66 deletions(-) create mode 100644 comment/load.c create mode 100644 comment/save.c create mode 100644 test/data/comment_0.json create mode 100644 test/data/comment_1.json diff --git a/comment.c b/comment.c index 49c8bda..4b3b3fa 100644 --- a/comment.c +++ b/comment.c @@ -194,61 +194,3 @@ void comment_repository_delete(CommentRepository* repository, uint16_t first, ui } } } - -#if 0 -// [todo] move to comment/load -// Load comments from file. -bool comment_repository_load(CommentRepository* repository, const char* filename) { - assert(filename != NULL); - assert(repository != NULL); - - bool ret = false; - - json_t* root; - json_error_t err; - json_t* value; - int index = 0; - root = json_load_file(filename, 0, &err); - if(!root) { - ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); - } else { - if(!json_is_array(root)) { - ERROR_MSG("Array expected."); - } else for (index = 0, ret = true; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) { - ret = false; - if(!json_is_object(value)) { - ERROR_MSG("Expected object."); - } else { - int num; - // logical - json_t *tmp = json_object_get(value, "logical"); - if(!json_validate_int(tmp, &num)) { - ERROR_MSG("Invalid or missing logical address."); - } else if((num < 0) || (num > 0xffff)) { - ERROR_MSG("Logical address out of range."); - } else { - uint16_t logical = (uint16_t)num; - // page - tmp = json_object_get(value, "page"); - if(!json_validate_int(tmp, &num)) { - ERROR_MSG("Invalid or missing page."); - } else { - // text (same format as section/label description) - char* text = json_load_description(value, "text"); - if(text == NULL) { - ERROR_MSG("Invalid or missing text."); - } else if((num < 0) || (num > 0xff)) { - ERROR_MSG("Page value out of range."); - } else if(comment_repository_add(repository, logical, (uint8_t)num, text)) { - ret = true; - } - free(text); - } - } - } - } - json_decref(root); - } - return ret; -} -#endif \ No newline at end of file diff --git a/comment.h b/comment.h index 1087f52..1cb7be5 100644 --- a/comment.h +++ b/comment.h @@ -95,10 +95,17 @@ bool comment_repository_get(CommentRepository* repository, int index, Comment *o void comment_repository_delete(CommentRepository* repository, uint16_t first, uint16_t end, uint8_t page); /// Load comments from file. +/// \param [in, out] repository Comment repository. /// \param [in] filename Input filename. -/// \param [out] repository Comment repository. /// \return true if the comments contained in the file was succesfully added to the repository. /// \return false if an error occured. bool comment_repository_load(CommentRepository* repository, const char* filename); +/// Save comments to file. +/// \param [in] repository Comment repository. +/// \param [in] filename Output filename. +/// \return true if the comments were succesfully saved. +/// \return false if an error occured. +bool comment_repository_save(CommentRepository* repository, const char* filename); + #endif // ETRIPATOR_COMMENT_H \ No newline at end of file diff --git a/comment/load.c b/comment/load.c new file mode 100644 index 0000000..710332a --- /dev/null +++ b/comment/load.c @@ -0,0 +1,94 @@ +/* +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + __/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__ + \_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2023 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include +#include "../message.h" +#include "../jsonhelpers.h" +#include "../comment.h" + +// Load comments from file. +bool comment_repository_load(CommentRepository* repository, const char* filename) { + assert(filename != NULL); + assert(repository != NULL); + + bool ret = false; + + json_t* root; + json_error_t err; + json_t* value; + int index = 0; + root = json_load_file(filename, 0, &err); + if(!root) { + ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); + } else { + if(!json_is_array(root)) { + ERROR_MSG("Array expected."); + } else for (index = 0, ret = true; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) { + ret = false; + if(!json_is_object(value)) { + ERROR_MSG("Expected object."); + } else { + int num; + // logical + json_t *tmp = json_object_get(value, "logical"); + if(!json_validate_int(tmp, &num)) { + ERROR_MSG("Invalid or missing logical address."); + } else if((num < 0) || (num > 0xffff)) { + ERROR_MSG("Logical address out of range."); + } else { + uint16_t logical = (uint16_t)num; + // page + tmp = json_object_get(value, "page"); + if(!json_validate_int(tmp, &num)) { + ERROR_MSG("Invalid or missing page."); + } else { + // text (same format as section/label description) + char* text = json_load_description (value, "text"); + if(text == NULL) { + ERROR_MSG("Invalid or missing text."); + } else if((num < 0) || (num > 0xFF)) { + ERROR_MSG("Page value out of range."); + } else if(comment_repository_add(repository, logical, (uint8_t)num, text)) { + ret = true; + } + free(text); + } + } + } + } + json_decref(root); + } + return ret; +} diff --git a/comment/save.c b/comment/save.c new file mode 100644 index 0000000..4b63db0 --- /dev/null +++ b/comment/save.c @@ -0,0 +1,91 @@ +/* +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + __/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__ + \_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2023 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include +#include + +#include "../message.h" +#include "../jsonhelpers.h" +#include "../comment.h" + +// Save comments to file. +bool comment_repository_save(CommentRepository* repository, const char* filename) { + assert(filename != NULL); + assert(repository != NULL); + + bool ret = false; + + int i, count = comment_repository_size(repository); + FILE *stream = fopen(filename, "wb"); + if(stream == NULL) { + ERROR_MSG("Failed to open %s: %s", filename, strerror(errno)); + } else { + fprintf(stream, "[\n"); + for(i=0; i Date: Sun, 8 Sep 2024 14:52:54 +0200 Subject: [PATCH 15/35] Fix build --- .github/workflows/build.yml | 17 +++++++---------- test/comment.c | 9 ++++++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 500be77..8bc7896 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,21 +17,18 @@ jobs: - name: Setup Dependencies run: | sudo apt install -y -qq libjansson-dev - - - name: Create Build Environment - run: cmake -E make_directory ${{github.workspace}}/build - - name: Configure CMake + - name: Configure shell: bash - working-directory: ${{github.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + working-directory: ${{github.workspace}} + run: cmake -Bbuild -S . -DCMAKE_BUILD_TYPE=$BUILD_TYPE - name: Build - working-directory: ${{github.workspace}}/build + working-directory: ${{github.workspace}} shell: bash - run: cmake --build . --config $BUILD_TYPE + run: cmake --build ./build --config $BUILD_TYPE - name: Test - working-directory: ${{github.workspace}}/build + working-directory: ${{github.workspace}} shell: bash - run: ctest -C $BUILD_TYPE + run: cmake --build ./build --target test diff --git a/test/comment.c b/test/comment.c index 352712c..b73a1f8 100644 --- a/test/comment.c +++ b/test/comment.c @@ -112,7 +112,14 @@ MunitResult comment_load_test(const MunitParameter params[] __attribute__((unuse munit_assert_int(comment_repository_size(repository), ==, 0); munit_assert_false(comment_repository_load(repository, "data/comment_1.json")); - munit_assert_int(comment_repository_size(repository), ==, 0); + munit_assert_int(comment_repository_size(repository), ==, 1); + + munit_assert_true(comment_repository_get(repository, 0, &comment)); + munit_assert_uint16(comment.logical, ==, 0xCAFEU); + munit_assert_uint8(comment.page, ==, 0x0AU); + munit_assert_string_equal(comment.text, "hello!"); + + comment_repository_destroy(repository); munit_assert_true(comment_repository_load(repository, "data/comment_0.json")); munit_assert_int(comment_repository_size(repository), ==, 2); From e144f571a5daf938ce86b869ee4dc3279fb745ba Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 8 Sep 2024 15:18:10 +0200 Subject: [PATCH 16/35] Update checkout version --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8bc7896..21cb6b3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: 'recursive' From 30591e37e69754745069efd1cbe34dc862f58397 Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 8 Sep 2024 15:58:47 +0200 Subject: [PATCH 17/35] Test label loading --- label/load.c | 28 +++++++++++----------- test/CMakeLists.txt | 4 +++- test/data/label_0.json | 11 +++++++++ test/data/label_1.json | 4 ++++ test/label.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 test/data/label_0.json create mode 100644 test/data/label_1.json diff --git a/label/load.c b/label/load.c index 990daba..eb4cc38 100644 --- a/label/load.c +++ b/label/load.c @@ -40,25 +40,23 @@ #define MAX_LABEL_NAME 128 -/** - * Load labels from file. - * \param [in] filename Input filename. - * \param [out] repository Label repository. - * \return 1 if the labels contained in the file were succesfully added to the repository. - * 0 if an error occured. - */ -int label_repository_load(const char* filename, label_repository_t* repository) { - json_t* root; +// Load labels from file. +bool label_repository_load(LabelRepository* repository, const char* filename) { + assert(repository != NULL); + assert(filename != NULL); + + bool ret = false; + json_error_t err; - json_t* value; - int ret = 0, index = 0; - root = json_load_file(filename, 0, &err); + json_t* root = json_load_file(filename, 0, &err); if(!root) { ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); } else { + json_t* value = NULL; + int index = 0; if(!json_is_array(root)) { ERROR_MSG("Array expected."); - } else for (index = 0, ret = 1; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) { + } else for (index = 0, ret = true; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) { ret = 0; if(!json_is_object(value)) { ERROR_MSG("Expected object."); @@ -74,7 +72,7 @@ int label_repository_load(const char* filename, label_repository_t* repository) tmp = json_object_get(value, "logical"); if(!json_validate_int(tmp, &num)) { ERROR_MSG("Invalid or missing logical address."); - } else if((num < 0) || (num > 0xffff)) { + } else if((num < 0) || (num > 0xFFFF)) { ERROR_MSG("Logical address out of range."); } else { uint16_t logical = (uint16_t)num; @@ -88,7 +86,7 @@ int label_repository_load(const char* filename, label_repository_t* repository) if((num < 0) || (num > 0xff)) { ERROR_MSG("Page value out of range."); } else if(label_repository_add(repository, key, logical, (uint8_t)num, description)) { - ret = 1; + ret = true; } free(description); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6f8fee7..5fc3b3e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -95,9 +95,11 @@ add_unit_test( SOURCES label.c ${PROJECT_SOURCE_DIR}/label.c + ${PROJECT_SOURCE_DIR}/label/load.c ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/jsonhelpers.c ${PROJECT_SOURCE_DIR}/message/console.c - LIBRARIES cwalk + LIBRARIES cwalk jansson INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) diff --git a/test/data/label_0.json b/test/data/label_0.json new file mode 100644 index 0000000..8055286 --- /dev/null +++ b/test/data/label_0.json @@ -0,0 +1,11 @@ +[ + { "name": "var", "logical": "31dc", "page": "f8" }, + { "name": "do_something", "logical": "eabc", "page": "00", "description": "do something" }, + { "name": "run", "logical" : "d6f7", "page": "1f", "description": [ + "line0", + "line1", + "line2", + "line3" + ] + } +] \ No newline at end of file diff --git a/test/data/label_1.json b/test/data/label_1.json new file mode 100644 index 0000000..b0770a0 --- /dev/null +++ b/test/data/label_1.json @@ -0,0 +1,4 @@ +[ + { "name": "ok", "logical": "5030", "page": "04" }, + { "name": "broken", "logical": "cafe", "page": ["5a"], "description": "!" } +] \ No newline at end of file diff --git a/test/label.c b/test/label.c index 1d47d4c..2480239 100644 --- a/test/label.c +++ b/test/label.c @@ -121,9 +121,62 @@ MunitResult label_delete_test(const MunitParameter params[] __attribute__((unuse return MUNIT_OK; } +MunitResult label_load_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + Label label = {}; + LabelRepository* repository = label_repository_create(); + munit_assert_not_null(repository); + + munit_assert_false(label_repository_load(repository, "/not_here/label.json")); + munit_assert_int(label_repository_size(repository), ==, 0); + + munit_assert_false(label_repository_load(repository, "data/label_1.json")); + munit_assert_int(label_repository_size(repository), ==, 1); + + munit_assert_true(label_repository_get(repository, 0, &label)); + munit_assert_uint16(label.logical, ==, 0x5030U); + munit_assert_uint8(label.page, ==, 4); + munit_assert_string_equal(label.name, "ok"); + munit_assert_null(label.description); + + label_repository_destroy(repository); + + munit_assert_true(label_repository_load(repository, "data/label_0.json")); + munit_assert_int(label_repository_size(repository), ==, 3); + + munit_assert_true(label_repository_find(repository, 0x31DC, 0xF8, &label)); + munit_assert_uint16(label.logical, ==, 0x31DCU); + munit_assert_uint8(label.page, ==, 0xF8); + munit_assert_string_equal(label.name, "var"); + munit_assert_null(label.description); + + munit_assert_true(label_repository_find(repository, 0xEABC, 0x00, &label)); + munit_assert_uint16(label.logical, ==, 0xEABCU); + munit_assert_uint8(label.page, ==, 0x00); + munit_assert_string_equal(label.name, "do_something"); + munit_assert_string_equal(label.description, "do something"); + + munit_assert_true(label_repository_find(repository, 0xD6F7, 0x1F, &label)); + munit_assert_uint16(label.logical, ==, 0xD6F7U); + munit_assert_uint8(label.page, ==, 0x1F); + munit_assert_string_equal(label.name, "run"); + munit_assert_string_equal(label.description, "line0\nline1\nline2\nline3"); + + label_repository_destroy(repository); + + return MUNIT_OK; +} + +MunitResult label_save_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + // [todo] + return MUNIT_OK; +} + + static MunitTest Labelests[] = { { "/add", label_add_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { "/delete", label_delete_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/load", label_load_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/save", label_save_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; From 15ebcba47eef8f56e112a11823bb187817964b39 Mon Sep 17 00:00:00 2001 From: MooZ Date: Sat, 12 Oct 2024 19:40:27 +0200 Subject: [PATCH 18/35] WIP --- comment/load.c | 8 +- comment/save.c | 4 +- irq.c | 92 ++++---- irq.h | 41 +++- jsonhelpers.c | 70 +++--- jsonhelpers.h | 4 +- label/load.c | 6 +- label/save.c | 37 ++-- opcodes.c | 562 ++++++++++++++++++++++++------------------------- opcodes.h | 95 ++++----- 10 files changed, 487 insertions(+), 432 deletions(-) diff --git a/comment/load.c b/comment/load.c index 710332a..a1687be 100644 --- a/comment/load.c +++ b/comment/load.c @@ -75,9 +75,11 @@ bool comment_repository_load(CommentRepository* repository, const char* filename ERROR_MSG("Invalid or missing page."); } else { // text (same format as section/label description) - char* text = json_load_description (value, "text"); - if(text == NULL) { - ERROR_MSG("Invalid or missing text."); + char* text = NULL; + if(json_load_description (value, "text", &text) != true) { + ERROR_MSG("Faile to retrieve text."); + } else if(text == NULL) { + ERROR_MSG("Empty text string"); } else if((num < 0) || (num > 0xFF)) { ERROR_MSG("Page value out of range."); } else if(comment_repository_add(repository, logical, (uint8_t)num, text)) { diff --git a/comment/save.c b/comment/save.c index 4b63db0..6a261bb 100644 --- a/comment/save.c +++ b/comment/save.c @@ -47,13 +47,13 @@ bool comment_repository_save(CommentRepository* repository, const char* filename bool ret = false; - int i, count = comment_repository_size(repository); FILE *stream = fopen(filename, "wb"); if(stream == NULL) { ERROR_MSG("Failed to open %s: %s", filename, strerror(errno)); } else { + int count = comment_repository_size(repository); fprintf(stream, "[\n"); - for(i=0; imemory[PCE_MEMORY_ROM].data == NULL) { + ERROR_MSG("No ROM in memory map."); + } else if(map->memory[PCE_MEMORY_ROM].length < (PCE_IRQ_TABLE + PCE_IRQ_COUNT)) { + ERROR_MSG("ROM is abnormally small."); + } else { + Section *tmp = (Section*)realloc(*section, (*count+PCE_IRQ_COUNT) * sizeof(Section)); + if(tmp == NULL) { + ERROR_MSG("Failed to allocate extra IRQ sections."); + } else { + int j = *count; + *section = tmp; + *count += PCE_IRQ_COUNT; + + for(size_t i=0; i struct (opaque pointer) +status_code: + ERROR + OK +*/ + +/// Get irq code offsets from rom. +/// \param [in] map Memory map. +/// \param [out] section Section list. +/// \return true if the IRQ vectors where successfully extradcted. +/// \return false otherwise (missing ROM, or offsets out of range). +bool irq_read(MemoryMap* map, Section *section); #endif // ETRIPATOR_IRQ_H diff --git a/jsonhelpers.c b/jsonhelpers.c index e28d261..9c96f91 100644 --- a/jsonhelpers.c +++ b/jsonhelpers.c @@ -38,8 +38,10 @@ #include #include -int json_validate_int(const json_t* obj, int* out) { - int ret = 0; +bool json_validate_int(const json_t* obj, int* out) { + assert(obj != NULL); + assert(out != NULL); + bool ret = false; if(json_is_string(obj)) { const char *str = json_string_value(obj); for(; (*str!='\0') && isspace(*str); str++) { @@ -50,44 +52,62 @@ int json_validate_int(const json_t* obj, int* out) { errno = 0; *out = strtoul(str, NULL, 16); if(errno == 0) { - ret = 1; + ret = true; } } else if(json_is_integer(obj)) { *out = (int)json_integer_value(obj); - ret = 1; + ret = true; } return ret; } -char* json_load_description(const json_t* obj, const char *key) { - json_t *tmp = json_object_get(obj, key); - char *out = NULL; - if(json_is_string(tmp)) { - out = strdup(json_string_value(tmp)); - } else if (json_is_array(tmp)) { - int index; - json_t* value; +bool json_load_description(const json_t* obj, const char *key, char **out) { + assert(out != NULL); + assert(out && (*out == NULL)); - size_t len = 0; - json_array_foreach(tmp, index, value) { - if(json_is_string(value)) { - const char *str = json_string_value(value); - if(out) { - out[len-1] = '\n'; + bool ret = false; + char *buffer = NULL; + json_t *tmp = json_object_get(obj, key); + + if(tmp == NULL) { + ret = true; + } else { + if(json_is_string(tmp)) { + buffer = strdup(json_string_value(tmp)); + } else if (json_is_array(tmp)) { + int index; + json_t* value; + size_t len = 0; + json_array_foreach(tmp, index, value) { + if(json_is_string(value)) { + const char *str = json_string_value(value); + if(buffer != NULL) { + buffer[len-1] = '\n'; + } + size_t n = len + strlen(str) + 1; + char *ptr = realloc(buffer, n); + if(ptr == NULL) { + free(buffer); + buffer = NULL; + break; + } + memcpy(ptr+len, str, strlen(str)); + ptr[n-1] = '\0'; + buffer = ptr; + len = n; } - size_t n = len + strlen(str) + 1; - char *ptr = realloc(out, n); - memcpy(ptr+len, str, strlen(str)); - ptr[n-1] = '\0'; - out = ptr; - len = n; } } + ret = (buffer != NULL); } - return out; + *out = buffer; + return ret; } void json_print_description(FILE *out, const char *key, const char *str) { + assert(out != NULL); + assert(key != NULL); + assert(str != NULL); fprintf(out, "\"%s\":[", key); while(*str) { fprintf(out, "\n\t\t\t\""); diff --git a/jsonhelpers.h b/jsonhelpers.h index b8d5e45..c1af5c7 100644 --- a/jsonhelpers.h +++ b/jsonhelpers.h @@ -40,8 +40,8 @@ #include -int json_validate_int(const json_t* obj, int* out); -char* json_load_description(const json_t* obj, const char *key); +bool json_validate_int(const json_t* obj, int* out); +bool json_load_description(const json_t* obj, const char *key, char **out); void json_print_description(FILE *out, const char *key, const char *str); #endif // ETRIPATOR_JSON_HELPERS_H \ No newline at end of file diff --git a/label/load.c b/label/load.c index eb4cc38..687f83e 100644 --- a/label/load.c +++ b/label/load.c @@ -82,8 +82,10 @@ bool label_repository_load(LabelRepository* repository, const char* filename) { ERROR_MSG("Invalid or missing page."); } else { // description - char* description = json_load_description(value, "description"); - if((num < 0) || (num > 0xff)) { + char* description = NULL; + if(json_load_description(value, "description", &description) != true) { + ERROR_MSG("Failed to load label description"); + } else if((num < 0) || (num > 0xff)) { ERROR_MSG("Page value out of range."); } else if(label_repository_add(repository, key, logical, (uint8_t)num, description)) { ret = true; diff --git a/label/save.c b/label/save.c index 0d91b47..49b5448 100644 --- a/label/save.c +++ b/label/save.c @@ -40,27 +40,30 @@ #include "../jsonhelpers.h" #include "../label.h" -/* Save labels to file. */ -int label_repository_save(const char* filename, label_repository_t* repository) { +// Save labels to file +bool label_repository_save(LabelRepository* repository, const char* filename) { + bool ret = false; FILE *stream = fopen(filename, "wb"); - int i, count = label_repository_size(repository); if(stream == NULL) { ERROR_MSG("Failed to open %s: %s", filename, strerror(errno)); - return 0; - } - fprintf(stream, "[\n"); - for(i=0; i= PCE_ARG_COUNT)) { return NULL; @@ -342,29 +338,25 @@ const char* opcode_format(const opcode_t *op, int i) { return pce_opstring[op->type][i]; } -/** - * Is the instruction a local jump ? - */ -int opcode_is_local_jump(uint8_t op) { +// Is the instruction a local jump ? +bool opcode_is_local_jump(uint8_t op) { return - ((op & 0x0F) == 0x0F) || /* BBR* and BBS* */ - (op == 0x90) || /* BCC */ - (op == 0xB0) || /* BCS */ - (op == 0x80) || /* BRA */ - (op == 0xF0) || /* BEQ */ - (op == 0x30) || /* BMI */ - (op == 0xD0) || /* BNE */ - (op == 0x10) || /* BPL */ - (op == 0x44) || /* BSR */ - (op == 0x50) || /* BVC */ - (op == 0x70); /* BVS */ + ((op & 0x0F) == 0x0F) || // BBR* and BBS* + (op == 0x90) || // BCC + (op == 0xB0) || // BCS + (op == 0x80) || // BRA + (op == 0xF0) || // BEQ + (op == 0x30) || // BMI + (op == 0xD0) || // BNE + (op == 0x10) || // BPL + (op == 0x44) || // BSR + (op == 0x50) || // BVC + (op == 0x70); // BVS } -/** - * Is the instruction a "far" jump ? - */ -int opcode_is_far_jump(uint8_t op) { +// Is the instruction a "far" jump ? +bool opcode_is_far_jump(uint8_t op) { return - (op == 0x4C) || /* JMP */ - (op == 0x20); /* JSR */ + (op == 0x4C) || // JMP + (op == 0x20); // JSR } diff --git a/opcodes.h b/opcodes.h index 9b04340..128fee4 100644 --- a/opcodes.h +++ b/opcodes.h @@ -38,32 +38,33 @@ #include "config.h" -/** - * Opcode types: - * -# `OPC` - * -# `OPC A` - * -# `OPC #nn` - * -# `OPC #nn, ZZ` - * -# `OPC #nn, ZZ, X` - * -# `OPC #nn, hhll` - * -# `OPC #nn, hhll, X` - * -# `OPC ZZ` - * -# `OPC ZZ, X` - * -# `OPC ZZ, Y` - * -# `OPC (ZZ)` - * -# `OPC (ZZ, X)` - * -# `OPC (ZZ), Y` - * -# `OPC ZZ, hhll` - * -# `OPC hhll` - * -# `OPC (hhll)` - * -# `OPC hhll, X` - * -# `OPC hhll, Y` - * -# `OPC shsl,dhdl,hhll` - * -# `OPC l_hhll` (label) - * -# `OPC ZZ, l_hhll` (label) - * -# `OPC [hhll, X]` - * -# `.db OPC` (unsupported opcode output as raw binary data) - */ +/// @defgroup Opcode Opcode +///@{ + +/// Opcode types: +/// -# `OPC` +/// -# `OPC A` +/// -# `OPC #nn` +/// -# `OPC #nn, ZZ` +/// -# `OPC #nn, ZZ, X` +/// -# `OPC #nn, hhll` +/// -# `OPC #nn, hhll, X` +/// -# `OPC ZZ` +/// -# `OPC ZZ, X` +/// -# `OPC ZZ, Y` +/// -# `OPC (ZZ)` +/// -# `OPC (ZZ, X)` +/// -# `OPC (ZZ), Y` +/// -# `OPC ZZ, hhll` +/// -# `OPC hhll` +/// -# `OPC (hhll)` +/// -# `OPC hhll, X` +/// -# `OPC hhll, Y` +/// -# `OPC shsl,dhdl,hhll` +/// -# `OPC l_hhll` (label) +/// -# `OPC ZZ, l_hhll` (label) +/// -# `OPC [hhll, X]` +/// -# `.db OPC` (unsupported opcode output as raw binary data) enum PCE_ADDRESSING_MODE { PCE_OP = 0, PCE_OP_A, @@ -90,33 +91,33 @@ enum PCE_ADDRESSING_MODE { PCE_unknown }; -/** - * Opcode - */ +#define OPCODE_NAME_MAX_LEN 5U + +/// Opcode typedef struct { - char name[5]; /**< name. **/ - uint8_t size; /**< size in bytes. **/ - uint8_t type; /**< addressing type. **/ -} opcode_t; + char name[OPCODE_NAME_MAX_LEN]; //< name + uint8_t size; //< size in bytes + uint8_t type; //< addressing type +} Opcode; -/** - * Get opcode description. - */ +/// Get opcode description +/// \param [in] op Opcode id +/// \return Pointer to opcode description const opcode_t* opcode_get(uint8_t op); -/** - * - */ +/// Get opcode format string +/// \param [in] op Pointer to opcode description +/// \param [in] i Opcode argument id +/// \return Argument format string +/// \return NULL if the argument id is out of opcode argument count const char* opcode_format(const opcode_t *op, int i); -/** - * Is the instruction a local jump ? - */ -int opcode_is_local_jump(uint8_t op); +/// Is the instruction a local jump ? +bool opcode_is_local_jump(uint8_t op); + +/// Is the instruction a "far" jump ? +bool opcode_is_far_jump(uint8_t op); -/** - * Is the instruction a "far" jump ? - */ -int opcode_is_far_jump(uint8_t op); +/// @} #endif // ETRIPATOR_OPCODES_H From c4c7cd5087fc85d793c313c264343a589123ae9d Mon Sep 17 00:00:00 2001 From: MooZ Date: Sat, 12 Oct 2024 23:05:32 +0200 Subject: [PATCH 19/35] Rework section Update copyright year --- cd.c | 2 +- cd.h | 2 +- cli/etripator.c | 2 +- cli/options.c | 2 +- cli/options.h | 2 +- comment.c | 2 +- comment.h | 2 +- comment/load.c | 2 +- comment/save.c | 2 +- config.h | 2 +- decode.c | 2 +- decode.h | 2 +- examples/youkai_douchuuki/password.c | 2 +- ipl.c | 2 +- ipl.h | 2 +- irq.c | 2 +- irq.h | 2 +- jsonhelpers.c | 2 +- jsonhelpers.h | 2 +- label.c | 2 +- label.h | 2 +- label/load.c | 2 +- label/save.c | 2 +- memory.c | 2 +- memory.h | 2 +- memory_map.c | 2 +- memory_map.h | 2 +- message.c | 2 +- message.h | 2 +- message/console.c | 2 +- message/console.h | 2 +- message/file.c | 2 +- message/file.h | 2 +- opcodes.c | 2 +- opcodes.h | 2 +- rom.c | 2 +- rom.h | 2 +- section.c | 84 +++--- section.h | 245 +++++----------- section/load.c | 405 +++++++++++++++++---------- section/save.c | 2 +- test/CMakeLists.txt | 15 + test/cd.c | 2 +- test/comment.c | 2 +- test/label.c | 2 +- test/memory.c | 2 +- test/memory_map.c | 2 +- test/message.c | 2 +- test/rom.c | 2 +- test/section.c | 2 +- 50 files changed, 430 insertions(+), 411 deletions(-) diff --git a/cd.c b/cd.c index 92560e0..88542f2 100644 --- a/cd.c +++ b/cd.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/cd.h b/cd.h index 15b4636..67fdc2c 100644 --- a/cd.h +++ b/cd.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/cli/etripator.c b/cli/etripator.c index 52fad01..19c4e93 100644 --- a/cli/etripator.c +++ b/cli/etripator.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/cli/options.c b/cli/options.c index 6bae600..e7b2c58 100644 --- a/cli/options.c +++ b/cli/options.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/cli/options.h b/cli/options.h index 48fdc70..6517c90 100644 --- a/cli/options.h +++ b/cli/options.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/comment.c b/comment.c index 4b3b3fa..9bc6d61 100644 --- a/comment.c +++ b/comment.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/comment.h b/comment.h index 1cb7be5..7fca303 100644 --- a/comment.h +++ b/comment.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/comment/load.c b/comment/load.c index a1687be..0f3d7a6 100644 --- a/comment/load.c +++ b/comment/load.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/comment/save.c b/comment/save.c index 6a261bb..3b62a45 100644 --- a/comment/save.c +++ b/comment/save.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/config.h b/config.h index 8a91251..c9f6f46 100644 --- a/config.h +++ b/config.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/decode.c b/decode.c index af69d38..9823cfa 100644 --- a/decode.c +++ b/decode.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/decode.h b/decode.h index 0791ce1..a1e923b 100644 --- a/decode.h +++ b/decode.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/examples/youkai_douchuuki/password.c b/examples/youkai_douchuuki/password.c index 38e65e9..fb9d0e1 100644 --- a/examples/youkai_douchuuki/password.c +++ b/examples/youkai_douchuuki/password.c @@ -1,6 +1,6 @@ /* * This file is part of Etripator, - * copyright (c) 2009--2023 Vincent Cruz. + * copyright (c) 2009--2024 Vincent Cruz. * * Etripator is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/ipl.c b/ipl.c index 28471ab..99fb33a 100644 --- a/ipl.c +++ b/ipl.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/ipl.h b/ipl.h index d794a11..387e430 100644 --- a/ipl.h +++ b/ipl.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/irq.c b/irq.c index 09a95c6..e51a142 100644 --- a/irq.c +++ b/irq.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/irq.h b/irq.h index 9839f1b..9881d17 100644 --- a/irq.h +++ b/irq.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/jsonhelpers.c b/jsonhelpers.c index 9c96f91..b91f281 100644 --- a/jsonhelpers.c +++ b/jsonhelpers.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/jsonhelpers.h b/jsonhelpers.h index c1af5c7..f5631a7 100644 --- a/jsonhelpers.h +++ b/jsonhelpers.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/label.c b/label.c index d7d9378..166dbf8 100644 --- a/label.c +++ b/label.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/label.h b/label.h index 86824cf..f140d4f 100644 --- a/label.h +++ b/label.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/label/load.c b/label/load.c index 687f83e..1ddc476 100644 --- a/label/load.c +++ b/label/load.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/label/save.c b/label/save.c index 49b5448..f901664 100644 --- a/label/save.c +++ b/label/save.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/memory.c b/memory.c index aa0b04a..4f3b785 100644 --- a/memory.c +++ b/memory.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/memory.h b/memory.h index 75e1011..e5bb2da 100644 --- a/memory.h +++ b/memory.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/memory_map.c b/memory_map.c index 05e2d1c..7903d5e 100644 --- a/memory_map.c +++ b/memory_map.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/memory_map.h b/memory_map.h index 42af452..16698ea 100644 --- a/memory_map.h +++ b/memory_map.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/message.c b/message.c index 461d465..95f9b65 100644 --- a/message.c +++ b/message.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/message.h b/message.h index 4839791..8b78edb 100644 --- a/message.h +++ b/message.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/message/console.c b/message/console.c index 69f3e73..e5c8f4c 100644 --- a/message/console.c +++ b/message/console.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/message/console.h b/message/console.h index ae2ddfe..dbf839e 100644 --- a/message/console.h +++ b/message/console.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/message/file.c b/message/file.c index ae8c5e6..31e54ca 100644 --- a/message/file.c +++ b/message/file.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/message/file.h b/message/file.h index cdcd6d6..0e70e84 100644 --- a/message/file.h +++ b/message/file.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/opcodes.c b/opcodes.c index 95a7603..a175904 100644 --- a/opcodes.c +++ b/opcodes.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/opcodes.h b/opcodes.h index 128fee4..81bcbfb 100644 --- a/opcodes.h +++ b/opcodes.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/rom.c b/rom.c index b1c8c8c..4a75011 100644 --- a/rom.c +++ b/rom.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/rom.h b/rom.h index 823485c..c0641e9 100644 --- a/rom.h +++ b/rom.h @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/section.c b/section.c index f39b850..3d54170 100644 --- a/section.c +++ b/section.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -43,53 +43,57 @@ static const int32_t g_default_element_size = 8; static const int32_t g_default_elements_per_line = 16; -static const char *g_supported_section_types[SectionTypeCount] = { - "data", - "code" -}; +// Retrieves section type name +const char* section_type_name(SectionType type) { + static const char *name[SECTION_TYPE_COUNT] = { + [SECTION_TYPE_DATA] = "data", + [SECTION_TYPE_CODE] = "code" + }; -static const char *g_supported_data_types[DataTypeCount] = { - "binary", - "hex", - "string", - "jumptable" -}; - -/* Retrieves section type name. */ -const char* section_type_name(section_type_t type) { - if((type <= UnknownSectionType) || (type >= SectionTypeCount)) { + if((type <= SECTION_TYPE_UNKNOWN) || (type >= SECTION_TYPE_COUNT)) { return "unknown"; } - return g_supported_section_types[type]; + return name[type]; } -/* Retrieves data type name. */ -const char* data_type_name(data_type_t type) { - if((type <= UnknownDataType) || (type >= DataTypeCount)) { +// Retrieves data type name +const char* data_type_name(DataType type) { + static const char *name[DATA_TYPE_COUNT] = { + [DATA_TYPE_BINARY] = "binary", + [DATA_TYPE_HEX] = "hex", + [DATA_TYPE_STRING] = "string", + [DATA_TYPE_JUMP_TABLE] = "jumptable" + }; + + if((type <= DATA_TYPE_UNKNOWN) || (type >= DATA_TYPE_COUNT)) { return "unknown"; } - return g_supported_data_types[type]; + return name[type]; } -/* Reset a section to its default values. */ -void section_reset(section_t *s) { +// Reset a section to its default values +void section_reset(Section *s) { + assert(s != NULL); s->name = NULL; - s->type = UnknownSectionType; + s->type = SECTION_TYPE_UNKNOWN; s->page = 0; s->logical = 0; s->offset = 0; s->size = 0; - memset(s->mpr, 0, 8*sizeof(uint8_t)); + for(unsigned int i=0; i<8U; i++) { + s->mpr[i] = 0; + } s->output = NULL; - s->data.type = UnknownDataType; + s->data.type = DATA_TYPE_UNKNOWN; s->data.element_size = g_default_element_size; s->data.elements_per_line = g_default_elements_per_line; s->description = NULL; } static int section_compare(const void *a, const void *b) { - section_t* s0 = (section_t*)a; - section_t* s1 = (section_t*)b; + Section* s0 = (Section*)a; + Section* s1 = (Section*)b; + int cmp = s0->page - s1->page; if(!cmp) { cmp = s0->logical - s1->logical; @@ -97,24 +101,18 @@ static int section_compare(const void *a, const void *b) { return cmp; } -/* Group section per output filename and sort them in bank/org order. */ -void section_sort(section_t *ptr, size_t n) { - qsort(ptr, n, sizeof(section_t), §ion_compare); +// Group section per output filename and sort them in bank/org order. +void section_sort(Section *ptr, size_t n) { + qsort(ptr, n, sizeof(Section), §ion_compare); } -/* Delete sections. */ -void section_delete(section_t *ptr, int n) { - int i; - for(i=0; itype = json_validate_section_type(json_string_value(tmp)); - if (out->type == UnknownSectionType) { +static inline bool json_parse_section_type(const json_t *obj, SectionType *out) { + bool ret = false; + const json_t *tmp = json_object_get(obj, "type"); + if (tmp == NULL) { + ERROR_MSG("Missing section type."); + } else if (!json_is_string(tmp)) { ERROR_MSG("Invalid section type."); - return 0; - } - /* page */ - tmp = json_object_get(obj, "page"); - if (!json_validate_int(tmp, &num)) { - ERROR_MSG("Invalid or missing memory page."); - return 0; - } - if ((num < 0) || (num > 255)) { - ERROR_MSG("Page out of range."); - return 0; - } - out->page = (uint8_t)num; - /* logical address */ - tmp = json_object_get(obj, "logical"); - if (!json_validate_int(tmp, &num)) { - ERROR_MSG("Invalid or missing logical address."); - return 0; + } else { + *out = json_validate_section_type(json_string_value(tmp)); + if (*out == SECTION_TYPE_UNKNOWN) { + ERROR_MSG("Invalid section type value."); + } else { + ret = true; + } } - if ((num < 0) || (num > 0xffff)) { - ERROR_MSG("Org value out of range."); - return 0; + return ret; +} + +static inline bool json_parse_section_page(const json_t *obj, uint8_t *out) { + int num; + bool ret = false; + const json_t *tmp = json_object_get(obj, "page"); + if (tmp == NULL) { + ERROR_MSG("Missing section page"); + } else if (!json_validate_int(tmp, &num)) { + ERROR_MSG("Invalid section memory page."); + } else if ((num < 0) || (num > 255)) { + ERROR_MSG("Section memory page out of range."); + } else { + *out = (uint8_t)num; + ret = true; } - out->logical = (uint16_t)num; + return ret; +} - out->offset = (out->page << 13) | (out->logical & 0x1fff); +static inline bool json_parse_section_logical(const json_t *obj, uint16_t *out) { + int num; + bool ret = false; + const json_t *tmp = json_object_get(obj, "logical"); + if (tmp == NULL) { + ERROR_MSG("Missing section logical address"); + } else if (!json_validate_int(tmp, &num)) { + ERROR_MSG("Invalid or missing section logical address."); + } else if ((num < 0) || (num > 0xFFFF)) { + ERROR_MSG("Section logical address out of range."); + } else { + *out = (uint16_t)num; + ret = true; + } + return ret; +} - /* offset */ - num = -1; - tmp = json_object_get(obj, "offset"); - if (tmp) { - if (!json_validate_int(tmp, &num)) { - ERROR_MSG("Invalid or missing offset value."); - return 0; - } else { - out->offset = (uint32_t)num; - } +static inline bool json_parse_section_offset(const json_t *obj, Section *out) { + int num; + bool ret = true; + json_t *tmp = json_object_get(obj, "offset"); + if(tmp == NULL) { + out->offset = (out->page << 13) | (out->logical & 0x1FFF); + } else if (json_validate_int(tmp, &num)) { + out->offset = (uint32_t)num; + } else { + ERROR_MSG("Invalid or missing offset value."); + ret = false; } + return ret; +} - /* size */ - tmp = json_object_get(obj, "size"); - if (tmp) { - if (!json_validate_int(tmp, &out->size)) { - ERROR_MSG("Invalid section size."); - return 0; - } +static inline bool json_parse_section_size(const json_t *obj, int32_t *out) { + bool ret = true; + int num; + const json_t *tmp = json_object_get(obj, "size"); + if (tmp == NULL) { + *out = -1; + } else if (json_validate_int(tmp, &num)) { + *out = (int32_t)num; + } else { + ERROR_MSG("Invalid section size."); + ret = false; } - /* mpr */ - tmp = json_object_get(obj, "mpr"); - if(json_is_array(tmp)) { + return ret; +} + +static inline bool json_parse_section_mpr(const json_t *obj, Section *out) { + bool ret = false; + const json_t *tmp = json_object_get(obj, "mpr"); + if(tmp == NULL) { + ERROR_MSG("Missing section memory map"); + } else if(!json_is_array(tmp)) { + ERROR_MSG("Invalid section memory map"); + } else { + int num; size_t index; json_t* value; json_array_foreach(tmp, index, value) { - if(index > 7) { - WARNING_MSG("Extra mpr values"); - break; - } - if(json_validate_int(value, &num)) { - if((num < 0) || (num > 0xff)) { - ERROR_MSG("Invalid mpr %d value", index); - return 0; - } + ret = false; + if(index > 7U) { + ERROR_MSG("Too many mpr values"); + } else if(!json_validate_int(value, &num)) { + ERROR_MSG("Invalid type for mpr value"); + } else if((num < 0) || (num > 0xFF)) { + ERROR_MSG("Invalid mpr %d value", index); + } else { out->mpr[index] = (uint8_t)num; + ret = true; } - } - } - /* output */ - tmp = json_object_get(obj, "filename"); - if (!json_is_string(tmp)) { - ERROR_MSG("Missing or invalid output filename."); - return 0; - } - out->output = strdup(json_string_value(tmp)); - /* data */ - tmp = json_object_get(obj, "data"); - if (tmp) { - json_t* value; - value = json_object_get(tmp, "type"); - if (!json_is_string(value)) { - ERROR_MSG("Invalid data for data type."); - return 0; - } - out->data.type = json_validate_data_type(json_string_value(value)); - if (out->data.type == UnknownDataType) { - ERROR_MSG("Invalid data type."); - return 0; - } - value = json_object_get(tmp, "element_size"); - if(value && (out->data.type == Hex)) { - if (!json_validate_int(value, &out->data.element_size) || (out->data.element_size > 2)) { - ERROR_MSG("Invalid element size."); - return 0; + if(!ret) { + break; } } - value = json_object_get(tmp, "elements_per_line"); - if(value && (out->data.type != Binary)) { - if (!json_validate_int(value, &out->data.elements_per_line)) { - ERROR_MSG("Invalid number of elements per line."); - return 0; - } + } + + return ret; +} + +static inline bool json_parse_section_output(const json_t *obj, Section *out) { + bool ret = false; + const json_t *tmp = json_object_get(obj, "filename"); + if (tmp == NULL) { + ERROR_MSG("Misssing section output filename"); + } else if (!json_is_string(tmp)) { + ERROR_MSG("Invalid output filename."); + } else { + out->output = strdup(json_string_value(tmp)); + if(out->output == NULL) { + ERROR_MSG("Failed to parse section output filename: %s", strerror(errno)); + } else { + ret = true; } } - /* description (optional) */ - out->description = json_load_description(obj, "description"); + return ret; +} - return 1; +static inline bool json_parse_data_config_type(const json_t *obj, DataType *out) { + bool ret = false; + const json_t *tmp = json_object_get(obj, "type"); + if (tmp == NULL) { + ERROR_MSG("Missing section data type."); + } else if (!json_is_string(tmp)) { + ERROR_MSG("Invalid section data type."); + } else { + *out = json_validate_section_type(json_string_value(tmp)); + if (*out == DATA_TYPE_UNKNOWN) { + ERROR_MSG("Invalid section data type value."); + } else { + ret = true; + } + } + return ret; } -/* Load sections from a JSON file. */ -int section_load(const char *filename, section_t **out, int *n) { - json_t* root; - json_t* obj; - json_error_t err; - section_t *ptr; - const char* key; - size_t size; - int ret = 1; +static inline bool json_parse_data_config_element_size(const json_t *obj, DataConfig *out) { + bool ret = false; + const json_t *value = json_object_get(obj, "element_size"); + if(value == NULL) { + ret = true; // use default value + } else if(out->type != DATA_TYPE_HEX) { + ERROR_MSG("Element size is only valid for hex data type"); + } else if(!json_validate_int(obj, &out->element_size)) { + ERROR_MSG("Invalid element size"); + } else if((out->element_size < 0) || (out->element_size > 2)) { + ERROR_MSG("Invalid element size value: %d", out->element_size); + } else { + ret = true; + } + return ret; +} - root = json_load_file(filename, 0, &err); - if(!root) { - ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); - return 0; +static inline bool json_parse_data_config_element_per_line(const json_t *obj, DataConfig *out) { + bool ret = false; + const json_t *value = json_object_get(obj, "elements_per_line"); + if(value == NULL) { + ret = true; // use default value + } else if(out->type == DATA_TYPE_BINARY) { + ERROR_MSG("Number of elements per line is invalid for binary data section"); + } else if (!json_validate_int(obj, &out->elements_per_line)) { + ERROR_MSG("Invalid number of elements per line."); + } else { + ret = true; } + return ret; +} - if(!json_is_object(root)) { - ERROR_MSG("Invalid root element"); - json_decref(root); - return ret; +static bool json_parse_section_data_config(const json_t *obj, DataConfig *out) { + bool ret = false; + const json_t *tmp = json_object_get(obj, "data"); + if (tmp == NULL) { + ret = true; + } else if(!json_parse_data_config_type(tmp, &out->type)) { + // ... + } else if(!json_parse_data_config_element_size(tmp, out)) { + // ... + } else { + ret = json_parse_data_config_element_per_line(tmp, out); } + return ret; +} + +/// Initializes section from JSON object. +/// \param [in] obj JSON object. +/// \param [out] out Section. +/// \return 1 upon success +/// \return 0 if an error occured. +static bool section_parse(const json_t *obj, Section *out) { + assert(obj != NULL); + assert(out != NULL); + + bool ret = false; + + section_reset(out); + if (!json_is_object(obj)) { + ERROR_MSG("Invalid json element."); + } else if(!json_parse_section_type(obj, &out->type)) { + // ... + } else if(!json_parse_section_page(obj, &out->page)) { + // ... + } else if(!json_parse_section_logical(obj, &out->logical)) { + // ... + } else if(!json_parse_section_offset(obj, out)) { + // ... + } else if(!json_parse_section_size(obj, &out->size)) { + // ... + } else if(!json_parse_section_mpr(obj, out)) { - size = json_object_size(root); - *out = (section_t*)realloc(*out, (*n+size) * sizeof(section_t)); - ptr = *out + *n; - *n += (int)size; - json_object_foreach(root, key, obj) { - section_reset(ptr); - ret = ret && section_parse(obj, ptr); - if(ret) { - ptr->name = strdup(key); + } else if(!json_parse_section_output(obj, out)) { + // ... + } else { + const json_t *data = json_object_get(obj, "data"); + if(data != NULL) { + if(out->type != SECTION_TYPE_DATA) { + ERROR_MSG("Data configuration only valid for data sections"); + } else if(!json_parse_section_data_config(data, &out->data)) { + // ... + } else { + // description (optional) + ret = json_load_description(data, "description", &out->description); + } + } else { + ret = true; } - ptr++; } + return ret; +} - json_decref(root); +// Load sections from a JSON file. +bool section_load(const char *filename, Section **out, int *n) { + bool ret = false; + json_error_t err; + Section *ptr; + const char* key; + + json_t* root = json_load_file(filename, 0, &err); + if(root == NULL) { + ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); + } else { + if(!json_is_object(root)) { + ERROR_MSG("Invalid root element"); + } else { + json_t* obj = NULL; + size_t size = json_object_size(root); + *out = (Section*)realloc(*out, (*n+size) * sizeof(Section)); + ptr = *out + *n; + *n += (int)size; + json_object_foreach(root, key, obj) { + section_reset(ptr); + ret = ret && section_parse(obj, ptr); + if(ret) { + ptr->name = strdup(key); + } + ptr++; + } + ret = true; + } + json_decref(root); + } return ret; } diff --git a/section/save.c b/section/save.c index 480d6ca..3649bfd 100644 --- a/section/save.c +++ b/section/save.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5fc3b3e..0729caa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -116,3 +116,18 @@ add_unit_test( LIBRARIES cwalk jansson INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) + +#[[ +add_unit_test( + NAME section + SOURCES + section.c + ${PROJECT_SOURCE_DIR}/section.c + ${PROJECT_SOURCE_DIR}/section/load.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/jsonhelpers.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk jansson + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) +#]] \ No newline at end of file diff --git a/test/cd.c b/test/cd.c index d042fbe..ce765ee 100644 --- a/test/cd.c +++ b/test/cd.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/comment.c b/test/comment.c index b73a1f8..14d0216 100644 --- a/test/comment.c +++ b/test/comment.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/label.c b/test/label.c index 2480239..95a9d6f 100644 --- a/test/label.c +++ b/test/label.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/memory.c b/test/memory.c index c74a683..1e0d780 100644 --- a/test/memory.c +++ b/test/memory.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/memory_map.c b/test/memory_map.c index ad348fd..6f1bb30 100644 --- a/test/memory_map.c +++ b/test/memory_map.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/message.c b/test/message.c index cf660b6..52068c6 100644 --- a/test/message.c +++ b/test/message.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/rom.c b/test/rom.c index c0ec916..b69f3d0 100644 --- a/test/rom.c +++ b/test/rom.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/test/section.c b/test/section.c index 954965d..2d2c64a 100644 --- a/test/section.c +++ b/test/section.c @@ -15,7 +15,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ This file is part of Etripator, - copyright (c) 2009--2023 Vincent Cruz. + copyright (c) 2009--2024 Vincent Cruz. Etripator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From 6dc54733ecf5ed695de7e9842991f6e819e0d24c Mon Sep 17 00:00:00 2001 From: MooZ Date: Sat, 12 Oct 2024 23:10:35 +0200 Subject: [PATCH 20/35] Fix markdown --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 330b359..7ad7099 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The options are : * **--help** or **-h** : displays help. * **--out** or **-o < file >** : main asm file containing includes for all sections as long the irq vector table if the irq-detect option is enabled. * **--labels** or **-l < file >** : labels definition filename. -* **--labels-out ** : extracted labels output filename. Otherwise the labels will be written to .YYMMDDhhmmss.lbl.\n" +* **--labels-out ** : extracted labels output filename. Otherwise the labels will be written to `".YYMMDDhhmmss.lbl"` * **--comments ** : comments description filename. * **--address** : print statement logical address and page in an inline comment. * **cfg** : configuration file. It is optional if irq detection is enabled. From dfbf35e59fdeb177360a3b69a02655a964741b0d Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 13 Oct 2024 12:43:38 +0200 Subject: [PATCH 21/35] Update section unit tests --- section.h | 8 ++-- section/load.c | 94 +++++++++++++++++++++------------------------ test/CMakeLists.txt | 2 - test/label.c | 1 - test/section.c | 65 ++++++++++++++----------------- 5 files changed, 76 insertions(+), 94 deletions(-) diff --git a/section.h b/section.h index c20f80d..8e5108e 100644 --- a/section.h +++ b/section.h @@ -105,19 +105,19 @@ void section_sort(Section *ptr, size_t n); void section_delete(Section *ptr, int n); // Load sections from a JSON file. -// \param [in] filename Input filename. // \param [out] out Loaded sections. // \param [out] n Number of loaded sections. +// \param [in] filename Input filename. // \return true if the sections contained in the file were succesfully loaded. // \return false if an error occured. -bool section_load(const char *filename, Section **out, int *n); +bool section_load(Section **out, int *n, const char *filename); // Save sections to a JSON file. -// \param [in] filename Output filename. // \param [in] ptr Sections to be saved. // \param [in] count Number of sections. +// \param [in] filename Output filename. // \return true if the sections were succesfully saved. // \return false if an error occured. -int section_save(const char *filename, Section *ptr, int n); +bool section_save(Section *ptr, int n, const char *filename); #endif // ETRIPATOR_SECTION_H diff --git a/section/load.c b/section/load.c index ea5ea41..5cfffdc 100644 --- a/section/load.c +++ b/section/load.c @@ -62,7 +62,7 @@ static inline DataType json_validate_data_type(const char *str) { return DATA_TYPE_UNKNOWN; } -static inline bool json_parse_section_type(const json_t *obj, SectionType *out) { +static inline bool json_parse_section_type(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "type"); if (tmp == NULL) { @@ -70,8 +70,8 @@ static inline bool json_parse_section_type(const json_t *obj, SectionType *out) } else if (!json_is_string(tmp)) { ERROR_MSG("Invalid section type."); } else { - *out = json_validate_section_type(json_string_value(tmp)); - if (*out == SECTION_TYPE_UNKNOWN) { + out->type = json_validate_section_type(json_string_value(tmp)); + if (out->type == SECTION_TYPE_UNKNOWN) { ERROR_MSG("Invalid section type value."); } else { ret = true; @@ -80,7 +80,7 @@ static inline bool json_parse_section_type(const json_t *obj, SectionType *out) return ret; } -static inline bool json_parse_section_page(const json_t *obj, uint8_t *out) { +static inline bool json_parse_section_page(Section *out, const json_t *obj) { int num; bool ret = false; const json_t *tmp = json_object_get(obj, "page"); @@ -91,13 +91,13 @@ static inline bool json_parse_section_page(const json_t *obj, uint8_t *out) { } else if ((num < 0) || (num > 255)) { ERROR_MSG("Section memory page out of range."); } else { - *out = (uint8_t)num; + out->page = (uint8_t)num; ret = true; } return ret; } -static inline bool json_parse_section_logical(const json_t *obj, uint16_t *out) { +static inline bool json_parse_section_logical(Section *out, const json_t *obj) { int num; bool ret = false; const json_t *tmp = json_object_get(obj, "logical"); @@ -108,13 +108,13 @@ static inline bool json_parse_section_logical(const json_t *obj, uint16_t *out) } else if ((num < 0) || (num > 0xFFFF)) { ERROR_MSG("Section logical address out of range."); } else { - *out = (uint16_t)num; + out->logical = (uint16_t)num; ret = true; } return ret; } -static inline bool json_parse_section_offset(const json_t *obj, Section *out) { +static inline bool json_parse_section_offset(Section *out, const json_t *obj) { int num; bool ret = true; json_t *tmp = json_object_get(obj, "offset"); @@ -129,14 +129,14 @@ static inline bool json_parse_section_offset(const json_t *obj, Section *out) { return ret; } -static inline bool json_parse_section_size(const json_t *obj, int32_t *out) { +static inline bool json_parse_section_size(Section *out, const json_t *obj) { bool ret = true; int num; const json_t *tmp = json_object_get(obj, "size"); if (tmp == NULL) { - *out = -1; + // use default value } else if (json_validate_int(tmp, &num)) { - *out = (int32_t)num; + out->size = (int32_t)num; } else { ERROR_MSG("Invalid section size."); ret = false; @@ -144,7 +144,7 @@ static inline bool json_parse_section_size(const json_t *obj, int32_t *out) { return ret; } -static inline bool json_parse_section_mpr(const json_t *obj, Section *out) { +static inline bool json_parse_section_mpr(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "mpr"); if(tmp == NULL) { @@ -176,7 +176,7 @@ static inline bool json_parse_section_mpr(const json_t *obj, Section *out) { return ret; } -static inline bool json_parse_section_output(const json_t *obj, Section *out) { +static inline bool json_parse_section_output(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "filename"); if (tmp == NULL) { @@ -194,7 +194,7 @@ static inline bool json_parse_section_output(const json_t *obj, Section *out) { return ret; } -static inline bool json_parse_data_config_type(const json_t *obj, DataType *out) { +static inline bool json_parse_data_config_type(DataConfig *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "type"); if (tmp == NULL) { @@ -202,8 +202,8 @@ static inline bool json_parse_data_config_type(const json_t *obj, DataType *out) } else if (!json_is_string(tmp)) { ERROR_MSG("Invalid section data type."); } else { - *out = json_validate_section_type(json_string_value(tmp)); - if (*out == DATA_TYPE_UNKNOWN) { + out->type = json_validate_data_type(json_string_value(tmp)); + if (out->type == DATA_TYPE_UNKNOWN) { ERROR_MSG("Invalid section data type value."); } else { ret = true; @@ -212,14 +212,14 @@ static inline bool json_parse_data_config_type(const json_t *obj, DataType *out) return ret; } -static inline bool json_parse_data_config_element_size(const json_t *obj, DataConfig *out) { +static inline bool json_parse_data_config_element_size(DataConfig *out, const json_t *obj) { bool ret = false; const json_t *value = json_object_get(obj, "element_size"); if(value == NULL) { ret = true; // use default value } else if(out->type != DATA_TYPE_HEX) { ERROR_MSG("Element size is only valid for hex data type"); - } else if(!json_validate_int(obj, &out->element_size)) { + } else if(!json_validate_int(value, &out->element_size)) { ERROR_MSG("Invalid element size"); } else if((out->element_size < 0) || (out->element_size > 2)) { ERROR_MSG("Invalid element size value: %d", out->element_size); @@ -229,14 +229,14 @@ static inline bool json_parse_data_config_element_size(const json_t *obj, DataCo return ret; } -static inline bool json_parse_data_config_element_per_line(const json_t *obj, DataConfig *out) { +static inline bool json_parse_data_config_element_per_line(DataConfig *out, const json_t *obj) { bool ret = false; const json_t *value = json_object_get(obj, "elements_per_line"); if(value == NULL) { ret = true; // use default value } else if(out->type == DATA_TYPE_BINARY) { ERROR_MSG("Number of elements per line is invalid for binary data section"); - } else if (!json_validate_int(obj, &out->elements_per_line)) { + } else if (!json_validate_int(value, &out->elements_per_line)) { ERROR_MSG("Invalid number of elements per line."); } else { ret = true; @@ -244,17 +244,19 @@ static inline bool json_parse_data_config_element_per_line(const json_t *obj, Da return ret; } -static bool json_parse_section_data_config(const json_t *obj, DataConfig *out) { +static bool json_parse_section_data_config(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "data"); if (tmp == NULL) { ret = true; - } else if(!json_parse_data_config_type(tmp, &out->type)) { + } else if(out->type != SECTION_TYPE_DATA) { + ERROR_MSG("Data configuration only valid for data sections"); + } else if(!json_parse_data_config_type(&out->data, tmp)) { // ... - } else if(!json_parse_data_config_element_size(tmp, out)) { + } else if(!json_parse_data_config_element_size(&out->data, tmp)) { // ... } else { - ret = json_parse_data_config_element_per_line(tmp, out); + ret = json_parse_data_config_element_per_line(&out->data, tmp); } return ret; } @@ -264,7 +266,7 @@ static bool json_parse_section_data_config(const json_t *obj, DataConfig *out) { /// \param [out] out Section. /// \return 1 upon success /// \return 0 if an error occured. -static bool section_parse(const json_t *obj, Section *out) { +static bool section_parse(Section *out, const json_t *obj) { assert(obj != NULL); assert(out != NULL); @@ -273,40 +275,31 @@ static bool section_parse(const json_t *obj, Section *out) { section_reset(out); if (!json_is_object(obj)) { ERROR_MSG("Invalid json element."); - } else if(!json_parse_section_type(obj, &out->type)) { + } else if(!json_parse_section_type(out, obj)) { // ... - } else if(!json_parse_section_page(obj, &out->page)) { + } else if(!json_parse_section_page(out, obj)) { // ... - } else if(!json_parse_section_logical(obj, &out->logical)) { + } else if(!json_parse_section_logical(out, obj)) { // ... - } else if(!json_parse_section_offset(obj, out)) { + } else if(!json_parse_section_offset(out, obj)) { // ... - } else if(!json_parse_section_size(obj, &out->size)) { + } else if(!json_parse_section_size(out, obj)) { // ... - } else if(!json_parse_section_mpr(obj, out)) { + } else if(!json_parse_section_mpr(out, obj)) { - } else if(!json_parse_section_output(obj, out)) { + } else if(!json_parse_section_output(out, obj)) { + // ... + } else if(!json_parse_section_data_config(out, obj)) { // ... } else { - const json_t *data = json_object_get(obj, "data"); - if(data != NULL) { - if(out->type != SECTION_TYPE_DATA) { - ERROR_MSG("Data configuration only valid for data sections"); - } else if(!json_parse_section_data_config(data, &out->data)) { - // ... - } else { - // description (optional) - ret = json_load_description(data, "description", &out->description); - } - } else { - ret = true; - } + // description (optional) + ret = json_load_description(obj, "description", &out->description); } return ret; } // Load sections from a JSON file. -bool section_load(const char *filename, Section **out, int *n) { +bool section_load(Section **out, int *n, const char *filename) { bool ret = false; json_error_t err; Section *ptr; @@ -324,15 +317,14 @@ bool section_load(const char *filename, Section **out, int *n) { *out = (Section*)realloc(*out, (*n+size) * sizeof(Section)); ptr = *out + *n; *n += (int)size; + ret = true; json_object_foreach(root, key, obj) { - section_reset(ptr); - ret = ret && section_parse(obj, ptr); - if(ret) { - ptr->name = strdup(key); + if(!section_parse(ptr, obj)) { + ret = false; } + ptr->name = strdup(key); ptr++; } - ret = true; } json_decref(root); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0729caa..05a84b4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -117,7 +117,6 @@ add_unit_test( INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) -#[[ add_unit_test( NAME section SOURCES @@ -130,4 +129,3 @@ add_unit_test( LIBRARIES cwalk jansson INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) -#]] \ No newline at end of file diff --git a/test/label.c b/test/label.c index 95a9d6f..3843991 100644 --- a/test/label.c +++ b/test/label.c @@ -37,7 +37,6 @@ #include "label.h" #include "message.h" #include "message/console.h" -#include "message/file.h" void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { message_printer_init(); diff --git a/test/section.c b/test/section.c index 2d2c64a..65509f3 100644 --- a/test/section.c +++ b/test/section.c @@ -38,29 +38,22 @@ #include "message.h" #include "message/console.h" -void* setup(const MunitParameter params[], void* user_data) { - (void) params; - (void) user_data; - - console_msg_printer_t *printer = (console_msg_printer_t*)malloc(sizeof(console_msg_printer_t)); - - msg_printer_init(); - console_msg_printer_init(printer); - msg_printer_add((msg_printer_t*)printer); - return (void*)printer; +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + message_printer_init(); + console_message_printer_init(); + return NULL; } -void tear_down(void* fixture) { - msg_printer_destroy(); - free(fixture); +void tear_down(void* fixture __attribute__((unused))) { + message_printer_destroy(); } MunitResult section_sort_test(const MunitParameter params[], void* fixture) { (void)params; (void)fixture; - section_t section[8]; + Section section[8]; section[0].output = "0002"; section[0].page = 0; @@ -110,39 +103,39 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { (void)params; (void)fixture; - static section_t bank0_0[4] = { - { "cdbios_functions", Code, 0, 0xe000, 0x0000, 0x505, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "unknown.0", Data, 0, 0xe504, 0x0504, 0x05, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "ex_colorcmd.impl", Code, 0, 0xe509, 0x0509, 0xce, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "unknown.1", Data, 0, 0xe5d7, 0x05d7, 0x03, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } } + static const Section bank0_0[4] = { + { "cdbios_functions", SECTION_TYPE_CODE, 0, 0xe000, 0x0000, 0x505, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "unknown.0", SECTION_TYPE_DATA, 0, 0xe504, 0x0504, 0x05, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "ex_colorcmd.impl", SECTION_TYPE_CODE, 0, 0xe509, 0x0509, 0xce, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "unknown.1", SECTION_TYPE_DATA, 0, 0xe5d7, 0x05d7, 0x03, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } } }; - static section_t bank0_1[9] = { - { "ex_satclr.impl", Code, 0, 0xe5da, 0x05da, 0x26, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "unknown.2", Data, 0, 0xf8a9, 0x18a9, 0x0f, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "bm_free.impl", Code, 0, 0xf8b8, 0x18b8, 0x575, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "jump_table.0", Data, 0, 0xfe2d, 0x1e2d, 0x2a, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "grp_bios.impl", Code, 0, 0xfe57, 0x1e57, 0x18, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "jump_table.1", Data, 0, 0xfe70, 0x1e70, 0x22, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "ex_memopen.impl", Code, 0, 0xfe92, 0x1e92, 0x30, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "unknown.3", Data, 0, 0xfec2, 0x1ec2, 0x134, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { UnknownDataType, 8, 16 } }, - { "irq_vectors", Data, 0, 0xfff6, 0x1ff6, 0x0a, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { Hex, 2, 1 } } + static const Section bank0_1[9] = { + { "ex_satclr.impl", SECTION_TYPE_CODE, 0, 0xe5da, 0x05da, 0x26, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "unknown.2", SECTION_TYPE_DATA, 0, 0xf8a9, 0x18a9, 0x0f, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "bm_free.impl", SECTION_TYPE_CODE, 0, 0xf8b8, 0x18b8, 0x575, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "jump_table.0", SECTION_TYPE_DATA, 0, 0xfe2d, 0x1e2d, 0x2a, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "grp_bios.impl", SECTION_TYPE_CODE, 0, 0xfe57, 0x1e57, 0x18, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "jump_table.1", SECTION_TYPE_DATA, 0, 0xfe70, 0x1e70, 0x22, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "ex_memopen.impl", SECTION_TYPE_CODE, 0, 0xfe92, 0x1e92, 0x30, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "unknown.3", SECTION_TYPE_DATA, 0, 0xfec2, 0x1ec2, 0x134, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "irq_vectors", SECTION_TYPE_DATA, 0, 0xfff6, 0x1ff6, 0x0a, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_HEX, 2, 1 } } }; - static const section_t* bank0[2] = { bank0_0, bank0_1 }; + static const Section* bank0[2] = { bank0_0, bank0_1 }; - section_t *section = NULL; + Section *section = NULL; int count[2] = { 0, 0 }; int i, j, k; int ret; - - ret = section_load("./data/bank0_0.json", §ion, &count[0]); + ret = section_load(§ion, &count[0], "./data/bank0_0.json"); + munit_assert_int(ret, !=, 0); munit_assert_int(count[0], ==, 4); section_sort(section, count[0]); - + for(i=0; i Date: Sun, 13 Oct 2024 13:01:40 +0200 Subject: [PATCH 22/35] Fix opcodes --- opcodes.c | 6 +++--- opcodes.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opcodes.c b/opcodes.c index a175904..2dce388 100644 --- a/opcodes.c +++ b/opcodes.c @@ -66,7 +66,7 @@ static char* pce_opstring[PCE_TYPE_COUNT][PCE_ARG_COUNT] = { }; // PC engine opcodes -static opcode_t pce_opcode[256] = { +static Opcode pce_opcode[256] = { /* 00 */ { "brk ", 1 , 0 }, // BRK /* 01 */ { "ora ", 2 , 11 }, // ORA (ZZ, X) /* 02 */ { "sxy ", 1 , 0 }, // SXY @@ -326,12 +326,12 @@ static opcode_t pce_opcode[256] = { }; // Get opcode description. -const opcode_t* opcode_get(uint8_t op) { +const Opcode* opcode_get(uint8_t op) { return &pce_opcode[op]; } // Get opcode description -const char* opcode_format(const opcode_t *op, int i) { +const char* opcode_format(const Opcode *op, int i) { if((i < 0) || (i >= PCE_ARG_COUNT)) { return NULL; } diff --git a/opcodes.h b/opcodes.h index 81bcbfb..d3b3a39 100644 --- a/opcodes.h +++ b/opcodes.h @@ -103,14 +103,14 @@ typedef struct { /// Get opcode description /// \param [in] op Opcode id /// \return Pointer to opcode description -const opcode_t* opcode_get(uint8_t op); +const Opcode* opcode_get(uint8_t op); /// Get opcode format string /// \param [in] op Pointer to opcode description /// \param [in] i Opcode argument id /// \return Argument format string /// \return NULL if the argument id is out of opcode argument count -const char* opcode_format(const opcode_t *op, int i); +const char* opcode_format(const Opcode *op, int i); /// Is the instruction a local jump ? bool opcode_is_local_jump(uint8_t op); From 88204550a8bd2ebbf8145904e496c81903d6371a Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 13 Oct 2024 16:07:30 +0200 Subject: [PATCH 23/35] Add opcode unit tests Keep on revamping stuffs --- CMakeLists.txt | 8 +-- decode.c | 80 ++++++++++++------------ decode.h | 89 ++++++++++++--------------- ipl.c | 118 +++++++++++++++++------------------ ipl.h | 96 +++++++++++++---------------- irq.c | 10 +-- irq.h | 32 ++-------- label/save.c | 4 +- section.h | 2 +- section/save.c | 69 ++++++++++----------- test/CMakeLists.txt | 11 ++++ test/opcodes.c | 147 ++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 391 insertions(+), 275 deletions(-) create mode 100644 test/opcodes.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f58cbb4..5b692bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ find_package(Jansson) set(CMAKE_C_STANDARDS 11) add_subdirectory(externals) -#[[ + set(etripator_SRC message.c message/file.c @@ -45,7 +45,7 @@ set(etripator_SRC label/save.c irq.c memory.c - memorymap.c + memory_map.c rom.c cd.c ipl.c @@ -64,7 +64,7 @@ set(etripator_HDR label.h irq.h memory.h - memorymap.h + memory_map.h rom.h cd.h ipl.h @@ -75,7 +75,7 @@ set_target_properties(etripator PROPERTIES C_STANDARD 11) target_include_directories(etripator PUBLIC ${JANSSON_INCLUDE_DIRS} ${EXTRA_INCLUDE} externals) target_compile_definitions(etripator PRIVATE _POSIX_C_SOURCE) target_link_libraries(etripator PUBLIC ${JANSSON_LIBRARIES} cwalk) - +#[[ add_executable(etripator_cli cli/etripator.c cli/options.c) set_target_properties(etripator_cli PROPERTIES diff --git a/decode.c b/decode.c index 9823cfa..e80d837 100644 --- a/decode.c +++ b/decode.c @@ -88,7 +88,7 @@ static void print_statement_address(FILE *out, int n, uint16_t logical, uint8_t fprintf(out, "%*c; bank: $%03x logical: $%04x", last_column_spacing(n), ' ', page, logical); } -static void print_label(FILE *out, label_t *label) { +static void print_label(FILE *out, Label *label) { int n = last_column_spacing((int)strlen(label->name) + 1); /* Print description */ print_comment(out, label->description); @@ -97,7 +97,7 @@ static void print_label(FILE *out, label_t *label) { } /* Finds any jump address from the current section. */ -int label_extract(section_t *section, memmap_t *map, label_repository_t *repository) { +bool label_extract(Section *section, MemoryMap *map, LabelRepository *repository) { int i; uint8_t inst; uint8_t data[6]; @@ -106,9 +106,9 @@ int label_extract(section_t *section, memmap_t *map, label_repository_t *reposit uint16_t logical; uint8_t page; - const opcode_t *opcode; + const Opcode *opcode; - if (section->type != Code) { + if (section->type != SECTION_TYPE_CODE) { return 1; } @@ -160,7 +160,7 @@ int label_extract(section_t *section, memmap_t *map, label_repository_t *reposit return 1; } -static int data_extract_binary(FILE *out, section_t *section, memmap_t *map, label_repository_t *repository) { +static int data_extract_binary(FILE *out, Section *section, MemoryMap *map, LabelRepository *repository) { uint16_t logical; int32_t i; for (i = 0, logical = section->logical; i < section->size; i++, logical++) { @@ -170,16 +170,16 @@ static int data_extract_binary(FILE *out, section_t *section, memmap_t *map, lab return 1; } -static int data_extract_hex(FILE *out, section_t *section, memmap_t *map, label_repository_t *repository, - comment_repository_t *comments, int extra_infos) { +static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRepository *repository, + CommentRepository *comments, int extra_infos) { const int32_t element_size = section->data.element_size; const int32_t elements_per_line = section->data.elements_per_line; int32_t i, j; uint16_t logical; - label_t label; - comment_t comment; + Label label; + Comment comment; uint8_t buffer[2] = {0}; int32_t top = 0; @@ -211,7 +211,7 @@ static int data_extract_hex(FILE *out, section_t *section, memmap_t *map, label_ j = 0; } - comment_t dummy; + Comment dummy; if (comment_repository_find(comments, logical, page, &dummy)) { if (has_comment) { if (top && (top < element_size)) { @@ -223,7 +223,7 @@ static int data_extract_hex(FILE *out, section_t *section, memmap_t *map, label_ } print_inline_comment(out, (int)(ftell(out) - line_offset), comment.text); } - memcpy(&comment, &dummy, sizeof(comment_t)); + memcpy(&comment, &dummy, sizeof(Comment)); has_comment = 1; j = 0; } @@ -288,8 +288,8 @@ static int data_extract_hex(FILE *out, section_t *section, memmap_t *map, label_ return 1; } -static int data_extract_string(FILE *out, section_t *section, memmap_t *map, label_repository_t *repository, - comment_repository_t *comments, int extra_infos) { +static int data_extract_string(FILE *out, Section *section, MemoryMap *map, LabelRepository *repository, + CommentRepository *comments, int extra_infos) { const int32_t elements_per_line = section->data.elements_per_line; int32_t i, j; @@ -303,13 +303,13 @@ static int data_extract_string(FILE *out, section_t *section, memmap_t *map, lab uint16_t line_logical = 0; uint8_t line_page; - comment_t comment = {0}; + Comment comment = {0}; for (i = 0, j = 0, logical = section->logical; i < section->size; i++, logical++) { uint8_t data = memmap_read(map, logical); uint8_t page = memmap_page(map, logical); - label_t label = {0}; + Label label = {0}; has_label = label_repository_find(repository, logical, page, &label); @@ -325,7 +325,7 @@ static int data_extract_string(FILE *out, section_t *section, memmap_t *map, lab print_label(out, &label); } - comment_t dummy; + Comment dummy; if (comment_repository_find(comments, logical, page, &dummy)) { if (j) { if (c) { // close string if neededs @@ -337,7 +337,7 @@ static int data_extract_string(FILE *out, section_t *section, memmap_t *map, lab if (has_comment) { print_inline_comment(out, (int)(ftell(out) - line_offset), comment.text); } - memcpy(&comment, &dummy, sizeof(comment_t)); + memcpy(&comment, &dummy, sizeof(Comment)); has_comment = 1; } @@ -409,16 +409,16 @@ static int data_extract_string(FILE *out, section_t *section, memmap_t *map, lab return 1; } -static int data_extract_jump_table(FILE *out, section_t *section, memmap_t *map, label_repository_t *repository, - comment_repository_t *comments, int extra_infos) { +static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, LabelRepository *repository, + CommentRepository *comments, int extra_infos) { const int32_t elements_per_line = section->data.elements_per_line; int32_t i, j; uint8_t page; uint16_t logical; - label_t label; - comment_t comment; + Label label; + Comment comment; size_t line_offset = ftell(out); uint8_t line_page = section->page; @@ -444,12 +444,12 @@ static int data_extract_jump_table(FILE *out, section_t *section, memmap_t *map, j = 0; } - comment_t dummy; + Comment dummy; if (comment_repository_find(comments, logical, page, &dummy)) { if (has_comment) { print_inline_comment(out, (int)(ftell(out) - line_offset), comment.text); } - memcpy(&comment, &dummy, sizeof(comment_t)); + memcpy(&comment, &dummy, sizeof(Comment)); has_comment = 1; j = 0; } @@ -498,25 +498,25 @@ static int data_extract_jump_table(FILE *out, section_t *section, memmap_t *map, } /* Process data section. The result will be output has a binary file or an asm file containing hex values or strings. */ -int data_extract(FILE *out, section_t *section, memmap_t *map, label_repository_t *repository, - comment_repository_t *comments, int extra_infos) { +bool data_extract(FILE *out, Section *section, MemoryMap *map, LabelRepository *repository, + CommentRepository *comments, int extra_infos) { switch (section->data.type) { - case Binary: + case DATA_TYPE_BINARY: return data_extract_binary(out, section, map, repository); - case Hex: + case DATA_TYPE_HEX: return data_extract_hex(out, section, map, repository, comments, extra_infos); - case String: + case DATA_TYPE_STRING: return data_extract_string(out, section, map, repository, comments, extra_infos); - case JumpTable: + case DATA_TYPE_JUMP_TABLE: return data_extract_jump_table(out, section, map, repository, comments, extra_infos); default: - return 0; + return false; } } /* Process code section. */ -int decode(FILE *out, uint16_t *logical, section_t *section, memmap_t *map, label_repository_t *repository, - comment_repository_t *comments, int extra_infos) { +int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, LabelRepository *repository, + CommentRepository *comments, int extra_infos) { int i, delta; uint8_t inst, data[6], is_jump; char eor; @@ -525,9 +525,9 @@ int decode(FILE *out, uint16_t *logical, section_t *section, memmap_t *map, labe uint8_t current_page; uint16_t current_logical; uint16_t next_logical; - label_t label; + Label label; - const opcode_t *opcode; + const Opcode *opcode; eor = 0; @@ -794,7 +794,7 @@ int decode(FILE *out, uint16_t *logical, section_t *section, memmap_t *map, labe } /* display inline comments if any */ - comment_t comment = {0}; + Comment comment = {0}; int n = (int)(ftell(out) - start); if(comment_repository_find(comments, current_logical, current_page, &comment)) { print_inline_comment(out, n, comment.text); @@ -806,10 +806,10 @@ int decode(FILE *out, uint16_t *logical, section_t *section, memmap_t *map, labe } /* Computes section size. */ -int32_t compute_size(section_t *sections, int index, int count, memmap_t *map) { +int32_t compute_size(Section *sections, int index, int count, MemoryMap *map) { uint8_t i; uint8_t data[7]; - section_t *current = §ions[index]; + Section *current = §ions[index]; uint32_t start = current->logical; uint32_t logical = start; @@ -833,7 +833,7 @@ int32_t compute_size(section_t *sections, int index, int count, memmap_t *map) { } uint8_t page = memmap_page(map, logical); data[0] = memmap_read(map, logical); - const opcode_t *opcode = opcode_get(data[0]); + const Opcode *opcode = opcode_get(data[0]); for (i = 1; i < opcode->size; i++) { data[i] = memmap_read(map, logical + i); } @@ -875,10 +875,10 @@ int32_t compute_size(section_t *sections, int index, int count, memmap_t *map) { } /* Output hardware IO port and RAM labels. */ -void label_dump(FILE *out, memmap_t *map, label_repository_t *repository) { +void label_dump(FILE *out, MemoryMap *map, LabelRepository *repository) { int count = label_repository_size(repository); for (int i = 0; i < count; i++) { - label_t label; + Label label; if (label_repository_get(repository, i, &label)) { // IO port and RAM if ((label.page == 0xff) || (label.page == 0xf8)) { diff --git a/decode.h b/decode.h index a1e923b..0f2b844 100644 --- a/decode.h +++ b/decode.h @@ -39,59 +39,52 @@ #include "config.h" #include "label.h" #include "section.h" -#include "memorymap.h" +#include "memory_map.h" #include "comment.h" -/** - * Finds any jump address from the current section. - * @param [in] section Current section. - * @param [in] map Memory map. - * @param [in out] repository Label repository. - * @return 1 upon success, 0 otherwise. - */ -int label_extract(section_t *section, memmap_t *map, label_repository_t *repository); +/// Finds any jump address from the current section. +/// \param [in] section Current section. +/// \param [in] map Memory map. +/// \param [in out] repository Label repository. +/// \return true upon success. +/// \return false if an error occured. +bool label_extract(Section *section, MemoryMap *map, LabelRepository *repository); -/** - * Process data section. The result will be output has a binary file or an asm file containing hex values or strings. - * @param [out] out File output. - * @param [in] section Current section. - * @param [in] map Memory map. - * @param [in] repository Label repository. - * @param [in] comments Comments repository. - * @param [in] extra_infos Display extra informations as comments (if none set). - * @return 1 upon success, 0 otherwise. - */ -int data_extract(FILE *out, section_t *section, memmap_t *map, label_repository_t *repository, comment_repository_t *comments, int extra_infos); +/// Process data section. The result will be output has a binary file or an asm file containing hex values or strings. +/// \param [out] out File output. +/// \param [in] section Current section. +/// \param [in] map Memory map. +/// \param [in] repository Label repository. +/// \param [in] comments Comments repository. +/// \param [in] extra_infos Display extra informations as comments (if none set). +/// \return true upon success. +/// \return false if an error occured. +bool data_extract(FILE *out, Section *section, MemoryMap *map, LabelRepository *repository, CommentRepository *comments, int extra_infos); -/** - * Process code section. - * @param [out] out File output. - * @param [in out] logical Current logical address. - * @param [in] section Current section. - * @param [in] map Memory map. - * @param [in] repository Label repository. - * @param [in] comments Comments repository. - * @param [in] extra_infos Display extra informations as comments (if none set). - * @return 1 if rts, rti or brk instruction was decoded, 0 otherwise. - */ -int decode(FILE *out, uint16_t *logical, section_t *section, memmap_t *map, label_repository_t *repository, comment_repository_t *comments, int extra_infos); +/// Process code section. +/// \param [out] out File output. +/// \param [in out] logical Current logical address. +/// \param [in] section Current section. +/// \param [in] map Memory map. +/// \param [in] repository Label repository. +/// \param [in] comments Comments repository. +/// \param [in] extra_infos Display extra informations as comments (if none set). +/// \return true if rts, rti or brk instruction was decoded. +/// \return false otherwise. +int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, LabelRepository *repository, CommentRepository *comments, int extra_infos); -/** - * Computes section size. - * @param [in] sections Section array. - * @param [in] index Index of the current section. - * @param [in] count Number of sections. - * @param [in] map Memory map. - * @return Section size. - */ -int32_t compute_size(section_t *sections, int index, int count, memmap_t *map); +/// Computes section size. +/// \param [in] sections Section array. +/// \param [in] index Index of the current section. +/// \param [in] count Number of sections. +/// \param [in] map Memory map. +/// \return Section size. +int32_t compute_size(Section *sections, int index, int count, MemoryMap *map); -/** - * Output hardware IO port and RAM labels. - * @param [out] out File output. - * @param [in] map Memory map. - * @param [in] repository Label repository. - */ -void label_dump(FILE *out, memmap_t *map, label_repository_t *repository); +/// Output hardware IO port and RAM labels. +/// \param [out] out File output. +/// \param [in] map Memory map. +/// \param [in] repository Label repository. +void label_dump(FILE *out, MemoryMap *map, LabelRepository *repository); #endif // ETRIPATOR_DECODE_H diff --git a/ipl.c b/ipl.c index 99fb33a..367a6ed 100644 --- a/ipl.c +++ b/ipl.c @@ -39,8 +39,8 @@ #define IPL_HEADER_SIZE 0x80 #define IPL_DATA_SIZE 0xB2 -static int ipl_read_header(ipl_t *out, FILE *in, const char *filename) { - int ret = 0; +static bool ipl_read_header(IPL *out, FILE *in, const char *filename) { + bool ret = false; if(fread(out->load_start_record, 1, 3, in) != 3) { ERROR_MSG("Failed to read IPLBLK from %s: %s", filename, strerror(errno)); } else if(fread(&out->load_sector_count, 1, 1, in) != 1) { @@ -76,12 +76,12 @@ static int ipl_read_header(ipl_t *out, FILE *in, const char *filename) { } else if(fread(out->extra, 1, 6, in) != 6) { ERROR_MSG("Failed to read EXTRA from %s: %s", filename, strerror(errno)); } else { - ret = 1; + ret = true; } return ret; } -void ipl_print(ipl_t *in) { +void ipl_print(IPL *in) { INFO_MSG("IPLBLK: hi:%02x mid:%02x lo:%02x", in->load_start_record[0], in->load_start_record[1], in->load_start_record[2]); INFO_MSG("IPLBKN: %02x", in->load_sector_count); INFO_MSG("IPLSTA: hi:%02x lo:%02x", in->load_store_address[1], in->load_store_address[0]); @@ -128,10 +128,10 @@ void ipl_print(ipl_t *in) { } } -/* Read IPL data from file. */ -int ipl_read(ipl_t *out, const char *filename) { +// Read IPL data from file. +bool ipl_read(IPL *out, const char *filename) { + bool ret = false; FILE *in = fopen(filename, "rb"); - int ret = 0; if(in == NULL) { ERROR_MSG("Failed to open %s: %s", filename, strerror(errno)); } else { @@ -139,73 +139,71 @@ int ipl_read(ipl_t *out, const char *filename) { ERROR_MSG("Failed to seek to IPL header in %s: %s", filename, strerror(errno)); } else if(ipl_read_header(out, in, filename)) { ipl_print(out); - ret = 1; + ret = true; } fclose(in); } return ret; } -/* Get irq code offsets from IPL. */ -int ipl_sections(ipl_t *in, section_t **out, int *count) { - int i, j, k, extra; - section_t *section; +// Get irq code offsets from IPL. +bool ipl_sections(IPL *in, Section **out, int *count) { static const char *section_name[2] = { "cd_start", "gfx_start" }; static const char *section_filename[2] = { "cd_start.asm", "gfx_start.bin" }; - uint32_t record; - extra = 0; + bool ret =true; + int extra = 0; if(in->load_sector_count) { extra++; } if(in->opening_gfx_sector_count) { extra++; } - if(0 == extra) { + if(extra == 0) { INFO_MSG("No section found from IPL data."); - return 1; - } - - j = *count; - section = (section_t*)realloc(*out, (j+extra) * sizeof(section_t)); - if(NULL == section) { - ERROR_MSG("Failed to add extra sections."); - return 0; - } - *count += extra; - *out = section; + } else { + int j = *count; + Section *section = (Section*)realloc(*out, (j+extra) * sizeof(Section)); + if(section == NULL) { + ERROR_MSG("Failed to add extra sections."); + ret = false; + } else { + *count += extra; + *out = section; - memset(§ion[j], 0, extra * sizeof(section_t)); + memset(§ion[j], 0, extra * sizeof(Section)); - for(k=0; kmpr[i]; + for(int k=0; kmpr[i]; + } + } + // "CD boot" + if(in->load_sector_count) { + uint32_t record = (in->load_start_record[0] << 16) | (in->load_start_record[1] << 8) | in->load_start_record[2]; + section[j].name = strdup(section_name[0]); + section[j].type = SECTION_TYPE_CODE; + section[j].page = section[j].mpr[in->load_exec_address[1]>>5]; + section[j].logical = (in->load_exec_address[1] << 8) | in->load_exec_address[0]; + section[j].offset = record * 2048; + section[j].size = in->load_sector_count * 2048; + section[j].output = strdup(section_filename[0]); + j++; + } + // "GFX" + if(in->opening_gfx_sector_count) { + uint32_t record = (in->opening_gfx_record[0] << 16) | (in->opening_gfx_record[1] << 8) | in->opening_gfx_record[2]; + section[j].name = strdup(section_name[1]); + section[j].type = SECTION_TYPE_DATA; + section[j].page = section[j].mpr[in->opening_gfx_read_address[1]>>5]; + section[j].logical = (in->opening_gfx_read_address[1] << 8) | in->opening_gfx_read_address[0]; + section[j].offset = record * 2048; + section[j].size = in->opening_gfx_sector_count * 2048; + section[j].output = strdup(section_filename[1]); + section[j].data.type = DATA_TYPE_BINARY; + section[j].data.element_size = 1; + section[j].data.elements_per_line = 16; + } } } - // "CD boot" - if(in->load_sector_count) { - record = (in->load_start_record[0] << 16) | (in->load_start_record[1] << 8) | in->load_start_record[2]; - section[j].name = strdup(section_name[0]); - section[j].type = Code; - section[j].page = section[j].mpr[in->load_exec_address[1]>>5]; - section[j].logical = (in->load_exec_address[1] << 8) | in->load_exec_address[0]; - section[j].offset = record * 2048; - section[j].size = in->load_sector_count * 2048; - section[j].output = strdup(section_filename[0]); - j++; - } - // "GFX" - if(in->opening_gfx_sector_count) { - record = (in->opening_gfx_record[0] << 16) | (in->opening_gfx_record[1] << 8) | in->opening_gfx_record[2]; - section[j].name = strdup(section_name[1]); - section[j].type = Data; - section[j].page = section[j].mpr[in->opening_gfx_read_address[1]>>5]; - section[j].logical = (in->opening_gfx_read_address[1] << 8) | in->opening_gfx_read_address[0]; - section[j].offset = record * 2048; - section[j].size = in->opening_gfx_sector_count * 2048; - section[j].output = strdup(section_filename[1]); - section[j].data.type = Binary; - section[j].data.element_size = 1; - section[j].data.elements_per_line = 16; - } - return 1; + return ret; } diff --git a/ipl.h b/ipl.h index 387e430..7f3d398 100644 --- a/ipl.h +++ b/ipl.h @@ -39,82 +39,74 @@ #include "config.h" #include "section.h" -/** - * IPL Information block data format - */ +/// IPL Information block data format typedef struct { - /** IPLBLK - load start record no. of CD (3 bytes high/medium/low) - * this is where the program is stored. **/ + /// IPLBLK - load start record no. of CD (3 bytes high/medium/low) + /// this is where the program is stored. uint8_t load_start_record[3]; - /** IPLBLN - load block length of CD (1 byte) - * number of sectors to read. **/ + /// IPLBLN - load block length of CD (1 byte) + /// number of sectors to read. uint8_t load_sector_count; - /** IPLSTA - program load address (2 bytes low/high) - * main memory address for program read. **/ + /// IPLSTA - program load address (2 bytes low/high) + /// main memory address for program read. uint8_t load_store_address[2]; - /** IPLJMP - program execute address (2 bytes low/high) - * starting address of execution after program read. **/ + /// IPLJMP - program execute address (2 bytes low/high) + /// starting address of execution after program read. uint8_t load_exec_address[2]; - /** IPLMPR - ipl set mpr2-6 (5 bytes) **/ + /// IPLMPR - ipl set mpr2-6 (5 bytes) uint8_t mpr[5]; - /** OPENMODE - opening mode - * bit 0: data read to vram (0: not read, 1: read) - * bit 1: data read to adpcm buffer (0: not read, 1: read) - * bit 5: bg display (0: display on, 1: display off) - * bit 6: adpcm play (0: play, 1: not play) - * bit 7: adpcm play mode (0: single, 1: repeat) **/ - uint8_t opening_mode; - /** GRPBLK - opening graphic data record no. (3 bytes high/medium/low) **/ + /// OPENMODE - opening mode + /// bit 0: data read to vram (0: not read, 1: read) + /// bit 1: data read to adpcm buffer (0: not read, 1: read) + /// bit 5: bg display (0: display on, 1: display off) + /// bit 6: adpcm play (0: play, 1: not play) + /// bit 7: adpcm play mode (0: single, 1: repeat) + uint8_t opening_mode; + /// GRPBLK - opening graphic data record no. (3 bytes high/medium/low) uint8_t opening_gfx_record[3]; - /** GRPBLN - opening graphic data length (1 byte) **/ + /// GRPBLN - opening graphic data length (1 byte) uint8_t opening_gfx_sector_count; - /** GRPADR - opening graphic data read address (2 bytes low/high) **/ + /// GRPADR - opening graphic data read address (2 bytes low/high) uint8_t opening_gfx_read_address[2]; - /** ADPBLK - opening ADPCM data record no. (3 bytes high/medium/low) **/ + /// ADPBLK - opening ADPCM data record no. (3 bytes high/medium/low) uint8_t opening_adpcm_record[3]; - /** ADPBLN - opening ADPCM data length (1 byte) **/ + /// ADPBLN - opening ADPCM data length (1 byte) uint8_t opening_adpcm_sector_count; - /** ADPRATE - opening ADPCM sampling rate (1 byte) **/ + /// ADPRATE - opening ADPCM sampling rate (1 byte) uint8_t opening_adpcm_sampling_rate; - /** RESERVED (7 bytes) **/ + /// RESERVED (7 bytes) uint8_t reserved[7]; - /** ID STR - "PC Engine CD-ROM SYSTEM", 0 **/ + /// ID STR - "PC Engine CD-ROM SYSTEM", 0 uint8_t id[24]; - /** LEGAL - "Copyright HUDSON SOFT / NEC Home Electronics, Ltd.", 0 **/ + /// LEGAL - "Copyright HUDSON SOFT / NEC Home Electronics, Ltd.", 0 uint8_t legal[50]; - /** PROGRAM NAME - program name (16 bytes) **/ + /// PROGRAM NAME - program name (16 bytes) uint8_t program_name[16]; - /** EXTRA - (6 bytes) **/ + /// EXTRA - (6 bytes) uint8_t extra[6]; -} ipl_t; -/* +} IPL; +/* [todo] IPL graphic block color palette - 1 record BAT data - 1 record BG font data - GRPBLN - 2 records */ -/** - * Display IPL infos. - * \param [in] in IPL infos. - */ -void ipl_print(ipl_t *in); +/// Display IPL infos. +/// \param [in] in IPL infos. +void ipl_print(IPL *in); -/** - * Read IPL data from file. - * \param [out] out IPL infos. - * \param [in] filename Input filename. - * \return 0 on error, 1 otherwise. - */ -int ipl_read(ipl_t *out, const char *filename); +/// Read IPL data from file. +/// \param [out] out IPL infos. +/// \param [in] filename Input filename. +/// \return 0 on error, 1 otherwise. +bool ipl_read(IPL *out, const char *filename); -/** - * Get irq code offsets from IPL. - * \param [in] in IPL infos. - * \param [out] section Sections. - * \param [out] count Section count. - * \return 0 on error, 1 otherwise. - */ -int ipl_sections(ipl_t *in, section_t **out, int *count); +/// Get irq code offsets from IPL. +/// \param [in] in IPL infos. +/// \param [out] section Sections. +/// \param [out] count Section count. +/// \return 0 on error, 1 otherwise. +bool ipl_sections(IPL *in, Section **out, int *count); #endif // IPL_H diff --git a/irq.c b/irq.c index e51a142..deeae34 100644 --- a/irq.c +++ b/irq.c @@ -65,6 +65,7 @@ bool irq_read(MemoryMap* map, Section **section, int *count) { ERROR_MSG("Failed to allocate extra IRQ sections."); } else { int j = *count; + uint16_t offset = PCE_IRQ_TABLE; *section = tmp; *count += PCE_IRQ_COUNT; @@ -72,13 +73,12 @@ bool irq_read(MemoryMap* map, Section **section, int *count) { // IRQ name. const char *name = g_irq_names[i]; // Read offset. - uint8_t lo = memmap_read(map, offset++); - uint8_t hi = memmap_read(map, offset++); + uint8_t lo = memory_map_read(map, offset++); + uint8_t hi = memory_map_read(map, offset++); -// [todo] code_add.... // Initialize section tmp[j].name = strdup(name); - tmp[j].type = Code; + tmp[j].type = SECTION_TYPE_CODE; tmp[j].page = 0; tmp[j].logical = (hi << 8) | lo; tmp[j].size = 0; @@ -89,7 +89,7 @@ bool irq_read(MemoryMap* map, Section **section, int *count) { tmp[j].mpr[k] = 0x00; // ROM } - filename_len = strlen(name) + 5U; // .asm\0 + size_t filename_len = strlen(name) + 5U; // .asm\0 tmp[j].output = (char*)malloc(filename_len); snprintf(tmp[j].output, filename_len, "%s.asm", name); diff --git a/irq.h b/irq.h index 9881d17..19a4140 100644 --- a/irq.h +++ b/irq.h @@ -37,39 +37,15 @@ #define ETRIPATOR_IRQ_H #include "config.h" -//#include "code.h" -#include "memorymap.h" - -/// Section. -typedef struct Section { - struct Section *previous; ///< Previous section. - struct Section *next; ///< Next section. - uint8_t page; ///< Memory page. - uint16_t logical; ///< Logical address. - uint8_t mpr[8]; ///< MPR registers value. - int32_t size; ///< Size (in bytes). - char *output; ///< Output filename. - // [todo] function pointers - // [todo] bool decode(???) -} Section; - -/* -status_code decode(Section *section, MemoryMap *map, LabelRepository *repository, CommentRepository *comments - , in: uint16_t current - , out: uint16_t *out - , in: void *payload -); -Section *section, MemoryMap *map, LabelRepository *repository, CommentRepository *comments => struct (opaque pointer) -status_code: - ERROR - OK -*/ +#include "memory_map.h" +#include "section.h" /// Get irq code offsets from rom. /// \param [in] map Memory map. /// \param [out] section Section list. +/// \param [out] count Number of extracted sections. /// \return true if the IRQ vectors where successfully extradcted. /// \return false otherwise (missing ROM, or offsets out of range). -bool irq_read(MemoryMap* map, Section *section); +bool irq_read(MemoryMap* map, Section **section, int *count); #endif // ETRIPATOR_IRQ_H diff --git a/label/save.c b/label/save.c index f901664..fc1977d 100644 --- a/label/save.c +++ b/label/save.c @@ -50,8 +50,8 @@ bool label_repository_save(LabelRepository* repository, const char* filename) { int count = label_repository_size(repository); fprintf(stream, "[\n"); - for(i=0; i #include -/* Save sections to a JSON file. */ -int section_save(const char *filename, section_t *ptr, int n) { - int i; +// Save sections to a JSON file +bool section_save(const Section *ptr, int n, const char *filename) { + bool ret = false; FILE *out = fopen(filename, "wb"); if(!out) { ERROR_MSG("Failed to open %s: %s", filename, strerror(errno)); - return 0; - } - - fprintf(out, "{\n"); - for(i=0; i ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2024 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include +#include "opcodes.h" +#include "message.h" +#include "message/console.h" + +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + message_printer_init(); + console_message_printer_init(); + return NULL; +} + +void tear_down(void* fixture __attribute__((unused))) { + message_printer_destroy(); +} + +MunitResult opcodes_get_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + const Opcode* op; + + op = opcode_get(0x00); + munit_assert_not_null(op); + munit_assert_string_equal(op->name, "brk "); + munit_assert_uint8(op->size, ==, 1U); + munit_assert_uint8(op->type, ==, PCE_OP); + + op = opcode_get(0xFF); + munit_assert_not_null(op); + munit_assert_string_equal(op->name, "bbs7"); + munit_assert_uint8(op->size, ==, 3U); + munit_assert_uint8(op->type, ==, PCE_OP_ZZ_lbl); + + op = opcode_get(0x2B); + munit_assert_not_null(op); + munit_assert_string_equal(op->name, ".db "); + munit_assert_uint8(op->size, ==, 1U); + munit_assert_uint8(op->type, ==, PCE_unknown); + + return MUNIT_OK; +} + +MunitResult opcodes_format_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + const Opcode* op; + unsigned int i; + + // tii + op = opcode_get(0x73); + munit_assert_uint8(op->type, ==, PCE_OP_shsl_dhdl_hhll); + for(i=0; i<(op->size-1); i++) { // skip opcode + munit_assert_not_null(opcode_format(op, i)); + } + for(; i<256; i++) { + munit_assert_null(opcode_format(op, i)); + } + + return MUNIT_OK; +} + +MunitResult opcodes_jump_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + // local jump + for(unsigned int i=0x0FU; i<0x100U; i+=0x10U) { + munit_assert_true(opcode_is_local_jump(i)); // BBR* and BBS* + } + munit_assert_true(opcode_is_local_jump(0x90U)); // BCC + munit_assert_true(opcode_is_local_jump(0xB0U)); // BCS + munit_assert_true(opcode_is_local_jump(0x80U)); // BRA + munit_assert_true(opcode_is_local_jump(0xF0U)); // BEQ + munit_assert_true(opcode_is_local_jump(0x30U)); // BMI + munit_assert_true(opcode_is_local_jump(0xD0U)); // BNE + munit_assert_true(opcode_is_local_jump(0x10U)); // BPL + munit_assert_true(opcode_is_local_jump(0x44U)); // BSR + munit_assert_true(opcode_is_local_jump(0x50U)); // BVC + munit_assert_true(opcode_is_local_jump(0x70U)); // BVS + + munit_assert_false(opcode_is_local_jump(0xEAU)); // NO + munit_assert_false(opcode_is_local_jump(0x4CU)); // JMP + munit_assert_false(opcode_is_local_jump(0x20U)); // JSP + + // far jump + for(unsigned int i=0x0FU; i<0x100U; i+=0x10U) { + munit_assert_false(opcode_is_far_jump(i)); // BBR* and BBS* + } + munit_assert_false(opcode_is_far_jump(0x90U)); // BCC + munit_assert_false(opcode_is_far_jump(0xB0U)); // BCS + munit_assert_false(opcode_is_far_jump(0x80U)); // BRA + munit_assert_false(opcode_is_far_jump(0xF0U)); // BEQ + munit_assert_false(opcode_is_far_jump(0x30U)); // BMI + munit_assert_false(opcode_is_far_jump(0xD0U)); // BNE + munit_assert_false(opcode_is_far_jump(0x10U)); // BPL + munit_assert_false(opcode_is_far_jump(0x44U)); // BSR + munit_assert_false(opcode_is_far_jump(0x50U)); // BVC + munit_assert_false(opcode_is_far_jump(0x70U)); // BVS + + munit_assert_false(opcode_is_far_jump(0xEAU)); // NOP + munit_assert_true(opcode_is_far_jump(0x4CU)); // JMP + munit_assert_true(opcode_is_far_jump(0x20U)); // JSR + + return MUNIT_OK; +} + +static MunitTest opcodes_tests[] = { + { "/get", opcodes_get_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/format", opcodes_format_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/jump", opcodes_jump_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } +}; + +static const MunitSuite opcodes_suite = { + "Opcodes test suite", opcodes_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE +}; + +int main (int argc, char* const* argv) { + return munit_suite_main(&opcodes_suite, NULL, argc, argv); +} \ No newline at end of file From 34286d7745d4d80cb1ce58331f8f83fa67a310cb Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 20 Oct 2024 16:35:29 +0200 Subject: [PATCH 24/35] Add IPL unit test & fixes --- ipl.c | 21 +++++-- test/CMakeLists.txt | 10 ++++ test/ipl.c | 137 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 test/ipl.c diff --git a/ipl.c b/ipl.c index 367a6ed..a4cf4d4 100644 --- a/ipl.c +++ b/ipl.c @@ -41,6 +41,7 @@ static bool ipl_read_header(IPL *out, FILE *in, const char *filename) { bool ret = false; + if(fread(out->load_start_record, 1, 3, in) != 3) { ERROR_MSG("Failed to read IPLBLK from %s: %s", filename, strerror(errno)); } else if(fread(&out->load_sector_count, 1, 1, in) != 1) { @@ -107,21 +108,29 @@ void ipl_print(IPL *in) { } else { fprintf(stream, "IPLBLK: .db $%02x, $%02x, $%02x\n", in->load_start_record[0], in->load_start_record[1], in->load_start_record[2]); fprintf(stream, "IPLBKN: .db $%02x\n", in->load_sector_count); - fprintf(stream, "IPLSTA: .dw $%02x%02x\n", in->load_store_address[0], in->load_store_address[1]); - fprintf(stream, "IPLJMP: .dw $%02x%02x\n", in->load_exec_address[0], in->load_exec_address[1]); + fprintf(stream, "IPLSTA: .dw $%02x%02x\n", in->load_store_address[1], in->load_store_address[0]); + fprintf(stream, "IPLJMP: .dw $%02x%02x\n", in->load_exec_address[1], in->load_exec_address[0]); fprintf(stream, "IPLMPR: .db $%02x, $%02x, $%02x, $%02x, $%02x\n", in->mpr[0], in->mpr[1], in->mpr[2], in->mpr[3], in->mpr[4]); fprintf(stream, "OPENMODE: .db $%02x\n", in->opening_mode); fprintf(stream, "GRPBLK: .db $%02x, $%02x, $%02x\n", in->opening_gfx_record[0], in->opening_gfx_record[1], in->opening_gfx_record[2]); fprintf(stream, "GRPBLN: .db $%02x\n", in->opening_gfx_sector_count); - fprintf(stream, "GRPADR: .dw $%02x%02x\n", in->opening_gfx_read_address[0], in->opening_gfx_read_address[1]); + fprintf(stream, "GRPADR: .dw $%02x%02x\n", in->opening_gfx_read_address[1], in->opening_gfx_read_address[0]); fprintf(stream, "ADPBLK: .db $%02x, $%02x, $%02x\n", in->opening_adpcm_record[0], in->opening_adpcm_record[1], in->opening_adpcm_record[2]); fprintf(stream, "ADPBLN: .db %02x\n", in->opening_adpcm_sector_count); - fprintf(stream, "ADPRATE: .db $%02x\b", in->opening_adpcm_sampling_rate); + fprintf(stream, "ADPRATE: .db $%02x\n", in->opening_adpcm_sampling_rate); fprintf(stream, "RESERVED: .db $%02x, $%02x, $%02x, $%02x, $%02x, $%02x, $%02x\n", in->reserved[0], in->reserved[1], in->reserved[2], in->reserved[3], in->reserved[4], in->reserved[5], in->reserved[6]); - fprintf(stream, "ID STR: .db \"%.24s\"\n", in->id); - fprintf(stream, "LEGAL: .db \"%.50s\"\n", in->legal); + fprintf(stream, "ID STR: .db \"%.24s\"", in->id); + for(int i=23; (i>=0) && (in->id[i] == '\0'); i--) { + fprintf(stream, ",0"); + } + fputc('\n', stream); + fprintf(stream, "LEGAL: .db \"%.50s\"", in->legal); + for(int i=49; (i>=0) && (in->legal[i] == '\0'); i--) { + fprintf(stream, ",0"); + } + fputc('\n', stream); fprintf(stream,"PROGRAM NAME: .db \"%.16s\"\n", in->program_name); fprintf(stream,"EXTRA: .db \"%.6s\"\n", in->extra); fclose(stream); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9402dc9..850d2bd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -140,3 +140,13 @@ add_unit_test( LIBRARIES cwalk jansson INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) + +add_unit_test( + NAME ipl + SOURCES + ipl.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} +) diff --git a/test/ipl.c b/test/ipl.c new file mode 100644 index 0000000..a021897 --- /dev/null +++ b/test/ipl.c @@ -0,0 +1,137 @@ +/* +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + __/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__ + \_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_ + _> ___/ ¯>__> <<__// __ _/ |> > <<__// /\ // __ _/ + _> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ \_ +|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::| +|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯| +|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _| + \|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/ + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ + + This file is part of Etripator, + copyright (c) 2009--2024 Vincent Cruz. + + Etripator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Etripator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Etripator. If not, see . + +¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸ +¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ +*/ +#include + +#include "../ipl.c" + +#include "message.h" +#include "message/console.h" + +static uint8_t g_hcd8004_ipl[] = { + 0x00, 0x00, 0x02, 0x04, 0x00, 0x40, 0x00, 0x40, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x43, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x43, 0x44, 0x2D, 0x52, 0x4F, 0x4D, + 0x20, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4D, 0x00, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x48, 0x55, 0x44, 0x53, 0x4F, 0x4E, 0x20, 0x53, 0x4F, 0x46, 0x54, 0x20, 0x2F, 0x20, + 0x4E, 0x45, 0x43, 0x20, 0x48, 0x6F, 0x6D, 0x65, 0x20, 0x45, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, + 0x6E, 0x69, 0x63, 0x73, 0x2C, 0x4C, 0x74, 0x64, 0x2E, 0x00, 0x53, 0x70, 0x61, 0x63, 0x65, 0x20, + 0x41, 0x64, 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x20, 0x43, 0x4F, 0x42, 0x52, 0x41, 0x20, +}; + +void* setup(const MunitParameter params[] __attribute__((unused)), void* user_data __attribute__((unused))) { + message_printer_init(); + console_message_printer_init(); + return NULL; +} + +void tear_down(void* fixture __attribute__((unused))) { + message_printer_destroy(); +} + +MunitResult ipl_read_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { + IPL ipl = {0}; + const char *filename = "data/HCD8004.ipl"; + + FILE *in = fmemopen(g_hcd8004_ipl, sizeof(g_hcd8004_ipl), "r"); + + munit_assert_not_null(in); + munit_assert_true(ipl_read_header(&ipl, in, filename)); + munit_assert_int(fclose(in), ==, 0); + + munit_assert_uint8(ipl.load_start_record[0], ==, 0x00U); + munit_assert_uint8(ipl.load_start_record[1], ==, 0x00U); + munit_assert_uint8(ipl.load_start_record[2], ==, 0x02U); + + munit_assert_uint8(ipl.load_sector_count, ==, 0x04U); + + munit_assert_uint8(ipl.load_store_address[0], ==, 0x00U); + munit_assert_uint8(ipl.load_store_address[1], ==, 0x40U); + + munit_assert_uint8(ipl.load_exec_address[0], ==, 0x00U); + munit_assert_uint8(ipl.load_exec_address[1], ==, 0x40U); + + munit_assert_uint8(ipl.mpr[0], ==, 0x00U); + munit_assert_uint8(ipl.mpr[1], ==, 0x01U); + munit_assert_uint8(ipl.mpr[2], ==, 0x02U); + munit_assert_uint8(ipl.mpr[3], ==, 0x03U); + munit_assert_uint8(ipl.mpr[4], ==, 0x04U); + + munit_assert_uint8(ipl.opening_mode, ==, 0x00U); + + munit_assert_uint8(ipl.opening_gfx_record[0], ==, 0x00U); + munit_assert_uint8(ipl.opening_gfx_record[1], ==, 0x00U); + munit_assert_uint8(ipl.opening_gfx_record[2], ==, 0x00U); + + munit_assert_uint8(ipl.opening_gfx_sector_count, ==, 0x00U); + + munit_assert_uint8(ipl.opening_gfx_read_address[0], ==, 0x00U); + munit_assert_uint8(ipl.opening_gfx_read_address[1], ==, 0x00U); + + munit_assert_uint8(ipl.opening_adpcm_record[0], ==, 0x00U); + munit_assert_uint8(ipl.opening_adpcm_record[1], ==, 0x00U); + munit_assert_uint8(ipl.opening_adpcm_record[2], ==, 0x00U); + + munit_assert_uint8(ipl.opening_adpcm_sector_count, ==, 0x00U); + + munit_assert_uint8(ipl.opening_adpcm_sampling_rate, ==, 0x00U); + + for(unsigned int i=0; i<7; i++) { + munit_assert_uint8(ipl.reserved[i], ==, 0x00U); + } + + munit_assert_memory_equal(24U, ipl.id, "PC Engine CD-ROM SYSTEM"); + + munit_assert_memory_equal(50U, ipl.legal, "Copyright HUDSON SOFT / NEC Home Electronics,Ltd."); + + munit_assert_memory_equal(16U, ipl.program_name, "Space Adventure "); + + munit_assert_memory_equal(6U, ipl.extra, "COBRA "); + + return MUNIT_OK; +} + +static MunitTest g_ipl_tests[] = { + { "/read", ipl_read_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } +}; + +static const MunitSuite g_ipl_test_suite = { + "Label test suite", g_ipl_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE +}; + +int main (int argc, char* const* argv) { + return munit_suite_main(&g_ipl_test_suite, NULL, argc, argv); +} \ No newline at end of file From cd0b9cb07c28a42131dea5ea840cd30b4d8dae65 Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 20 Oct 2024 17:39:32 +0200 Subject: [PATCH 25/35] Remove Games Express bank 0 from examples (use the repo instead) --- README.md | 2 +- examples/games_express/bank0.json | 93 ---------------------------- examples/games_express/comments.json | 17 ----- examples/games_express/labels.json | 13 ---- 4 files changed, 1 insertion(+), 124 deletions(-) delete mode 100644 examples/games_express/bank0.json delete mode 100644 examples/games_express/comments.json delete mode 100644 examples/games_express/labels.json diff --git a/README.md b/README.md index 7ad7099..4414f81 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ * [Gfx unpacking](examples/maerchen_maze) in Maerchen Maze - メルヘンメイズ . * [Memory Base 128 detection](examples/tadaima) in Taidama Yusha Boshuchu - ただいま勇者募集中. * [Joypad routine](examples/sf2) of Street Fighter II' Champion Edition - ストリートファイターII'. -* [Games Express CD Card bank #0](examples/games_express). +* [Games Express CD Card](https://github.com/BlockoS/GamesExpressCDCard). * [Password check](examples/youkai_douchuuki) in Youkai Douchuuki - 妖怪道中記. ## Usage diff --git a/examples/games_express/bank0.json b/examples/games_express/bank0.json deleted file mode 100644 index 704e35f..0000000 --- a/examples/games_express/bank0.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "le22a": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "e22a", - "mpr": ["ff", "f8", 0, 0, 0, 0, 1, 0 ] - }, - "le267": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "e267", - "mpr": ["ff", "f8", 0, 0, 0, 0, 1, 0 ] - }, - "le865_00": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "e865", - "mpr": ["ff", "f8", 0, 0, 0, 0, 1, 0 ] - }, - "le903_00": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "e903", - "mpr": ["ff", "f8", 0, 0, 0, 0, 1, 0 ] - }, - "le98c_00": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "e98c", - "mpr": ["ff", "f8", 0, 0, 0, 0, 1, 0 ] - }, - "irq_1": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "eba5", - "mpr": ["ff", "f8", 0, 0, 0, 0, 0, 0 ] - }, - "irq_2": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "eaa3", - "mpr": ["ff", "f8", 0, 0, 0, 0, 0, 0 ] - }, - "irq_nmi": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "ea9b", - "mpr": ["ff", "f8", 0, 0, 0, 0, 0, 0 ] - }, - "irq_reset": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "eab3", - "mpr": ["ff", "f8", 0, 0, 0, 0, 0, 0 ], - "description": [ - "-------------------------------------------------------------------------------", - " \"RESET\" interrupt handler", - "-------------------------------------------------------------------------------" - ] - }, - "led03_00": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "ed03", - "mpr": ["ff", "f8", 0, 0, 0, 0, 1, 0 ] - }, - "lf8a4_00": { - "filename": "games_express.asm", - "type": "code", - "page": 0, - "logical": "f8a4", - "mpr": ["ff", "f8", 0, 0, 0, 0, 1, 0 ] - }, - "irq_vectors": { - "filename": "games_express.asm", - "type": "data", - "page": 0, - "logical" :"fff6", - "size": "a", - "mpr": ["ff", "f8", 0, 0, 0, 0, 0, 0 ], - "data": { "type": "hex", "element_size": 2, "elements_per_line": 1 } - } -} diff --git a/examples/games_express/comments.json b/examples/games_express/comments.json deleted file mode 100644 index 844c2e7..0000000 --- a/examples/games_express/comments.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { "logical": "eab3", "page":"00", "text": "switch CPU to high speed mode"}, - { "logical": "eab4", "page":"00", "text": "disable interrupts"}, - { "logical": "eab5", "page":"00", "text": "clear decimal flag"}, - { "logical": "eab6", "page":"00", "text": "map I/O to the 1st memory page"}, - { "logical": "eaba", "page":"00", "text": "map RAM to the 2nd memory page"}, - { "logical": "eabe", "page":"00", "text": "clear zero page"}, - { "logical": "eac7", "page":"00", "text": "clear bss"}, - { "logical": "ead1", "page":"00", "text": [ - "disable interrupts", - "this looks like the soft reset entry point" - ] - }, - { "logical": "ead2", "page":"00", "text": "disable CPU timer"}, - { "logical": "ead5", "page":"00", "text": "switch CPU to high speed mode"}, - { "logical": "ead6", "page":"00", "text": "reset stack pointer"} -] diff --git a/examples/games_express/labels.json b/examples/games_express/labels.json deleted file mode 100644 index 6d65776..0000000 --- a/examples/games_express/labels.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { "name":"cd_reset", "logical":"e22a", "page":"00" }, - { "name":"irq_2", "logical":"eaa3", "page":"00" }, - { "name":"leaeb_00", "logical":"eaeb", "page":"00" }, - { "name":"irq_1", "logical":"eba5", "page":"00" }, - { "name":"irq_timer", "logical":"ea9c", "page":"00" }, - { "name":"irq_nmi", "logical":"ea9b", "page":"00" }, - { "name":"irq_reset", "logical":"eab3", "page":"00" }, - { "name":"main", "logical":"f8a4", "page":"00" }, - { "name":"irq1_jmp", "logical":"2200", "page":"f8" }, - { "name":"irq2_jmp", "logical":"2202", "page":"f8" }, - { "name":"timer_jmp", "logical":"2263", "page":"f8" } -] From 352e3707649006af741b5e404a1e4498ae4ddb3d Mon Sep 17 00:00:00 2001 From: MooZ Date: Fri, 1 Nov 2024 17:34:15 +0100 Subject: [PATCH 26/35] Fix build --- CMakeLists.txt | 4 +- cmake/FindJansson.cmake | 51 +++++++++++-------- decode.c | 105 ++++++++++++++++++++-------------------- label.c | 10 ++-- test/CMakeLists.txt | 33 ++++++++----- 5 files changed, 109 insertions(+), 94 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b692bc..1160e2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,9 +72,9 @@ set(etripator_HDR add_library(etripator STATIC ${etripator_SRC} ${etripator_HDR}) set_target_properties(etripator PROPERTIES C_STANDARD 11) -target_include_directories(etripator PUBLIC ${JANSSON_INCLUDE_DIRS} ${EXTRA_INCLUDE} externals) +target_include_directories(etripator PUBLIC ${EXTRA_INCLUDE} externals) target_compile_definitions(etripator PRIVATE _POSIX_C_SOURCE) -target_link_libraries(etripator PUBLIC ${JANSSON_LIBRARIES} cwalk) +target_link_libraries(etripator PUBLIC jansson cwalk) #[[ add_executable(etripator_cli cli/etripator.c cli/options.c) set_target_properties(etripator_cli diff --git a/cmake/FindJansson.cmake b/cmake/FindJansson.cmake index 3225923..e31f92c 100755 --- a/cmake/FindJansson.cmake +++ b/cmake/FindJansson.cmake @@ -26,34 +26,43 @@ else (JANSSON_LIBRARIES AND JANSSON_INCLUDE_DIRS) /sw/include ) -find_library(JANSSON_LIBRARY - NAMES - jansson - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /sw/lib + find_library(JANSSON_LIBRARY + NAMES + jansson + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib ) -set(JANSSON_INCLUDE_DIRS - ${JANSSON_INCLUDE_DIR} + set(JANSSON_INCLUDE_DIRS + ${JANSSON_INCLUDE_DIR} ) -if (JANSSON_LIBRARY) - set(JANSSON_LIBRARIES - ${JANSSON_LIBRARIES} - ${JANSSON_LIBRARY} + if (JANSSON_LIBRARY) + set(JANSSON_LIBRARIES + ${JANSSON_LIBRARIES} + ${JANSSON_LIBRARY} ) -endif (JANSSON_LIBRARY) + endif (JANSSON_LIBRARY) +endif (JANSSON_LIBRARIES AND JANSSON_INCLUDE_DIRS) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Jansson DEFAULT_MSG - JANSSON_LIBRARIES JANSSON_INCLUDE_DIRS) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Jansson DEFAULT_MSG + JANSSON_LIBRARIES JANSSON_INCLUDE_DIRS) - # show the JANSSON_INCLUDE_DIRS and JANSSON_LIBRARIES variables only in the advanced view - mark_as_advanced(JANSSON_INCLUDE_DIRS JANSSON_LIBRARIES) +if(JANSSON_FOUND) + add_library(jansson UNKNOWN IMPORTED) + set_target_properties(jansson + PROPERTIES + IMPORTED_LOCATION "${JANSSON_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${JANSSON_INCLUDE_DIRS}" + ) +endif() + +# show the JANSSON_INCLUDE_DIRS and JANSSON_LIBRARIES variables only in the advanced view +mark_as_advanced(JANSSON_INCLUDE_DIRS JANSSON_LIBRARIES) -endif (JANSSON_LIBRARIES AND JANSSON_INCLUDE_DIRS) diff --git a/decode.c b/decode.c index e80d837..6a209d7 100644 --- a/decode.c +++ b/decode.c @@ -41,25 +41,24 @@ #define ETRIPATOR_LAST_COLUMN 80U -static const char *spacing = " "; +static const char g_spacing[] = " "; -static int last_column_spacing(int current_char_count) { +static inline int last_column_spacing(int current_char_count) { return (current_char_count < ETRIPATOR_LAST_COLUMN) ? (ETRIPATOR_LAST_COLUMN - current_char_count) : 1; } static void print_comment(FILE *out, const char *str) { - if (!str) { - return; - } - while (*str) { - fputc(';', out); - fputc(' ', out); - for (; *str && (*str != '\n'); str++) { - fputc(*str, out); - } - fputc('\n', out); - if (*str) { - str++; + if(str != NULL) { + while (*str != '\0') { + fputc(';', out); + fputc(' ', out); + for (; (*str != '\0') && (*str != '\n'); str++) { + fputc(*str, out); + } + fputc('\n', out); + if (*str != '\0') { + str++; + } } } } @@ -115,11 +114,11 @@ bool label_extract(Section *section, MemoryMap *map, LabelRepository *repository /* Walk along section */ for (logical = section->logical; logical < (section->logical + section->size); logical += opcode->size) { /* Read instruction */ - inst = memmap_read(map, logical); + inst = memory_map_read(map, logical); opcode = opcode_get(inst); /* Read data (if any) */ for (i = 0; i < (opcode->size - 1); i++) { - data[i] = memmap_read(map, logical + i + 1); + data[i] = memory_map_read(map, logical + i + 1); } if (opcode_is_local_jump(inst)) { @@ -135,7 +134,7 @@ bool label_extract(Section *section, MemoryMap *map, LabelRepository *repository } delta += opcode->size; jump = logical + delta; - page = memmap_page(map, jump); + page = memory_map_page(map, jump); /* Create label name */ snprintf(buffer, 32, "l%04x_%02d", jump, page); @@ -146,7 +145,7 @@ bool label_extract(Section *section, MemoryMap *map, LabelRepository *repository INFO_MSG("%04x short jump to %04x (%02x)", logical, jump, page); } else if (opcode_is_far_jump(inst)) { uint16_t jump = data[0] | (data[1] << 8); - page = memmap_page(map, jump); + page = memory_map_page(map, jump); /* Create label name */ snprintf(buffer, 32, "l%04x_%02d", jump, page); /* Insert offset to repository */ @@ -164,7 +163,7 @@ static int data_extract_binary(FILE *out, Section *section, MemoryMap *map, Labe uint16_t logical; int32_t i; for (i = 0, logical = section->logical; i < section->size; i++, logical++) { - uint8_t data = memmap_read(map, logical); + uint8_t data = memory_map_read(map, logical); fwrite(&data, 1, 1, out); } return 1; @@ -191,14 +190,14 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe int has_comment = 0; for (i = 0, j = 0, logical = section->logical; i < section->size; i++, logical++) { - uint8_t page = memmap_page(map, logical); + uint8_t page = memory_map_page(map, logical); int has_label = label_repository_find(repository, logical, page, &label); if (has_label) { // flush any bytes left in the buffer. if (top && (top < element_size)) { - fprintf(out, "\n%s.db $%02x", spacing, buffer[0]); + fprintf(out, "\n%s.db $%02x", g_spacing, buffer[0]); for (int32_t l = 1; l < top; l++) { // useless as top is always equal to 1 fprintf(out, ",$%02x", buffer[l]); } @@ -215,7 +214,7 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe if (comment_repository_find(comments, logical, page, &dummy)) { if (has_comment) { if (top && (top < element_size)) { - fprintf(out, "\n%s.db $%02x", spacing, buffer[0]); + fprintf(out, "\n%s.db $%02x", g_spacing, buffer[0]); for (int32_t l = 1; l < top; l++) { // useless as top is always equal to 1 fprintf(out, ",$%02x", buffer[l]); } @@ -228,7 +227,7 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe j = 0; } - buffer[top++] = memmap_read(map, logical); + buffer[top++] = memory_map_read(map, logical); if (top >= element_size) { char sep; @@ -241,7 +240,7 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe const char *data_decl = (top > 1) ? ".dw" : ".db"; - fprintf(out, "%s%s", spacing, data_decl); + fprintf(out, "%s%s", g_spacing, data_decl); sep = ' '; } else { sep = ','; @@ -279,7 +278,7 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe } else if (extra_infos) { print_statement_address(out, (int)(ftell(out) - line_offset), line_logical, line_page); } - fprintf(out, "\n%s.db $%02x", spacing, buffer[0]); + fprintf(out, "\n%s.db $%02x", g_spacing, buffer[0]); for (int32_t j = 1; j < top; j++) { // useless as top is always equal to 1 fprintf(out, ",$%02x", buffer[j]); } @@ -306,8 +305,8 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe Comment comment = {0}; for (i = 0, j = 0, logical = section->logical; i < section->size; i++, logical++) { - uint8_t data = memmap_read(map, logical); - uint8_t page = memmap_page(map, logical); + uint8_t data = memory_map_read(map, logical); + uint8_t page = memory_map_page(map, logical); Label label = {0}; @@ -347,7 +346,7 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe line_offset = ftell(out); // record star of line line_logical = logical; line_page = page; - fprintf(out, "%s.db ", spacing); + fprintf(out, "%s.db ", g_spacing); } // print char @@ -430,9 +429,9 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, uint8_t data[2] = {0}; for (i = 0, j = 0, logical = section->logical; i < section->size; i += 2, logical += 2) { - page = memmap_page(map, logical); - data[0] = memmap_read(map, logical); - data[1] = memmap_read(map, logical + 1); + page = memory_map_page(map, logical); + data[0] = memory_map_read(map, logical); + data[1] = memory_map_read(map, logical + 1); has_label = label_repository_find(repository, logical, page, &label); @@ -459,7 +458,7 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, line_offset = ftell(out); line_logical = logical; line_page = page; - fprintf(out, "%s.dw ", spacing); + fprintf(out, "%s.dw ", g_spacing); } if (j) { @@ -467,7 +466,7 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, } uint16_t jump_logical = data[0] | (data[1] << 8); - uint8_t jump_page = memmap_page(map, jump_logical); + uint8_t jump_page = memory_map_page(map, jump_logical); if (label_repository_find(repository, jump_logical, jump_page, &label)) { fprintf(out, "%s", label.name); @@ -532,10 +531,10 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label eor = 0; memset(data, 0, 6); - page = memmap_page(map, *logical); + page = memory_map_page(map, *logical); /* Opcode */ - inst = memmap_read(map, *logical); + inst = memory_map_read(map, *logical); opcode = opcode_get(inst); current_page = page; @@ -552,13 +551,13 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label size_t start = ftell(out); /* Front spacing */ - fwrite(spacing, 1, 10, out); + fwrite(g_spacing, 1, 10, out); /* Print opcode string */ fwrite(opcode->name, 1, 4, out); /* Add spacing */ - fwrite(spacing, 1, 4, out); + fwrite(g_spacing, 1, 4, out); /* End Of Routine (eor) is set to 1 if the instruction is RTI, RTS or BRK */ eor = ((inst == 0x40) || (inst == 0x60) || (inst == 0x00)); @@ -566,7 +565,7 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label /* Data */ if (opcode->size > 1) { for (i = 0; i < (opcode->size - 1); i++) { - data[i] = memmap_read(map, *logical + i + 1); + data[i] = memory_map_read(map, *logical + i + 1); } } @@ -624,14 +623,14 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label /* BBR* and BBS* */ if ((inst & 0x0F) == 0x0F) { uint16_t zp_offset = 0x2000 + data[0]; // [todo] RAM may not be in mpr1 ... - page = memmap_page(map, zp_offset); + page = memory_map_page(map, zp_offset); if (label_repository_find(repository, zp_offset, page, &label)) { fprintf(out, "<%s, ", label.name); } else { fprintf(out, "<$%02x, ", data[0]); } } - page = memmap_page(map, offset); + page = memory_map_page(map, offset); // Label name should have been set by the label extraction pass. label_repository_find(repository, offset, page, &label); fwrite(label.name, 1, strlen(label.name), out); @@ -656,7 +655,7 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label /* fall through */ case PCE_OP_nn_ZZ: /* #$aa, <$zp */ offset = 0x2000 + data[1]; - page = memmap_page(map, offset); + page = memory_map_page(map, offset); has_label = label_repository_find(repository, offset, page, &label); if (has_label) { fprintf(out, "#$%02x, <%s%s", data[0], label.name, extra); @@ -667,7 +666,7 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label /* fall through */ case PCE_OP_nn_hhll: /* #$aa, $hhll */ offset = (data[1] << 8) + data[2]; - page = memmap_page(map, offset); + page = memory_map_page(map, offset); has_label = label_repository_find(repository, offset, page, &label); if (has_label) { fprintf(out, "#$%02x, %s%s", data[0], label.name, extra); @@ -684,7 +683,7 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label /* fall through */ case PCE_OP_ZZ: /* = max_offset) { break; } - uint8_t page = memmap_page(map, logical); - data[0] = memmap_read(map, logical); + uint8_t page = memory_map_page(map, logical); + data[0] = memory_map_read(map, logical); const Opcode *opcode = opcode_get(data[0]); for (i = 1; i < opcode->size; i++) { - data[i] = memmap_read(map, logical + i); + data[i] = memory_map_read(map, logical + i); } logical += opcode->size; if (opcode_is_far_jump(data[0])) { uint32_t jump = data[1] | (data[2] << 8); if (data[0] == 0x4c) { // jmp hhll - uint8_t jump_page = memmap_page(map, jump); + uint8_t jump_page = memory_map_page(map, jump); if (page == jump_page) { if (jump < logical) { eor = 1; diff --git a/label.c b/label.c index 166dbf8..07f64b4 100644 --- a/label.c +++ b/label.c @@ -40,9 +40,9 @@ /// Label repository. struct LabelRepositoryImpl { - size_t size; //< Size of label repository. - size_t last; //< Last element in the repository. - Label *labels; //< Labels. + size_t size; //< Size of label repository. + size_t last; //< Last element in the repository. + Label *labels; //< Labels. }; /// Get label index by its address. @@ -151,7 +151,7 @@ bool label_repository_find(LabelRepository* repository, uint16_t logical, uint8_ return ret; } -/// Get the number of labels stored in the repository. +// Get the number of labels stored in the repository. int label_repository_size(LabelRepository* repository) { assert(repository != NULL); return (int)repository->last; @@ -169,7 +169,7 @@ bool label_repository_get(LabelRepository* repository, int index, Label *out) { return ret; } -/// Delete labels. +// Delete labels. void label_repository_delete(LabelRepository* repository, uint16_t first, uint16_t end, uint8_t page) { size_t i; for(i=0; ilast; i++) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 850d2bd..bd888d1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,6 +17,11 @@ function(add_unit_test) target_link_libraries(${target_name} PRIVATE ${ut_LIBRARIES} munit) target_include_directories(${target_name} PRIVATE ${ut_INCLUDE_DIRECTORIES} ${EXTRA_INCLUDE}) set_target_properties(${target_name} PROPERTIES C_STANDARD 11) + + if(ut_WRAP AND NOT CMAKE_COMPILER_IS_GNUCC) + message(FATAL_ERROR "WRAP can only be used with GCC") + endif() + foreach(_wrap ${ut_WRAP}) target_link_options(${target_name} PRIVATE LINKER:--wrap=${_wrap}) endforeach() @@ -63,19 +68,21 @@ add_unit_test( INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) -add_unit_test( - NAME rom - SOURCES - rom.c - ${PROJECT_SOURCE_DIR}/rom.c - ${PROJECT_SOURCE_DIR}/memory_map.c - ${PROJECT_SOURCE_DIR}/memory.c - ${PROJECT_SOURCE_DIR}/message.c - ${PROJECT_SOURCE_DIR}/message/console.c - LIBRARIES cwalk fff - INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} - WRAP fopen fileno fstat fseek fread fclose -) +if(CMAKE_COMPILER_IS_GNUCC) + add_unit_test( + NAME rom + SOURCES + rom.c + ${PROJECT_SOURCE_DIR}/rom.c + ${PROJECT_SOURCE_DIR}/memory_map.c + ${PROJECT_SOURCE_DIR}/memory.c + ${PROJECT_SOURCE_DIR}/message.c + ${PROJECT_SOURCE_DIR}/message/console.c + LIBRARIES cwalk fff + INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} + WRAP fopen fileno fstat fseek fread fclose + ) +endif() add_unit_test( NAME cd From 1c0a06a6b73282084e32b51a825c1882117e5e8c Mon Sep 17 00:00:00 2001 From: MooZ Date: Mon, 4 Nov 2024 20:07:53 +0100 Subject: [PATCH 27/35] Section rework wip --- section.c | 124 ++++++++++++++++++++++++++++++++++++++++++++ section.h | 42 +++++++++++++-- test/CMakeLists.txt | 1 - test/section.c | 52 ++++++++++++++++++- 4 files changed, 213 insertions(+), 6 deletions(-) diff --git a/section.c b/section.c index 3d54170..f138858 100644 --- a/section.c +++ b/section.c @@ -116,3 +116,127 @@ void section_delete(Section *ptr, int n) { } free(ptr); } + +// Reset a section array. +void section_array_reset(SectionArray *arr) { + assert(arr != NULL); + if(arr->data != NULL) { + for(size_t i=0; icount; i++) { + free(arr->data[i].name); + free(arr->data[i].output); + free(arr->data[i].description); + section_reset(&arr->data[i]); + } + } + arr->count = 0; +} + +// Release section array memory. +void section_array_delete(SectionArray *arr) { + assert(arr != NULL); + section_array_reset(arr); + free(arr->data); + arr->data = NULL; + arr->capacity = 0; +} + +// Check if 2 sections overlaps. +// \return 1 Both sections has the same time and overlaps +// \return 0 Sections don't overlap +// \return -1 Sections overlap but they are not of the same type. +static int section_overlap(const Section *a, const Section *b) { + assert(a != NULL); + assert(b != NULL); + + int ret = 0; + + if(a->page == b->page) { + if(a->logical > b->logical) { + const Section *tmp = b; + b = a; + a = tmp; + } + if(b->logical <= (a->logical + a->size)) { + if(a->type == b->type) { + ret = 1; + } else { + ret = -1; + } + } + } + return ret; +} + +static inline uint16_t minu16(uint16_t a, uint16_t b) { + return (a < b) ? a : b; +} + +static inline uint16_t maxi32(int32_t a, int32_t b) { + return (a > b) ? a : b; +} + +// Merge 2 sections the 2nd section into the 1st one. +static void section_merge(Section *a, const Section *b) { + assert(a != NULL); + assert(b != NULL); + + uint16_t begin = minu16(a->logical, b->logical); + int32_t end = maxi32(a->logical+a->size, b->logical+b->size); + a->logical = begin; + a->size = end - begin; +} + +// Add a new section. +int section_array_add(SectionArray *arr, const Section* in) { + assert(arr != NULL); + assert(in != NULL); + + int ret = -1;//todo + size_t i; + // Search for overlapping section. + for(i=0; icount; i++) { + int overlap = section_overlap(&arr->data[i], in); + if(overlap == 1) { + section_merge(&arr->data[i], in); + INFO_MSG("Section %s has been merged with %s!", arr->data[i].name, in->name); + break; + } else if(overlap == -1) { + WARNING_MSG("Section %s and %s overlaps! %x %x.%x", arr->data[i].name, in->name); + break; + } + } + + if(i >= arr->count) { + // Check if we need to expand section array buffer + if(i >= arr->capacity) { + size_t n = arr->capacity + 4U; + Section *ptr = realloc(arr->data, n*sizeof(Section)); + if(ptr == NULL) { + ERROR_MSG("Failed to expand section array buffer", strerror(errno)); + } else { + arr->data = ptr; + arr->capacity = n; + ret = true; + } + } else { + ret = true; + } + + // Append new section. + if(ret) { + arr->data[arr->count++] = *in; + } + } + return ret; +} + +// Retrieve the ith section from the array. +const Section* section_array_get(SectionArray *arr, size_t i) { + const Section *ret = NULL; + if(arr != NULL) { + if((arr->data != NULL) && (i < arr->count)) { + ret = &arr->data[i]; + } + } + return ret; +} \ No newline at end of file diff --git a/section.h b/section.h index deea575..256f7f1 100644 --- a/section.h +++ b/section.h @@ -99,10 +99,10 @@ void section_reset(Section *s); /// Group section per output filename and sort them in page/logical address order. /// \param [in out] ptr Sections. /// \param [in] n Number of sections to sort. -void section_sort(Section *ptr, size_t n); +void section_sort(Section *ptr, size_t n); // [todo] will be removed /// Delete sections. -void section_delete(Section *ptr, int n); +void section_delete(Section *ptr, int n); // [todo] will be removed // Load sections from a JSON file. // \param [out] out Loaded sections. @@ -110,7 +110,7 @@ void section_delete(Section *ptr, int n); // \param [in] filename Input filename. // \return true if the sections contained in the file were succesfully loaded. // \return false if an error occured. -bool section_load(Section **out, int *n, const char *filename); +bool section_load(Section **out, int *n, const char *filename); // [todo] use SectionArray // Save sections to a JSON file. // \param [in] ptr Sections to be saved. @@ -118,6 +118,40 @@ bool section_load(Section **out, int *n, const char *filename); // \param [in] filename Output filename. // \return true if the sections were succesfully saved. // \return false if an error occured. -bool section_save(const Section *ptr, int n, const char *filename); +bool section_save(const Section *ptr, int n, const char *filename); // [todo] use SectionArray + +// Section array +typedef struct { + Section *data; ///< Pointer to section array. + size_t count; ///< Number of sections currently in use. + size_t capacity; ///< Number the section array can hold. + // [todo] index array of sorted sections ? +} SectionArray; + +/// Reset a section array. +/// \note The internal data pointer will not be freed. +/// \param [in out] arr Section array to be reseted. +void section_array_reset(SectionArray *arr); + +/// Release section array memory. +/// \param [in out] arr Section array. +void section_array_delete(SectionArray *arr); + +/// Add a new section. +/// Note that if the section overlaps an already existing one, it will be merged if both sections have the +/// same type. +/// \param [in out] arr Section array the section will be added to. +/// \param [in] in Section that will be added to the section array. +/// \return 1 if the section was succesfully added. +/// \return 0 if the section was merged with one from the section array. +/// \return -1 if the section can not be merged or if there is not enough memory to add a new one. +int section_array_add(SectionArray *arr, const Section* in); + +/// Retrieve the ith section from the array. +/// \param [in] arr Section array. +/// \param [in] i Index of the section to be retrieved. +/// \return A pointer to the section if the index is within the section array bounds. +/// \return NULL if the index is out of the section array bounds. +const Section* section_array_get(SectionArray *arr, size_t i); #endif // ETRIPATOR_SECTION_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bd888d1..a13cb86 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -128,7 +128,6 @@ add_unit_test( NAME section SOURCES section.c - ${PROJECT_SOURCE_DIR}/section.c ${PROJECT_SOURCE_DIR}/section/load.c ${PROJECT_SOURCE_DIR}/message.c ${PROJECT_SOURCE_DIR}/jsonhelpers.c diff --git a/test/section.c b/test/section.c index 65509f3..0814cec 100644 --- a/test/section.c +++ b/test/section.c @@ -34,7 +34,7 @@ ¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯ */ #include -#include "section.h" +#include "../section.c" #include "message.h" #include "message/console.h" @@ -175,9 +175,59 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { return MUNIT_OK; } +MunitResult section_overlap_test(const MunitParameter params[], void* fixture) { + Section a = { + .type = SECTION_TYPE_CODE, + .page = 0x01, + }; + Section b = { + .type = SECTION_TYPE_CODE, + .page = 0x01, + }; + + a.logical = 0xe000; + a.size = 0x100; + + b.logical = 0xe010; + b.size = 0x40; + + munit_assert_int(section_overlap(&a, &b), ==, 1); + + b.type = SECTION_TYPE_DATA; + munit_assert_int(section_overlap(&a, &b), ==, -1); + + a.type = SECTION_TYPE_DATA; + a.logical = 0x0200; + a.size = 0x10; + + b.logical = 0x01e0; + b.size = 0x50; + + munit_assert_int(section_overlap(&a, &b), ==, 1); + + b.page = 0x02; + munit_assert_int(section_overlap(&a, &b), ==, 0); + + b.page = a.page; + b.size = 0x01; + munit_assert_int(section_overlap(&a, &b), ==, 0); + + return MUNIT_OK; +} + + +MunitResult section_add_test(const MunitParameter params[], void* fixture) { + // [todo] add sections + // [todo] add one that merge + // [todo] add one with merge+error + return MUNIT_OK; +} + static MunitTest section_tests[] = { { "/sort", section_sort_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { "/load", section_load_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/overlap", section_overlap_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, + { "/add", section_add_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; From d4bdb0ab95873b10be3af8e6e780e1c486a0d0bf Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 1 Dec 2024 11:27:48 +0100 Subject: [PATCH 28/35] Fix cli --- CMakeLists.txt | 6 +- cli/etripator.c | 241 +++++++++++++++++++++++------------------------- cli/options.c | 78 ++++++++-------- cli/options.h | 10 +- decode.c | 106 +++++++++++---------- section.h | 3 + section/load.c | 73 +++++++++++---- 7 files changed, 278 insertions(+), 239 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1160e2c..e782c41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,8 @@ set(etripator_SRC section/save.c opcodes.c comment.c + comment/load.c + comment/save.c label.c label/load.c label/save.c @@ -75,7 +77,7 @@ set_target_properties(etripator PROPERTIES C_STANDARD 11) target_include_directories(etripator PUBLIC ${EXTRA_INCLUDE} externals) target_compile_definitions(etripator PRIVATE _POSIX_C_SOURCE) target_link_libraries(etripator PUBLIC jansson cwalk) -#[[ + add_executable(etripator_cli cli/etripator.c cli/options.c) set_target_properties(etripator_cli PROPERTIES @@ -84,7 +86,7 @@ set_target_properties(etripator_cli ) target_include_directories(etripator_cli PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(etripator_cli etripator argparse) -#]] + set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/doxyfile.in) set(DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/doxyfile) diff --git a/cli/etripator.c b/cli/etripator.c index 19c4e93..734e618 100644 --- a/cli/etripator.c +++ b/cli/etripator.c @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include @@ -58,149 +58,134 @@ #include "options.h" -/* - exit callback - */ -void exit_callback(void) { msg_printer_destroy(); } - -/* - output labels -*/ -int label_output(cli_opt_t *option, label_repository_t *repository) { - char buffer[256]; +// exit callback +void exit_callback() { + message_printer_destroy(); +} - if (NULL == option->labels_out) { - /* We don't want to destroy the original label file. */ +// save found labels to a file named .YYmmddHHMMSS.lbl +static bool label_output(CommandLineOptions *options, LabelRepository *repository) { + bool ret = false; + char buffer[256U] = {0}; + if (options->labels_out == NULL) { + // Create a new filename as we don't want to destroy the original label file. const char *filename; size_t length; - char dateString[128]; - -#if defined(_MSC_VER) - struct tm now; - __time64_t tv; - _time64(&tv); - errno_t err = _localtime64_s(&now, &tv); - if (err == 0) { - strftime(dateString, 128, "%Y%m%d%H%M%S", &now); - } else { - sprintf(dateString, 128, "19871030133700"); - } -#else - struct timeval tv; - time_t t; - struct tm *now; - gettimeofday(&tv, NULL); - t = tv.tv_sec; - now = localtime(&t); - strftime(dateString, 128, "%Y%m%d%H%M%S", now); -#endif - cwk_path_get_basename(option->rom_filename, &filename, &length); + cwk_path_get_basename(options->rom_filename, &filename, &length); if(filename == NULL) { - filename = option->rom_filename; + filename = options->rom_filename; } - snprintf(buffer, 256, "%s.%s.lbl", filename, dateString); - option->labels_out = buffer; + time_t t = time(NULL); + struct tm *now = localtime(&t); + + char date_string[128U] = {0}; + strftime(date_string, sizeof(date_string), "%Y%m%d%H%M%S", now); + + snprintf(buffer, 256, "%s.%s.lbl", filename, date_string); + options->labels_out = buffer; + } + if (!label_repository_save(repository, options->labels_out)) { + ERROR_MSG("Failed to write/update label file: %s", options->labels_out); + } else { + ret = true; } - if (!label_repository_save(option->labels_out, repository)) { - ERROR_MSG("Failed to write/update label file: %s", option->labels_out); - return 0; + if(options->labels_out == buffer) { + options->labels_out = NULL; } - return 1; + return ret; } -static console_msg_printer_t g_console_printer; -static file_msg_printer_t g_file_printer; +// log command line +static bool log_cli(int argc, const char* argv[]) { + bool ret = false; + + size_t len = 0; + for(int i=0; idata; +static int opt_callback(struct argparse *self, const struct argparse_option *options) { + struct payload_t *payload = (struct payload_t*)options->data; size_t last = payload->size++; if(payload->capacity <= payload->size) { payload->capacity += 4; @@ -57,12 +57,12 @@ static int opt_callback(struct argparse *self, const struct argparse_option *opt memset(tmp+last, 0, 4*sizeof(const char*)); *payload->array = tmp; } - (*payload->array)[last] = *(char**)option->value; + (*payload->array)[last] = *(char**)options->value; return 1; } -/* Extract command line options */ -int get_cli_opt(int argc, const char** argv, cli_opt_t* option) { +// Extract command line options +bool cli_opt_get(CommandLineOptions *options, int argc, const char** argv) { static const char *const usages[] = { "etripator [options] [--] ", NULL @@ -71,47 +71,47 @@ int get_cli_opt(int argc, const char** argv, cli_opt_t* option) { int ret = 0; char *dummy; - struct payload_t labels_payload = { 0, 0, &option->labels_in }; - struct payload_t comments_payload = {0, 0, &option->comments_in}; + struct payload_t labels_payload = { 0, 0, &options->labels_in }; + struct payload_t comments_payload = {0, 0, &options->comments_in}; - struct argparse_option options[] = { + struct argparse_option arg_opt[] = { OPT_HELP(), - OPT_BOOLEAN('i', "irq-detect", &option->extract_irq, "automatically detect and extract irq vectors when disassembling a ROM, or extract opening code and gfx from CDROM IPL data", NULL, 0, 0), - OPT_BOOLEAN('c', "cd", &option->cdrom, "cdrom image disassembly. Irq detection and rom. Header jump is not performed", NULL, 0, 0), - OPT_STRING('o', "out", &option->main_filename, "main asm file containing includes for all sections as long the irq vector table if the irq-detect option is enabled", NULL, 0, 0), + OPT_BOOLEAN('i', "irq-detect", &options->extract_irq, "automatically detect and extract irq vectors when disassembling a ROM, or extract opening code and gfx from CDROM IPL data", NULL, 0, 0), + OPT_BOOLEAN('c', "cd", &options->cdrom, "cdrom image disassembly. Irq detection and rom. Header jump is not performed", NULL, 0, 0), + OPT_STRING('o', "out", &options->main_filename, "main asm file containing includes for all sections as long the irq vector table if the irq-detect option is enabled", NULL, 0, 0), OPT_STRING('l', "labels", &dummy, "labels definition filename", opt_callback, (intptr_t)&labels_payload, 0), - OPT_STRING(0, "labels-out", &option->labels_out, "extracted labels output filename. Otherwise the labels will be written to .YYMMDDhhmmss.lbl", NULL, 0, 0), + OPT_STRING(0, "labels-out", &options->labels_out, "extracted labels output filename. Otherwise the labels will be written to .YYMMDDhhmmss.lbl", NULL, 0, 0), OPT_STRING(0, "comments", &dummy, "comments description filename", opt_callback, (intptr_t)&comments_payload, 0), - OPT_BOOLEAN(0, "address", &option->address, "print statement address as comment", NULL, 0, 0), - OPT_INTEGER(0, "sector_size", &option->sector_size, "2352 bytes sectors (cd only)", NULL, 0, 0), + OPT_BOOLEAN(0, "address", &options->address, "print statement address as comment", NULL, 0, 0), + OPT_INTEGER(0, "sector_size", &options->sector_size, "2352 bytes sectors (cd only)", NULL, 0, 0), OPT_END(), }; struct argparse argparse; - option->extract_irq = 0; - option->cdrom = 0; - option->cfg_filename = NULL; - option->rom_filename = NULL; - option->main_filename = "main.asm"; - option->labels_in = NULL; - option->labels_out = NULL; - option->comments_in = NULL; - option->address = 0; - option->sector_size = 2048; - - argparse_init(&argparse, options, usages, 0); + options->extract_irq = 0; + options->cdrom = 0; + options->cfg_filename = NULL; + options->rom_filename = NULL; + options->main_filename = "main.asm"; + options->labels_in = NULL; + options->labels_out = NULL; + options->comments_in = NULL; + options->address = 0; + options->sector_size = 2048; + + argparse_init(&argparse, arg_opt, usages, 0); argparse_describe(&argparse, "\nEtripator : a PC Engine disassembler", " "); argc = argparse_parse(&argparse, argc, argv); if(!argc) { // ... - } else if((option->sector_size != 2048) && (option->sector_size != 2352)) { + } else if((options->sector_size != 2048) && (options->sector_size != 2352)) { ERROR_MSG("invalid sector size (must be 2048 or 2352)."); } else if(argc != 2) { - if((option->extract_irq) && (argc == 1)) { + if((options->extract_irq) && (argc == 1)) { /* Config file is optional with automatic irq vector extraction. */ - option->cfg_filename = NULL; - option->rom_filename = argv[0]; + options->cfg_filename = NULL; + options->rom_filename = argv[0]; ret = 1; } else { @@ -119,8 +119,8 @@ int get_cli_opt(int argc, const char** argv, cli_opt_t* option) { } } else { - option->cfg_filename = argv[0]; - option->rom_filename = argv[1]; + options->cfg_filename = argv[0]; + options->rom_filename = argv[1]; ret = 1; } @@ -131,13 +131,13 @@ int get_cli_opt(int argc, const char** argv, cli_opt_t* option) { return ret; } -/* Release allocated resources during command line parsing */ -void release_cli_opt(cli_opt_t* option) { - if(option->comments_in) { - free(option->comments_in); +// Release allocated resources during command line parsing +void cli_opt_release(CommandLineOptions *options) { + if(options->comments_in) { + free(options->comments_in); } - if(option->labels_in) { - free(option->labels_in); + if(options->labels_in) { + free(options->labels_in); } - memset(option, 0, sizeof(cli_opt_t)); + memset(options, 0, sizeof(CommandLineOptions)); } diff --git a/cli/options.h b/cli/options.h index 6517c90..e12b3d2 100644 --- a/cli/options.h +++ b/cli/options.h @@ -50,12 +50,12 @@ typedef struct { const char *labels_out; const char **labels_in; const char **comments_in; -} cli_opt_t; +} CommandLineOptions; -/* Extract command line options */ -int get_cli_opt(int argc, const char** argv, cli_opt_t* option); +/// Extract command line options +bool cli_opt_get(CommandLineOptions *options, int argc, const char** argv); -/* Release allocated resources during command line parsing */ -void release_cli_opt(cli_opt_t* option); +/// Release allocated resources during command line parsing +void cli_opt_release(CommandLineOptions *options); #endif // ETRIPATOR_OPTIONS_H diff --git a/decode.c b/decode.c index 6a209d7..aad74dd 100644 --- a/decode.c +++ b/decode.c @@ -177,29 +177,27 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe int32_t i, j; uint16_t logical; - Label label; - Comment comment; - - uint8_t buffer[2] = {0}; - int32_t top = 0; - size_t line_offset = ftell(out); uint8_t line_page = section->page; uint16_t line_logical = section->logical; - int has_comment = 0; + bool has_comment = false; + + Comment comment = {0}; + + uint8_t data[2] = {0}; + int32_t top = 0; for (i = 0, j = 0, logical = section->logical; i < section->size; i++, logical++) { uint8_t page = memory_map_page(map, logical); - - int has_label = label_repository_find(repository, logical, page, &label); - - if (has_label) { + Label label = {0}; + bool has_label = label_repository_find(repository, logical, page, &label); + if (has_label) { // flush any bytes left in the buffer. if (top && (top < element_size)) { - fprintf(out, "\n%s.db $%02x", g_spacing, buffer[0]); + fprintf(out, "\n%s.db $%02x", g_spacing, data[0]); for (int32_t l = 1; l < top; l++) { // useless as top is always equal to 1 - fprintf(out, ",$%02x", buffer[l]); + fprintf(out, ",$%02x", data[l]); } top = 0; } @@ -214,20 +212,20 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe if (comment_repository_find(comments, logical, page, &dummy)) { if (has_comment) { if (top && (top < element_size)) { - fprintf(out, "\n%s.db $%02x", g_spacing, buffer[0]); + fprintf(out, "\n%s.db $%02x", g_spacing, data[0]); for (int32_t l = 1; l < top; l++) { // useless as top is always equal to 1 - fprintf(out, ",$%02x", buffer[l]); + fprintf(out, ",$%02x", data[l]); } top = 0; } print_inline_comment(out, (int)(ftell(out) - line_offset), comment.text); } - memcpy(&comment, &dummy, sizeof(Comment)); - has_comment = 1; + comment = dummy; + has_comment = true; j = 0; } - buffer[top++] = memory_map_read(map, logical); + data[top++] = memory_map_read(map, logical); if (top >= element_size) { char sep; @@ -249,10 +247,10 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe fputc('$', out); if (top > 1) { while (top--) { - fprintf(out, "%02x", buffer[top]); + fprintf(out, "%02x", data[top]); } } else { - fprintf(out, "%02x", buffer[0]); + fprintf(out, "%02x", data[0]); } top = 0; j++; @@ -262,7 +260,7 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe int n = (int)(ftell(out) - line_offset); if (has_comment) { print_inline_comment(out, n, comment.text); - has_comment = 0; + has_comment = false; } else if (extra_infos) { print_statement_address(out, n, line_logical, line_page); } @@ -274,13 +272,13 @@ static int data_extract_hex(FILE *out, Section *section, MemoryMap *map, LabelRe int n = (int)(ftell(out) - line_offset); if (has_comment) { print_inline_comment(out, n, comment.text); - has_comment = 0; + has_comment = false; } else if (extra_infos) { - print_statement_address(out, (int)(ftell(out) - line_offset), line_logical, line_page); + print_statement_address(out, n, line_logical, line_page); } - fprintf(out, "\n%s.db $%02x", g_spacing, buffer[0]); + fprintf(out, "\n%s.db $%02x", g_spacing, data[0]); for (int32_t j = 1; j < top; j++) { // useless as top is always equal to 1 - fprintf(out, ",$%02x", buffer[j]); + fprintf(out, ",$%02x", data[j]); } } fputc('\n', out); @@ -291,12 +289,11 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe CommentRepository *comments, int extra_infos) { const int32_t elements_per_line = section->data.elements_per_line; - int32_t i, j; + int32_t i, j, k; uint16_t logical; int c = 0; - int has_label = 0; - int has_comment = 0; + bool has_comment = false; size_t line_offset = 0; uint16_t line_logical = 0; @@ -304,14 +301,17 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe Comment comment = {0}; - for (i = 0, j = 0, logical = section->logical; i < section->size; i++, logical++) { + fprintf(stdout, "----------------------------> "); + for(k=0; kdata.delimiter_size; k++) { + fprintf(stdout, "%c", section->data.delimiter[k]); + } + fprintf(stdout, "\n"); + for (i = 0, j = 0, k = 0, logical = section->logical; i < section->size; i++, logical++) { uint8_t data = memory_map_read(map, logical); uint8_t page = memory_map_page(map, logical); Label label = {0}; - - has_label = label_repository_find(repository, logical, page, &label); - + bool has_label = label_repository_find(repository, logical, page, &label); if (has_label) { if (c) { // close string if neededs fputc('"', out); @@ -324,7 +324,7 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe print_label(out, &label); } - Comment dummy; + Comment dummy = {0}; if (comment_repository_find(comments, logical, page, &dummy)) { if (j) { if (c) { // close string if neededs @@ -336,8 +336,8 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe if (has_comment) { print_inline_comment(out, (int)(ftell(out) - line_offset), comment.text); } - memcpy(&comment, &dummy, sizeof(Comment)); - has_comment = 1; + comment = dummy; + has_comment = true; } // display directives @@ -374,9 +374,22 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe } fprintf(out, "$%02x", data); } + + bool newline = false; + if(section->data.delimiter_size && (k < section->data.delimiter_size)) { + if(data == section->data.delimiter[k]) { + k++; + if(k >= section->data.delimiter_size) { + newline = true; + k = 0; + } + } else { + k = 0; + } + } j++; - if (j == elements_per_line) { + if ((j == elements_per_line) || newline) { j = 0; if (c) { fputc('"', out); @@ -386,7 +399,7 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe int n = (int)(ftell(out) - line_offset); if (has_comment) { print_inline_comment(out, n, comment.text); - has_comment = 0; + has_comment = false; } else if (extra_infos) { print_statement_address(out, n, line_logical, line_page); } @@ -399,7 +412,7 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe int n = (int)(ftell(out) - line_offset); if (has_comment) { print_inline_comment(out, n, comment.text); - has_comment = 0; + has_comment = false; } else if (extra_infos) { print_statement_address(out, n, line_logical, line_page); } @@ -423,8 +436,7 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, uint8_t line_page = section->page; uint16_t line_logical = section->logical; - int has_label = 0; - int has_comment = 0; + bool has_comment = false; uint8_t data[2] = {0}; @@ -433,8 +445,7 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, data[0] = memory_map_read(map, logical); data[1] = memory_map_read(map, logical + 1); - has_label = label_repository_find(repository, logical, page, &label); - + bool has_label = label_repository_find(repository, logical, page, &label); if (has_label) { if (i) { fputc('\n', out); @@ -443,13 +454,13 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, j = 0; } - Comment dummy; + Comment dummy = {0}; if (comment_repository_find(comments, logical, page, &dummy)) { if (has_comment) { print_inline_comment(out, (int)(ftell(out) - line_offset), comment.text); } - memcpy(&comment, &dummy, sizeof(Comment)); - has_comment = 1; + comment = dummy; + has_comment = true; j = 0; } @@ -486,10 +497,11 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, } } if (j) { + int n = (int)(ftell(out) - line_offset); if (has_comment) { - print_inline_comment(out, (int)(ftell(out) - line_offset), comment.text); + print_inline_comment(out, n, comment.text); } else if (extra_infos) { - print_statement_address(out, (int)(ftell(out) - line_offset), line_logical, line_page); + print_statement_address(out, n, line_logical, line_page); } } fputc('\n', out); diff --git a/section.h b/section.h index 256f7f1..ed37582 100644 --- a/section.h +++ b/section.h @@ -77,6 +77,9 @@ typedef struct { DataType type; //< type int32_t element_size; //< element size (string=0, byte=1, word=2) int32_t elements_per_line; //< number of elements per line + + uint8_t delimiter[8U]; //< string delimiter + int32_t delimiter_size; //< string delimiter length } DataConfig; // Section description diff --git a/section/load.c b/section/load.c index 5cfffdc..531ea6e 100644 --- a/section/load.c +++ b/section/load.c @@ -62,7 +62,7 @@ static inline DataType json_validate_data_type(const char *str) { return DATA_TYPE_UNKNOWN; } -static inline bool json_parse_section_type(Section *out, const json_t *obj) { +static bool json_parse_section_type(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "type"); if (tmp == NULL) { @@ -80,9 +80,9 @@ static inline bool json_parse_section_type(Section *out, const json_t *obj) { return ret; } -static inline bool json_parse_section_page(Section *out, const json_t *obj) { - int num; +static bool json_parse_section_page(Section *out, const json_t *obj) { bool ret = false; + int num = -1; const json_t *tmp = json_object_get(obj, "page"); if (tmp == NULL) { ERROR_MSG("Missing section page"); @@ -97,9 +97,9 @@ static inline bool json_parse_section_page(Section *out, const json_t *obj) { return ret; } -static inline bool json_parse_section_logical(Section *out, const json_t *obj) { - int num; +static bool json_parse_section_logical(Section *out, const json_t *obj) { bool ret = false; + int num = -1; const json_t *tmp = json_object_get(obj, "logical"); if (tmp == NULL) { ERROR_MSG("Missing section logical address"); @@ -114,9 +114,9 @@ static inline bool json_parse_section_logical(Section *out, const json_t *obj) { return ret; } -static inline bool json_parse_section_offset(Section *out, const json_t *obj) { - int num; +static bool json_parse_section_offset(Section *out, const json_t *obj) { bool ret = true; + int num = 1; json_t *tmp = json_object_get(obj, "offset"); if(tmp == NULL) { out->offset = (out->page << 13) | (out->logical & 0x1FFF); @@ -129,9 +129,9 @@ static inline bool json_parse_section_offset(Section *out, const json_t *obj) { return ret; } -static inline bool json_parse_section_size(Section *out, const json_t *obj) { +static bool json_parse_section_size(Section *out, const json_t *obj) { bool ret = true; - int num; + int num = -1; const json_t *tmp = json_object_get(obj, "size"); if (tmp == NULL) { // use default value @@ -144,7 +144,7 @@ static inline bool json_parse_section_size(Section *out, const json_t *obj) { return ret; } -static inline bool json_parse_section_mpr(Section *out, const json_t *obj) { +static bool json_parse_section_mpr(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "mpr"); if(tmp == NULL) { @@ -172,11 +172,10 @@ static inline bool json_parse_section_mpr(Section *out, const json_t *obj) { } } } - return ret; } -static inline bool json_parse_section_output(Section *out, const json_t *obj) { +static bool json_parse_section_output(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "filename"); if (tmp == NULL) { @@ -194,7 +193,7 @@ static inline bool json_parse_section_output(Section *out, const json_t *obj) { return ret; } -static inline bool json_parse_data_config_type(DataConfig *out, const json_t *obj) { +static bool json_parse_data_config_type(DataConfig *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "type"); if (tmp == NULL) { @@ -212,7 +211,7 @@ static inline bool json_parse_data_config_type(DataConfig *out, const json_t *ob return ret; } -static inline bool json_parse_data_config_element_size(DataConfig *out, const json_t *obj) { +static bool json_parse_data_config_element_size(DataConfig *out, const json_t *obj) { bool ret = false; const json_t *value = json_object_get(obj, "element_size"); if(value == NULL) { @@ -229,13 +228,13 @@ static inline bool json_parse_data_config_element_size(DataConfig *out, const js return ret; } -static inline bool json_parse_data_config_element_per_line(DataConfig *out, const json_t *obj) { +static bool json_parse_data_config_element_per_line(DataConfig *out, const json_t *obj) { bool ret = false; const json_t *value = json_object_get(obj, "elements_per_line"); if(value == NULL) { ret = true; // use default value - } else if(out->type == DATA_TYPE_BINARY) { - ERROR_MSG("Number of elements per line is invalid for binary data section"); + } else if(out->type != DATA_TYPE_HEX) { + ERROR_MSG("Number of elements per line is only valid for hex data section"); } else if (!json_validate_int(value, &out->elements_per_line)) { ERROR_MSG("Invalid number of elements per line."); } else { @@ -244,6 +243,40 @@ static inline bool json_parse_data_config_element_per_line(DataConfig *out, cons return ret; } +static bool json_parse_section_data_string_delimiter(DataConfig *out, const json_t *obj) { + bool ret = false; + const json_t *tmp = json_object_get(obj, "delimiter"); + if(tmp == NULL) { + ret = true; // use default value + } else if(out->type != DATA_TYPE_STRING) { + ERROR_MSG("string delimiter is only valid for string data section"); + } else if(!json_is_array(tmp)) { + ERROR_MSG("Invalid string delimiter"); + } else { + int num; + size_t index; + json_t* value; + json_array_foreach(tmp, index, value) { + ret = false; + if(index > 7U) { + ERROR_MSG("too many char in string delimiter"); + } else if(!json_validate_int(value, &num)) { + ERROR_MSG("Invalid type for string delimiter char"); + } else if((num < 0) || (num > 0xFF)) { + ERROR_MSG("Invalid char %d value", index); + } else { + out->delimiter[index] = (uint8_t)num; + ret = true; + } + if(!ret) { + break; + } + } + out->delimiter_size = index; + } + return ret; +} + static bool json_parse_section_data_config(Section *out, const json_t *obj) { bool ret = false; const json_t *tmp = json_object_get(obj, "data"); @@ -255,8 +288,12 @@ static bool json_parse_section_data_config(Section *out, const json_t *obj) { // ... } else if(!json_parse_data_config_element_size(&out->data, tmp)) { // ... + } else if(json_parse_data_config_element_per_line(&out->data, tmp) == false) { + // ... + } else if(json_parse_section_data_string_delimiter(&out->data, tmp) == false) { + // ... } else { - ret = json_parse_data_config_element_per_line(&out->data, tmp); + ret = true; } return ret; } From 358a2f9fba5be3a1ab2caaf5f383837d12c56bf0 Mon Sep 17 00:00:00 2001 From: MooZ Date: Sun, 1 Dec 2024 11:49:25 +0100 Subject: [PATCH 29/35] Update submodules --- .gitmodules | 1 + CMakeLists.txt | 13 ++++++------- externals/argparse | 2 +- externals/cwalk | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitmodules b/.gitmodules index 999665f..adf1a7f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,7 @@ [submodule "externals/cwalk"] path = externals/cwalk url = https://github.com/likle/cwalk.git + branch=v1.2.9 [submodule "externals/fff"] path = externals/fff url = https://github.com/meekrosoft/fff.git diff --git a/CMakeLists.txt b/CMakeLists.txt index e782c41..e5a3e59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.16) +cmake_minimum_required (VERSION 3.30) project(etripator VERSION 0.9.0 @@ -8,7 +8,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") add_compile_definitions(_XOPEN_SOURCE=700) endif() -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") enable_testing() @@ -17,17 +17,16 @@ include(CheckSymbolExists) check_symbol_exists(strdup "string.h" HAVE_STRDUP) if(NOT CMAKE_BUILD_TYPE) + message(STATUS, "No build type specified. Force build type to Debug.") set(CMAKE_BUILD_TYPE "Debug") endif() -set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}") - find_package(Doxygen) find_package(Jansson) set(CMAKE_C_STANDARDS 11) -add_subdirectory(externals) +add_subdirectory(externals EXCLUDE_FROM_ALL) set(etripator_SRC message.c @@ -74,7 +73,6 @@ set(etripator_HDR add_library(etripator STATIC ${etripator_SRC} ${etripator_HDR}) set_target_properties(etripator PROPERTIES C_STANDARD 11) -target_include_directories(etripator PUBLIC ${EXTRA_INCLUDE} externals) target_compile_definitions(etripator PRIVATE _POSIX_C_SOURCE) target_link_libraries(etripator PUBLIC jansson cwalk) @@ -85,6 +83,7 @@ set_target_properties(etripator_cli C_STANDARD 11 ) target_include_directories(etripator_cli PRIVATE ${CMAKE_SOURCE_DIR}) +target_include_directories(etripator_cli PUBLIC externals) target_link_libraries(etripator_cli etripator argparse) set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/doxyfile.in) @@ -102,4 +101,4 @@ add_custom_target(doc add_subdirectory(test) -# install(TARGETS etripator_cli DESTINATION bin) +install(TARGETS etripator_cli DESTINATION bin) diff --git a/externals/argparse b/externals/argparse index fafc503..682d452 160000 --- a/externals/argparse +++ b/externals/argparse @@ -1 +1 @@ -Subproject commit fafc503d23d077bda40c29e8a20ea74707452721 +Subproject commit 682d4520b4bc2b646cdfcf078b2fed00b3d2da30 diff --git a/externals/cwalk b/externals/cwalk index 08e7520..f45a23a 160000 --- a/externals/cwalk +++ b/externals/cwalk @@ -1 +1 @@ -Subproject commit 08e7520d332b700392248227bc07a68c429dc2bf +Subproject commit f45a23a13abf39d94b347d7c83810eca26a5a8d0 From b167e740621b40943ef4c1694e88a1c584fda93c Mon Sep 17 00:00:00 2001 From: MooZ Date: Mon, 23 Dec 2024 21:08:06 +0100 Subject: [PATCH 30/35] Section update cont'd --- cli/etripator.c | 110 +++++++++++++++++++++----------------------- ipl.c | 74 ++++++++++++++--------------- ipl.h | 5 +- irq.c | 69 +++++++++++++-------------- irq.h | 5 +- section.c | 6 +-- section.h | 59 ++++++++++++------------ section/load.c | 20 +++++--- test/CMakeLists.txt | 3 +- test/section.c | 21 ++++----- 10 files changed, 184 insertions(+), 188 deletions(-) diff --git a/cli/etripator.c b/cli/etripator.c index 734e618..06f460d 100644 --- a/cli/etripator.c +++ b/cli/etripator.c @@ -148,13 +148,11 @@ int main(int argc, const char **argv) { MemoryMap map = {0}; - Section *section = NULL; - int section_count = 0; - + SectionArray section_arr = {0}; failure = 1; - section_count = 0; - section = NULL; + + section_array_reset(§ion_arr); /* Extract command line options */ ret = cli_opt_get(&options, argc, argv); @@ -164,7 +162,7 @@ int main(int argc, const char **argv) { /* Read configuration file */ if (options.cfg_filename) { - ret = section_load(§ion, §ion_count, options.cfg_filename); + ret = section_load(§ion_arr, options.cfg_filename); if (!ret) { ERROR_MSG("Unable to read %s", options.cfg_filename); goto error_1; @@ -186,7 +184,7 @@ int main(int argc, const char **argv) { /* Get irq offsets */ if (options.extract_irq) { - ret = irq_read(&map, §ion, §ion_count); + ret = irq_read(&map, §ion_arr); if (!ret) { ERROR_MSG("An error occured while reading irq vector offsets"); goto error_2; @@ -201,7 +199,7 @@ int main(int argc, const char **argv) { if (options.extract_irq) { IPL ipl; ret = ipl_read(&ipl, options.rom_filename); - ret = ret && ipl_sections(&ipl, §ion, §ion_count); + ret = ret && ipl_sections(&ipl, §ion_arr); if (!ret) { ERROR_MSG("An error occured while setting up sections from IPL data."); goto error_2; @@ -210,7 +208,7 @@ int main(int argc, const char **argv) { /* Data will be loaded during section disassembly */ } - section_sort(section, section_count); +// [todo] section_sort(section, section_count); CommentRepository *comments_repository = comment_repository_create(); /* Load comments */ @@ -237,59 +235,64 @@ int main(int argc, const char **argv) { } /* For each section reset every existing files */ - for (int i = 0; i < section_count; ++i) { - out = fopen(section[i].output, "wb"); + for (int i = 0; i < section_arr.count; ++i) { + Section *section = §ion_arr.data[i]; + out = fopen(section->output, "wb"); if (NULL == out) { - ERROR_MSG("Can't open %s : %s", section[i].output, strerror(errno)); + ERROR_MSG("Can't open %s : %s", section->output, strerror(errno)); goto error_4; } fclose(out); } /* Add section name to label repository. */ - for (int i = 0; i < section_count; ++i) { - ret = label_repository_add(repository, section[i].name, section[i].logical, section[i].page, section[i].description); + for (int i = 0; i < section_arr.count; ++i) { + Section *section = §ion_arr.data[i]; + ret = label_repository_add(repository, section->name, section->logical, section->page, section->description); if (!ret) { - ERROR_MSG("Failed to add section name (%s) to labels", section[i].name); + ERROR_MSG("Failed to add section name (%s) to labels", section->name); goto error_4; } } /* Disassemble and output */ - for (int i = 0; i < section_count; ++i) { - out = fopen(section[i].output, "ab"); + Section *previous = NULL; + Section *current = NULL; + for (int i = 0; i < section_arr.count; ++i, previous=current) { + current = §ion_arr.data[i]; + out = fopen(current->output, "ab"); if (!out) { - ERROR_MSG("Can't open %s : %s", section[i].output, strerror(errno)); + ERROR_MSG("Can't open %s : %s", current->output, strerror(errno)); goto error_4; } - if (options.cdrom || (section[i].offset != ((section[i].page << 13) | (section[i].logical & 0x1fff)))) { - size_t offset = section[i].offset; + if (options.cdrom || (current->offset != ((current->page << 13) | (current->logical & 0x1fff)))) { + size_t offset = current->offset; /* Copy CDROM data */ - ret = cd_load(options.rom_filename, section[i].offset, section[i].size, options.sector_size, section[i].page, section[i].logical, &map); + ret = cd_load(options.rom_filename, current->offset, current->size, options.sector_size, current->page, current->logical, &map); if (0 == ret) { ERROR_MSG("Failed to load CD data (section %d)", i); goto error_4; } } - if((i > 0) && (section[i].logical < (section[i-1].logical + section[i-1].size)) - && (section[i].page == section[i-1].page) - && (section[i].type != section[i-1].type)) { - WARNING_MSG("Section %s and %s overlaps! %x %x.%x", section[i].name, section[i-1].name); + if((previous != NULL) && (current->logical < (previous->logical + previous->size)) + && (current->page == previous->page) + && (current->type != previous->type)) { + WARNING_MSG("Section %s and %s overlaps! %x %x.%x", current->name, previous->name); } - if((i > 0) && (0 == strcmp(section[i].output, section[i-1].output)) - && (section[i].page == section[i-1].page) - && (section[i].logical <= (section[i-1].logical + section[i-1].size))) { + if((previous != NULL) && (0 == strcmp(current->output, previous->output)) + && (current->page == previous->page) + && (current->logical <= (previous->logical + previous->size))) { // "Merge" sections and adjust size if necessary. - if(section[i].size > 0) { - uint32_t end0 = section[i-1].logical + section[i-1].size; - uint32_t end1 = section[i].logical + section[i].size; + if(current->size > 0) { + uint32_t end0 = previous->logical + previous->size; + uint32_t end1 = current->logical + current->size; if(end1 > end0) { - section[i].size = end1 - end0; - section[i].logical = end0; - INFO_MSG("Section %s has been merged with %s!", section[i].name, section[i-1].name); + current->size = end1 - end0; + current->logical = end0; + INFO_MSG("Section %s has been merged with %s!", current->name, previous->name); } else { // The previous section overlaps the current one. @@ -297,40 +300,38 @@ int main(int argc, const char **argv) { fclose(out); continue; } + } else { + current->logical = previous->logical + previous->size; + INFO_MSG("Section %s has been merged with %s!", current->name, previous->name); } - else { - section[i].logical = section[i-1].logical + section[i-1].size; - INFO_MSG("Section %s has been merged with %s!", section[i].name, section[i-1].name); - } - } - else if((section[i].type != SECTION_TYPE_DATA) || (section[i].data.type != DATA_TYPE_BINARY)) { + } else if((current->type != SECTION_TYPE_DATA) || (current->data.type != DATA_TYPE_BINARY)) { /* Print header */ fprintf(out, "\t.%s\n" "\t.bank $%03x\n" "\t.org $%04x\n", - (section[i].type == SECTION_TYPE_CODE) ? "code" : "data", section[i].page, section[i].logical); + (current->type == SECTION_TYPE_CODE) ? "code" : "data", current->page, current->logical); } - memory_map_mpr(&map, section[i].mpr); + memory_map_mpr(&map, current->mpr); - if (section[i].type == SECTION_TYPE_CODE) { - if(section[i].size <= 0) { - section[i].size = compute_size(section, i, section_count, &map); + if (current->type == SECTION_TYPE_CODE) { + if(current->size <= 0) { + current->size = compute_size(current, i, section_arr.count, &map); } /* Extract labels */ - ret = label_extract(§ion[i], &map, repository); + ret = label_extract(current, &map, repository); if (!ret) { goto error_4; } /* Process opcodes */ - uint16_t logical = section[i].logical; + uint16_t logical = current->logical; do { - (void)decode(out, &logical, §ion[i], &map, repository, comments_repository, options.address); - } while (logical < (section[i].logical+section[i].size)); + (void)decode(out, &logical, current, &map, repository, comments_repository, options.address); + } while (logical < (current->logical+current->size)); fputc('\n', out); } else { - ret = data_extract(out, §ion[i], &map, repository, comments_repository, options.address); + ret = data_extract(out, current, &map, repository, comments_repository, options.address); if (!ret) { // [todo] } @@ -351,7 +352,7 @@ int main(int argc, const char **argv) { if (!options.cdrom && options.extract_irq) { fprintf(main_file, "\n\t.data\n\t.bank 0\n\t.org $FFF6\n"); for (int i = 0; i < 5; ++i) { - fprintf(main_file, "\t.dw $%04x\n", section[i].logical); + fprintf(main_file, "\t.dw $%04x\n", current->logical); } } @@ -372,12 +373,7 @@ int main(int argc, const char **argv) { error_1: cli_opt_release(&options); - for (int i = 0; i < section_count; ++i) { - free(section[i].name); - free(section[i].output); - section[i].name = NULL; - } - free(section); + section_array_delete(§ion_arr); return failure; } diff --git a/ipl.c b/ipl.c index a4cf4d4..5149533 100644 --- a/ipl.c +++ b/ipl.c @@ -156,7 +156,11 @@ bool ipl_read(IPL *out, const char *filename) { } // Get irq code offsets from IPL. -bool ipl_sections(IPL *in, Section **out, int *count) { +bool ipl_sections(IPL *in, SectionArray *out) { + assert(in != NULL); + assert(out != NULL); + assert(out->data != NULL); + static const char *section_name[2] = { "cd_start", "gfx_start" }; static const char *section_filename[2] = { "cd_start.asm", "gfx_start.bin" }; @@ -167,50 +171,46 @@ bool ipl_sections(IPL *in, Section **out, int *count) { if(extra == 0) { INFO_MSG("No section found from IPL data."); } else { - int j = *count; - Section *section = (Section*)realloc(*out, (j+extra) * sizeof(Section)); - if(section == NULL) { - ERROR_MSG("Failed to add extra sections."); - ret = false; - } else { - *count += extra; - *out = section; - - memset(§ion[j], 0, extra * sizeof(Section)); - - for(int k=0; kmpr[i]; - } + size_t j = out->count; + for(int k=0; ret && (kmpr[i]; } + if(section_array_add(out, &tmp) < 0) { + ret = false; + } + } + if(ret) { // "CD boot" if(in->load_sector_count) { + Section *section = &out->data[j++]; uint32_t record = (in->load_start_record[0] << 16) | (in->load_start_record[1] << 8) | in->load_start_record[2]; - section[j].name = strdup(section_name[0]); - section[j].type = SECTION_TYPE_CODE; - section[j].page = section[j].mpr[in->load_exec_address[1]>>5]; - section[j].logical = (in->load_exec_address[1] << 8) | in->load_exec_address[0]; - section[j].offset = record * 2048; - section[j].size = in->load_sector_count * 2048; - section[j].output = strdup(section_filename[0]); - j++; + section->name = strdup(section_name[0]); + section->type = SECTION_TYPE_CODE; + section->page = section->mpr[in->load_exec_address[1]>>5]; + section->logical = (in->load_exec_address[1] << 8) | in->load_exec_address[0]; + section->offset = record * 2048; + section->size = in->load_sector_count * 2048; + section->output = strdup(section_filename[0]); } // "GFX" if(in->opening_gfx_sector_count) { + Section *section = &out->data[j++]; uint32_t record = (in->opening_gfx_record[0] << 16) | (in->opening_gfx_record[1] << 8) | in->opening_gfx_record[2]; - section[j].name = strdup(section_name[1]); - section[j].type = SECTION_TYPE_DATA; - section[j].page = section[j].mpr[in->opening_gfx_read_address[1]>>5]; - section[j].logical = (in->opening_gfx_read_address[1] << 8) | in->opening_gfx_read_address[0]; - section[j].offset = record * 2048; - section[j].size = in->opening_gfx_sector_count * 2048; - section[j].output = strdup(section_filename[1]); - section[j].data.type = DATA_TYPE_BINARY; - section[j].data.element_size = 1; - section[j].data.elements_per_line = 16; + section->name = strdup(section_name[1]); + section->type = SECTION_TYPE_DATA; + section->page = section->mpr[in->opening_gfx_read_address[1]>>5]; + section->logical = (in->opening_gfx_read_address[1] << 8) | in->opening_gfx_read_address[0]; + section->offset = record * 2048; + section->size = in->opening_gfx_sector_count * 2048; + section->output = strdup(section_filename[1]); + section->data.type = DATA_TYPE_BINARY; + section->data.element_size = 1; + section->data.elements_per_line = 16; } } } diff --git a/ipl.h b/ipl.h index 7f3d398..59b2cdb 100644 --- a/ipl.h +++ b/ipl.h @@ -104,9 +104,8 @@ bool ipl_read(IPL *out, const char *filename); /// Get irq code offsets from IPL. /// \param [in] in IPL infos. -/// \param [out] section Sections. -/// \param [out] count Section count. +/// \param [out] out Sections. /// \return 0 on error, 1 otherwise. -bool ipl_sections(IPL *in, Section **out, int *count); +bool ipl_sections(IPL *in, SectionArray *out); #endif // IPL_H diff --git a/irq.c b/irq.c index deeae34..8dce2ea 100644 --- a/irq.c +++ b/irq.c @@ -49,10 +49,11 @@ static char* g_irq_names[PCE_IRQ_COUNT] = { // [todo] add an extra section for the address table // Get irq code offsets from rom. -bool irq_read(MemoryMap* map, Section **section, int *count) { +bool irq_read(MemoryMap* map, SectionArray *out) { assert(map != NULL); - assert(section != NULL); - assert(count != NULL); + assert(out != NULL); + assert(out->data != NULL); + assert((out->count + PCE_IRQ_COUNT) <= out->capacity); bool ret = false; if(map->memory[PCE_MEMORY_ROM].data == NULL) { @@ -60,45 +61,41 @@ bool irq_read(MemoryMap* map, Section **section, int *count) { } else if(map->memory[PCE_MEMORY_ROM].length < (PCE_IRQ_TABLE + PCE_IRQ_COUNT)) { ERROR_MSG("ROM is abnormally small."); } else { - Section *tmp = (Section*)realloc(*section, (*count+PCE_IRQ_COUNT) * sizeof(Section)); - if(tmp == NULL) { - ERROR_MSG("Failed to allocate extra IRQ sections."); - } else { - int j = *count; - uint16_t offset = PCE_IRQ_TABLE; - *section = tmp; - *count += PCE_IRQ_COUNT; + uint16_t offset = PCE_IRQ_TABLE; + ret = true; + for(size_t i=0; ret && (icount; i++) { @@ -216,10 +216,10 @@ int section_array_add(SectionArray *arr, const Section* in) { } else { arr->data = ptr; arr->capacity = n; - ret = true; + ret = 1; } } else { - ret = true; + ret = 1; } // Append new section. diff --git a/section.h b/section.h index ed37582..80f5ee1 100644 --- a/section.h +++ b/section.h @@ -72,7 +72,7 @@ typedef enum { /// \return "unknown" otherwise const char* data_type_name(DataType type); -// Data section configuration +/// Data section configuration typedef struct { DataType type; //< type int32_t element_size; //< element size (string=0, byte=1, word=2) @@ -82,7 +82,7 @@ typedef struct { int32_t delimiter_size; //< string delimiter length } DataConfig; -// Section description +/// Section description typedef struct { char *name; //< Name SectionType type; //< Type @@ -96,34 +96,7 @@ typedef struct { char *description; //< optional description } Section; -/// Reset a section to its default values. -void section_reset(Section *s); - -/// Group section per output filename and sort them in page/logical address order. -/// \param [in out] ptr Sections. -/// \param [in] n Number of sections to sort. -void section_sort(Section *ptr, size_t n); // [todo] will be removed - -/// Delete sections. -void section_delete(Section *ptr, int n); // [todo] will be removed - -// Load sections from a JSON file. -// \param [out] out Loaded sections. -// \param [out] n Number of loaded sections. -// \param [in] filename Input filename. -// \return true if the sections contained in the file were succesfully loaded. -// \return false if an error occured. -bool section_load(Section **out, int *n, const char *filename); // [todo] use SectionArray - -// Save sections to a JSON file. -// \param [in] ptr Sections to be saved. -// \param [in] count Number of sections. -// \param [in] filename Output filename. -// \return true if the sections were succesfully saved. -// \return false if an error occured. -bool section_save(const Section *ptr, int n, const char *filename); // [todo] use SectionArray - -// Section array +/// Section array typedef struct { Section *data; ///< Pointer to section array. size_t count; ///< Number of sections currently in use. @@ -157,4 +130,30 @@ int section_array_add(SectionArray *arr, const Section* in); /// \return NULL if the index is out of the section array bounds. const Section* section_array_get(SectionArray *arr, size_t i); +/// Reset a section to its default values. +void section_reset(Section *s); + +/// Group section per output filename and sort them in page/logical address order. +/// \param [in out] ptr Sections. +/// \param [in] n Number of sections to sort. +void section_sort(Section *ptr, size_t n); // [todo] will be removed + +/// Delete sections. +void section_delete(Section *ptr, int n); // [todo] will be removed + +// Load sections from a JSON file. +// \param [out] arr Loaded sections. +// \param [in] filename Input filename. +// \return true if the sections contained in the file were succesfully loaded. +// \return false if an error occured. +bool section_load(SectionArray *arr, const char *filename); + +// Save sections to a JSON file. +// \param [in] ptr Sections to be saved. +// \param [in] count Number of sections. +// \param [in] filename Output filename. +// \return true if the sections were succesfully saved. +// \return false if an error occured. +bool section_save(const Section *ptr, int n, const char *filename); // [todo] use SectionArray + #endif // ETRIPATOR_SECTION_H diff --git a/section/load.c b/section/load.c index 531ea6e..1f93f81 100644 --- a/section/load.c +++ b/section/load.c @@ -336,12 +336,14 @@ static bool section_parse(Section *out, const json_t *obj) { } // Load sections from a JSON file. -bool section_load(Section **out, int *n, const char *filename) { +bool section_load(SectionArray *arr, const char *filename) { bool ret = false; json_error_t err; Section *ptr; const char* key; + section_array_reset(arr); + json_t* root = json_load_file(filename, 0, &err); if(root == NULL) { ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); @@ -351,16 +353,20 @@ bool section_load(Section **out, int *n, const char *filename) { } else { json_t* obj = NULL; size_t size = json_object_size(root); - *out = (Section*)realloc(*out, (*n+size) * sizeof(Section)); - ptr = *out + *n; - *n += (int)size; + ret = true; json_object_foreach(root, key, obj) { - if(!section_parse(ptr, obj)) { + Section tmp = {0}; + section_reset(&tmp); + + if(!section_parse(&tmp, obj)) { ret = false; + } else { + tmp.name = strdup(key); + if(section_array_add(arr, &tmp) <= 0) { + section_delete(&tmp, 1); + } } - ptr->name = strdup(key); - ptr++; } } json_decref(root); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a13cb86..8d083ce 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -151,8 +151,9 @@ add_unit_test( NAME ipl SOURCES ipl.c + ${PROJECT_SOURCE_DIR}/section.c ${PROJECT_SOURCE_DIR}/message.c ${PROJECT_SOURCE_DIR}/message/console.c - LIBRARIES cwalk + LIBRARIES cwalk jansson INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR} ) diff --git a/test/section.c b/test/section.c index 0814cec..d7318b7 100644 --- a/test/section.c +++ b/test/section.c @@ -124,16 +124,15 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { static const Section* bank0[2] = { bank0_0, bank0_1 }; - Section *section = NULL; - int count[2] = { 0, 0 }; + SectionArray arr = {0}; int i, j, k; int ret; - ret = section_load(§ion, &count[0], "./data/bank0_0.json"); + ret = section_load(&arr, "./data/bank0_0.json"); munit_assert_int(ret, !=, 0); - munit_assert_int(count[0], ==, 4); - + munit_assert_int(arr.count, ==, 4); +/* section_sort(section, count[0]); for(i=0; i Date: Wed, 25 Dec 2024 23:03:42 +0100 Subject: [PATCH 31/35] Adding a new section keeps the array sorted and merge sections if necessary --- cli/etripator.c | 2 -- section.c | 61 ++++++++++++++++++++++---------- section/load.c | 2 -- test/data/bank0_0.json | 2 +- test/section.c | 79 ++++++++++++++++++++++-------------------- 5 files changed, 84 insertions(+), 62 deletions(-) diff --git a/cli/etripator.c b/cli/etripator.c index 06f460d..d04df25 100644 --- a/cli/etripator.c +++ b/cli/etripator.c @@ -208,8 +208,6 @@ int main(int argc, const char **argv) { /* Data will be loaded during section disassembly */ } -// [todo] section_sort(section, section_count); - CommentRepository *comments_repository = comment_repository_create(); /* Load comments */ if(NULL != options.comments_in) { diff --git a/section.c b/section.c index 23fba99..2e87698 100644 --- a/section.c +++ b/section.c @@ -156,11 +156,14 @@ static int section_overlap(const Section *a, const Section *b) { b = a; a = tmp; } - if(b->logical <= (a->logical + a->size)) { - if(a->type == b->type) { - ret = 1; + + if(a->type != b->type) { + ret = (b->logical < (a->logical + a->size)) ? -1 : 0; + } else if(b->logical <= (a->logical + a->size)) { + if(a->type == SECTION_TYPE_DATA) { + ret = (a->data.type == b->data.type) ? 1 : -1; } else { - ret = -1; + ret = 1; } } } @@ -193,22 +196,38 @@ int section_array_add(SectionArray *arr, const Section* in) { int ret = -1; size_t i; - // Search for overlapping section. - for(i=0; icount; i++) { - int overlap = section_overlap(&arr->data[i], in); - if(overlap == 1) { - section_merge(&arr->data[i], in); - INFO_MSG("Section %s has been merged with %s!", arr->data[i].name, in->name); - break; - } else if(overlap == -1) { - WARNING_MSG("Section %s and %s overlaps! %x %x.%x", arr->data[i].name, in->name); - break; + bool insert = false; + + // Find the slot where the section will be inserted or merged + for(i=0; (!insert) && (icount); ) { + if(in->page > arr->data[i].page) { + // ... + } else if(in->page < arr->data[i].page) { + insert = true; + } else { + int overlap = section_overlap(&arr->data[i], in); + if(overlap == 1) { + section_merge(&arr->data[i], in); + INFO_MSG("Section %s has been merged with %s!", arr->data[i].name, in->name); + ret = 1; + break; + } else if (overlap == -1) { + WARNING_MSG("Section %s and %s overlaps!", arr->data[i].name, in->name); + } else if(overlap == 0) { + // ... + } + if(in->offset < arr->data[i].offset) { + insert = true; + } + } + if(!insert) { + i++; } } - if(i >= arr->count) { + if((i >= arr->count) || insert) { // Check if we need to expand section array buffer - if(i >= arr->capacity) { + if(arr->count >= arr->capacity) { size_t n = arr->capacity + 4U; Section *ptr = realloc(arr->data, n*sizeof(Section)); if(ptr == NULL) { @@ -222,9 +241,13 @@ int section_array_add(SectionArray *arr, const Section* in) { ret = 1; } - // Append new section. - if(ret) { - arr->data[arr->count++] = *in; + size_t ii = i; + if(ret > 0) { + for(size_t j=arr->count; j>i; j--) { + arr->data[j] = arr->data[j-1]; + } + arr->count++; + arr->data[i] = *in; } } return ret; diff --git a/section/load.c b/section/load.c index 1f93f81..00f25b8 100644 --- a/section/load.c +++ b/section/load.c @@ -342,8 +342,6 @@ bool section_load(SectionArray *arr, const char *filename) { Section *ptr; const char* key; - section_array_reset(arr); - json_t* root = json_load_file(filename, 0, &err); if(root == NULL) { ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text); diff --git a/test/data/bank0_0.json b/test/data/bank0_0.json index 06b09ab..af12643 100644 --- a/test/data/bank0_0.json +++ b/test/data/bank0_0.json @@ -4,7 +4,7 @@ "type": "code", "page": "0", "logical" : "e000", - "size": "505", + "size": "504", "mpr": ["ff", "f8", 0, 0, 0, 0, 0, 0 ] }, diff --git a/test/section.c b/test/section.c index d7318b7..45eccab 100644 --- a/test/section.c +++ b/test/section.c @@ -104,7 +104,7 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { (void)fixture; static const Section bank0_0[4] = { - { "cdbios_functions", SECTION_TYPE_CODE, 0, 0xe000, 0x0000, 0x505, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, + { "cdbios_functions", SECTION_TYPE_CODE, 0, 0xe000, 0x0000, 0x504, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, { "unknown.0", SECTION_TYPE_DATA, 0, 0xe504, 0x0504, 0x05, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, { "ex_colorcmd.impl", SECTION_TYPE_CODE, 0, 0xe509, 0x0509, 0xce, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, { "unknown.1", SECTION_TYPE_DATA, 0, 0xe5d7, 0x05d7, 0x03, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } } @@ -121,10 +121,9 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { { "unknown.3", SECTION_TYPE_DATA, 0, 0xfec2, 0x1ec2, 0x134, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_UNKNOWN, 8, 16 } }, { "irq_vectors", SECTION_TYPE_DATA, 0, 0xfff6, 0x1ff6, 0x0a, { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }, "syscard.asm", { DATA_TYPE_HEX, 2, 1 } } }; - - static const Section* bank0[2] = { bank0_0, bank0_1 }; - + SectionArray arr = {0}; + section_array_reset(&arr); int i, j, k; int ret; @@ -132,44 +131,48 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { munit_assert_int(ret, !=, 0); munit_assert_int(arr.count, ==, 4); -/* - section_sort(section, count[0]); - - for(i=0; i Date: Thu, 26 Dec 2024 15:58:34 +0100 Subject: [PATCH 32/35] Rework section delete --- section.c | 24 +++++++----------------- section.h | 10 ++-------- section/load.c | 2 +- test/section.c | 51 -------------------------------------------------- 4 files changed, 10 insertions(+), 77 deletions(-) diff --git a/section.c b/section.c index 2e87698..b841ab4 100644 --- a/section.c +++ b/section.c @@ -101,20 +101,13 @@ static int section_compare(const void *a, const void *b) { return cmp; } -// Group section per output filename and sort them in bank/org order. -void section_sort(Section *ptr, size_t n) { - qsort(ptr, n, sizeof(Section), §ion_compare); -} - -// Delete sections. -void section_delete(Section *ptr, int n) { +// Delete section. +void section_delete(Section *ptr) { assert(ptr != NULL); - for(int i=0; iname); + free(ptr->output); + free(ptr->description); + section_reset(ptr); } // Reset a section array. @@ -122,10 +115,7 @@ void section_array_reset(SectionArray *arr) { assert(arr != NULL); if(arr->data != NULL) { for(size_t i=0; icount; i++) { - free(arr->data[i].name); - free(arr->data[i].output); - free(arr->data[i].description); - section_reset(&arr->data[i]); + section_delete(&arr->data[i]); } } arr->count = 0; diff --git a/section.h b/section.h index 80f5ee1..fb6a3fa 100644 --- a/section.h +++ b/section.h @@ -101,7 +101,6 @@ typedef struct { Section *data; ///< Pointer to section array. size_t count; ///< Number of sections currently in use. size_t capacity; ///< Number the section array can hold. - // [todo] index array of sorted sections ? } SectionArray; /// Reset a section array. @@ -133,13 +132,8 @@ const Section* section_array_get(SectionArray *arr, size_t i); /// Reset a section to its default values. void section_reset(Section *s); -/// Group section per output filename and sort them in page/logical address order. -/// \param [in out] ptr Sections. -/// \param [in] n Number of sections to sort. -void section_sort(Section *ptr, size_t n); // [todo] will be removed - -/// Delete sections. -void section_delete(Section *ptr, int n); // [todo] will be removed +/// Delete section. +void section_delete(Section *ptr); // Load sections from a JSON file. // \param [out] arr Loaded sections. diff --git a/section/load.c b/section/load.c index 00f25b8..3554ca6 100644 --- a/section/load.c +++ b/section/load.c @@ -362,7 +362,7 @@ bool section_load(SectionArray *arr, const char *filename) { } else { tmp.name = strdup(key); if(section_array_add(arr, &tmp) <= 0) { - section_delete(&tmp, 1); + section_delete(&tmp); } } } diff --git a/test/section.c b/test/section.c index 45eccab..eb15778 100644 --- a/test/section.c +++ b/test/section.c @@ -49,56 +49,6 @@ void tear_down(void* fixture __attribute__((unused))) { message_printer_destroy(); } -MunitResult section_sort_test(const MunitParameter params[], void* fixture) { - (void)params; - (void)fixture; - - Section section[8]; - - section[0].output = "0002"; - section[0].page = 0; - section[0].logical = 1; - - section[1].output = "0001"; - section[1].page = 0; - section[1].logical = 0; - - section[2].output = "0002"; - section[2].page = 1; - section[2].logical = 0; - - section[3].output = "0001"; - section[3].page = 1; - section[3].logical = 0; - - section[4].output = "0000"; - section[4].page = 0; - section[4].logical = 2; - - section[5].output = "0000"; - section[5].page = 0; - section[5].logical = 1; - - section[6].output = "0001"; - section[6].page = 0; - section[6].logical = 1; - - section[7].output = "0002"; - section[7].page = 0; - section[7].logical = 0; - - section_sort(section, 8); - - for(int i=0; i<7; i++) { - munit_assert_int(section[i].page, <=, section[i+1].page); - if(section[i].page == section[i+1].page) { - munit_assert_int(section[i].logical, <=, section[i+1].logical); - } - } - - return MUNIT_OK; -} - MunitResult section_load_test(const MunitParameter params[], void* fixture) { (void)params; (void)fixture; @@ -226,7 +176,6 @@ MunitResult section_add_test(const MunitParameter params[], void* fixture) { } static MunitTest section_tests[] = { - { "/sort", section_sort_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { "/load", section_load_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { "/overlap", section_overlap_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, { "/add", section_add_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL }, From c5f77b44d3ab99ecb1d5e93a387575d000bfa593 Mon Sep 17 00:00:00 2001 From: MooZ Date: Thu, 26 Dec 2024 20:10:33 +0100 Subject: [PATCH 33/35] Rework section merge --- cli/etripator.c | 18 +++------ decode.c | 10 ++--- decode.h | 2 +- irq.c | 25 +++++++++++-- section.c | 98 +++++++++++++++++++++++-------------------------- section.h | 6 ++- test/section.c | 3 +- 7 files changed, 85 insertions(+), 77 deletions(-) diff --git a/cli/etripator.c b/cli/etripator.c index d04df25..36757db 100644 --- a/cli/etripator.c +++ b/cli/etripator.c @@ -253,6 +253,9 @@ int main(int argc, const char **argv) { } } + /* Sort & merge sections */ + section_array_tidy(§ion_arr); + /* Disassemble and output */ Section *previous = NULL; Section *current = NULL; @@ -264,7 +267,7 @@ int main(int argc, const char **argv) { goto error_4; } - if (options.cdrom || (current->offset != ((current->page << 13) | (current->logical & 0x1fff)))) { + if (options.cdrom && (current->offset != ((current->page << 13) | (current->logical & 0x1fff)))) { size_t offset = current->offset; /* Copy CDROM data */ ret = cd_load(options.rom_filename, current->offset, current->size, options.sector_size, current->page, current->logical, &map); @@ -314,7 +317,7 @@ int main(int argc, const char **argv) { if (current->type == SECTION_TYPE_CODE) { if(current->size <= 0) { - current->size = compute_size(current, i, section_arr.count, &map); + current->size = compute_size(§ion_arr, i, section_arr.count, &map); } /* Extract labels */ @@ -339,21 +342,12 @@ int main(int argc, const char **argv) { } /* Open main asm file */ - main_file = fopen(options.main_filename, "w"); + main_file = fopen(options.main_filename, "a+"); // [todo] if (!main_file) { ERROR_MSG("Unable to open %s : %s", options.main_filename, strerror(errno)); goto error_4; } - label_dump(main_file, &map, repository); - - if (!options.cdrom && options.extract_irq) { - fprintf(main_file, "\n\t.data\n\t.bank 0\n\t.org $FFF6\n"); - for (int i = 0; i < 5; ++i) { - fprintf(main_file, "\t.dw $%04x\n", current->logical); - } - } - fclose(main_file); /* Output labels */ diff --git a/decode.c b/decode.c index aad74dd..97a84d8 100644 --- a/decode.c +++ b/decode.c @@ -504,7 +504,7 @@ static int data_extract_jump_table(FILE *out, Section *section, MemoryMap *map, print_statement_address(out, n, line_logical, line_page); } } - fputc('\n', out); + return 1; } @@ -817,10 +817,10 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label } /* Computes section size. */ -int32_t compute_size(Section *sections, int index, int count, MemoryMap *map) { +int32_t compute_size(SectionArray *sections, int index, int count, MemoryMap *map) { uint8_t i; uint8_t data[7]; - Section *current = §ions[index]; + Section *current = §ions->data[index]; uint32_t start = current->logical; uint32_t logical = start; @@ -829,9 +829,9 @@ int32_t compute_size(Section *sections, int index, int count, MemoryMap *map) { uint32_t max_offset = 0xffffffff; for (i = 0; i < count; i++) { if (i != index) { - if (current->page == sections[i].page) { + if (current->page == sections->data[i].page) { uint32_t offset_current = current->offset & 0x1fff; - uint32_t offset_it = sections[i].offset & 0x1fff; + uint32_t offset_it = sections->data[i].offset & 0x1fff; if ((offset_current < offset_it) && (max_offset > offset_it)) { max_offset = offset_it; } diff --git a/decode.h b/decode.h index 0f2b844..ba59f8d 100644 --- a/decode.h +++ b/decode.h @@ -79,7 +79,7 @@ int decode(FILE *out, uint16_t *logical, Section *section, MemoryMap *map, Label /// \param [in] count Number of sections. /// \param [in] map Memory map. /// \return Section size. -int32_t compute_size(Section *sections, int index, int count, MemoryMap *map); +int32_t compute_size(SectionArray *sections, int index, int count, MemoryMap *map); /// Output hardware IO port and RAM labels. /// \param [out] out File output. diff --git a/irq.c b/irq.c index 8dce2ea..1a597db 100644 --- a/irq.c +++ b/irq.c @@ -47,13 +47,10 @@ static char* g_irq_names[PCE_IRQ_COUNT] = { "irq_reset" }; -// [todo] add an extra section for the address table // Get irq code offsets from rom. bool irq_read(MemoryMap* map, SectionArray *out) { assert(map != NULL); assert(out != NULL); - assert(out->data != NULL); - assert((out->count + PCE_IRQ_COUNT) <= out->capacity); bool ret = false; if(map->memory[PCE_MEMORY_ROM].data == NULL) { @@ -62,7 +59,10 @@ bool irq_read(MemoryMap* map, SectionArray *out) { ERROR_MSG("ROM is abnormally small."); } else { uint16_t offset = PCE_IRQ_TABLE; + map->mpr[7] = 0; + ret = true; + for(size_t i=0; ret && (itype != b->type) { ret = (b->logical < (a->logical + a->size)) ? -1 : 0; } else if(b->logical <= (a->logical + a->size)) { @@ -185,60 +184,24 @@ int section_array_add(SectionArray *arr, const Section* in) { assert(in != NULL); int ret = -1; - size_t i; - bool insert = false; - - // Find the slot where the section will be inserted or merged - for(i=0; (!insert) && (icount); ) { - if(in->page > arr->data[i].page) { - // ... - } else if(in->page < arr->data[i].page) { - insert = true; - } else { - int overlap = section_overlap(&arr->data[i], in); - if(overlap == 1) { - section_merge(&arr->data[i], in); - INFO_MSG("Section %s has been merged with %s!", arr->data[i].name, in->name); - ret = 1; - break; - } else if (overlap == -1) { - WARNING_MSG("Section %s and %s overlaps!", arr->data[i].name, in->name); - } else if(overlap == 0) { - // ... - } - if(in->offset < arr->data[i].offset) { - insert = true; - } - } - if(!insert) { - i++; - } - } - - if((i >= arr->count) || insert) { - // Check if we need to expand section array buffer - if(arr->count >= arr->capacity) { - size_t n = arr->capacity + 4U; - Section *ptr = realloc(arr->data, n*sizeof(Section)); - if(ptr == NULL) { - ERROR_MSG("Failed to expand section array buffer", strerror(errno)); - } else { - arr->data = ptr; - arr->capacity = n; - ret = 1; - } + // Check if we need to expand section array buffer + if(arr->count >= arr->capacity) { + size_t n = arr->capacity + 4U; + Section *ptr = realloc(arr->data, n*sizeof(Section)); + if(ptr == NULL) { + ERROR_MSG("Failed to expand section array buffer", strerror(errno)); } else { + arr->data = ptr; + arr->capacity = n; ret = 1; } + } else { + ret = 1; + } - size_t ii = i; - if(ret > 0) { - for(size_t j=arr->count; j>i; j--) { - arr->data[j] = arr->data[j-1]; - } - arr->count++; - arr->data[i] = *in; - } + if(ret > 0) { + arr->data[arr->count] = *in; + arr->count++; } return ret; } @@ -252,4 +215,33 @@ const Section* section_array_get(SectionArray *arr, size_t i) { } } return ret; -} \ No newline at end of file +} + +// Merge and sort sections. +void section_array_tidy(SectionArray *arr) { + assert(arr != NULL); + assert(arr->count != 0); + + Section *section = calloc(arr->count, sizeof(Section)); + + qsort(arr->data, arr->count, sizeof(Section), section_compare); + + size_t j = 0; + section[0] = arr->data[0]; + for(size_t i=1; icount; i++) { + int overlap = section_overlap(§ion[j], &arr->data[i]); + if(overlap == 1) { + section_merge(§ion[j], &arr->data[i]); + INFO_MSG("Section %s has been merged with %s!", arr->data[i].name, section[j].name); + section_delete(&arr->data[i]); + } else { + if(overlap == -1) { + WARNING_MSG("Section %s and %s overlaps!", arr->data[i].name, section[j].name); + } + section[++j] = arr->data[i]; + } + } + free(arr->data); + arr->data = section; + arr->count = j+1; +} diff --git a/section.h b/section.h index fb6a3fa..0869797 100644 --- a/section.h +++ b/section.h @@ -113,8 +113,6 @@ void section_array_reset(SectionArray *arr); void section_array_delete(SectionArray *arr); /// Add a new section. -/// Note that if the section overlaps an already existing one, it will be merged if both sections have the -/// same type. /// \param [in out] arr Section array the section will be added to. /// \param [in] in Section that will be added to the section array. /// \return 1 if the section was succesfully added. @@ -122,6 +120,10 @@ void section_array_delete(SectionArray *arr); /// \return -1 if the section can not be merged or if there is not enough memory to add a new one. int section_array_add(SectionArray *arr, const Section* in); +/// Merge and sort sections. +/// \param [in out] arr Section array the section will be added to. +void section_array_tidy(SectionArray *arr); + /// Retrieve the ith section from the array. /// \param [in] arr Section array. /// \param [in] i Index of the section to be retrieved. diff --git a/test/section.c b/test/section.c index eb15778..4c1c735 100644 --- a/test/section.c +++ b/test/section.c @@ -78,7 +78,7 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { int i, j, k; int ret; ret = section_load(&arr, "./data/bank0_0.json"); - + section_array_tidy(&arr); munit_assert_int(ret, !=, 0); munit_assert_int(arr.count, ==, 4); @@ -96,6 +96,7 @@ MunitResult section_load_test(const MunitParameter params[], void* fixture) { } ret = section_load(&arr, "./data/bank0_1.json"); + section_array_tidy(&arr); munit_assert_int(ret, !=, 0); munit_assert_int(arr.count, ==, 13); for(i=0, k=0; k<4; i++, k++) { From b697c189edde91283f0681c290baab152cbf72c7 Mon Sep 17 00:00:00 2001 From: MooZ Date: Thu, 26 Dec 2024 20:33:42 +0100 Subject: [PATCH 34/35] Fix data section parsing --- section/load.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/section/load.c b/section/load.c index 3554ca6..e4e6a36 100644 --- a/section/load.c +++ b/section/load.c @@ -233,8 +233,8 @@ static bool json_parse_data_config_element_per_line(DataConfig *out, const json_ const json_t *value = json_object_get(obj, "elements_per_line"); if(value == NULL) { ret = true; // use default value - } else if(out->type != DATA_TYPE_HEX) { - ERROR_MSG("Number of elements per line is only valid for hex data section"); + } else if((out->type != DATA_TYPE_HEX) && (out->type != DATA_TYPE_STRING)) { + ERROR_MSG("Number of elements per line is only valid for hex and string data section"); } else if (!json_validate_int(value, &out->elements_per_line)) { ERROR_MSG("Invalid number of elements per line."); } else { From 3a0e208deee0ae65c38a0aefa8c046ac27bb40d0 Mon Sep 17 00:00:00 2001 From: MooZ Date: Fri, 27 Dec 2024 22:09:24 +0100 Subject: [PATCH 35/35] Finish cleaning things up --- cli/etripator.c | 398 ++++++++++++++++++++++++------------------------ cli/options.c | 8 +- comment.c | 39 ++--- comment.h | 14 +- decode.c | 6 - label.c | 39 ++--- label.h | 14 +- memory_map.h | 4 +- test/comment.c | 76 ++++----- test/label.c | 102 ++++++------- 10 files changed, 343 insertions(+), 357 deletions(-) diff --git a/cli/etripator.c b/cli/etripator.c index 36757db..b86fb8c 100644 --- a/cli/etripator.c +++ b/cli/etripator.c @@ -64,7 +64,7 @@ void exit_callback() { } // save found labels to a file named .YYmmddHHMMSS.lbl -static bool label_output(CommandLineOptions *options, LabelRepository *repository) { +static bool label_output(LabelRepository *repository, CommandLineOptions *options) { bool ret = false; char buffer[256U] = {0}; if (options->labels_out == NULL) { @@ -122,250 +122,248 @@ static bool log_cli(int argc, const char* argv[]) { return ret; } -/* ---------------------------------------------------------------- */ -int main(int argc, const char **argv) { - int ret = EXIT_FAILURE; - - atexit(exit_callback); - - message_printer_init(); - - if (file_message_printer_init() != true) { - fprintf(stderr, "Failed to setup file printer.\n"); - } else if (console_message_printer_init() != true) { - fprintf(stderr, "Failed to setup console printer.\n"); - } else if (log_cli(argc, argv) != true) { - fprintf(stderr, "Failed to log command line.\n"); - } else { - // [todo] - } - - CommandLineOptions options; - - FILE *out; - FILE *main_file; - int failure; - - MemoryMap map = {0}; - - SectionArray section_arr = {0}; - - failure = 1; - - section_array_reset(§ion_arr); - - /* Extract command line options */ - ret = cli_opt_get(&options, argc, argv); - if (ret <= 0) { - goto error_1; - } - - /* Read configuration file */ - if (options.cfg_filename) { - ret = section_load(§ion_arr, options.cfg_filename); - if (!ret) { - ERROR_MSG("Unable to read %s", options.cfg_filename); - goto error_1; +static bool load_sections(SectionArray *arr, const char *filename) { + bool ret = true; + if (filename) { + if (!section_load(arr, filename)) { + ERROR_MSG("Unable to read %s", filename); + ret = false; } } + return ret; +} - /* Initialize memory map */ - ret = memory_map_init(&map); - if (!ret) { - goto error_1; - } - - /* Read ROM */ - if (!options.cdrom) { - ret = rom_load(options.rom_filename, &map); - if (!ret) { - goto error_2; - } - - /* Get irq offsets */ - if (options.extract_irq) { - ret = irq_read(&map, §ion_arr); +static bool load_labels(LabelRepository *repository, const char **filename) { + bool ret = label_repository_create(repository); + if (filename != NULL) { + for(int i=0; ret && filename[i]; i++) { + ret = label_repository_load(repository, filename[i]); if (!ret) { - ERROR_MSG("An error occured while reading irq vector offsets"); - goto error_2; + ERROR_MSG("An error occured while loading labels from %s", filename[i]); } } - } else { - ret = cd_memory_map(&map); - if (!ret) { - goto error_2; - } + } + return ret; +} - if (options.extract_irq) { - IPL ipl; - ret = ipl_read(&ipl, options.rom_filename); - ret = ret && ipl_sections(&ipl, §ion_arr); +static bool load_comments(CommentRepository *repository, const char **filename) { + bool ret = comment_repository_create(repository); + if(filename != NULL) { + for(int i=0; ret && filename[i]; i++) { + ret = comment_repository_load(repository, filename[i]); if (!ret) { - ERROR_MSG("An error occured while setting up sections from IPL data."); - goto error_2; + ERROR_MSG("An error occured while loading comments from %s", filename[i]); } } - /* Data will be loaded during section disassembly */ } + return ret; +} - CommentRepository *comments_repository = comment_repository_create(); - /* Load comments */ - if(NULL != options.comments_in) { - for(int i=0; options.comments_in[i]; i++) { - ret = comment_repository_load(comments_repository, options.comments_in[i]); - if (!ret) { - ERROR_MSG("An error occured while loading comments from %s : %s", options.comments_in[i], strerror(errno)); - goto error_3; - } - } +static bool load_rom(MemoryMap *map, const CommandLineOptions *options) { + bool ret = false; + if (options->cdrom) { + ret = cd_memory_map(map); + /* Data will be loaded during section disassembly */ + } else { + ret = rom_load(options->rom_filename, map); } + return ret; +} - LabelRepository *repository = label_repository_create(); - /* Load labels */ - if (NULL != options.labels_in) { - for(int i=0; options.labels_in[i]; i++) { - ret = label_repository_load(repository, options.labels_in[i]); - if (!ret) { - ERROR_MSG("An error occured while loading labels from %s : %s", options.labels_in[i], strerror(errno)); - goto error_4; - } +static bool load_irq(MemoryMap *map, SectionArray *arr, const CommandLineOptions *options) { + bool ret = false; + if(!options->extract_irq) { + ret = true; + } else if (options->cdrom) { + IPL ipl = {0}; + if (!ipl_read(&ipl, options->rom_filename)) { + // ... + } else if (!ipl_sections(&ipl, arr)) { + ERROR_MSG("An error occured while setting up sections from IPL data."); + } else { + ret = true; } + } else if (!irq_read(map, arr)) { + ERROR_MSG("An error occured while reading irq vector offsets"); + } else { + ret = true; } + return ret; +} +static bool reset_output(SectionArray *arr) { + bool ret = true; /* For each section reset every existing files */ - for (int i = 0; i < section_arr.count; ++i) { - Section *section = §ion_arr.data[i]; - out = fopen(section->output, "wb"); - if (NULL == out) { + for (int i = 0; ret && (i < arr->count); ++i) { + Section *section = &arr->data[i]; + FILE *out = fopen(section->output, "wb"); + if (out == NULL) { ERROR_MSG("Can't open %s : %s", section->output, strerror(errno)); - goto error_4; + ret = false; + } else { + fclose(out); } - fclose(out); } + return ret; +} +static bool fill_label_reporitory(LabelRepository *labels, SectionArray *arr) { + bool ret = true; /* Add section name to label repository. */ - for (int i = 0; i < section_arr.count; ++i) { - Section *section = §ion_arr.data[i]; - ret = label_repository_add(repository, section->name, section->logical, section->page, section->description); + for (int i = 0; ret && (i < arr->count); ++i) { + Section *section = &arr->data[i]; + ret = label_repository_add(labels, section->name, section->logical, section->page, section->description); if (!ret) { ERROR_MSG("Failed to add section name (%s) to labels", section->name); - goto error_4; } } + return ret; +} - /* Sort & merge sections */ - section_array_tidy(§ion_arr); +static bool output_main(MemoryMap *map, LabelRepository *labels, const CommandLineOptions *options) { + bool ret = false; + FILE *out = fopen(options->main_filename, "w"); + if (out == NULL) { + ERROR_MSG("Unable to open %s : %s", options->main_filename, strerror(errno)); + } else { + label_dump(out, map, labels); + fclose(out); + ret = true; + } + return ret; +} - /* Disassemble and output */ +static bool code_extract(FILE *out, SectionArray *arr, int index, MemoryMap *map, LabelRepository *labels, CommentRepository *comments, int address) { + bool ret = false; + Section *current = &arr->data[index]; + if(current->size <= 0) { + current->size = compute_size(arr, index, arr->count, map); + } + if (!label_extract(current, map, labels)) { + // ... + } else { + /* Process opcodes */ + uint16_t logical = current->logical; + do { + (void)decode(out, &logical, current, map, labels, comments, address); + } while (logical < (current->logical+current->size)); + fputc('\n', out); + ret = true; + } + return true; +} + +static void print_header(FILE *out, Section *current, Section *previous) { + if(previous && ((previous->logical + previous->size) == current->logical)) { + // ... + } else if((current->type != SECTION_TYPE_DATA) || (current->data.type != DATA_TYPE_BINARY)) { + /* Print header */ + fprintf(out, "\t.%s\n" + "\t.bank $%03x\n" + "\t.org $%04x\n", + (current->type == SECTION_TYPE_CODE) ? "code" : "data", current->page, current->logical); + } +} + +static bool disassemble(SectionArray *arr, MemoryMap *map, LabelRepository *labels, CommentRepository *comments, CommandLineOptions *options) { + bool ret = true; Section *previous = NULL; Section *current = NULL; - for (int i = 0; i < section_arr.count; ++i, previous=current) { - current = §ion_arr.data[i]; - out = fopen(current->output, "ab"); - if (!out) { + for (int i = 0; ret && (i < arr->count); ++i, previous=current) { + current = &arr->data[i]; + FILE *out = fopen(current->output, "ab"); + if (out == NULL) { ERROR_MSG("Can't open %s : %s", current->output, strerror(errno)); - goto error_4; - } - - if (options.cdrom && (current->offset != ((current->page << 13) | (current->logical & 0x1fff)))) { - size_t offset = current->offset; - /* Copy CDROM data */ - ret = cd_load(options.rom_filename, current->offset, current->size, options.sector_size, current->page, current->logical, &map); - if (0 == ret) { - ERROR_MSG("Failed to load CD data (section %d)", i); - goto error_4; + } else { + if (options->cdrom && (current->offset != ((current->page << 13) | (current->logical & 0x1fff)))) { + size_t offset = current->offset; + /* Copy CDROM data */ + if (!cd_load(options->rom_filename, current->offset, current->size, options->sector_size, current->page, current->logical, map)) { + ERROR_MSG("Failed to load CD data (section %d)", i); + } else { + ret = false; + } } - } - - if((previous != NULL) && (current->logical < (previous->logical + previous->size)) - && (current->page == previous->page) - && (current->type != previous->type)) { - WARNING_MSG("Section %s and %s overlaps! %x %x.%x", current->name, previous->name); - } - if((previous != NULL) && (0 == strcmp(current->output, previous->output)) - && (current->page == previous->page) - && (current->logical <= (previous->logical + previous->size))) { - // "Merge" sections and adjust size if necessary. - if(current->size > 0) { - uint32_t end0 = previous->logical + previous->size; - uint32_t end1 = current->logical + current->size; - if(end1 > end0) { - current->size = end1 - end0; - current->logical = end0; - INFO_MSG("Section %s has been merged with %s!", current->name, previous->name); + if(ret) { + print_header(out, current, previous); + memory_map_mpr(map, current->mpr); + + if (current->type == SECTION_TYPE_CODE) { + ret = code_extract(out, arr, i, map, labels, comments, options->address); + } else { + ret = data_extract(out, current, map, labels, comments, options->address); } - else { - // The previous section overlaps the current one. - // We skip it as it has already been processed. - fclose(out); - continue; - } - } else { - current->logical = previous->logical + previous->size; - INFO_MSG("Section %s has been merged with %s!", current->name, previous->name); } - } else if((current->type != SECTION_TYPE_DATA) || (current->data.type != DATA_TYPE_BINARY)) { - /* Print header */ - fprintf(out, "\t.%s\n" - "\t.bank $%03x\n" - "\t.org $%04x\n", - (current->type == SECTION_TYPE_CODE) ? "code" : "data", current->page, current->logical); + fclose(out); } + } + return ret; +} - memory_map_mpr(&map, current->mpr); - - if (current->type == SECTION_TYPE_CODE) { - if(current->size <= 0) { - current->size = compute_size(§ion_arr, i, section_arr.count, &map); - } +/* ---------------------------------------------------------------- */ +int main(int argc, const char **argv) { + int ret = EXIT_FAILURE; - /* Extract labels */ - ret = label_extract(current, &map, repository); - if (!ret) { - goto error_4; - } - /* Process opcodes */ - uint16_t logical = current->logical; - do { - (void)decode(out, &logical, current, &map, repository, comments_repository, options.address); - } while (logical < (current->logical+current->size)); - fputc('\n', out); - } else { - ret = data_extract(out, current, &map, repository, comments_repository, options.address); - if (!ret) { - // [todo] - } - } + CommandLineOptions options = {0}; - fclose(out); - } + MemoryMap map = {0}; + SectionArray section_arr = {0}; - /* Open main asm file */ - main_file = fopen(options.main_filename, "a+"); // [todo] - if (!main_file) { - ERROR_MSG("Unable to open %s : %s", options.main_filename, strerror(errno)); - goto error_4; - } - label_dump(main_file, &map, repository); - fclose(main_file); + LabelRepository labels = {0}; + + CommentRepository comments = {0}; + + section_array_reset(§ion_arr); + + atexit(exit_callback); - /* Output labels */ - if (!label_output(&options, repository)) { - goto error_4; + message_printer_init(); + + if (file_message_printer_init() != true) { + fprintf(stderr, "Failed to setup file printer.\n"); + } else if (console_message_printer_init() != true) { + fprintf(stderr, "Failed to setup console printer.\n"); + } else if (log_cli(argc, argv) != true) { + fprintf(stderr, "Failed to log command line.\n"); + } else if (cli_opt_get(&options, argc, argv) != true) { + // ... + } else if (memory_map_init(&map) != true) { + // ... + } else if (!load_sections(§ion_arr, options.cfg_filename)) { + // ... + } else if (!load_labels(&labels, options.labels_in)) { + // ... + } else if (!load_comments(&comments, options.comments_in)) { + // ... + } else if (!load_rom(&map, &options)) { + // ... + } else if (!load_irq(&map, §ion_arr, &options)) { + // ... + } else if (!reset_output(§ion_arr)) { + // ... + } else if (!fill_label_reporitory(&labels, §ion_arr)) { + // ... + } else { + section_array_tidy(§ion_arr); + if(!output_main(&map, &labels, &options)) { + // ... + } else { + ret = EXIT_SUCCESS; + if(!disassemble(§ion_arr, &map, &labels, &comments, &options)) { + ret = EXIT_FAILURE; + } + if (label_output(&labels, &options)) { + ret = EXIT_FAILURE; + } + } } - failure = 0; -error_4: - label_repository_destroy(repository); -error_3: - comment_repository_destroy(comments_repository); -error_2: + label_repository_destroy(&labels); + comment_repository_destroy(&comments); memory_map_destroy(&map); -error_1: - cli_opt_release(&options); - section_array_delete(§ion_arr); + cli_opt_release(&options); - return failure; + return ret; } diff --git a/cli/options.c b/cli/options.c index c409d0e..0357d33 100644 --- a/cli/options.c +++ b/cli/options.c @@ -68,7 +68,7 @@ bool cli_opt_get(CommandLineOptions *options, int argc, const char** argv) { NULL }; - int ret = 0; + bool ret = false; char *dummy; struct payload_t labels_payload = { 0, 0, &options->labels_in }; @@ -112,7 +112,7 @@ bool cli_opt_get(CommandLineOptions *options, int argc, const char** argv) { /* Config file is optional with automatic irq vector extraction. */ options->cfg_filename = NULL; options->rom_filename = argv[0]; - ret = 1; + ret = true; } else { // ... @@ -121,10 +121,10 @@ bool cli_opt_get(CommandLineOptions *options, int argc, const char** argv) { else { options->cfg_filename = argv[0]; options->rom_filename = argv[1]; - ret = 1; + ret = true; } - if(ret == 0) { + if(!ret) { argparse_usage(&argparse); } diff --git a/comment.c b/comment.c index 9bc6d61..9fa0c21 100644 --- a/comment.c +++ b/comment.c @@ -41,13 +41,6 @@ #define COMMENT_ARRAY_INC 16 -/// Comment repository. -struct CommentRepositoryImpl { - size_t size; //< Size of comment repository. - size_t last; //< Last element in the repository. - Comment *comments; //< Comments. -}; - /// Get comment index by its address. /// \param [in] repository Coment repository. /// \param [in] logical Logical address. @@ -66,25 +59,21 @@ static int comment_repository_index(CommentRepository* repository, uint16_t logi } // Create comment repository. -CommentRepository* comment_repository_create() { - CommentRepository *repository; - repository = (CommentRepository*)malloc(sizeof(CommentRepository)); - if(repository == NULL) { - ERROR_MSG("Failed to create comment repository: %s", strerror(errno)); - } else { - repository->last = 0; - repository->comments = NULL; +bool comment_repository_create(CommentRepository *repository) { + assert(repository != NULL); + bool ret = true; - repository->size = COMMENT_ARRAY_INC; - repository->comments = (Comment*)malloc(repository->size * sizeof(Comment)); - if(repository->comments == NULL) { - ERROR_MSG("Failed to create comments: %s", strerror(errno)); - comment_repository_destroy(repository); - free(repository); - repository = NULL; - } - } - return repository; + repository->last = 0; + repository->comments = NULL; + + repository->size = COMMENT_ARRAY_INC; + repository->comments = (Comment*)malloc(repository->size * sizeof(Comment)); + if(repository->comments == NULL) { + ERROR_MSG("Failed to create comments: %s", strerror(errno)); + comment_repository_destroy(repository); + ret = false; + } + return ret; } // Release comment repository resources. diff --git a/comment.h b/comment.h index 7fca303..d909214 100644 --- a/comment.h +++ b/comment.h @@ -45,12 +45,18 @@ typedef struct { char* text; //< Comment text. } Comment; -typedef struct CommentRepositoryImpl CommentRepository; +/// Comment repository. +typedef struct { + size_t size; //< Size of comment repository. + size_t last; //< Last element in the repository. + Comment *comments; //< Comments. +} CommentRepository; /// Create comment repository. -/// \return A pointer to a comment repository. -/// \return NULL if an error occured. -CommentRepository* comment_repository_create(); +/// \param [in out] repository Comment repository. +/// \return true if the repository was succesfully initialized +/// \return false if an error occured +bool comment_repository_create(CommentRepository* repository); /// Release comment repository resources. /// \param [in,out] repository Comment repository. diff --git a/decode.c b/decode.c index 97a84d8..1b306c6 100644 --- a/decode.c +++ b/decode.c @@ -300,12 +300,6 @@ static int data_extract_string(FILE *out, Section *section, MemoryMap *map, Labe uint8_t line_page; Comment comment = {0}; - - fprintf(stdout, "----------------------------> "); - for(k=0; kdata.delimiter_size; k++) { - fprintf(stdout, "%c", section->data.delimiter[k]); - } - fprintf(stdout, "\n"); for (i = 0, j = 0, k = 0, logical = section->logical; i < section->size; i++, logical++) { uint8_t data = memory_map_read(map, logical); uint8_t page = memory_map_page(map, logical); diff --git a/label.c b/label.c index 07f64b4..4eeeec0 100644 --- a/label.c +++ b/label.c @@ -36,14 +36,9 @@ #include "label.h" #include "message.h" -#define LABEL_ARRAY_INC 16 +#include -/// Label repository. -struct LabelRepositoryImpl { - size_t size; //< Size of label repository. - size_t last; //< Last element in the repository. - Label *labels; //< Labels. -}; +#define LABEL_ARRAY_INC 16 /// Get label index by its address. /// \param [in] repository Label repository. @@ -63,23 +58,19 @@ static int label_repository_index(LabelRepository *repository, uint16_t logical, } // Create label repository. -LabelRepository* label_repository_create() { - LabelRepository *repository = (LabelRepository*)malloc(sizeof(LabelRepository)); - if(repository == NULL) { - ERROR_MSG("Failed to create label repository: %s", strerror(errno)); - } else { - repository->last = 0; - repository->labels = NULL; - repository->size = LABEL_ARRAY_INC; - repository->labels = (Label*)malloc(repository->size * sizeof(Label)); - if(repository->labels == NULL) { - ERROR_MSG("Failed to create label: %s", strerror(errno)); - label_repository_destroy(repository); - free(repository); - repository = NULL; - } - } - return repository; +bool label_repository_create(LabelRepository* repository) { + assert(repository != NULL); + bool ret = true; + repository->last = 0; + repository->labels = NULL; + repository->size = LABEL_ARRAY_INC; + repository->labels = (Label*)malloc(repository->size * sizeof(Label)); + if(repository->labels == NULL) { + ERROR_MSG("Failed to create label: %s", strerror(errno)); + label_repository_destroy(repository); + ret = false; + } + return ret; } // Delete label repository. diff --git a/label.h b/label.h index f140d4f..55dd1eb 100644 --- a/label.h +++ b/label.h @@ -46,12 +46,18 @@ typedef struct { char* description; //< Description (optional) } Label; -typedef struct LabelRepositoryImpl LabelRepository; +/// Label repository. +typedef struct { + size_t size; //< Size of label repository. + size_t last; //< Last element in the repository. + Label *labels; //< Labels. +} LabelRepository; /// Create label repository. -/// \return A pointer to a label repository. -/// \return NULL if an error occured. -LabelRepository* label_repository_create(); +/// \param [in out] repository Label repository. +/// \return true if the repository was succesfully initialized +/// \return false if an error occured +bool label_repository_create(LabelRepository* repository); /// Release label repository resources. /// \param [in,out] repository Label repository. diff --git a/memory_map.h b/memory_map.h index 16698ea..b4906fc 100644 --- a/memory_map.h +++ b/memory_map.h @@ -69,8 +69,8 @@ typedef struct { /// Initializes memory map. /// \param [in out] map Memory map. -/// \return true -/// \return false +/// \return true if the memory map was succesfully initialized +/// \return false if an error occured bool memory_map_init(MemoryMap *map); /// Releases resources used by the memory map. diff --git a/test/comment.c b/test/comment.c index 14d0216..717a341 100644 --- a/test/comment.c +++ b/test/comment.c @@ -50,91 +50,93 @@ void tear_down(void* fixture __attribute__((unused))) { MunitResult comment_add_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { Comment comment = {0}; - CommentRepository *repository = comment_repository_create(); - munit_assert_not_null(repository); + CommentRepository repository = {0}; + munit_assert_true(comment_repository_create(&repository)); - munit_assert_true(comment_repository_add(repository, 0x0002, 0x00, "comment #0")); - munit_assert_true(comment_repository_add(repository, 0x0001, 0x00, "comment #1")); - munit_assert_true(comment_repository_add(repository, 0x0003, 0x00, "comment #3")); - munit_assert_true(comment_repository_add(repository, 0x0001, 0x01, "comment #2")); + munit_assert_true(comment_repository_add(&repository, 0x0002, 0x00, "comment #0")); + munit_assert_true(comment_repository_add(&repository, 0x0001, 0x00, "comment #1")); + munit_assert_true(comment_repository_add(&repository, 0x0003, 0x00, "comment #3")); + munit_assert_true(comment_repository_add(&repository, 0x0001, 0x01, "comment #2")); - munit_assert_true(comment_repository_find(repository, 0x0001, 0x01, &comment)); + munit_assert_true(comment_repository_find(&repository, 0x0001, 0x01, &comment)); munit_assert_uint16(comment.logical, ==, 0x0001); munit_assert_uint8(comment.page, ==, 0x01); munit_assert_string_equal(comment.text, "comment #2"); - munit_assert_true(comment_repository_find(repository, 0x0001, 0x00, &comment)); + munit_assert_true(comment_repository_find(&repository, 0x0001, 0x00, &comment)); munit_assert_uint16(comment.logical, ==, 0x0001); munit_assert_uint8(comment.page, ==, 0x00); munit_assert_string_equal(comment.text, "comment #1"); - munit_assert_true(comment_repository_find(repository, 0x0003, 0x00, &comment)); + munit_assert_true(comment_repository_find(&repository, 0x0003, 0x00, &comment)); munit_assert_uint16(comment.logical, ==, 0x0003); munit_assert_uint8(comment.page, ==, 0x00); munit_assert_string_equal(comment.text, "comment #3"); - munit_assert_int(comment_repository_size(repository), ==, 4); + munit_assert_int(comment_repository_size(&repository), ==, 4); - comment_repository_destroy(repository); + comment_repository_destroy(&repository); return MUNIT_OK; } MunitResult comment_delete_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { Comment comment = {0}; - CommentRepository *repository = comment_repository_create(); - munit_assert_not_null(repository); + CommentRepository repository = {0}; + munit_assert_true(comment_repository_create(&repository)); - munit_assert_true(comment_repository_add(repository, 0x0002, 0x03, "comment #7")); - munit_assert_true(comment_repository_add(repository, 0x0002, 0x01, "comment #6")); - munit_assert_true(comment_repository_add(repository, 0x0002, 0x02, "comment #5")); - munit_assert_true(comment_repository_add(repository, 0x000a, 0x00, "comment #4")); - munit_assert_true(comment_repository_add(repository, 0x0008, 0x00, "comment #3")); - munit_assert_true(comment_repository_add(repository, 0x0004, 0x00, "comment #2")); - munit_assert_true(comment_repository_add(repository, 0x0002, 0x00, "comment #1")); - munit_assert_true(comment_repository_add(repository, 0x0000, 0x00, "comment #0")); - munit_assert_int(comment_repository_size(repository), ==, 8); + munit_assert_true(comment_repository_add(&repository, 0x0002, 0x03, "comment #7")); + munit_assert_true(comment_repository_add(&repository, 0x0002, 0x01, "comment #6")); + munit_assert_true(comment_repository_add(&repository, 0x0002, 0x02, "comment #5")); + munit_assert_true(comment_repository_add(&repository, 0x000a, 0x00, "comment #4")); + munit_assert_true(comment_repository_add(&repository, 0x0008, 0x00, "comment #3")); + munit_assert_true(comment_repository_add(&repository, 0x0004, 0x00, "comment #2")); + munit_assert_true(comment_repository_add(&repository, 0x0002, 0x00, "comment #1")); + munit_assert_true(comment_repository_add(&repository, 0x0000, 0x00, "comment #0")); + munit_assert_int(comment_repository_size(&repository), ==, 8); - comment_repository_delete(repository, 0x0001, 0x0009, 0x00); + comment_repository_delete(&repository, 0x0001, 0x0009, 0x00); - munit_assert_int(comment_repository_size(repository), ==, 5); + munit_assert_int(comment_repository_size(&repository), ==, 5); - comment_repository_destroy(repository); + comment_repository_destroy(&repository); return MUNIT_OK; } MunitResult comment_load_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { Comment comment = {0}; - CommentRepository *repository = comment_repository_create(); + CommentRepository repository = {0}; + + munit_assert_true(comment_repository_create(&repository)); - munit_assert_false(comment_repository_load(repository, "/not_here/comment.json")); - munit_assert_int(comment_repository_size(repository), ==, 0); + munit_assert_false(comment_repository_load(&repository, "/not_here/comment.json")); + munit_assert_int(comment_repository_size(&repository), ==, 0); - munit_assert_false(comment_repository_load(repository, "data/comment_1.json")); - munit_assert_int(comment_repository_size(repository), ==, 1); + munit_assert_false(comment_repository_load(&repository, "data/comment_1.json")); + munit_assert_int(comment_repository_size(&repository), ==, 1); - munit_assert_true(comment_repository_get(repository, 0, &comment)); + munit_assert_true(comment_repository_get(&repository, 0, &comment)); munit_assert_uint16(comment.logical, ==, 0xCAFEU); munit_assert_uint8(comment.page, ==, 0x0AU); munit_assert_string_equal(comment.text, "hello!"); - comment_repository_destroy(repository); + comment_repository_destroy(&repository); - munit_assert_true(comment_repository_load(repository, "data/comment_0.json")); - munit_assert_int(comment_repository_size(repository), ==, 2); + munit_assert_true(comment_repository_load(&repository, "data/comment_0.json")); + munit_assert_int(comment_repository_size(&repository), ==, 2); - munit_assert_true(comment_repository_find(repository, 0xC105U, 3, &comment)); + munit_assert_true(comment_repository_find(&repository, 0xC105U, 3, &comment)); munit_assert_uint16(comment.logical, ==, 0xC105U); munit_assert_uint8(comment.page, ==, 3); munit_assert_string_equal(comment.text, "line 0\nline 1\nline 2"); - munit_assert_true(comment_repository_find(repository, 0xEABCU, 0, &comment)); + munit_assert_true(comment_repository_find(&repository, 0xEABCU, 0, &comment)); munit_assert_uint16(comment.logical, ==, 0xEABCU); munit_assert_uint8(comment.page, ==, 0); munit_assert_string_equal(comment.text, "single line comment"); - comment_repository_destroy(repository); + comment_repository_destroy(&repository); return MUNIT_OK; } diff --git a/test/label.c b/test/label.c index 3843991..aa99e6d 100644 --- a/test/label.c +++ b/test/label.c @@ -50,117 +50,117 @@ void tear_down(void* fixture __attribute__((unused))) { MunitResult label_add_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { Label label = {}; - LabelRepository* repository = label_repository_create(); - munit_assert_not_null(repository); + LabelRepository repository = {0}; + munit_assert_true(label_repository_create(&repository)); - munit_assert_true(label_repository_add(repository, "l_0001", 0x0001, 0x00, NULL)); - munit_assert_true(label_repository_add(repository, "l_0020", 0x0020, 0x00, NULL)); - munit_assert_true(label_repository_add(repository, "l_000a", 0x000a, 0xb1, NULL)); - munit_assert_true(label_repository_add(repository, "l_cafe", 0xcafe, 0xf7, NULL)); - munit_assert_true(label_repository_add(repository, "l_0001", 0x0001, 0x00, NULL)); + munit_assert_true(label_repository_add(&repository, "l_0001", 0x0001, 0x00, NULL)); + munit_assert_true(label_repository_add(&repository, "l_0020", 0x0020, 0x00, NULL)); + munit_assert_true(label_repository_add(&repository, "l_000a", 0x000a, 0xb1, NULL)); + munit_assert_true(label_repository_add(&repository, "l_cafe", 0xcafe, 0xf7, NULL)); + munit_assert_true(label_repository_add(&repository, "l_0001", 0x0001, 0x00, NULL)); - munit_assert_int(label_repository_size(repository), ==, 4); + munit_assert_int(label_repository_size(&repository), ==, 4); - munit_assert_true(label_repository_find(repository, 0x000a, 0xb1, &label)); + munit_assert_true(label_repository_find(&repository, 0x000a, 0xb1, &label)); munit_assert_string_equal(label.name, "l_000a"); - munit_assert_true(label_repository_find(repository, 0x0020, 0x00, &label)); + munit_assert_true(label_repository_find(&repository, 0x0020, 0x00, &label)); munit_assert_string_equal(label.name, "l_0020"); - munit_assert_true(label_repository_find(repository, 0xcafe, 0xf7, &label)); + munit_assert_true(label_repository_find(&repository, 0xcafe, 0xf7, &label)); munit_assert_string_equal(label.name, "l_cafe"); - munit_assert_true(label_repository_find(repository, 0x0001, 0x00, &label)); + munit_assert_true(label_repository_find(&repository, 0x0001, 0x00, &label)); munit_assert_string_equal(label.name, "l_0001"); - munit_assert_false(label_repository_find(repository, 0xbeef, 0xac, &label)); + munit_assert_false(label_repository_find(&repository, 0xbeef, 0xac, &label)); - label_repository_destroy(repository); + label_repository_destroy(&repository); return MUNIT_OK; } MunitResult label_delete_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { Label label = {}; - LabelRepository* repository = label_repository_create(); - munit_assert_not_null(repository); - - munit_assert_true(label_repository_add(repository, "label01", 0x0110, 0x1a, NULL)); - munit_assert_true(label_repository_add(repository, "label02", 0x0220, 0x1a, NULL)); - munit_assert_true(label_repository_add(repository, "label03", 0x0330, 0x1b, "description")); - munit_assert_true(label_repository_add(repository, "label04", 0x0440, 0x1a, NULL)); - munit_assert_true(label_repository_add(repository, "label05", 0x0550, 0x1b, NULL)); - munit_assert_true(label_repository_add(repository, "label06", 0x0553, 0x1b, NULL)); - munit_assert_true(label_repository_add(repository, "label07", 0x0555, 0x1b, NULL)); - munit_assert_true(label_repository_add(repository, "label08", 0x0557, 0x1b, NULL)); + LabelRepository repository = {0}; + munit_assert_true(label_repository_create(&repository)); + + munit_assert_true(label_repository_add(&repository, "label01", 0x0110, 0x1a, NULL)); + munit_assert_true(label_repository_add(&repository, "label02", 0x0220, 0x1a, NULL)); + munit_assert_true(label_repository_add(&repository, "label03", 0x0330, 0x1b, "description")); + munit_assert_true(label_repository_add(&repository, "label04", 0x0440, 0x1a, NULL)); + munit_assert_true(label_repository_add(&repository, "label05", 0x0550, 0x1b, NULL)); + munit_assert_true(label_repository_add(&repository, "label06", 0x0553, 0x1b, NULL)); + munit_assert_true(label_repository_add(&repository, "label07", 0x0555, 0x1b, NULL)); + munit_assert_true(label_repository_add(&repository, "label08", 0x0557, 0x1b, NULL)); - munit_assert_int(label_repository_size(repository), ==, 8); + munit_assert_int(label_repository_size(&repository), ==, 8); - label_repository_delete(repository, 0x04a0, 0x0556, 0x1b); + label_repository_delete(&repository, 0x04a0, 0x0556, 0x1b); - munit_assert_int(label_repository_size(repository), ==, 5); + munit_assert_int(label_repository_size(&repository), ==, 5); - munit_assert_true(label_repository_find(repository, 0x0557, 0x1b, &label)); + munit_assert_true(label_repository_find(&repository, 0x0557, 0x1b, &label)); munit_assert_string_equal(label.name, "label08"); - munit_assert_true(label_repository_find(repository, 0x0440, 0x1a, &label)); + munit_assert_true(label_repository_find(&repository, 0x0440, 0x1a, &label)); munit_assert_string_equal(label.name, "label04"); - munit_assert_true(label_repository_find(repository, 0x0330, 0x1b, &label)); + munit_assert_true(label_repository_find(&repository, 0x0330, 0x1b, &label)); munit_assert_string_equal(label.name, "label03"); munit_assert_string_equal(label.description, "description"); - munit_assert_true(label_repository_find(repository, 0x0220, 0x1a, &label)); + munit_assert_true(label_repository_find(&repository, 0x0220, 0x1a, &label)); munit_assert_string_equal(label.name, "label02"); - munit_assert_true(label_repository_find(repository, 0x0110, 0x1a, &label)); + munit_assert_true(label_repository_find(&repository, 0x0110, 0x1a, &label)); munit_assert_string_equal(label.name, "label01"); - munit_assert_false(label_repository_find(repository, 0x0555, 0x1b, &label)); - munit_assert_false(label_repository_find(repository, 0x0553, 0x1b, &label)); - munit_assert_false(label_repository_find(repository, 0x0550, 0x1b, &label)); + munit_assert_false(label_repository_find(&repository, 0x0555, 0x1b, &label)); + munit_assert_false(label_repository_find(&repository, 0x0553, 0x1b, &label)); + munit_assert_false(label_repository_find(&repository, 0x0550, 0x1b, &label)); - label_repository_destroy(repository); + label_repository_destroy(&repository); return MUNIT_OK; } MunitResult label_load_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) { Label label = {}; - LabelRepository* repository = label_repository_create(); - munit_assert_not_null(repository); + LabelRepository repository = {0}; + munit_assert_true(label_repository_create(&repository)); - munit_assert_false(label_repository_load(repository, "/not_here/label.json")); - munit_assert_int(label_repository_size(repository), ==, 0); + munit_assert_false(label_repository_load(&repository, "/not_here/label.json")); + munit_assert_int(label_repository_size(&repository), ==, 0); - munit_assert_false(label_repository_load(repository, "data/label_1.json")); - munit_assert_int(label_repository_size(repository), ==, 1); + munit_assert_false(label_repository_load(&repository, "data/label_1.json")); + munit_assert_int(label_repository_size(&repository), ==, 1); - munit_assert_true(label_repository_get(repository, 0, &label)); + munit_assert_true(label_repository_get(&repository, 0, &label)); munit_assert_uint16(label.logical, ==, 0x5030U); munit_assert_uint8(label.page, ==, 4); munit_assert_string_equal(label.name, "ok"); munit_assert_null(label.description); - label_repository_destroy(repository); + label_repository_destroy(&repository); - munit_assert_true(label_repository_load(repository, "data/label_0.json")); - munit_assert_int(label_repository_size(repository), ==, 3); + munit_assert_true(label_repository_load(&repository, "data/label_0.json")); + munit_assert_int(label_repository_size(&repository), ==, 3); - munit_assert_true(label_repository_find(repository, 0x31DC, 0xF8, &label)); + munit_assert_true(label_repository_find(&repository, 0x31DC, 0xF8, &label)); munit_assert_uint16(label.logical, ==, 0x31DCU); munit_assert_uint8(label.page, ==, 0xF8); munit_assert_string_equal(label.name, "var"); munit_assert_null(label.description); - munit_assert_true(label_repository_find(repository, 0xEABC, 0x00, &label)); + munit_assert_true(label_repository_find(&repository, 0xEABC, 0x00, &label)); munit_assert_uint16(label.logical, ==, 0xEABCU); munit_assert_uint8(label.page, ==, 0x00); munit_assert_string_equal(label.name, "do_something"); munit_assert_string_equal(label.description, "do something"); - munit_assert_true(label_repository_find(repository, 0xD6F7, 0x1F, &label)); + munit_assert_true(label_repository_find(&repository, 0xD6F7, 0x1F, &label)); munit_assert_uint16(label.logical, ==, 0xD6F7U); munit_assert_uint8(label.page, ==, 0x1F); munit_assert_string_equal(label.name, "run"); munit_assert_string_equal(label.description, "line0\nline1\nline2\nline3"); - label_repository_destroy(repository); + label_repository_destroy(&repository); return MUNIT_OK; }