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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#![no_std]
use core::ptr::{read_volatile, write_volatile};
pub mod z80;
pub mod vdp;
pub mod ports;
pub mod fm;
pub mod psg;
extern "C" {
static _data_src: *const u32;
static _data_start: *mut u32;
static _data_end: *mut u32;
static _bss_start: *mut u32;
static _bss_end: *mut u32;
}
#[no_mangle]
fn _init_runtime() {
init_tmss();
z80::halt(true);
z80::request_bus(true);
z80::halt(false);
unsafe {
let data_count = _data_end.offset_from(_data_start) as usize;
let data_src = core::slice::from_raw_parts(_data_src, data_count);
let data_dest = core::slice::from_raw_parts_mut(_data_start, data_count);
for (dst, src) in data_dest.into_iter().zip(data_src.into_iter()) {
*dst = *src;
}
let bss_count = _bss_end.offset_from(_bss_start) as usize;
let bss = core::slice::from_raw_parts_mut(_bss_start, bss_count);
for b in bss {
*b = 0;
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Region {
Invalid,
Japan,
Europe,
USA,
}
#[derive(Clone, Copy, Debug)]
pub struct Version(u8);
impl Version {
pub fn hardware_revision(self) -> u8 { self.0 & 0xf }
pub fn has_fdd(self) -> bool { (self.0 & 0x20) != 0 }
pub fn is_pal(self) -> bool { (self.0 & 0x40) != 0 }
pub fn is_ntsc(self) -> bool { !self.is_pal() }
pub fn is_overseas(self) -> bool { (self.0 & 0x80) != 0 }
pub fn region(self) -> Region {
match (self.is_pal(), self.is_overseas()) {
(false, false) => Region::Japan,
(false, true) => Region::USA,
(true, false) => Region::Europe,
(true, true) => Region::Invalid,
}
}
}
const VERSION_REG: *mut u8 = (0xa10001) as _;
pub fn version() -> Version {
let v = unsafe { read_volatile(VERSION_REG) };
Version(v)
}
const TMSS_CODE: &'static [u8; 4] = b"SEGA";
const TMSS_REG: *mut u32 = 0xa14000 as _;
fn init_tmss() {
if version().hardware_revision() > 0 {
unsafe {
let tmss_code: *const u32 = core::mem::transmute(&TMSS_CODE[0]);
write_volatile(TMSS_REG, *tmss_code);
}
}
}