1#![no_std]
2
3use core::ptr::{read_volatile, write_volatile};
4
5pub mod z80;
6pub mod vdp;
7pub mod ports;
8pub mod fm;
9pub mod psg;
10
11extern "C" {
12 static _data_src: *const u32;
13 static _data_start: *mut u32;
14 static _data_end: *mut u32;
15 static _bss_start: *mut u32;
16 static _bss_end: *mut u32;
17}
18
19#[no_mangle]
20fn _init_runtime() {
21 init_tmss();
23
24 z80::halt(true);
29 z80::request_bus(true);
30 z80::halt(false);
31
32 unsafe {
34 let data_count = _data_end.offset_from(_data_start) as usize;
35 let data_src = core::slice::from_raw_parts(_data_src, data_count);
36 let data_dest = core::slice::from_raw_parts_mut(_data_start, data_count);
37 for (dst, src) in data_dest.into_iter().zip(data_src.into_iter()) {
38 *dst = *src;
39 }
40
41 let bss_count = _bss_end.offset_from(_bss_start) as usize;
42 let bss = core::slice::from_raw_parts_mut(_bss_start, bss_count);
43 for b in bss {
44 *b = 0;
45 }
46 }
47}
48
49#[derive(Clone, Copy, Debug)]
51pub enum Region {
52 Invalid,
53 Japan,
54 Europe,
55 USA,
56}
57
58#[derive(Clone, Copy, Debug)]
63pub struct Version(u8);
64
65impl Version {
66 pub fn hardware_revision(self) -> u8 { self.0 & 0xf }
68
69 pub fn has_fdd(self) -> bool { (self.0 & 0x20) != 0 }
71
72 pub fn is_pal(self) -> bool { (self.0 & 0x40) != 0 }
74
75 pub fn is_ntsc(self) -> bool { !self.is_pal() }
77
78 pub fn is_overseas(self) -> bool { (self.0 & 0x80) != 0 }
80
81 pub fn region(self) -> Region {
83 match (self.is_pal(), self.is_overseas()) {
84 (false, false) => Region::Japan,
85 (false, true) => Region::USA,
86 (true, false) => Region::Europe,
87 (true, true) => Region::Invalid,
88 }
89 }
90}
91
92const VERSION_REG: *mut u8 = (0xa10001) as _;
93
94pub fn version() -> Version {
96 let v = unsafe { read_volatile(VERSION_REG) };
97 Version(v)
98}
99
100const TMSS_CODE: &'static [u8; 4] = b"SEGA";
102const TMSS_REG: *mut u32 = 0xa14000 as _;
103
104fn init_tmss() {
105 if version().hardware_revision() > 0 {
106 unsafe {
107 let tmss_code: *const u32 = core::mem::transmute(&TMSS_CODE[0]);
108 write_volatile(TMSS_REG, *tmss_code);
109 }
110 }
111}