Skip to content

Commit

Permalink
Add inline lpeek_i() function for llvm
Browse files Browse the repository at this point in the history
Using inline assembly can reduce binary file size due
to inlining and by the bypassing the calling convention. This is
currently a llvm/clang feature only and is for experiemtal use.
  • Loading branch information
mlund committed Sep 1, 2024
1 parent b489ceb commit 1f83cf7
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
30 changes: 30 additions & 0 deletions include/mega65/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,36 @@ __attribute__((leaf))
#endif
uint8_t lpeek(uint32_t address);

#ifdef __llvm__
/**
* @brief Inlined version of `lpeek()`
* @param ADDRESS 28-bit address; must be a compile-time constant.
* @returns Value at address
* @warning This function is experimental and may change/be removed in future versions
*/
inline uint8_t lpeek_i(const uint32_t ADDRESS)
{
// Helper to (dis)assemble 32-bit int; optimizes out fully
const union {
uint32_t value;
uint8_t byte[4];
} adr = { ADDRESS };

uint8_t value;

__attribute__((leaf)) __asm__ volatile(
"ldz #%4 \n" // complete Q=AXYZ register
"stq __rc2 \n" // Q -> rc2-5
"ldz #0 \n"
"lda [__rc2], z \n"
: "=a"(value)
: "a"(adr.byte[0]), "x"(adr.byte[1]), "y"(adr.byte[2]), "i"(adr.byte[3])
: "rc2", "rc3", "rc4", "rc5", "p");

return value;
}
#endif

uint8_t lpeek_debounced(uint32_t address);

/**
Expand Down
22 changes: 21 additions & 1 deletion tests/test-memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/
#include <mega65/memory.h>
#include <mega65/tests.h>
#include <mega65/debug.h>
#include <stdlib.h>
#include <stdint.h>

Expand All @@ -21,6 +22,7 @@ int main(void)
assert_eq(sizeof(struct dmagic_dmalist), 20);

// PEEK and POKE macros
debug_msg("TEST: peek/poke macro");
POKE(0x3000, 7);
POKE(0x3001, 9);
POKE(0x3002, 13);
Expand All @@ -29,45 +31,63 @@ int main(void)
assert_eq(PEEK(0x3002), 13);

// lcopy
debug_msg("TEST: lcopy()");
lcopy(0x3000, 0x4000, 3);
assert_eq(PEEK(0x4000), 7);
assert_eq(PEEK(0x4001), 9);
assert_eq(PEEK(0x4002), 13);

// lpoke and lpeek
debug_msg("TEST: lpeek() and lpoke()");
lpoke(0x4000, 13);
assert_eq(lpeek(0x4000), 13);
#ifdef __llvm__
assert_eq(lpeek_i(0x4000), 13);
#endif

lpoke(0x4001, 9);
assert_eq(lpeek(0x4001), 9);
#ifdef __llvm__
assert_eq(lpeek_i(0x4001), 9);
#endif

lpoke(0x4002, 7);
assert_eq(lpeek(0x4002), 7);
assert_eq(501, 501);
#ifdef __llvm__
assert_eq(lpeek_i(0x4002), 7);
#endif

// dma_poke and dma_peek
debug_msg("TEST: dma_poke() and dma_peek()");
dma_poke(0x4000, 9);
dma_poke(0x4001, 10);
dma_poke(0x4002, 11);
assert_eq(dma_peek(0x4000), 9);
assert_eq(dma_peek(0x4001), 10);
assert_eq(dma_peek(0x4002), 11);


// lfill
debug_msg("TEST: lfill()");
lfill(0x3000, 1, 3);
assert_eq(PEEK(0x3000), 1);
assert_eq(PEEK(0x3001), 1);
assert_eq(PEEK(0x3002), 1);

// lfill_skip
debug_msg("TEST: lfill() with skip");
lfill_skip(0x3000, 0, 3, 2);
assert_eq(PEEK(0x3000), 0);
assert_eq(PEEK(0x3001), 1);
assert_eq(PEEK(0x3002), 0);

// POKE16 and PEEK16 macros
debug_msg("TEST: poke/peek 16");
POKE16(0x3000, 0xAABB);
assert_eq(PEEK16(0x3000), 0xAABB);

// POKE32 and PEEK32 macros
debug_msg("TEST: poke/peek 32");
POKE32(0x3000, 0xAABBCCDD);
assert_eq(PEEK32(0x3000), 0xAABBCCDD);

Expand Down

0 comments on commit 1f83cf7

Please sign in to comment.