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