mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 19:01:30 +11:00
More registers!
This commit is contained in:
parent
4217a2b795
commit
f825d78e71
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "gba"
|
||||
description = "A crate (and book) for making GBA games with Rust."
|
||||
version = "0.3.0-pre"
|
||||
version = "0.3.0"
|
||||
authors = ["Lokathor <zefria@gmail.com>", "Thomas Winwood <twwinwood@gmail.com>"]
|
||||
repository = "https://github.com/rust-console/gba"
|
||||
readme = "README.md"
|
||||
|
@ -9,7 +9,7 @@ keywords = ["gba"]
|
|||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
publish = false
|
||||
#publish = false
|
||||
|
||||
[dependencies]
|
||||
typenum = "1.10"
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
use super::*;
|
||||
|
||||
pub mod background;
|
||||
pub mod color_blend;
|
||||
pub mod display;
|
||||
pub mod dma;
|
||||
pub mod keypad;
|
||||
pub mod sound;
|
||||
pub mod timers;
|
||||
pub mod window;
|
||||
|
|
66
src/io/color_blend.rs
Normal file
66
src/io/color_blend.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
//! Module that holds stuff for the color blending ability.
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Color Special Effects Selection (R/W)
|
||||
pub const BLDCNT: VolAddress<ColorEffectSetting> = unsafe { VolAddress::new_unchecked(0x400_0050) };
|
||||
|
||||
newtype! {
|
||||
ColorEffectSetting, u16
|
||||
}
|
||||
|
||||
impl ColorEffectSetting {
|
||||
phantom_fields! {
|
||||
self.0: u16,
|
||||
bg0_1st_target_pixel: 0,
|
||||
bg1_1st_target_pixel: 1,
|
||||
bg2_1st_target_pixel: 2,
|
||||
bg3_1st_target_pixel: 3,
|
||||
obj_1st_target_pixel: 4,
|
||||
backdrop_1st_target_pixel: 5,
|
||||
color_special_effect: 6-7=ColorSpecialEffect<None, AlphaBlending, BrightnessIncrease, BrightnessDecrease>,
|
||||
bg0_2nd_target_pixel: 8,
|
||||
bg1_2nd_target_pixel: 9,
|
||||
bg2_2nd_target_pixel: 10,
|
||||
bg3_2nd_target_pixel: 11,
|
||||
obj_2nd_target_pixel: 12,
|
||||
backdrop_2nd_target_pixel: 13,
|
||||
}
|
||||
}
|
||||
|
||||
newtype_enum! {
|
||||
ColorSpecialEffect = u16,
|
||||
None = 0,
|
||||
AlphaBlending = 1,
|
||||
BrightnessIncrease = 2,
|
||||
BrightnessDecrease = 3,
|
||||
}
|
||||
|
||||
/// Alpha Blending Coefficients (R/W) (not W)
|
||||
pub const BLDALPHA: VolAddress<AlphaBlendingSetting> = unsafe { VolAddress::new_unchecked(0x400_0052) };
|
||||
|
||||
newtype! {
|
||||
AlphaBlendingSetting, u16
|
||||
}
|
||||
|
||||
impl AlphaBlendingSetting {
|
||||
phantom_fields! {
|
||||
self.0: u16,
|
||||
eva_coefficient: 0-4,
|
||||
evb_coefficient: 8-12,
|
||||
}
|
||||
}
|
||||
|
||||
/// Brightness (Fade-In/Out) Coefficient (W) (not R/W)
|
||||
pub const BLDY: VolAddress<BrightnessSetting> = unsafe { VolAddress::new_unchecked(0x400_0054) };
|
||||
|
||||
newtype! {
|
||||
BrightnessSetting, u32
|
||||
}
|
||||
|
||||
impl BrightnessSetting {
|
||||
phantom_fields! {
|
||||
self.0: u32,
|
||||
evy_coefficient: 0-4,
|
||||
}
|
||||
}
|
|
@ -33,7 +33,6 @@ impl DisplayControlSetting {
|
|||
phantom_fields! {
|
||||
self.0: u16,
|
||||
mode: 0-2=DisplayMode<Mode0, Mode1, Mode2, Mode3, Mode4, Mode5>,
|
||||
cgb_mode: 3,
|
||||
frame1: 4,
|
||||
hblank_interval_free: 5,
|
||||
oam_memory_1d: 6,
|
||||
|
|
183
src/io/dma.rs
183
src/io/dma.rs
|
@ -124,6 +124,189 @@ pub enum DMAStartTiming {
|
|||
Special = 3,
|
||||
}
|
||||
|
||||
pub struct DMA0;
|
||||
impl DMA0 {
|
||||
/// DMA 0 Source Address, read only.
|
||||
const DMA0SAD: VolAddress<*const u32> = unsafe { VolAddress::new_unchecked(0x400_00B0) };
|
||||
/// DMA 0 Destination Address, read only.
|
||||
const DMA0DAD: VolAddress<*mut u32> = unsafe { VolAddress::new_unchecked(0x400_00B4) };
|
||||
/// DMA 0 Word Count, read only.
|
||||
const DMA0CNT_L: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_00B8) };
|
||||
/// DMA 0 Control, read/write.
|
||||
const DMA0CNT_H: VolAddress<DMAControlSetting> = unsafe { VolAddress::new_unchecked(0x400_00BA) };
|
||||
|
||||
/// Assigns the source register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The source pointer must be aligned and valid to read from.
|
||||
pub unsafe fn set_source(src: *const u32) {
|
||||
Self::DMA0SAD.write(src)
|
||||
}
|
||||
|
||||
/// Assigns the destination register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The source pointer must be aligned and valid to write to.
|
||||
pub unsafe fn set_dest(dest: *mut u32) {
|
||||
Self::DMA0DAD.write(dest)
|
||||
}
|
||||
|
||||
/// Assigns the count register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The count given must specify a valid number of units to write, starting at
|
||||
/// the assigned destination address.
|
||||
pub unsafe fn set_count(count: u16) {
|
||||
Self::DMA0CNT_L.write(count)
|
||||
}
|
||||
|
||||
/// Reads the current control setting.
|
||||
pub fn control() -> DMAControlSetting {
|
||||
Self::DMA0CNT_H.read()
|
||||
}
|
||||
|
||||
/// Writes the control setting given.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// You must ensure that the Source, Destination, and Count values are set
|
||||
/// correctly **before** you activate the Enable bit.
|
||||
pub unsafe fn set_control(setting: DMAControlSetting) {
|
||||
Self::DMA0CNT_H.write(setting)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DMA1;
|
||||
impl DMA1 {
|
||||
/// DMA 1 Source Address, read only.
|
||||
const DMA1SAD: VolAddress<*const u32> = unsafe { VolAddress::new_unchecked(0x400_00BC) };
|
||||
/// DMA 1 Destination Address, read only.
|
||||
const DMA1DAD: VolAddress<*mut u32> = unsafe { VolAddress::new_unchecked(0x400_00C0) };
|
||||
/// DMA 1 Word Count, read only.
|
||||
const DMA1CNT_L: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_00C4) };
|
||||
/// DMA 1 Control, read/write.
|
||||
const DMA1CNT_H: VolAddress<DMAControlSetting> = unsafe { VolAddress::new_unchecked(0x400_00C6) };
|
||||
|
||||
/// Assigns the source register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The source pointer must be aligned and valid to read from.
|
||||
pub unsafe fn set_source(src: *const u32) {
|
||||
Self::DMA1SAD.write(src)
|
||||
}
|
||||
|
||||
/// Assigns the destination register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The source pointer must be aligned and valid to write to.
|
||||
pub unsafe fn set_dest(dest: *mut u32) {
|
||||
Self::DMA1DAD.write(dest)
|
||||
}
|
||||
|
||||
/// Assigns the count register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The count given must specify a valid number of units to write, starting at
|
||||
/// the assigned destination address.
|
||||
pub unsafe fn set_count(count: u16) {
|
||||
Self::DMA1CNT_L.write(count)
|
||||
}
|
||||
|
||||
/// Reads the current control setting.
|
||||
pub fn control() -> DMAControlSetting {
|
||||
Self::DMA1CNT_H.read()
|
||||
}
|
||||
|
||||
/// Writes the control setting given.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// You must ensure that the Source, Destination, and Count values are set
|
||||
/// correctly **before** you activate the Enable bit.
|
||||
pub unsafe fn set_control(setting: DMAControlSetting) {
|
||||
Self::DMA1CNT_H.write(setting)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DMA2;
|
||||
impl DMA2 {
|
||||
/// DMA 2 Source Address, read only.
|
||||
const DMA2SAD: VolAddress<*const u32> = unsafe { VolAddress::new_unchecked(0x400_00C8) };
|
||||
/// DMA 2 Destination Address, read only.
|
||||
const DMA2DAD: VolAddress<*mut u32> = unsafe { VolAddress::new_unchecked(0x400_00CC) };
|
||||
/// DMA 2 Word Count, read only.
|
||||
const DMA2CNT_L: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_00D0) };
|
||||
/// DMA 2 Control, read/write.
|
||||
const DMA2CNT_H: VolAddress<DMAControlSetting> = unsafe { VolAddress::new_unchecked(0x400_00D2) };
|
||||
|
||||
/// Assigns the source register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The source pointer must be aligned and valid to read from.
|
||||
pub unsafe fn set_source(src: *const u32) {
|
||||
Self::DMA2SAD.write(src)
|
||||
}
|
||||
|
||||
/// Assigns the destination register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The source pointer must be aligned and valid to write to.
|
||||
pub unsafe fn set_dest(dest: *mut u32) {
|
||||
Self::DMA2DAD.write(dest)
|
||||
}
|
||||
|
||||
/// Assigns the count register.
|
||||
///
|
||||
/// This register is read only, so it is not exposed directly.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The count given must specify a valid number of units to write, starting at
|
||||
/// the assigned destination address.
|
||||
pub unsafe fn set_count(count: u16) {
|
||||
Self::DMA2CNT_L.write(count)
|
||||
}
|
||||
|
||||
/// Reads the current control setting.
|
||||
pub fn control() -> DMAControlSetting {
|
||||
Self::DMA2CNT_H.read()
|
||||
}
|
||||
|
||||
/// Writes the control setting given.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// You must ensure that the Source, Destination, and Count values are set
|
||||
/// correctly **before** you activate the Enable bit.
|
||||
pub unsafe fn set_control(setting: DMAControlSetting) {
|
||||
Self::DMA2CNT_H.write(setting)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the "general purpose" DMA unit, with the fewest limits.
|
||||
pub struct DMA3;
|
||||
impl DMA3 {
|
||||
|
|
89
src/io/window.rs
Normal file
89
src/io/window.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
//! Module that holds stuff for the Window ability.
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Window 0 Horizontal Dimensions (W)
|
||||
pub const WIN0H: VolAddress<HorizontalWindowSetting> = unsafe { VolAddress::new_unchecked(0x400_0040) };
|
||||
|
||||
/// Window 1 Horizontal Dimensions (W)
|
||||
pub const WIN1H: VolAddress<HorizontalWindowSetting> = unsafe { VolAddress::new_unchecked(0x400_0042) };
|
||||
|
||||
newtype! {
|
||||
HorizontalWindowSetting, u16
|
||||
}
|
||||
|
||||
impl HorizontalWindowSetting {
|
||||
phantom_fields! {
|
||||
self.0: u16,
|
||||
col_end: 0-7,
|
||||
col_start: 8-15,
|
||||
}
|
||||
}
|
||||
|
||||
/// Window 0 Vertical Dimensions (W)
|
||||
pub const WIN0V: VolAddress<VerticalWindowSetting> = unsafe { VolAddress::new_unchecked(0x400_0044) };
|
||||
|
||||
/// Window 1 Vertical Dimensions (W)
|
||||
pub const WIN1V: VolAddress<VerticalWindowSetting> = unsafe { VolAddress::new_unchecked(0x400_0046) };
|
||||
|
||||
newtype! {
|
||||
VerticalWindowSetting, u16
|
||||
}
|
||||
|
||||
impl VerticalWindowSetting {
|
||||
phantom_fields! {
|
||||
self.0: u16,
|
||||
row_end: 0-7,
|
||||
row_start: 8-15,
|
||||
}
|
||||
}
|
||||
|
||||
/// Control of Inside of Window(s) (R/W)
|
||||
pub const WININ: VolAddress<InsideWindowSetting> = unsafe { VolAddress::new_unchecked(0x400_0048) };
|
||||
|
||||
newtype! {
|
||||
InsideWindowSetting, u16
|
||||
}
|
||||
|
||||
impl InsideWindowSetting {
|
||||
phantom_fields! {
|
||||
self.0: u16,
|
||||
win0_bg0: 0,
|
||||
win0_bg1: 1,
|
||||
win0_bg2: 2,
|
||||
win0_bg3: 3,
|
||||
win0_obj: 4,
|
||||
win0_color_special: 5,
|
||||
win1_bg0: 8,
|
||||
win1_bg1: 9,
|
||||
win1_bg2: 10,
|
||||
win1_bg3: 11,
|
||||
win1_obj: 12,
|
||||
win1_color_special: 13,
|
||||
}
|
||||
}
|
||||
|
||||
/// Control of Outside of Windows & Inside of OBJ Window (R/W)
|
||||
pub const WINOUT: VolAddress<OutsideWindowSetting> = unsafe { VolAddress::new_unchecked(0x400_004A) };
|
||||
|
||||
newtype! {
|
||||
OutsideWindowSetting, u16
|
||||
}
|
||||
|
||||
impl OutsideWindowSetting {
|
||||
phantom_fields! {
|
||||
self.0: u16,
|
||||
outside_bg0: 0,
|
||||
outside_bg1: 1,
|
||||
outside_bg2: 2,
|
||||
outside_bg3: 3,
|
||||
outside_obj: 4,
|
||||
outside_color_special: 5,
|
||||
obj_win_bg0: 8,
|
||||
obj_win_bg1: 9,
|
||||
obj_win_bg2: 10,
|
||||
obj_win_bg3: 11,
|
||||
obj_win_obj: 12,
|
||||
obj_win_color_special: 13,
|
||||
}
|
||||
}
|
64
src/oam.rs
64
src/oam.rs
|
@ -127,3 +127,67 @@ impl OBJAttr2 {
|
|||
palbank: 12-15,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: OBJAttr0,
|
||||
attr1: OBJAttr1,
|
||||
attr2: OBJAttr2,
|
||||
}
|
||||
|
||||
/// The object attributes, but there are gaps in the array, so we must not
|
||||
/// expose this directly.
|
||||
const OBJ_ATTR_APPROX: VolAddressBlock<[u16; 4]> = unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(0x700_0000), 128) };
|
||||
|
||||
pub fn write_obj_attributes(slot: usize, attributes: ObjectAttributes) -> Option<()> {
|
||||
OBJ_ATTR_APPROX.get(slot).map(|va| unsafe {
|
||||
let va_u16 = va.cast::<u16>();
|
||||
va_u16.cast::<OBJAttr0>().write(attributes.attr0);
|
||||
va_u16.offset(1).cast::<OBJAttr1>().write(attributes.attr1);
|
||||
va_u16.offset(2).cast::<OBJAttr2>().write(attributes.attr2);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_obj_attributes(slot: usize) -> Option<ObjectAttributes> {
|
||||
OBJ_ATTR_APPROX.get(slot).map(|va| unsafe {
|
||||
let va_u16 = va.cast::<u16>();
|
||||
let attr0 = va_u16.cast::<OBJAttr0>().read();
|
||||
let attr1 = va_u16.offset(1).cast::<OBJAttr1>().read();
|
||||
let attr2 = va_u16.offset(2).cast::<OBJAttr2>().read();
|
||||
ObjectAttributes { attr0, attr1, attr2 }
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AffineParameters {
|
||||
pa: i16,
|
||||
pb: i16,
|
||||
pc: i16,
|
||||
pd: i16,
|
||||
}
|
||||
// TODO: find the correct fixed-point type here.
|
||||
|
||||
/// The object attributes, but there are gaps in the array, so we must not
|
||||
/// expose this directly.
|
||||
const AFFINE_PARAMS_APPROX: VolAddressBlock<[i16; 16]> = unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(0x700_0000), 32) };
|
||||
|
||||
pub fn write_affine_parameters(slot: usize, params: AffineParameters) -> Option<()> {
|
||||
AFFINE_PARAMS_APPROX.get(slot).map(|va| unsafe {
|
||||
let va_i16 = va.cast::<i16>();
|
||||
va_i16.offset(3).write(params.pa);
|
||||
va_i16.offset(7).write(params.pb);
|
||||
va_i16.offset(11).write(params.pc);
|
||||
va_i16.offset(15).write(params.pd);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_affine_parameters(slot: usize) -> Option<AffineParameters> {
|
||||
AFFINE_PARAMS_APPROX.get(slot).map(|va| unsafe {
|
||||
let va_i16 = va.cast::<i16>();
|
||||
let pa = va_i16.offset(3).read();
|
||||
let pb = va_i16.offset(7).read();
|
||||
let pc = va_i16.offset(11).read();
|
||||
let pd = va_i16.offset(15).read();
|
||||
AffineParameters { pa, pb, pc, pd }
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue