Subversion Repositories Shiroi

Rev

Rev 5 | Rev 8 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 nishi 1
/* $Id: shiroi.c 7 2024-08-28 14:02:52Z nishi $ */
2
 
3
unsigned char inp(unsigned char);
4
void outp(unsigned char, unsigned char);
5
void write_vram(unsigned short);
6
void putchar(char);
7
void putstr(char*);
8
void scroll_y(void);
9
void beep(void);
10
void _beep(unsigned long howlong);
11
void init_cards(void);
3 nishi 12
void print_ptr(void*);
13
char getch(void);
7 nishi 14
void clear(void);
15
void basic(void);
16
int strlen(const char*);
17
void cursor(void);
18
void killcursor(void);
19
char toupper(char c);
20
long modl(long a, long b);
21
long divl(long a, long b);
22
long mull(long a, long b);
1 nishi 23
 
7 nishi 24
#define AM_SR       0x80 /* service request on completion */
25
#define AM_SINGLE   0x60 /* 16 bit integer */
26
#define AM_DOUBLE   0x20 /* 32 bit integer */
27
#define AM_FIXED    0x20 /* fixed point */
28
#define AM_FLOAT    0x00 /* 32 bit float */
29
 
30
#define AM_NOP      0x00 /* no operation */
31
#define AM_SQRT     0x01 /* square root */
32
#define AM_SIN      0x02 /* sine */
33
#define AM_COS      0x03 /* cosine */
34
#define AM_TAN      0x04 /* tangent */
35
#define AM_ASIN     0x05 /* inverse sine */
36
#define AM_ACOS     0x06 /* inverse cosine */
37
#define AM_ATAN     0x07 /* inverse tangent */
38
#define AM_LOG      0x08 /* common logarithm (base 10) */
39
#define AM_LN       0x09 /* natural logairth (base e) */
40
#define AM_EXP      0x0a /* exponential (e^x) */
41
#define AM_PWR      0x0b /* power nos^tos */
42
#define AM_ADD      0x0c /* add */
43
#define AM_SUB      0x0d /* subtract nos-tos */
44
#define AM_MUL      0x0e /* multiply, lower half */
45
#define AM_DIV      0x0f /* divide nos/tos */
46
#define AM_FADD     0x10 /* floating add */
47
#define AM_FSUB     0x11 /* floating subtract */
48
#define AM_FMUL     0x12 /* floating multiply */
49
#define AM_FDIV     0x13 /* floating divide */
50
#define AM_CHS      0x14 /* change sign */
51
#define AM_CHSF     0x15 /* floating change sign */ 
52
#define AM_MUU      0x16 /* multiply, upper half */
53
#define AM_PTO      0x17 /* push tos to nos (copy) */
54
#define AM_POP      0x18 /* pop */
55
#define AM_XCH      0x19 /* exchange tos and nos */
56
#define AM_PUPI     0x1a /* push pi */
57
/*                  0x1b */
58
#define AM_FLTD     0x1c /* 32 bit to float */
59
#define AM_FLTS     0x1d /* 16 bit to float */
60
#define AM_FIXD     0x1e /* float to 32 bit */
61
#define AM_FIXS     0x1f /* float to 16 bit */
62
 
63
#define AM_BUSY     0x80 /* chip is busy */
64
#define AM_SIGN     0x40 /* tos negative */
65
#define AM_ZERO     0x20 /* tos zero */
66
#define AM_ERR_MASK 0x1E /* mask for errors */
67
#define AM_CARRY    0x01 /* carry/borrow from most significant bit */
68
 
1 nishi 69
unsigned short posx;
70
unsigned short posy;
7 nishi 71
unsigned short curx;
72
unsigned short cury;
1 nishi 73
 
74
short vdp_addr;
75
short vdp_data;
7 nishi 76
short vdg_addr;
77
short vdg_data;
1 nishi 78
short psg_addr;
79
short psg_data;
7 nishi 80
short fpu_stack;
81
short fpu_command;
3 nishi 82
short text_kbd_data;
1 nishi 83
 
7 nishi 84
int scrwidth;
85
int scrheight;
86
 
4 nishi 87
char caps;
88
 
89
unsigned char keylist[13 * 4];
90
unsigned char keylist_caps[13 * 4];
91
 
3 nishi 92
unsigned char basicbuffer[1024 * 30];
93
 
2 nishi 94
void main(void){
1 nishi 95
	int i;
4 nishi 96
	caps = 0;
1 nishi 97
 
4 nishi 98
/*
99
 * / 1 2 3 4 5 6 7 8 9 10 11 12 13
7 nishi 100
 * 1 1 2 3 4 5 6 7 8 9 0  -  =  bs
4 nishi 101
 * 2 q w e r t y u i o p  [  ]  rt
102
 * 3 a s d f g h j k l ;  '  \  cl
103
 * 4 z x c v b n m , . /  sp
5 nishi 104
 *
105
 * When Caps Lock
106
 *
107
 * / 1 2 3 4 5 6 7 8 9 10 11 12 13
7 nishi 108
 * 1 ! @ # $ % ^ & * ( )  _  +  bs
5 nishi 109
 * 2 Q W E R T Y U I O P  {  }  rt
110
 * 3 A S D F G H J K L :  "  |  cl
111
 * 4 Z X C V B N M < > ?  sp
4 nishi 112
 */
113
	const char* keys;
114
 
7 nishi 115
	keys = "1234567890-=\x08";
4 nishi 116
	for(i = 0; i < 13; i++){
117
		keylist[i] = keys[i];
118
	}
119
	keys = "qwertyuiop[]\n";
120
	for(i = 0; i < 13; i++){
121
		keylist[13 + i] = keys[i];
122
	}
123
	keys = "asdfghjkl;'\\!";
124
	for(i = 0; i < 13; i++){
125
		keylist[26 + i] = keys[i];
126
	}
127
	keys = "zxcvbnm,./    ";
128
	for(i = 0; i < 13; i++){
129
		keylist[39 + i] = keys[i];
130
	}
131
 
7 nishi 132
	keys = "!@#$%^&*()_+\x08";
4 nishi 133
	for(i = 0; i < 13; i++){
134
		keylist_caps[i] = keys[i];
135
	}
136
	keys = "QWERTYUIOP{}\n";
137
	for(i = 0; i < 13; i++){
138
		keylist_caps[13 + i] = keys[i];
139
	}
140
	keys = "ASDFGHJKL:\"|!";
141
	for(i = 0; i < 13; i++){
142
		keylist_caps[26 + i] = keys[i];
143
	}
144
	keys = "ZXCVBNM<>?    ";
145
	for(i = 0; i < 13; i++){
146
		keylist_caps[39 + i] = keys[i];
147
	}
148
 
1 nishi 149
	posx = 0;
150
	posy = 0;
7 nishi 151
	curx = 0;
152
	cury = 0;
1 nishi 153
 
154
	vdp_addr = -1;
7 nishi 155
	vdg_addr = -1;
1 nishi 156
	psg_addr = -1;
7 nishi 157
	fpu_stack = -1;
3 nishi 158
	text_kbd_data = -1;
1 nishi 159
 
160
	init_cards();
161
 
7 nishi 162
	if(vdp_addr == -1 && vdg_addr == -1){
1 nishi 163
		int i;
2 nishi 164
		for(i = 0; i < 3; i++){
1 nishi 165
			_beep(3L * 1024);
166
			unsigned long j;
2 nishi 167
			for(j = 0; j < 3L * 1024; j++);
1 nishi 168
		}
2 nishi 169
		while(1);
1 nishi 170
	}
171
 
7 nishi 172
	if(vdp_addr != -1){	
173
		scrwidth = 32;
174
		scrheight = 24;
1 nishi 175
 
7 nishi 176
		outp(vdp_addr, 0x00);
177
		outp(vdp_addr, 0x80);
178
 
179
		outp(vdp_addr, 0xd8);
180
		outp(vdp_addr, 0x81);
181
 
182
		outp(vdp_addr, 0x02);
183
		outp(vdp_addr, 0x82);
184
 
185
		outp(vdp_addr, 0x50);
186
		outp(vdp_addr, 0x83);
187
 
188
		outp(vdp_addr, 0x00);
189
		outp(vdp_addr, 0x84);
190
 
191
		outp(vdp_addr, 0x29);
192
		outp(vdp_addr, 0x85);
193
 
194
		outp(vdp_addr, 0x03);
195
		outp(vdp_addr, 0x86);
196
 
197
		outp(vdp_addr, 0xe4);
198
		outp(vdp_addr, 0x87);
199
	}else if(vdg_addr != -1){
200
		scrwidth = 32;
201
		scrheight = 16;
202
	}
1 nishi 203
 
7 nishi 204
	if(vdp_addr != -1){
205
		/*
206
		 * VDP:
207
		 * 0x0000-0x0800: font
208
		 * 0x0800-0x1400: pattern
209
		 * 0x1400-0x1480: color
210
		 * 0x1480-0x1500: sprite attr
211
		 * 0x1800-0x2000: sprite pattern
212
		 */
213
 
214
		write_vram(0);
215
		for(i = 0; i < 0x800; i++) outp(vdp_data, *((unsigned char*)(0x6000 - 2048 + i)));
216
 
217
		write_vram(0x1400);
218
		for(i = 0; i < 0x20; i++) outp(vdp_data, 0xf0);
219
		write_vram(0x1400 + 0x10);
220
		for(i = 0; i < 0x10; i++) outp(vdp_data, ((i & 0xf) << 4) | 0);
221
	}
1 nishi 222
 
7 nishi 223
	clear();
1 nishi 224
 
4 nishi 225
//	beep();
1 nishi 226
 
3 nishi 227
	if(text_kbd_data == -1){
228
		putstr("Text  Card Mark I not present\r\n");
229
		putstr("Text  Card Mark I is required to use the BASIC\r\n");
230
		putstr("Halted. Get one.\r\n");
231
		while(1);
232
	}
7 nishi 233
	if(fpu_stack == -1){
234
		putstr("Math  Card Mark I not present\r\n");
235
		putstr("Math  Card Mark I is required to use the BASIC\r\n");
236
		putstr("Halted. Get one.\r\n");
237
		while(1);
238
	}
1 nishi 239
 
7 nishi 240
	int incr;
241
	int move = 0;
242
	char k;
243
	int wait = 0;
244
 
245
	const char* title;
246
 
247
	if(vdp_addr != -1){
248
		title = "Shiroi Microcomputer";
249
		write_vram(0x800 + scrwidth / 2 - strlen(title) / 2 + mull(scrheight / 2 - 1, scrwidth));
250
		for(i = 0; title[i] != 0; i++) outp(vdp_data, title[i] - 0x20);
251
 
252
		title = "\x82 2024 Nishi";
253
		write_vram(0x800 + scrwidth / 2 - strlen(title) / 2 + mull(scrheight - 2, scrwidth));
254
		for(i = 0; title[i] != 0; i++) outp(vdp_data, title[i] - 0x20);
255
 
256
		title = "Press any key to begin";
257
		write_vram(0x800 + scrwidth / 2 - strlen(title) / 2 + mull(scrheight / 2 + 1, scrwidth));
258
		for(i = 0; title[i] != 0; i++) outp(vdp_data, title[i] - 0x20);
259
	}else if(vdg_addr != -1){
260
		title = "Shiroi Microcomputer";
261
		write_vram(scrwidth / 2 - strlen(title) / 2 + mull(scrheight / 2 - 1, scrwidth));
262
		for(i = 0; title[i] != 0; i++) outp(vdg_data, toupper(title[i]) - 'A' + 1);
263
 
264
		title = "(C) 2024 Nishi";
265
		write_vram(scrwidth / 2 - strlen(title) / 2 + mull(scrheight - 2, scrwidth));
266
		for(i = 0; title[i] != 0; i++) outp(vdg_data, toupper(title[i]) - 'A' + 1);
267
 
268
		title = "Press any key to begin";
269
		write_vram(scrwidth / 2 - strlen(title) / 2 + mull(scrheight / 2 + 1, scrwidth));
270
		for(i = 0; title[i] != 0; i++) outp(vdg_data, toupper(title[i]) - 'A' + 1);
271
	}
272
 
273
move_bar:
274
	if(vdp_addr != -1){
275
	}else if(vdg_addr != -1){
276
		goto skip;
277
	}
278
	incr = move;
279
	for(i = 0; i < 16; i++){
280
		int j;
281
		for(j = 0; j < 3; j++){
282
			int p = incr;
283
			if(p >= 15) p = p - 15;
284
			if(wait == 0){
285
				write_vram(0x800 + i * 2 + j * 32);
286
				outp(vdp_data, (p + 1) * 8 + 0x80);
287
				outp(vdp_data, (p + 1) * 8 + 0x80);
288
				write_vram(0x800 + i * 2 + 32 * 20 - j * 32);
289
				outp(vdp_data, (p + 1) * 8 + 0x80);
290
				outp(vdp_data, (p + 1) * 8 + 0x80);
291
			}else{
292
				if(i * 2 - 1 < 0){
293
					write_vram(0x800 + i * 2 + j * 32);
294
					outp(vdp_data, (p + 1) * 8 + 0x80);
295
				}else{
296
					write_vram(0x800 + i * 2 + j * 32 - 1);
297
					outp(vdp_data, (p + 1) * 8 + 0x80);
298
					outp(vdp_data, (p + 1) * 8 + 0x80);
299
				}
300
				if(i * 2 - 1 < 0){
301
					write_vram(0x800 + i * 2 + 32 * 20 - j * 32);
302
					outp(vdp_data, (p + 1) * 8 + 0x80);
303
				}else{
304
					write_vram(0x800 + i * 2 + 32 * 20 - j * 32 - 1);
305
					outp(vdp_data, (p + 1) * 8 + 0x80);
306
					outp(vdp_data, (p + 1) * 8 + 0x80);
307
				}
308
			}
309
		}
310
		incr++;
311
		if(incr == 15) incr = 0;
312
	}
313
	wait++;
314
	if(wait == 2){
315
		wait = 0;
316
		move++;
317
		if(move == 15) move = 0;
318
	}
319
	for(i = 0; i < 3 * 1024; i++);
320
 
321
skip:
322
	if((k = inp(text_kbd_data)) == 0) goto move_bar;
323
	while(inp(text_kbd_data) != 0);
324
 
325
	basic();
326
}
327
 
328
void basic(void){
329
	clear();
330
 
331
	if(vdp_addr == -1){
332
		outp(vdp_addr, 0xf0);
333
		outp(vdp_addr, 0x87);
334
	}
335
 
336
	putstr("Shiroi Microcomputer BASIC\r\n");
337
	cursor();
3 nishi 338
	while(1){
7 nishi 339
		char c = getch();
340
		killcursor();
341
		if(c == '\n'){
342
			putstr("\r\n");
343
		}else{
344
			putchar(c);
345
		}
346
		cursor();
3 nishi 347
	}
348
}
1 nishi 349
 
7 nishi 350
int strlen(const char* str){
351
	int i;
352
	for(i = 0; str[i] != 0; i++);
353
	return i;
354
}
355
 
356
void clear(void){
357
	int i;
358
	int size = mull(scrwidth, scrheight);
359
	if(vdp_addr != -1){
360
		write_vram(0x800);
361
		for(i = 0; i < size; i++) outp(vdp_data, 0);
362
	}else if(vdg_addr != -1){
363
		write_vram(0);
364
		for(i = 0; i < size; i++){
365
			outp(vdg_data, 0x20);
366
		}
367
	}
368
}
369
 
3 nishi 370
char getch(void){
371
	char k = 0;
4 nishi 372
rep:
3 nishi 373
	while((k = inp(text_kbd_data)) == 0);
374
	while(inp(text_kbd_data) != 0);
4 nishi 375
	unsigned char top = (k & 0xf0) >> 4;
376
	unsigned char bot = (k & 0x0f);
377
	top--;
378
	bot--;
379
	if(keylist[top * 13 + bot] == '!'){
380
		caps = caps == 0 ? 1 : 0;
381
		goto rep;
382
	}
383
	return caps ? keylist_caps[top * 13 + bot] : keylist[top * 13 + bot];
1 nishi 384
}
385
 
3 nishi 386
void print_ptr(void* ptr){
387
	unsigned short p = (unsigned short)ptr;
388
	int i;
389
	const char hex[] = "0123456789ABCDEF";
390
	putstr("0x");
391
	for(i = 0; i < 4; i++){
392
		putchar(hex[(p & 0xf000) >> 12]);
393
		p = p << 4;
394
	}
395
}
396
 
2 nishi 397
void init_cards(void){
1 nishi 398
	int i;
399
	int port = 2;
2 nishi 400
	for(i = 0; i < 256 / 3; i++){
1 nishi 401
		int t = inp(port);
2 nishi 402
		if(t != 0){
403
			if(t == 0x01){
1 nishi 404
				vdp_addr = port - 2;
405
				vdp_data = port - 1;
7 nishi 406
			}else if(t == 0x02){
407
				vdg_addr = port - 2;
408
				vdg_data = port - 1;
2 nishi 409
			}else if(t == 0x11){
1 nishi 410
				psg_addr = port - 2;
411
				psg_data = port - 1;
2 nishi 412
			}else if(t == 0x21){
7 nishi 413
				fpu_stack = port - 2;
414
				fpu_command = port - 1;
3 nishi 415
			}else if(t == 0x22){
416
				text_kbd_data = port - 2;
1 nishi 417
			}
3 nishi 418
 
1 nishi 419
		}
420
		port += 3;
421
	}
422
}
423
 
2 nishi 424
void beep(void){
425
	_beep(3L * 1024);
426
}
1 nishi 427
 
2 nishi 428
void _beep(unsigned long howlong){
1 nishi 429
	if(psg_addr == -1) return;
430
	unsigned long i;
431
 
432
	outp(psg_addr, 8);
433
	outp(psg_data, 0x0f);
434
 
435
	outp(psg_addr, 0);
436
	outp(psg_data, 0xd6);
437
 
438
	outp(psg_addr, 1);
439
	outp(psg_data, 0x0);
440
 
441
	outp(psg_addr, 7);
442
	outp(psg_data, 0x3e);
443
 
2 nishi 444
	for(i = 0; i < howlong; i++);
1 nishi 445
 
446
	outp(psg_addr, 7);
447
	outp(psg_data, 0x3f);
448
}
449
 
2 nishi 450
void write_vram(unsigned short addr){
7 nishi 451
	if(vdp_addr != -1){
452
		addr |= 0x4000;
453
		outp(vdp_addr, addr & 0x00ff);
454
		outp(vdp_addr, ((addr & 0xff00) >> 8));
455
	}else if(vdg_addr != -1){
456
		outp(vdg_addr, addr & 0x00ff);
457
		outp(vdg_addr, ((addr & 0xff00) >> 8));
458
	}
1 nishi 459
}
460
 
2 nishi 461
void read_vram(unsigned short addr){
7 nishi 462
	if(vdp_addr != -1){
463
		outp(vdp_addr, addr & 0x00ff);
464
		outp(vdp_addr, ((addr & 0xff00) >> 8));
465
	}else{
466
		outp(vdg_addr, addr & 0x00ff);
467
		outp(vdg_addr, ((addr & 0xff00) >> 8));
468
	}
1 nishi 469
}
470
 
2 nishi 471
void scroll_y(void){
1 nishi 472
	int i;
7 nishi 473
	int size = mull(scrwidth, scrheight - 1);
474
	for(i = 0; i < size; i++){
475
		if(vdp_addr != -1){
476
			read_vram(0x800 + i + 32);
477
			unsigned char ch = inp(vdp_data);
478
			write_vram(0x800 + i);
479
			outp(vdp_data, ch);
480
		}else if(vdg_addr != -1){
481
			read_vram(i + 32);
482
			unsigned char ch = inp(vdg_data);
483
			write_vram(i);
484
			outp(vdg_data, ch);
485
		}
1 nishi 486
	}
7 nishi 487
	for(i = 0; i < scrwidth; i++){
488
		if(vdp_addr != -1){
489
			outp(vdp_data, 0);
490
		}else if(vdg_addr != -1){
491
			outp(vdg_data, 0x20);
492
		}
493
	}
494
}
495
 
496
void cursor(void){
497
	if(vdp_addr != -1){
498
		write_vram(0x800 + mull(posy, scrwidth) + posx);
499
		outp(vdp_data, 248);
500
	}else if(vdg_addr != -1){
501
		write_vram(mull(posy, scrwidth) + posx);
502
		outp(vdg_data, 0);
503
	}
504
	curx = posx;
505
	cury = posy;
506
	if(curx == scrwidth){
507
		curx = 0;
508
		cury++;
509
	}
510
}
511
 
512
void killcursor(void){
513
	if(vdp_addr != -1){
514
		write_vram(0x800 + mull(cury, scrwidth) + curx);
1 nishi 515
		outp(vdp_data, 0);
7 nishi 516
	}else if(vdg_addr != -1){
517
		write_vram(mull(cury, scrwidth) + curx);
518
		outp(vdg_data, 0x20);
1 nishi 519
	}
520
}
521
 
7 nishi 522
char toupper(char c){
523
	if('a' <= c && c <= 'z'){
524
		return c - 'a' + 'A';
525
	}
526
	return c;
527
}
528
 
2 nishi 529
void putchar(char c){
530
	if(c == '\r'){
1 nishi 531
		posx = 0;
2 nishi 532
	}else if(c == '\n'){
1 nishi 533
		posy++;
2 nishi 534
	}else{
7 nishi 535
		if(vdp_addr != -1){
536
			write_vram(0x800 + mull(posy, scrwidth) + posx);
537
		}else if(vdg_addr != -1){
538
			write_vram(mull(posy, scrwidth) + posx);
539
		}
540
		if(vdp_addr != -1){
541
			outp(vdp_data, c - 0x20);
542
		}else if(vdg_addr != -1){
543
			outp(vdg_data, toupper(c) - 'A' + 1);
544
		}
1 nishi 545
		posx++;
7 nishi 546
		if(posx == scrwidth){
1 nishi 547
			posx = 0;
548
			posy++;
549
		}
550
	}
7 nishi 551
	if(posy == scrheight){
1 nishi 552
		scroll_y();
7 nishi 553
		posy = scrheight - 1;
1 nishi 554
		posx = 0;
555
	}
556
}
557
 
2 nishi 558
void putstr(char* str){
1 nishi 559
	int i;
560
	for(i = 0; str[i] != 0; i++) putchar(str[i]);
561
}
562
 
7 nishi 563
long modl(long a, long b){
564
	return a - mull(b, divl(a, b));
565
}
566
 
567
long divl(long a, long b){
568
	int i;
569
	for(i = 0; i < 4; i++){
570
		outp(fpu_stack, a & 0xff);
571
		a = a >> 8;
572
	}
573
	for(i = 0; i < 4; i++){
574
		outp(fpu_stack, b & 0xff);
575
		b = b >> 8;
576
	}
577
	outp(fpu_command, AM_DOUBLE | AM_DIV);
578
	unsigned long r = 0;
579
	for(i = 0; i < 4; i++){
580
		r = r << 8;
581
		r |= inp(fpu_stack);
582
	}
583
	return r;
584
}
585
 
586
long mull(long a, long b){
587
	int i;
588
	for(i = 0; i < 4; i++){
589
		outp(fpu_stack, a & 0xff);
590
		a = a >> 8;
591
	}
592
	for(i = 0; i < 4; i++){
593
		outp(fpu_stack, b & 0xff);
594
		b = b >> 8;
595
	}
596
	outp(fpu_command, AM_DOUBLE | AM_MUL);
597
	long r = 0;
598
	for(i = 0; i < 4; i++){
599
		r = r << 8;
600
		r |= inp(fpu_stack);
601
	}
602
	return r;
603
}
604
 
605
 
2 nishi 606
unsigned char inp(unsigned char port) __naked {
607
__asm
608
	ld      hl,#2
609
	add     hl,sp
610
	ld      c,(hl)
611
	in      a,(c)
612
	ld      l,a
613
	ld      h,#0
614
	ret
615
__endasm;
616
}
1 nishi 617
 
2 nishi 618
void outp(unsigned char port, unsigned char data) __naked {
619
__asm
620
	push bc
621
	ld      hl,#4
622
	add     hl,sp
623
	ld      c,(hl)
624
	inc     hl
625
	ld      b,(hl)
626
	out     (c),b
627
	pop     bc
628
	ret
629
__endasm;
630
}