Skip to content

Commit acd9e6c

Browse files
committed
initial hle flash support
1 parent d106733 commit acd9e6c

File tree

14 files changed

+662
-25
lines changed

14 files changed

+662
-25
lines changed

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ endif()
158158
#--------------------------------------------------
159159

160160
set(REDREAM_SOURCES
161+
src/bios/bios.c
162+
src/bios/flash.c
161163
src/core/assert.c
162164
src/core/exception_handler.c
163165
src/core/filesystem.c
@@ -224,7 +226,8 @@ set(REDREAM_SOURCES
224226
src/emulator.c
225227
src/memory.c
226228
src/scheduler.c
227-
src/tracer.c)
229+
src/tracer.c
230+
)
228231

229232
if(PLATFORM_WINDOWS)
230233
list(APPEND REDREAM_DEFS PLATFORM_WINDOWS=1)

docs/_docs/running.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@ title: Running
33
---
44

55
```
6-
redream --bios=path/to/dc_boot.bin --flash=path/to/dc_flash.bin <cdi, gdi or bin file>
6+
redream --bios=path/to/dc_boot.bin <cdi, gdi or bin file>
77
```
88

9-
Command line flags are loaded from and saved to `$HOME/.redream/flags` each run. This means that bios and flash path, etc. only need to be set on the first run.
9+
Command line flags are loaded from and saved to `$HOME/.redream/flags` each run. This means that bios path, etc. only need to be set on the first run.
1010

1111
### All options
1212

1313
```
14-
--bios Path to BIOS [default: dc_boot.bin]
15-
--flash Path to flash ROM [default: dc_flash.bin]
16-
--audio Enable audio [default: 1]
17-
--latency Preferred audio latency in MS [default: 100]
18-
--verbose Enable debug logging [default: 0]
19-
--perf Write perf-compatible maps for generated code [default: 0]
14+
--bios Path to BIOS [default: dc_boot.bin]
15+
--region System region [default: america, valid: japan, america, europe]
16+
--language System language [default: english, valid: japanese, english, german, french, spanish, italian]
17+
--broadcast System broadcast mode [default: ntsc, valid: ntsc, pal, pal_m, pal_n]
18+
--audio Enable audio [default: 1]
19+
--latency Preferred audio latency in MS [default: 100]
20+
--verbose Enable debug logging [default: 0]
21+
--perf Write perf-compatible maps for generated code [default: 0]
2022
```

src/bios/bios.c

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#include <time.h>
2+
#include "bios/bios.h"
3+
#include "bios/flash.h"
4+
#include "core/math.h"
5+
#include "core/option.h"
6+
#include "dreamcast.h"
7+
#include "hw/aica/aica.h"
8+
#include "hw/rom/flash.h"
9+
#include "render/imgui.h"
10+
11+
DEFINE_OPTION_STRING(region, "america", "System region");
12+
DEFINE_OPTION_STRING(language, "english", "System language");
13+
DEFINE_OPTION_STRING(broadcast, "ntsc", "System broadcast mode");
14+
15+
static const char *regions[] = {
16+
"japan", "america", "europe",
17+
};
18+
19+
static const char *languages[] = {
20+
"japanese", "english", "german", "french", "spanish", "italian",
21+
};
22+
23+
static const char *broadcasts[] = {
24+
"ntsc", "pal", "pal_m", "pal_n",
25+
};
26+
27+
struct bios {
28+
struct dreamcast *dc;
29+
};
30+
31+
static uint32_t bios_local_time() {
32+
/* dreamcast system time is relative to 1/1/1950 00:00 */
33+
struct tm timeinfo;
34+
timeinfo.tm_year = 50;
35+
timeinfo.tm_mon = 0;
36+
timeinfo.tm_mday = 1;
37+
timeinfo.tm_hour = 0;
38+
timeinfo.tm_min = 0;
39+
timeinfo.tm_sec = 0;
40+
41+
time_t base_time = mktime(&timeinfo);
42+
time_t curr_time = time(NULL);
43+
double delta = difftime(curr_time, base_time);
44+
return (uint32_t)delta;
45+
}
46+
47+
static void bios_override_flash_settings(struct bios *bios) {
48+
struct dreamcast *dc = bios->dc;
49+
struct flash *flash = dc->flash;
50+
51+
int region = 0;
52+
int lang = 0;
53+
int bcast = 0;
54+
uint32_t time = bios_local_time();
55+
56+
for (int i = 0; i < array_size(regions); i++) {
57+
if (!strcmp(OPTION_region, regions[i])) {
58+
region = i;
59+
break;
60+
}
61+
}
62+
63+
for (int i = 0; i < array_size(languages); i++) {
64+
if (!strcmp(OPTION_language, languages[i])) {
65+
lang = i;
66+
break;
67+
}
68+
}
69+
70+
for (int i = 0; i < array_size(broadcasts); i++) {
71+
if (!strcmp(OPTION_broadcast, broadcasts[i])) {
72+
bcast = i;
73+
break;
74+
}
75+
}
76+
77+
/* the region, language and broadcast settings exist in two locations:
78+
79+
1. 0x8c000070-74. this data seems to be the "factory settings" and is read
80+
from 0x1a000 of the flash rom on init. this data is read-only
81+
82+
2. 0x8c000078-7f. this data seems to be the "user settings" and is copied
83+
from partition 2, logical block 5 of the flash rom on init
84+
85+
in order to force these settings, write to all of the locations in flash
86+
memory that they are ever read from */
87+
88+
/* overwrite factory flash settings */
89+
char sysinfo[16];
90+
memcpy(sysinfo, "00000Dreamcast ", sizeof(sysinfo));
91+
sysinfo[2] = '0' + region;
92+
sysinfo[3] = '0' + lang;
93+
sysinfo[4] = '0' + bcast;
94+
95+
flash_write(flash, 0x1a000, sysinfo, sizeof(sysinfo));
96+
flash_write(flash, 0x1a0a0, sysinfo, sizeof(sysinfo));
97+
98+
/* overwrite user flash settings */
99+
struct flash_syscfg_block syscfg;
100+
int res = flash_read_block(flash, FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg);
101+
CHECK_EQ(res, 1);
102+
103+
syscfg.time_lo = time & 0xffff;
104+
syscfg.time_hi = (time & 0xffff0000) >> 16;
105+
syscfg.lang = lang;
106+
107+
res = flash_write_block(flash, FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg);
108+
CHECK_EQ(res, 1);
109+
110+
/* overwrite aica clock to match the bios */
111+
aica_set_clock(dc->aica, time);
112+
}
113+
114+
static void bios_validate_flash(struct bios *bios) {
115+
struct dreamcast *dc = bios->dc;
116+
struct flash *flash = dc->flash;
117+
struct flash_header_block header;
118+
119+
/* validate partition 0 (factory settings) */
120+
char sysinfo[2][16];
121+
flash_read(flash, 0x1a000, sysinfo[0], sizeof(sysinfo[0]));
122+
flash_read(flash, 0x1a0a0, sysinfo[1], sizeof(sysinfo[1]));
123+
124+
/* write out default sysinfo if missing */
125+
if (memcmp(&sysinfo[0][5], "Dreamcast ", 11) != 0 ||
126+
memcmp(&sysinfo[1][5], "Dreamcast ", 11) != 0) {
127+
memcpy(sysinfo[0], "00000Dreamcast ", sizeof(sysinfo[0]));
128+
flash_write(flash, 0x1a000, sysinfo[0], sizeof(sysinfo[0]));
129+
flash_write(flash, 0x1a0a0, sysinfo[0], sizeof(sysinfo[0]));
130+
}
131+
132+
/* validate partition 1 (reserved) */
133+
flash_erase_partition(flash, FLASH_PT_RESERVED);
134+
135+
/* validate partition 2 (user settings, block allocated) */
136+
if (!flash_read_block(flash, FLASH_PT_USER, 0, &header)) {
137+
flash_erase_partition(flash, FLASH_PT_USER);
138+
139+
/* write out default user settings */
140+
struct flash_syscfg_block syscfg;
141+
memset(&syscfg, 0xff, sizeof(syscfg));
142+
syscfg.time_lo = 0;
143+
syscfg.time_hi = 0;
144+
syscfg.lang = 0;
145+
syscfg.mono = 0;
146+
syscfg.autostart = 1;
147+
148+
int res =
149+
flash_write_block(flash, FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg);
150+
CHECK_EQ(res, 1);
151+
}
152+
153+
/* validate partition 3 (game settings, block allocated) */
154+
if (!flash_read_block(flash, FLASH_PT_GAME, 0, &header)) {
155+
flash_erase_partition(flash, FLASH_PT_GAME);
156+
}
157+
158+
/* validate partition 4 (unknown, block allocated) */
159+
if (!flash_read_block(flash, FLASH_PT_UNKNOWN, 0, &header)) {
160+
flash_erase_partition(flash, FLASH_PT_UNKNOWN);
161+
}
162+
}
163+
164+
void bios_debug_menu(struct bios *bios) {
165+
int changed = 0;
166+
167+
if (igBeginMainMenuBar()) {
168+
if (igBeginMenu("BIOS", 1)) {
169+
if (igBeginMenu("region", 1)) {
170+
for (int i = 0; i < array_size(regions); i++) {
171+
const char *region = regions[i];
172+
int selected = !strcmp(OPTION_region, region);
173+
174+
if (igMenuItem(region, NULL, selected, 1)) {
175+
changed = 1;
176+
strncpy(OPTION_region, region, sizeof(OPTION_region));
177+
}
178+
}
179+
igEndMenu();
180+
}
181+
182+
if (igBeginMenu("language", 1)) {
183+
for (int i = 0; i < array_size(languages); i++) {
184+
const char *language = languages[i];
185+
int selected = !strcmp(OPTION_language, language);
186+
187+
if (igMenuItem(language, NULL, selected, 1)) {
188+
changed = 1;
189+
strncpy(OPTION_language, language, sizeof(OPTION_language));
190+
}
191+
}
192+
igEndMenu();
193+
}
194+
195+
if (igBeginMenu("broadcast", 1)) {
196+
for (int i = 0; i < array_size(broadcasts); i++) {
197+
const char *broadcast = broadcasts[i];
198+
int selected = !strcmp(OPTION_broadcast, broadcast);
199+
200+
if (igMenuItem(broadcast, NULL, selected, 1)) {
201+
changed = 1;
202+
strncpy(OPTION_broadcast, broadcast, sizeof(OPTION_broadcast));
203+
}
204+
}
205+
igEndMenu();
206+
}
207+
208+
igEndMenu();
209+
}
210+
igEndMainMenuBar();
211+
}
212+
213+
if (changed) {
214+
LOG_WARNING("bios settings changed, restart for changes to take effect");
215+
}
216+
}
217+
218+
int bios_init(struct bios *bios) {
219+
bios_validate_flash(bios);
220+
221+
bios_override_flash_settings(bios);
222+
223+
return 1;
224+
}
225+
226+
void bios_destroy(struct bios *bios) {
227+
free(bios);
228+
}
229+
230+
struct bios *bios_create(struct dreamcast *dc) {
231+
struct bios *bios = calloc(1, sizeof(struct bios));
232+
233+
bios->dc = dc;
234+
235+
return bios;
236+
}

src/bios/bios.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef BIOS_H
2+
#define BIOS_H
3+
4+
struct dreamcast;
5+
struct bios;
6+
7+
struct bios *bios_create(struct dreamcast *dc);
8+
void bios_destroy(struct bios *bios);
9+
10+
int bios_init(struct bios *bios);
11+
void bios_debug_menu(struct bios *bios);
12+
13+
#endif

0 commit comments

Comments
 (0)