Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests to cc65 build as well as fileio test #39

Merged
merged 22 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:

- name: Build using cc65
working-directory: ${{github.workspace}}
run: USE_LOCAL_CC65=1 make -f Makefile_cc65
run: USE_LOCAL_CC65=1 make -f Makefile_cc65 all

- name: Install llvm-mos-sdk
working-directory: ${{github.workspace}}
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# PRG files
*.prg
tests/*.prg

# Prerequisites
*.d

Expand Down
39 changes: 32 additions & 7 deletions Makefile_cc65
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@

SHELL:=/bin/bash
XEMU=xmega65
TESTS_DIR := tests
TESTS_SRCS := $(wildcard $(TESTS_DIR)/*.c)
TESTS_PRGS := $(TESTS_SRCS:.c=.prg)

ifdef USE_LOCAL_CC65
# use locally installed binary (requires 'cc65,ld65,etc' to be in the $PATH)
Expand All @@ -10,10 +14,11 @@ else
endif

CC65=$(CC65_PREFIX)cc65
CL65=$(CC65_PREFIX)cl65
CA65=$(CC65_PREFIX)ca65 --cpu 4510
AR65=$(CC65_PREFIX)ar65

CFLAGS=-O -t c64 -W +unused-param,+error,+unused-label,+no-effect,+unused-var,+no-effect -I include/
CFLAGS=-O -t c64 -I include/

LIB_OBJECTS = \
src/cc65/dirent.o \
Expand All @@ -32,21 +37,20 @@ LIB_OBJECTS = \
src/tests.o \
src/time.o

.PHONY: all clean cleanall
.PHONY: all clean cleanall test

all: libmega65.a

libmega65.a: $(LIB_OBJECTS)
$(AR65) a $@ $^

clean:
rm -f src/*.o
rm -f src/cc65/*.o
rm -f $(LIB_OBJECTS) $(TESTS_PRGS) tests/*.o
rm -rf work

cleanall: clean
rm -f libmega65.a

libmega65.a: $(LIB_OBJECTS)
$(AR65) a $@ $^

src/cc65/%.o: src/cc65/%.s
$(CA65) -o $@ $<

Expand All @@ -56,3 +60,24 @@ src/%.o: src/%.c
fi
$(CC65) $(CFLAGS) -o work/$*.s $<
$(CA65) -o $@ work/$*.s

# Unit tests using Xemu in "testing" mode
#
# - Xemu `xmega65` must be in your path
# - Xemu's return code is controlled by register 0xD6CF
# - All tests are in the `tests/` directory
tests/%.prg: tests/%.c libmega65.a
$(CL65) $(CFLAGS) $< -o $@ libmega65.a
test: | $(TESTS_PRGS)
@if ! command -v $(XEMU) &> /dev/null; then \
echo "Cannot run tests as xmega65 (Xemu) is not in your path."; \
else \
for test in $(TESTS_PRGS); do \
if $(XEMU) -testing -sleepless -headless -model 3 -prg $$test &> /dev/null; then \
echo "Test passed: $$test"; \
else \
echo "Test FAILED: $$test"; \
fi; \
done; \
fi

16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,23 @@ Simple C library for the MEGA65
## Clang

1. Install [llvm-mos-sdk](https://github.com/llvm-mos/llvm-mos-sdk#getting-started).
This e.g. downloads for linux and unpacks into `$HOME/llvm-mos`:
~~~ sh
wget https://github.com/llvm-mos/llvm-mos-sdk/releases/latest/download/llvm-mos-linux.tar.xz
tar xf llvm-mos-linux.tar.xz -C $HOME
~~~
2. Configure and make with:
~~~ sh
cmake -DCMAKE_PREFIX_PATH=<llvm-mos-sdk-install-prefix> -B build/ mega65-libc/
cd build/
cmake -DCMAKE_PREFIX_PATH=$HOME/llvm-mos -B build/ mega65-libc/
cd build
make
make test # if `xmega65` (Xemu) is in your path
make test # if `xmega65` (Xemu) was in your patch when running cmake
~~~

### Dependent CMake projects
### Dependent projects

`CMakeLists.txt` of a dependent project could look like this:
It's trivial to write a classic `Makefile` for clang.
For dependent CMake based projects, `CMakeLists.txt` could look like this:
~~~ cmake
cmake_minimum_required(VERSION 3.5)
set(LLVM_MOS_PLATFORM mega65)
Expand Down
6 changes: 5 additions & 1 deletion include/mega65/debug.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#ifndef __MEGA65_DEBUG_H
#define __MEGA65_DEBUG_H

void debug_msg(char* m);
/**
* @brief Write debug message to serial monitor
* @param msg Text message to write
*/
void debug_msg(char* msg);

#endif // __MEGA65_DEBUG_H
16 changes: 11 additions & 5 deletions include/mega65/dirent.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@

#include <stdint.h>

/// Open a directory
unsigned char opendir(void);

/// Read directory entry
struct m65_dirent* readdir(unsigned char);

/// Close directory entry
void closedir(unsigned char);

/// Structure describing an open directory
#ifdef __clang__
struct __attribute__((__packed__)) m65_dirent {
#else
struct m65_dirent {
#endif
uint32_t d_ino;
uint16_t d_off;
uint32_t d_reclen;
uint16_t d_type;
char d_name[256];
uint32_t d_ino; //!< File number of entry
uint16_t d_off; //!< Offset
uint32_t d_reclen; //!< Length of this record
uint16_t d_type; //!< File type
char d_name[256]; //!< Filename string of entry
};

#endif // __MEGA65_DIRENT_H
10 changes: 4 additions & 6 deletions include/mega65/fcio.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@

/*! @file fcio.h
@brief Full colour mode i/o library for the MEGA65

Details.
*/
/**
* @file fcio.h
* @brief Full colour mode i/o library for the MEGA65
*/

#ifndef __MEGA65_FCIO_H
#define __MEGA65_FCIO_H
Expand Down
48 changes: 36 additions & 12 deletions include/mega65/fileio.h
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
#ifndef __MEGA65_FILEIO_H
#define __MEGA65_FILEIO_H

void toggle_rom_write_protect();
#include <stdint.h>
#include <stddef.h>

void toggle_rom_write_protect(void);

/** Closes all open files */
void closeall(void);
void close(unsigned char fd);

// Returns file descriptor
unsigned char open(char* filename);
/**
* @brief Close a single file
* @param fd File descriptor pointing to file to close
*/
void close(uint8_t fd);

/**
* @brief Open file
* @param filename to open
* @return File descriptor or `0xff` if error
*/
uint8_t open(char* filename);

// Read upto one sector of data into the supplied buffer.
// Returns the number of bytes actually read.
unsigned short read512(unsigned char* buffer);
/**
* @brief Read up to 512 bytes from file
* @param buffer Input buffer
* @return Number of bytes read
*/
size_t read512(uint8_t* buffer);

// Change working directory
// (only accepts one directory segment at a time
unsigned char chdir(char* filename);
/**
* @brief Change working directory
* @param filename Directory name
* @return Error code (currently unused)
* @note Only accepts one directory segment at a time
*/
uint8_t chdir(char* filename);

// Change working directory to the root directory
unsigned char chdirroot(void);
/**
* @brief Change working directory to the root directory
* @return Error code (currently unused)
*/
uint8_t chdirroot(void);

#endif // __MEGA65_FILEIO_H
4 changes: 4 additions & 0 deletions include/mega65/hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

#include <stdint.h>

/**
* @brief Sleep for the given number of microseconds
* @param micros Microseconds to sleep
*/
void usleep(uint32_t micros);

#endif // __MEGA65_HAL_H
63 changes: 59 additions & 4 deletions include/mega65/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
#define __MEGA65_MEMORY_H

#include <stdint.h>
#include <stddef.h>

#define DMA_COPY_CMD 0x00;
#define DMA_FILL_CMD 0x03;

/**
* @brief DMA list structure
*/
#ifdef __clang__
struct __attribute__((__packed__)) dmagic_dmalist {
#else
Expand Down Expand Up @@ -37,17 +44,65 @@ extern struct dmagic_dmalist dmalist;
extern uint8_t dma_byte;
#endif

/**
* @brief Enable Mega65 mode
*/
void mega65_io_enable(void);

/**
* @brief Peek a byte from the given address
* @param address 28-bit address
* @return uint8_t with the value at the given address
*/
uint8_t lpeek(uint32_t address);
uint8_t lpeek_debounced(uint32_t address);

/**
* @brief Peek a byte from the given address using DMA copy
* @param address 28-bit address
* @return Single byte from the given address
*/
uint8_t dma_peek(uint32_t address);

/**
* @brief Poke a byte to the given address
* @param address 28-bit address
* @param value Single byte to write to the given address
*/
void lpoke(uint32_t address, uint8_t value);

/**
* @brief Poke a byte to the given address using DMA copy
* @param address 28-bit address
* @param value Single byte to write to the given address
*/
void dma_poke(uint32_t address, uint8_t value);
void lcopy(
uint32_t source_address, uint32_t destination_address, uint16_t count);
void lfill(uint32_t destination_address, uint8_t value, uint16_t count);

/**
* @brief Copy a block of memory using DMA
* @param source_address 28-bit address to copy from
* @param destination_address 28-bit address to copy to
* @param count Number of bytes to copy
*/
void lcopy(uint32_t source_address, uint32_t destination_address, size_t count);

/**
* @brief Fill a block of memory with a single byte using DMA
* @param destination_address Start address (28-bit)
* @param value Fill value
* @param count Number of bytes to fill
*/
void lfill(uint32_t destination_address, uint8_t value, size_t count);

/**
* @brief Fill a block of memory with a single byte using DMA with a step
* @param destination_address Start address (28-bit)
* @param value Fill value
* @param count Number of bytes to fill
* @param skip Skip every n bytes
*/
void lfill_skip(
uint32_t destination_address, uint8_t value, uint16_t count, uint8_t skip);
uint32_t destination_address, uint8_t value, size_t count, uint8_t skip);

#ifdef __clang__
#define POKE(X, Y) (*(volatile uint8_t*)(X)) = Y
Expand Down
6 changes: 5 additions & 1 deletion include/mega65/targets.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef __MEGA65_TARGETS_H
#define __MEGA65_TARGETS_H

#include <stdint.h>

#define TARGET_UNKNOWN 0
#define TARGET_MEGA65R1 1
#define TARGET_MEGA65R2 2
Expand All @@ -12,7 +14,9 @@
#define TARGET_NEXYS4DDRWIDGET 0x42
#define TARGET_WUKONG 0xFD
#define TARGET_SIMULATION 0xFE
#define TARGET_EMULATION 0xFF //!< Emulator like Xemu

unsigned char detect_target(void);
/// Detects the target on which we're running
uint8_t detect_target(void);

#endif // __MEGA65_TARGETS_H
11 changes: 11 additions & 0 deletions include/mega65/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
#define TEST_LOG 0xfd
#define TEST_SETNAME 0xfe
#define TEST_DONEALL 0xff
#define XEMU_CONTROL 0xD6CF
#define XEMU_QUIT 0x42

/**
* @brief Quits Xemu with given exit code
* @param exit_code Exit code passed to Xemu, e.g. EXIT_SUCCESS or EXIT_FAILURE
*
* Xemu must be run in `-testing` mode for this to have any effect and
* also make sure to call `mega65_io_enable()` before calling this function.
*/
void xemu_exit(int exit_code);

// convenience methods

Expand Down
2 changes: 2 additions & 0 deletions include/mega65/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ struct m65_tm {
unsigned char tm_isdst; /* Daylight saving time */
};

/// Get real-time clock
void getrtc(struct m65_tm* tm);
/// Set real-time clock
void setrtc(struct m65_tm* tm);

#endif // __MEGA65_TIME_H
Loading