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