Skip to content

Commit

Permalink
Reformat changelog in Markdown; Add test program (including build scr…
Browse files Browse the repository at this point in the history
…ipt); Update readme (make Markdown); Rewrite and restructure project; Update optimisation flags; Depend on ctrlc, sdl2, and toml; Set window title according to image; Draw video memory; Update naming convention; Update gitignore; Never hang on trap; Run CPU on seperate thread; Rework logs;
  • Loading branch information
bjoernager committed Nov 4, 2023
1 parent 2ff708d commit 7176c1f
Show file tree
Hide file tree
Showing 68 changed files with 2,536 additions and 2,025 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
*.agb
*.elf
*.o
*.sav
vgcore.*
/target
/old
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.txt → CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# 0.2D

* Reformat changelog in Markdown
* Add test program (including build script)
* Update readme (make Markdown)
* Rewrite and restructure project
* Update optimisation flags
* Depend on ctrlc, sdl2, and toml
* Set window title according to image
* Draw video memory
* Update naming convention
* Update gitignore
* Never hang on trap
* Run CPU on seperate thread
* Rework logs

# 0.2C

* Fill window according to first palette entry;
Expand Down
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "luma"
version = "0.44.0"
version = "0.45.0"
authors = ["Gabriel Jensen"]
edition = "2021"
description = "AGB emulator."
Expand All @@ -14,10 +14,10 @@ name = "luma"
path = "src/main.rs"

[profile.release]
lto = true
codegen-units = 1
lto = "fat"

[dependencies]
toml = "0.7.5"
libc = "0.2.147"
ctrlc = "3.4.1"
sdl2 = "0.35.2"
serde = { version = "1.0.166", features = ["derive"] }
toml = "0.8.4"
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Luma

luma is an emulator for the AGB—Game Boy Advance platform.

# Usage

```
luma [configuration]
```

Invoke the emulator via the `luma` command.

## Configuration

The emulator tries to read the configuration file at `${HOME}/.luma.toml`. If successful, the following fields are read (all must be present):

`luma`:
* `version`: The configuration format (currently 0)

`device`:
* `bootloader`: The path to the bootloader file
* `image`: The path to the image file

`video`:
* `scale`: The scale modifier applied to the screen (1-4294967295)

If a path is parsed as a terminal parameter, the configuration at that location is read instead.

# Compatibility

Currently, the emulator has limited support for the Arm instruction set. All of the instructions used in the provided test program are – however – implemented.

The entire memory space (`0x00000000` to `0x0E00FFFF`) is available, however, no I/O-mapped addresses are currently functional.

Improved support is, of course, planned.

# Copyright & License

Copyright 2021-2023 Gabriel Bjørnager Jensen.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
85 changes: 0 additions & 85 deletions README.txt

This file was deleted.

14 changes: 14 additions & 0 deletions make_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env sh

echo Making object file...
arm-none-eabi-as -otest.o test.s

echo Making binary...
arm-none-eabi-ld -Ttest.ld -otest.elf test.o

echo Stripping binary...
arm-none-eabi-strip --strip-debug --strip-unneeded test.elf
arm-none-eabi-objcopy -Obinary test.elf test.agb

echo Patching header...
agbsum -psitest.agb
72 changes: 50 additions & 22 deletions src/luma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,63 @@
If not, see <https://www.gnu.org/licenses/>.
*/

pub mod application;
use sdl2::pixels::Color;

pub mod app;
pub mod configuration;
pub mod device;
pub mod cpu;
pub mod cpu_handle;
pub mod instruction;
pub mod state;

pub const VERSION: (u32, u32) = (
0x0, // major
0x2D, // minor
);

pub struct VersionType<T> {
major: T,
minor: T,
pub enum Error {
BadAlignment( u32, u32),
InvalidArmOpcode( u32, u32),
InvalidThumbOpcode(u32, u16),
OutOfBounds( u32),
}

pub const VERSION: VersionType::<u32> = VersionType::<u32> {
major: 0x0,
minor: 0x2C,
};
impl Error {
pub fn trap(&self) {
let message = match self {
Error::BadAlignment( address, alignment) => format!("bad alignment of address {address:#010X} (should be {alignment}-byte aligned)"),
Error::InvalidArmOpcode( address, opcode) => format!("invalid opcode {opcode:#034b} at {address:#010X}"),
Error::InvalidThumbOpcode( address, opcode) => format!("invalid opcode {opcode:#018b} at {address:#010X}"),
Error::OutOfBounds( address) => format!("out-of-bounds address {address:#010X} (limit is {:#010X})", MEMORY_LENGTH),
};

pub struct WidthHeight<T> {
width: T,
height: T,
eprintln!("trap: {message}");
}
}

pub const CONFIGURATION_VERSION: u32 = 0x0;
pub const MEMORY_LENGTH: u32 = 0x0E010000;

pub const BOOTLOADER_LENGTH: u32 = 0x00004000;
pub const IMAGE_LENGTH: u32 = 0x02000000;
pub const VIDEO_LENGTH: u32 = 0x00018000;
pub const PALETTE_LENGTH: u32 = 0x00000400;

pub const MEMORY_SIZE: usize = 0x0E010000;
pub const SCREEN_SIZE: (u8, u8) = (
0xF0, // width
0xA0, // height
);

pub const BOOTLOADER_SIZE: usize = 0x00004000;
pub const IMAGE_SIZE: usize = 0x02000000;
pub const VIDEO_SIZE: usize = 0x00018000;
pub const PALETTE_SIZE: usize = 0x00000400;
pub const fn decode_colour(colour: u16) -> Color {
let red = ((colour & 0b0000000000011111) << 0x3) as u8;
let green = ((colour & 0b0000001111100000) >> 0x2) as u8;
let blue = ((colour & 0b0111110000000000) >> 0x7) as u8;

pub const SCREEN_SIZE: WidthHeight::<u8> = WidthHeight::<u8> {
width: 0xF0,
height: 0xA0,
};
return Color::RGB(red, green, blue);
}

pub fn log(message: &str) {
// This optimises the function away.
if cfg!(debug_assertions) {
eprintln!("{message}");
}
}
9 changes: 2 additions & 7 deletions src/luma/application/drop.rs → src/luma/agb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,5 @@
If not, see <https://www.gnu.org/licenses/>.
*/

use crate::luma::application::Application;

impl Drop for Application {
fn drop(&mut self) {
eprintln!("ending");
}
}
pub mod arm;
pub mod thumb;
30 changes: 18 additions & 12 deletions src/luma/device/exchange.rs → src/luma/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@
If not, see <https://www.gnu.org/licenses/>.
*/

use crate::luma::device::{Device, Log};
use sdl2::Sdl;
use sdl2::render::WindowCanvas;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;

impl Device {
pub fn exchange(&mut self, thumb: bool) {
// Conditionally exchanges the instruction set.
// cpsr is set by the caller.
pub mod check_events;
pub mod draw_video;
pub mod init;
pub mod load;
pub mod run;
pub mod sync_video;

self.log(Log::Exchange, format!("T => {thumb}"));
pub struct App {
bootloader: String,
image: String,

let decoders = [
Device::decode_arm,
Device::decode_thumb,
];
scale: u32,

self.decode = decoders[thumb as usize];
}
got_terminate: Arc::<AtomicBool>,

sdl: Sdl,
canvas: WindowCanvas,
}
34 changes: 21 additions & 13 deletions src/luma/device/continue.rs → src/luma/app/check_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,32 @@
If not, see <https://www.gnu.org/licenses/>.
*/

use crate::luma::device::{Device, Log};
use crate::luma::app::App;

impl Device {
pub fn arm_continue(&mut self) {
// Increment the program counter by one
// instruction.
use sdl2::event::Event;
use std::sync::atomic::Ordering;

(self.registers[0xF], _) = self.registers[0xF].overflowing_add(0x4);
impl App {
pub fn check_events(&mut self) -> Result<bool, String> {
// Return true if we should quit.

self.log(Log::Continue, format!("pc => pc+4 ({:#010X})", self.registers[0xF]));
}
let mut event_pump = match self.sdl.event_pump() {
Ok(pump) => pump,
_ => return Err("unable to get event pump".to_string()),
};

pub fn thumb_continue(&mut self) {
// Increment the program counter by one
// instruction.
if self.got_terminate.load(Ordering::Relaxed) {
eprintln!("got terminate");
return Ok(true)
};

(self.registers[0xF], _) = self.registers[0xF].overflowing_add(0x2);
for event in event_pump.poll_iter() {
match event {
Event::Quit {..} => return Ok(true),
_ => {},
};
}

self.log(Log::Continue, format!("pc => pc+2 ({:#010X})", self.registers[0xF]));
return Ok(false);
}
}
Loading

0 comments on commit 7176c1f

Please sign in to comment.