From fbd8961be1df70303bcfb35e7ba7f93671f29c42 Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Tue, 3 Dec 2024 21:21:49 +0100 Subject: [PATCH] sim65: changing memory access types to uint8_t and uint16_t. In sim65, simulator memory access to a 64 KB array is implemented via functions defined in src/sim65/memory.h and src/sim65/memory.c. In the old version, the types for both content bytes (8 bits), content words (16 bits), regular addresses (16 bits), and zero-page addresses (8 bits) were all given as bare 'unsigned'. This lead to several cases of address overrun (e.g., when an instruction wraps around from address 0xffff to 0x0000) when running the simulator against a stress test (specifically, the 65x02 test suite). To protect from this, and to more properly express the bit width of the types involved which is a good idea anyway, we start using the fixed-width types provided by 'stdint.h'. In the process, we also change the MemReadByte macro to a full function call. This may impact performance (by a small amount), but it improves memory safety, as cases where the address is accidentally expressed as a value exceeding 0xffff are handled by wrap-around (as it is in the actual hardware), rather than causing access outside of the Mem[] array where the 64 KB of simulated RAM resides. The reason for this patch is twofold. (1) It is a partial patch for issue #2539. Several issues brought to the surface by running the 65x02 testsuite are eliminated by these changes. In the discussion about this issue, it was concluded that it is a Good Idea to use the stdint-types, both for the simulated CPU registers and for the memory. This patch addresses the memory-part of that change. (2) It is a precursor patch for issue #2355. For that issue, we will implement a memory-mapped timer register. This will make handling of memory access in the simulator a bit more complex. Having proper functions with the proper types in place will help to make the timer register patch easier. --- src/sim65/memory.c | 24 ++++++++++++++++-------- src/sim65/memory.h | 21 +++++++-------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/sim65/memory.c b/src/sim65/memory.c index 68e7bb93b..b93693b91 100644 --- a/src/sim65/memory.c +++ b/src/sim65/memory.c @@ -45,8 +45,8 @@ -/* THE memory */ -unsigned char Mem[0x10000]; +/* The memory */ +uint8_t Mem[0x10000]; @@ -56,7 +56,7 @@ unsigned char Mem[0x10000]; -void MemWriteByte (unsigned Addr, unsigned char Val) +void MemWriteByte (uint16_t Addr, uint8_t Val) /* Write a byte to a memory location */ { Mem[Addr] = Val; @@ -64,7 +64,7 @@ void MemWriteByte (unsigned Addr, unsigned char Val) -void MemWriteWord (unsigned Addr, unsigned Val) +void MemWriteWord (uint16_t Addr, uint16_t Val) /* Write a word to a memory location */ { MemWriteByte (Addr, Val & 0xFF); @@ -73,22 +73,30 @@ void MemWriteWord (unsigned Addr, unsigned Val) -unsigned MemReadWord (unsigned Addr) +uint8_t MemReadByte (uint16_t Addr) +/* Read a byte from a memory location */ +{ + return Mem[Addr]; +} + + + +uint16_t MemReadWord (uint16_t Addr) /* Read a word from a memory location */ { - unsigned W = MemReadByte (Addr++); + uint8_t W = MemReadByte (Addr++); return (W | (MemReadByte (Addr) << 8)); } -unsigned MemReadZPWord (unsigned char Addr) +uint16_t MemReadZPWord (uint8_t Addr) /* Read a word from the zero page. This function differs from MemReadWord in that ** the read will always be in the zero page, even in case of an address ** overflow. */ { - unsigned W = MemReadByte (Addr++); + uint8_t W = MemReadByte (Addr++); return (W | (MemReadByte (Addr) << 8)); } diff --git a/src/sim65/memory.h b/src/sim65/memory.h index cef786aaa..b70c5bd05 100644 --- a/src/sim65/memory.h +++ b/src/sim65/memory.h @@ -36,9 +36,9 @@ #ifndef MEMORY_H #define MEMORY_H -#include "inline.h" +#include -extern unsigned char Mem[0x10000]; +extern uint8_t Mem[0x10000]; /*****************************************************************************/ /* Code */ @@ -46,26 +46,19 @@ extern unsigned char Mem[0x10000]; -void MemWriteByte (unsigned Addr, unsigned char Val); +void MemWriteByte (uint16_t Addr, uint8_t Val); /* Write a byte to a memory location */ -void MemWriteWord (unsigned Addr, unsigned Val); +void MemWriteWord (uint16_t Addr, uint16_t Val); /* Write a word to a memory location */ -#if defined(HAVE_INLINE) -INLINE unsigned char MemReadByte (unsigned Addr) +uint8_t MemReadByte (uint16_t Addr); /* Read a byte from a memory location */ -{ - return Mem[Addr]; -} -#else -#define MemReadByte(Addr) Mem[Addr] -#endif -unsigned MemReadWord (unsigned Addr); +uint16_t MemReadWord (uint16_t Addr); /* Read a word from a memory location */ -unsigned MemReadZPWord (unsigned char Addr); +uint16_t MemReadZPWord (uint8_t Addr); /* Read a word from the zero page. This function differs from MemReadWord in that ** the read will always be in the zero page, even in case of an address ** overflow.