Subversion Repositories Shiroi

Rev

Rev 41 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 nishi 1
/* $Id: main.c 42 2024-09-02 04:07:45Z nishi $ */
2
 
3
#include <stdio.h>
4
#include <stdbool.h>
5
#include <sys/stat.h>
6
#include <stdlib.h>
7
#include <string.h>
8
 
9
#include <raylib.h>
10
 
11
#include "shiroi.h"
12
 
12 nishi 13
#define ON_COLOR ((Color){0xc0, 0, 0, 0xff})
14
#define OFF_COLOR ((Color){0x20, 0x20, 0x20, 0xff})
15
 
1 nishi 16
shiroi_t shiroi;
17
 
18
void thread_start(void);
19
void thread_end(void);
20
 
12 nishi 21
bool get_bit(int n, int f) { return (n & (1 << f)) ? true : false; }
22
 
1 nishi 23
int main(int argc, char** argv) {
24
	FILE* fconf = fopen("shiroi.ini", "r");
25
	if(fconf == NULL) {
26
		printf("Creating config.\n");
27
		fconf = fopen("shiroi.ini", "w");
28
		if(fconf == NULL) {
29
			fprintf(stderr, "Failed to create config\n");
30
			return 1;
31
		}
32
		fprintf(fconf, "slot1=video_mark_1\n");
33
		fprintf(fconf, "slot2=sound_mark_1\n");
34
		fprintf(fconf, "slot3=math_mark_1\n");
3 nishi 35
		fprintf(fconf, "slot4=text_mark_1\n");
1 nishi 36
		fprintf(fconf, "rom=shiroi.rom\n");
37
		fclose(fconf);
38
	}
39
 
40
	shiroi_init_cards(&shiroi);
41
 
42
	fconf = fopen("shiroi.ini", "r");
43
 
44
	struct stat s;
45
	stat("shiroi.ini", &s);
46
 
47
	char* ini = malloc(s.st_size + 1);
48
	fread(ini, s.st_size, 1, fconf);
49
 
50
	ini[s.st_size] = 0;
51
 
52
	fclose(fconf);
53
 
54
	int incr = 0;
55
	int i;
56
	for(i = 0;; i++) {
57
		if(ini[i] == 0 || ini[i] == '\n') {
58
			char oldc = ini[i];
59
			ini[i] = 0;
60
 
61
			char* line = ini + incr;
62
 
3 nishi 63
			if(strlen(line) != 0 && line[0] != '#') {
1 nishi 64
				int j;
65
				for(j = 0; line[j] != 0; j++) {
66
					if(line[j] == '=') {
67
						line[j] = 0;
68
						if(strcmp(line, "rom") == 0) {
69
							printf("ROM: %s\n", line + j + 1);
70
							if(stat(line + j + 1, &s) != 0) {
71
								fprintf(stderr, "ROM not found\n");
72
								free(ini);
73
								return 1;
74
							}
75
							printf("ROM size: %d\n", s.st_size);
76
							FILE* f = fopen(line + j + 1, "rb");
77
							fread(shiroi.ram, s.st_size, 1, f);
78
							fclose(f);
34 nishi 79
						} else if(strcmp(line, "romcard") == 0) {
80
							printf("ROMcard: %s\n", line + j + 1);
81
							if(stat(line + j + 1, &s) != 0) {
82
								fprintf(stderr, "ROM not found\n");
83
								free(ini);
84
								return 1;
85
							}
86
							printf("ROMcard size: %d\n", s.st_size);
87
							shiroi_card_t* card = shiroi_get_romcard_card(&shiroi);
88
							if(card != NULL) {
89
								FILE* f = fopen(line + j + 1, "rb");
90
								fread(card->romcard.data, s.st_size, 1, f);
91
								fclose(f);
92
							} else {
93
								fprintf(stderr, "ROMcard is not installed ; ignored\n");
94
							}
1 nishi 95
						} else if(line[0] == 's' && line[1] == 'l' && line[2] == 'o' && line[3] == 't') {
96
							int slot = atoi(line + 4);
97
							const char* n = "";
98
							int dev = -1;
99
							if(strcmp(line + j + 1, "video_mark_1") == 0) {
100
								dev = SHIROI_VIDEO_MARK_I;
101
								n = "Video Mark I";
7 nishi 102
							} else if(strcmp(line + j + 1, "video_mark_2") == 0) {
103
								dev = SHIROI_VIDEO_MARK_II;
104
								n = "Video Mark II";
1 nishi 105
							} else if(strcmp(line + j + 1, "sound_mark_1") == 0) {
106
								dev = SHIROI_SOUND_MARK_I;
107
								n = "Sound Mark I";
108
							} else if(strcmp(line + j + 1, "math_mark_1") == 0) {
109
								dev = SHIROI_MATH_MARK_I;
110
								n = "Math Mark I";
3 nishi 111
							} else if(strcmp(line + j + 1, "text_mark_1") == 0) {
112
								dev = SHIROI_TEXT_MARK_I;
113
								n = "Text Mark I";
12 nishi 114
							} else if(strcmp(line + j + 1, "debug") == 0) {
115
								dev = SHIROI_DEBUG;
116
								n = "Debug";
34 nishi 117
							} else if(strcmp(line + j + 1, "romcard_mark_1") == 0) {
118
								dev = SHIROI_ROMCARD_MARK_I;
119
								n = "ROMcard Mark I";
1 nishi 120
							}
121
							if(dev == -1) {
122
								fprintf(stderr, "No such device called `%s' ; ignoring\n", line + j + 1);
123
							} else {
124
								shiroi_install(&shiroi, slot, dev);
125
								printf("Installed `%s' into slot %d\n", n, slot);
126
							}
127
						}
128
						break;
129
					}
130
				}
131
			}
132
 
133
			incr = i + 1;
134
			if(oldc == 0) break;
135
		}
136
	}
137
 
138
	free(ini);
139
 
140
	shiroi_init(&shiroi);
141
 
142
	double scx = 2;
143
	double scy = 2;
144
 
145
	shiroi_card_t* videocard = shiroi_get_video_card(&shiroi);
146
	shiroi_video_t* video = NULL;
147
	if(videocard != NULL) {
148
		video = videocard->videoptr;
149
	}
12 nishi 150
 
3 nishi 151
	shiroi_card_t* textcard = shiroi_get_text_card(&shiroi);
152
	shiroi_text_t* text = NULL;
153
	if(textcard != NULL) {
154
		text = textcard->textptr;
155
	}
1 nishi 156
 
12 nishi 157
	shiroi_card_t* debugcard = shiroi_get_debug_card(&shiroi);
158
	shiroi_debug_t* debug = NULL;
159
	if(debugcard != NULL) {
160
		debug = debugcard->debugptr;
161
	}
162
 
1 nishi 163
	SetTraceLogLevel(LOG_NONE);
164
	if(video != NULL) {
13 nishi 165
		InitWindow(video->width * scx + ((debug == NULL && text == NULL) ? 0 : 200), video->height * scy, "Shiroi Emulator");
1 nishi 166
	} else {
13 nishi 167
		InitWindow(640 + ((debug == NULL && text == NULL) ? 0 : 200), 480, "Shiroi Emulator");
1 nishi 168
	}
42 nishi 169
	SetExitKey(KEY_NULL);
1 nishi 170
	InitAudioDevice();
171
	SetAudioStreamBufferSizeDefault(512);
172
	AudioStream as = LoadAudioStream(48000, 16, 1);
173
	SetAudioStreamCallback(as, shiroi.play_audio);
174
	SetTargetFPS(60);
175
	uint32_t* fb = NULL;
176
 
177
	if(video != NULL) {
178
		fb = malloc(sizeof(*fb) * video->width * video->height);
179
 
180
		int x, y;
181
		for(y = 0; y < video->height; y++) {
182
			for(x = 0; x < video->width; x++) {
183
				fb[y * video->width + x] = 0xffffff;
184
			}
185
		}
186
	}
187
 
188
	RenderTexture r;
12 nishi 189
	if(video != NULL) {
190
		r = LoadRenderTexture(video->width, video->height);
191
		BeginTextureMode(r);
192
		ClearBackground(BLACK);
193
		EndTextureMode();
194
	}
1 nishi 195
	PlayAudioStream(as);
196
	thread_start();
197
	while(!WindowShouldClose()) {
198
		BeginDrawing();
199
 
200
		ClearBackground(BLACK);
201
 
3 nishi 202
		if(text != NULL) {
4 nishi 203
			/*
204
			 * / 1 2 3 4 5 6 7 8 9 10 11 12 13
7 nishi 205
			 * 1 1 2 3 4 5 6 7 8 9 0  -  =  bs
4 nishi 206
			 * 2 q w e r t y u i o p  [  ]  rt
207
			 * 3 a s d f g h j k l ;  '  \  cl
20 nishi 208
			 * 4 z x c v b n m , . /  sp bk
4 nishi 209
			 */
210
			int c = GetKeyPressed();
7 nishi 211
			if(KEY_ONE <= c && c <= KEY_NINE) {
4 nishi 212
				text->key = (1 << 4) | (c - KEY_ONE + 1);
5 nishi 213
			} else if(c == KEY_ZERO) {
4 nishi 214
				text->key = (1 << 4) | 10;
5 nishi 215
			} else if(c == KEY_MINUS) {
4 nishi 216
				text->key = (1 << 4) | 11;
5 nishi 217
			} else if(c == KEY_EQUAL) {
4 nishi 218
				text->key = (1 << 4) | 12;
7 nishi 219
			} else if(c == KEY_BACKSPACE) {
220
				text->key = (1 << 4) | 13;
5 nishi 221
			} else if(c == KEY_LEFT_BRACKET) {
4 nishi 222
				text->key = (2 << 4) | 11;
5 nishi 223
			} else if(c == KEY_RIGHT_BRACKET) {
4 nishi 224
				text->key = (2 << 4) | 12;
5 nishi 225
			} else if(c == KEY_ENTER) {
4 nishi 226
				text->key = (2 << 4) | 13;
5 nishi 227
			} else if(c == KEY_SEMICOLON) {
4 nishi 228
				text->key = (3 << 4) | 10;
5 nishi 229
			} else if(c == KEY_APOSTROPHE) {
4 nishi 230
				text->key = (3 << 4) | 11;
5 nishi 231
			} else if(c == KEY_BACKSLASH) {
4 nishi 232
				text->key = (3 << 4) | 12;
5 nishi 233
			} else if(c == KEY_LEFT_SHIFT || c == KEY_RIGHT_SHIFT) {
4 nishi 234
				text->key = (3 << 4) | 13;
6 nishi 235
				text->caps = !text->caps;
11 nishi 236
			} else if(c == KEY_F1) {
237
				if(shiroi.stop) {
238
					shiroi.stop = false;
239
					shiroi.reset = true;
240
					thread_start();
241
				} else {
242
					shiroi.reset = true;
243
					shiroi.stop = true;
244
					thread_end();
245
				}
10 nishi 246
			} else if(c == KEY_F2) {
247
				shiroi.reset = true;
5 nishi 248
			} else if(c == KEY_COMMA) {
4 nishi 249
				text->key = (4 << 4) | 8;
5 nishi 250
			} else if(c == KEY_PERIOD) {
4 nishi 251
				text->key = (4 << 4) | 9;
5 nishi 252
			} else if(c == KEY_SLASH) {
4 nishi 253
				text->key = (4 << 4) | 10;
5 nishi 254
			} else if(c == KEY_SPACE) {
4 nishi 255
				text->key = (4 << 4) | 11;
20 nishi 256
			} else if((IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)) && c == KEY_PAUSE) {
257
				text->key = (4 << 4) | 12;
5 nishi 258
			} else if(c == KEY_Q) {
4 nishi 259
				text->key = (2 << 4) | 1;
5 nishi 260
			} else if(c == KEY_W) {
4 nishi 261
				text->key = (2 << 4) | 2;
5 nishi 262
			} else if(c == KEY_E) {
4 nishi 263
				text->key = (2 << 4) | 3;
5 nishi 264
			} else if(c == KEY_R) {
4 nishi 265
				text->key = (2 << 4) | 4;
5 nishi 266
			} else if(c == KEY_T) {
4 nishi 267
				text->key = (2 << 4) | 5;
5 nishi 268
			} else if(c == KEY_Y) {
4 nishi 269
				text->key = (2 << 4) | 6;
5 nishi 270
			} else if(c == KEY_U) {
4 nishi 271
				text->key = (2 << 4) | 7;
5 nishi 272
			} else if(c == KEY_I) {
4 nishi 273
				text->key = (2 << 4) | 8;
5 nishi 274
			} else if(c == KEY_O) {
4 nishi 275
				text->key = (2 << 4) | 9;
5 nishi 276
			} else if(c == KEY_P) {
4 nishi 277
				text->key = (2 << 4) | 10;
5 nishi 278
			} else if(c == KEY_A) {
4 nishi 279
				text->key = (3 << 4) | 1;
5 nishi 280
			} else if(c == KEY_S) {
4 nishi 281
				text->key = (3 << 4) | 2;
5 nishi 282
			} else if(c == KEY_D) {
4 nishi 283
				text->key = (3 << 4) | 3;
5 nishi 284
			} else if(c == KEY_F) {
4 nishi 285
				text->key = (3 << 4) | 4;
5 nishi 286
			} else if(c == KEY_G) {
4 nishi 287
				text->key = (3 << 4) | 5;
5 nishi 288
			} else if(c == KEY_H) {
4 nishi 289
				text->key = (3 << 4) | 6;
5 nishi 290
			} else if(c == KEY_J) {
4 nishi 291
				text->key = (3 << 4) | 7;
5 nishi 292
			} else if(c == KEY_K) {
4 nishi 293
				text->key = (3 << 4) | 8;
5 nishi 294
			} else if(c == KEY_L) {
4 nishi 295
				text->key = (3 << 4) | 9;
5 nishi 296
			} else if(c == KEY_Z) {
4 nishi 297
				text->key = (4 << 4) | 1;
5 nishi 298
			} else if(c == KEY_X) {
4 nishi 299
				text->key = (4 << 4) | 2;
5 nishi 300
			} else if(c == KEY_C) {
4 nishi 301
				text->key = (4 << 4) | 3;
5 nishi 302
			} else if(c == KEY_V) {
4 nishi 303
				text->key = (4 << 4) | 4;
5 nishi 304
			} else if(c == KEY_B) {
4 nishi 305
				text->key = (4 << 4) | 5;
5 nishi 306
			} else if(c == KEY_N) {
4 nishi 307
				text->key = (4 << 4) | 6;
5 nishi 308
			} else if(c == KEY_M) {
4 nishi 309
				text->key = (4 << 4) | 7;
310
			}
3 nishi 311
		}
312
 
1 nishi 313
		if(video != NULL) {
314
			BeginTextureMode(r);
315
 
316
			int y, x;
317
			for(y = 0; y < video->height; y++) {
318
				for(x = 0; x < video->width; x++) {
7 nishi 319
					if(video->fb[y * video->width + x] != fb[y * video->width + x]) {
1 nishi 320
						uint32_t c = video->fb[y * video->width + x];
7 nishi 321
						DrawPixel(x, y, (Color){(c >> 24) & 0xff, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff});
1 nishi 322
						fb[y * video->width + x] = c;
323
					}
324
				}
325
			}
326
 
327
			EndTextureMode();
328
 
13 nishi 329
			DrawTexturePro(r.texture, (Rectangle){0, 0, video->width, -video->height}, (Rectangle){(text == NULL && debug == NULL) ? 0 : 200, 0, GetScreenWidth() - ((text == NULL && debug == NULL) ? 0 : 200), GetScreenHeight()}, (Vector2){0, 0}, 0, WHITE);
1 nishi 330
		} else {
13 nishi 331
			DrawText("No Video", 200 + 5, 5, 20, WHITE);
1 nishi 332
		}
333
 
13 nishi 334
		if(text != NULL) {
335
			DrawText("Caps Lock", 5, 5, 10, WHITE);
6 nishi 336
 
13 nishi 337
			DrawCircle(200 - 10, 10, 5, text->caps ? ON_COLOR : OFF_COLOR);
338
		}
6 nishi 339
 
12 nishi 340
		if(debug != NULL) {
341
			DrawText("Debug", 5, 5 + 10 + 5, 10, WHITE);
342
			for(i = 0; i < 4; i++) {
343
				int shx = i * (5 + 20 + 5 + 5 + 10);
344
				DrawRectangle(shx + 10, 5 + 5 + 10 + 5 + 10 + 5, 20, 5, get_bit(debug->latch[i], 0) ? ON_COLOR : OFF_COLOR);
345
				DrawRectangle(shx + 5, 5 + 5 + 10 + 5 + 10 + 10, 5, 20, get_bit(debug->latch[i], 1) ? ON_COLOR : OFF_COLOR);
346
				DrawRectangle(shx + 5 + 20 + 5, 5 + 5 + 10 + 5 + 10 + 10, 5, 20, get_bit(debug->latch[i], 2) ? ON_COLOR : OFF_COLOR);
347
				DrawRectangle(shx + 10, 5 + 5 + 10 + 5 + 10 + 5 + 20 + 5, 20, 5, get_bit(debug->latch[i], 3) ? ON_COLOR : OFF_COLOR);
348
				DrawRectangle(shx + 5, 5 + 5 + 10 + 5 + 10 + 10 + 5 + 20, 5, 20, get_bit(debug->latch[i], 4) ? ON_COLOR : OFF_COLOR);
349
				DrawRectangle(shx + 5 + 20 + 5, 5 + 5 + 10 + 5 + 10 + 10 + 5 + 20, 5, 20, get_bit(debug->latch[i], 5) ? ON_COLOR : OFF_COLOR);
350
				DrawRectangle(shx + 10, 5 + 5 + 10 + 5 + 10 + 5 + 20 + 5 + 20 + 5, 20, 5, get_bit(debug->latch[i], 6) ? ON_COLOR : OFF_COLOR);
351
				DrawRectangle(shx + 5 + 5 + 20 + 5 + 5, 5 + 5 + 10 + 5 + 10 + 5 + 20 + 5 + 20 + 5, 5, 5, get_bit(debug->latch[i], 7) ? ON_COLOR : OFF_COLOR);
352
			}
353
		}
354
 
1 nishi 355
		EndDrawing();
356
	}
41 nishi 357
	if(video != NULL) UnloadRenderTexture(r);
1 nishi 358
	CloseWindow();
359
	UnloadAudioStream(as);
360
	shiroi.stop = true;
361
	thread_end();
362
}