summaryrefslogtreecommitdiff
path: root/src/state/read.rs
blob: 927d5280ec11dd8f702b6db554e7f550befe01aa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
	Copyright 2021-2023 Gabriel Jensen.

	This file is part of Luma.

	Luma 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.

	Luma 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 Luma.
	If not, see <https://www.gnu.org/licenses/>.
*/

use crate::{Error, MEMORY_LENGTH};
use crate::cpu_mode::CpuMode;
use crate::state::State;

const MAX_BYTE_ADDRESS:     u32 = MEMORY_LENGTH;
const MAX_HALFWORD_ADDRESS: u32 = MEMORY_LENGTH - 0x1;
const MAX_WORD_ADDRESS:     u32 = MEMORY_LENGTH - 0x3;

impl State {
	#[inline(always)]
	#[must_use]
	pub fn read_register(&self, register: u8) -> u32 {
		// Limit to 0..=15.
		let index = (register & 0b00001111) as usize;

		return unsafe { **self.registers.get_unchecked(index) };
	}

	#[must_use]
	pub fn read_word(&self, address: u32) -> u32 {
		if address > MAX_WORD_ADDRESS { Error::OutOfBounds( address).trap();      return 0xFFFFFFFF; }
		if address % 0x4 != 0x0       { Error::BadAlignment(address, 0x4).trap(); return 0xFFFFFFFF; }

		unsafe {
			let pointer = (self.memory.as_ptr() as *const u8).add(address as usize) as *const u32;
			return *pointer;
		}
	}

	#[must_use]
	pub fn read_halfword(&self, address: u32) -> u16 {
		if address > MAX_HALFWORD_ADDRESS { Error::OutOfBounds( address).trap();      return 0xFFFF; }
		if address % 0x2 != 0x0           { Error::BadAlignment(address, 0x2).trap(); return 0xFFFF; }

		unsafe {
			let pointer = (self.memory.as_ptr() as *const u8).add(address as usize) as *const u16;
			return *pointer;
		}
	}

	#[must_use]
	pub fn read_byte(&self, address: u32) -> u8 {
		if address > MAX_BYTE_ADDRESS { Error::OutOfBounds(address).trap(); return 0xFF; }

		unsafe {
			let pointer = (self.memory.as_ptr() as *const u8).add(address as usize);
			return *pointer;
		}
	}

	#[inline(always)]
	#[must_use]
	pub fn read_cpsr(&self) -> u32 {
		return self.cpsr;
	}

	#[inline(always)]
	#[must_use]
	pub fn read_spsr(&self, mode: CpuMode) -> u32 {
		return unsafe { *self.spsr.get_unchecked(Self::spsr_index(mode)) };
	}
}