-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscreen.c
714 lines (629 loc) · 24.2 KB
/
screen.c
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
#include <stdio.h>
#include <stdlib.h>
#include "tc_conio.h"
#include "tc_graphics.h"
#include "header.h"
#include "screen.h"
#include "io.h"
void update_full_text_screen(void);
void (*update_screen)(void) = update_full_text_screen; // initialise update
// screen function
uint screen_start = 0x7C00; // init screen variables for teletext
uint ram_screen_start = 0x7C00; //
ubyte teletext = 1; //
// Declare graphics variables..
ubyte disp_chars; // displayed characters per row
ubyte colour_bits; // bits per pixel
/*
Teletext screen write function.
*/
void text_screen_byte(ubyte iobyte, uint address) {
ubyte column = 1; // init column (first column=1)
ubyte row = 1; // init row (first row=1)
if (address < screen_start) address += 0x400;// deal with hardware wrap-around
address -= screen_start; //
column += address % 40; // calculate column
row += address / 40; // calculate row
if (column == 40 && row == 25) // if bottom right, return since, any putchar
return; // in this position will scroll the screen
gotoxy(column, row); // move pc cursor to correct position
switch (iobyte) { // convert pc characters to teletext
// characters
case '_':
iobyte = '#';
break;
case '[':
iobyte = '\x1B';
break; // some of these conversion are not
case '\\':
iobyte = '?';
break; // stricly correct, since no corresponding
case ']':
iobyte = '\x1A';
break; // character in the pc set exists
case '^':
iobyte = '\x18';
break; //
case '`':
iobyte = '?';
break; // notably the } characters is not
case '#':
iobyte = '?';
break; // converted to the proper 3/4 symbol
case '{':
iobyte = '?';
break;
case '|':
iobyte = '?';
break;
case '}':
iobyte = '}';
break;
case '~':
iobyte = '?';
break;
case 0x7F:
iobyte = '?';
break; // This conversion takes place because
// 0x7F is used for the cursor when
// copying
}
putch(iobyte); // Ouput the character
update_cursor(); // update to the correct position
// as specified in the BBC hardware
}
/*
This function is used for graphics modes with 1 bit per pixel
*/
void screen_byte_1(ubyte iobyte, uint address) {
uint x_cord = 0; // init real x cordinate variable
uint y_cord = 0; // init real y cordinate variable
uint virt_y_cord = 0; // init actual pc output y coordinate
uint bitsperline; // variable holding bits per line
// deal with hardware wrap-around
if (address < screen_start) address += (0x8000 - ram_screen_start);
address -= screen_start;
bitsperline = crt_regs[1] << 3; // calculate bits per line
y_cord = address / (bitsperline); // calculate character row of address
y_cord *= 8; // convert to pixel row
y_cord += (address % 8); // add fraction of character to pixel row
virt_y_cord += y_cord + y_cord / 4; // scale output to pc screen
x_cord = address % (bitsperline); // calculate x coordinate
x_cord &= 0xFFF8; // mask off lower 3 bits
if (bitsperline == 640) // if an 80 character mode
{
putpixel(x_cord + 0, virt_y_cord, (iobyte & 0x80) ? 8 : 0);
putpixel(x_cord + 1, virt_y_cord, (iobyte & 0x40) ? 8 : 0);
putpixel(x_cord + 2, virt_y_cord, (iobyte & 0x20) ? 8 : 0);
putpixel(x_cord + 3, virt_y_cord, (iobyte & 0x10) ? 8 : 0);
putpixel(x_cord + 4, virt_y_cord, (iobyte & 0x08) ? 8 : 0);
putpixel(x_cord + 5, virt_y_cord, (iobyte & 0x04) ? 8 : 0);
putpixel(x_cord + 6, virt_y_cord, (iobyte & 0x02) ? 8 : 0);
putpixel(x_cord + 7, virt_y_cord, (iobyte & 0x01) ? 8 : 0);
}
else // if not an 80 character mode
{
x_cord <<= 1; // scale output to fit pc screen
putpixel(x_cord + 0, virt_y_cord, (iobyte & 0x80) ? 8 : 0);
putpixel(x_cord + 1, virt_y_cord, (iobyte & 0x80) ? 8 : 0);
putpixel(x_cord + 2, virt_y_cord, (iobyte & 0x40) ? 8 : 0);
putpixel(x_cord + 3, virt_y_cord, (iobyte & 0x40) ? 8 : 0);
putpixel(x_cord + 4, virt_y_cord, (iobyte & 0x20) ? 8 : 0);
putpixel(x_cord + 5, virt_y_cord, (iobyte & 0x20) ? 8 : 0);
putpixel(x_cord + 6, virt_y_cord, (iobyte & 0x10) ? 8 : 0);
putpixel(x_cord + 7, virt_y_cord, (iobyte & 0x10) ? 8 : 0);
putpixel(x_cord + 8, virt_y_cord, (iobyte & 0x08) ? 8 : 0);
putpixel(x_cord + 9, virt_y_cord, (iobyte & 0x08) ? 8 : 0);
putpixel(x_cord + 10, virt_y_cord, (iobyte & 0x04) ? 8 : 0);
putpixel(x_cord + 11, virt_y_cord, (iobyte & 0x04) ? 8 : 0);
putpixel(x_cord + 12, virt_y_cord, (iobyte & 0x02) ? 8 : 0);
putpixel(x_cord + 13, virt_y_cord, (iobyte & 0x02) ? 8 : 0);
putpixel(x_cord + 14, virt_y_cord, (iobyte & 0x01) ? 8 : 0);
putpixel(x_cord + 15, virt_y_cord, (iobyte & 0x01) ? 8 : 0);
}
if (!(y_cord & 3)) // if the vertical coordinate has been scaled
{
virt_y_cord--; // file in the extra pixels
if (bitsperline == 640) // if an 80 character mode
{
putpixel(x_cord + 0, virt_y_cord, (iobyte & 0x80) ? 8 : 0);
putpixel(x_cord + 1, virt_y_cord, (iobyte & 0x40) ? 8 : 0);
putpixel(x_cord + 2, virt_y_cord, (iobyte & 0x20) ? 8 : 0);
putpixel(x_cord + 3, virt_y_cord, (iobyte & 0x10) ? 8 : 0);
putpixel(x_cord + 4, virt_y_cord, (iobyte & 0x08) ? 8 : 0);
putpixel(x_cord + 5, virt_y_cord, (iobyte & 0x04) ? 8 : 0);
putpixel(x_cord + 6, virt_y_cord, (iobyte & 0x02) ? 8 : 0);
putpixel(x_cord + 7, virt_y_cord, (iobyte & 0x01) ? 8 : 0);
}
else // if not an 80 character mode
{
putpixel(x_cord + 0, virt_y_cord, (iobyte & 0x80) ? 8 : 0);
putpixel(x_cord + 1, virt_y_cord, (iobyte & 0x80) ? 8 : 0);
putpixel(x_cord + 2, virt_y_cord, (iobyte & 0x40) ? 8 : 0);
putpixel(x_cord + 3, virt_y_cord, (iobyte & 0x40) ? 8 : 0);
putpixel(x_cord + 4, virt_y_cord, (iobyte & 0x20) ? 8 : 0);
putpixel(x_cord + 5, virt_y_cord, (iobyte & 0x20) ? 8 : 0);
putpixel(x_cord + 6, virt_y_cord, (iobyte & 0x10) ? 8 : 0);
putpixel(x_cord + 7, virt_y_cord, (iobyte & 0x10) ? 8 : 0);
putpixel(x_cord + 8, virt_y_cord, (iobyte & 0x08) ? 8 : 0);
putpixel(x_cord + 9, virt_y_cord, (iobyte & 0x08) ? 8 : 0);
putpixel(x_cord + 10, virt_y_cord, (iobyte & 0x04) ? 8 : 0);
putpixel(x_cord + 11, virt_y_cord, (iobyte & 0x04) ? 8 : 0);
putpixel(x_cord + 12, virt_y_cord, (iobyte & 0x02) ? 8 : 0);
putpixel(x_cord + 13, virt_y_cord, (iobyte & 0x02) ? 8 : 0);
putpixel(x_cord + 14, virt_y_cord, (iobyte & 0x01) ? 8 : 0);
putpixel(x_cord + 15, virt_y_cord, (iobyte & 0x01) ? 8 : 0);
}
}
}
/*
Screen output function for 2 bits per pixels (4 colour) modes.
*/
void screen_byte_2(ubyte iobyte, uint address) {
uint x_cord = 0; // general x coordinate variable
uint y_cord = 0; // general y coordinate variable
uint virt_y_cord = 0; // vertically scaled pc y coordinate
uint bitsperline; // bits per line variable
ubyte colpix1; // colour of pixel 1
ubyte colpix2; // colour of pixel 2
ubyte colpix3; // colour of pixel 3
ubyte colpix4; // colour of pixel 4
// deal with hardware wraparound
if (address < screen_start) address += (0x8000 - ram_screen_start);
address -= screen_start;
bitsperline = 8 * crt_regs[1]; // calculate bits per scanline
y_cord = address / bitsperline; // calculate character row
y_cord *= 8; // convert to pixel row
y_cord += (address % 8); // add fraction of character offset
virt_y_cord += y_cord + y_cord / 4; // scale output to fit pc screen
x_cord = address % bitsperline; // calculate x character column
x_cord &= 0xFFF8; // mask off lower 3 bits
switch (iobyte & 0x88) // calculate colour of pixel 1
{
case 0x00:
colpix1 = 0x00;
break;
case 0x08:
colpix1 = 0x02;
break;
case 0x80:
colpix1 = 0x08;
break;
case 0x88:
colpix1 = 0x0A;
break;
}
switch (iobyte & 0x44) // calculate colour of pixel 2
{
case 0x00:
colpix2 = 0x00;
break;
case 0x04:
colpix2 = 0x02;
break;
case 0x40:
colpix2 = 0x08;
break;
case 0x44:
colpix2 = 0x0A;
break;
}
switch (iobyte & 0x22) // calculate colour of pixel 3
{
case 0x00:
colpix3 = 0x00;
break;
case 0x02:
colpix3 = 0x02;
break;
case 0x20:
colpix3 = 0x08;
break;
case 0x22:
colpix3 = 0x0A;
break;
}
switch (iobyte & 0x11) // calcalate colour of pixel 4
{
case 0x00:
colpix4 = 0x00;
break;
case 0x01:
colpix4 = 0x02;
break;
case 0x10:
colpix4 = 0x08;
break;
case 0x11:
colpix4 = 0x0A;
break;
}
if (bitsperline == 640) // if this is a 40 character mode
{
putpixel(x_cord + 0, virt_y_cord, colpix1);
putpixel(x_cord + 1, virt_y_cord, colpix1);
putpixel(x_cord + 2, virt_y_cord, colpix2);
putpixel(x_cord + 3, virt_y_cord, colpix2);
putpixel(x_cord + 4, virt_y_cord, colpix3);
putpixel(x_cord + 5, virt_y_cord, colpix3);
putpixel(x_cord + 6, virt_y_cord, colpix4);
putpixel(x_cord + 7, virt_y_cord, colpix4);
}
else // if this is not a 40 character mode
{
x_cord <<= 1; // scale the x coorinate to fit the scren
putpixel(x_cord + 0, virt_y_cord, colpix1);
putpixel(x_cord + 1, virt_y_cord, colpix1);
putpixel(x_cord + 2, virt_y_cord, colpix1);
putpixel(x_cord + 3, virt_y_cord, colpix1);
putpixel(x_cord + 4, virt_y_cord, colpix2);
putpixel(x_cord + 5, virt_y_cord, colpix2);
putpixel(x_cord + 6, virt_y_cord, colpix2);
putpixel(x_cord + 7, virt_y_cord, colpix2);
putpixel(x_cord + 8, virt_y_cord, colpix3);
putpixel(x_cord + 9, virt_y_cord, colpix3);
putpixel(x_cord + 10, virt_y_cord, colpix3);
putpixel(x_cord + 11, virt_y_cord, colpix3);
putpixel(x_cord + 12, virt_y_cord, colpix4);
putpixel(x_cord + 13, virt_y_cord, colpix4);
putpixel(x_cord + 14, virt_y_cord, colpix4);
putpixel(x_cord + 15, virt_y_cord, colpix4);
}
if (!(y_cord & 3)) // if the y coordinate was scaled,
{
virt_y_cord--; // put the pixels on the original line
if (bitsperline == 640) // if this is a 40 character mode
{
putpixel(x_cord + 0, virt_y_cord, colpix1);
putpixel(x_cord + 1, virt_y_cord, colpix1);
putpixel(x_cord + 2, virt_y_cord, colpix2);
putpixel(x_cord + 3, virt_y_cord, colpix2);
putpixel(x_cord + 4, virt_y_cord, colpix3);
putpixel(x_cord + 5, virt_y_cord, colpix3);
putpixel(x_cord + 6, virt_y_cord, colpix4);
putpixel(x_cord + 7, virt_y_cord, colpix4);
}
else // if this is not a 40 character mode
{
putpixel(x_cord + 0, virt_y_cord, colpix1);
putpixel(x_cord + 1, virt_y_cord, colpix1);
putpixel(x_cord + 2, virt_y_cord, colpix1);
putpixel(x_cord + 3, virt_y_cord, colpix1);
putpixel(x_cord + 4, virt_y_cord, colpix2);
putpixel(x_cord + 5, virt_y_cord, colpix2);
putpixel(x_cord + 6, virt_y_cord, colpix2);
putpixel(x_cord + 7, virt_y_cord, colpix2);
putpixel(x_cord + 8, virt_y_cord, colpix3);
putpixel(x_cord + 9, virt_y_cord, colpix3);
putpixel(x_cord + 10, virt_y_cord, colpix3);
putpixel(x_cord + 11, virt_y_cord, colpix3);
putpixel(x_cord + 12, virt_y_cord, colpix4);
putpixel(x_cord + 13, virt_y_cord, colpix4);
putpixel(x_cord + 14, virt_y_cord, colpix4);
putpixel(x_cord + 15, virt_y_cord, colpix4);
}
}
}
/*
Screen output function for 16 colour modes
*/
void screen_byte_4(ubyte iobyte, uint address) {
uint x_cord = 0; // general x coordinate
uint y_cord = 0; // general y coordinate
uint virt_y_cord = 0; // scaled pc y coordinate
uint bitsperline; // bits per scaline
ubyte colpix1; // holds the colour of pixel 1
ubyte colpix2; // holds the colour of pixel 2
bitsperline = 8 * crt_regs[1]; // calculate bits per line
// deal with hardware wraparound
if (address < screen_start) address += (0x8000 - ram_screen_start);
address -= screen_start;
y_cord = address / bitsperline; // calculate the character row
y_cord *= 8; // convert to the pixel row
y_cord += (address % 8); // add fraction of character offset
virt_y_cord += y_cord + y_cord / 4; // scale output to fit screen
x_cord = address % bitsperline; // calcalate the character column
x_cord &= 0xFFF8; // mask off the lower 3 bits
switch (iobyte & 0xAA) // calculate the colour of pixel 1
{
case 0x00:
colpix1 = 0x0;
break;
case 0x02:
colpix1 = 0x1;
break;
case 0x08:
colpix1 = 0x2;
break;
case 0x0A:
colpix1 = 0x3;
break;
case 0x20:
colpix1 = 0x4;
break;
case 0x22:
colpix1 = 0x5;
break;
case 0x28:
colpix1 = 0x6;
break;
case 0x2A:
colpix1 = 0x7;
break;
case 0x80:
colpix1 = 0x8;
break;
case 0x82:
colpix1 = 0x9;
break;
case 0x88:
colpix1 = 0xA;
break;
case 0x8A:
colpix1 = 0xB;
break;
case 0xA0:
colpix1 = 0xC;
break;
case 0xA2:
colpix1 = 0xD;
break;
case 0xA8:
colpix1 = 0xE;
break;
case 0xAA:
colpix1 = 0xF;
break;
}
switch (iobyte & 0x55) // calculate the colour of pixel 2
{
case 0x00:
colpix2 = 0x0;
break;
case 0x01:
colpix2 = 0x1;
break;
case 0x04:
colpix2 = 0x2;
break;
case 0x05:
colpix2 = 0x3;
break;
case 0x10:
colpix2 = 0x4;
break;
case 0x11:
colpix2 = 0x5;
break;
case 0x14:
colpix2 = 0x6;
break;
case 0x15:
colpix2 = 0x7;
break;
case 0x40:
colpix2 = 0x8;
break;
case 0x41:
colpix2 = 0x9;
break;
case 0x44:
colpix2 = 0xA;
break;
case 0x45:
colpix2 = 0xB;
break;
case 0x50:
colpix2 = 0xC;
break;
case 0x51:
colpix2 = 0xD;
break;
case 0x54:
colpix2 = 0xE;
break;
case 0x55:
colpix2 = 0xF;
break;
}
// only a twenty column mode is
// officially supported,
// so no need to scale output
putpixel(x_cord + 0, virt_y_cord, colpix1);
putpixel(x_cord + 1, virt_y_cord, colpix1);
putpixel(x_cord + 2, virt_y_cord, colpix1);
putpixel(x_cord + 3, virt_y_cord, colpix1);
putpixel(x_cord + 4, virt_y_cord, colpix2);
putpixel(x_cord + 5, virt_y_cord, colpix2);
putpixel(x_cord + 6, virt_y_cord, colpix2);
putpixel(x_cord + 7, virt_y_cord, colpix2);
if (!(y_cord & 3)) // if the y_cord was scaled,
// fill in the pixels for the
{ // original line
virt_y_cord--;
putpixel(x_cord + 0, virt_y_cord, colpix1);
putpixel(x_cord + 1, virt_y_cord, colpix1);
putpixel(x_cord + 2, virt_y_cord, colpix1);
putpixel(x_cord + 3, virt_y_cord, colpix1);
putpixel(x_cord + 4, virt_y_cord, colpix2);
putpixel(x_cord + 5, virt_y_cord, colpix2);
putpixel(x_cord + 6, virt_y_cord, colpix2);
putpixel(x_cord + 7, virt_y_cord, colpix2);
}
}
void update_cursor(void) {
uint cursor_add; // cursor address
uint cursor_wid; // cursor width in bytes
static uint old_cursor_add; // static variable to hold the
static uint old_cursor_wid; // previous cursor data,
// so that it may be erased
if (teletext) { // if in teletext mode
cursor_add = crt_regs[14] * 0x100 + crt_regs[15];
cursor_add ^= 0x2000;
cursor_add += 0x7400; // calculate actual address
// move the cursor to the relevant place
if (cursor_add < screen_start) cursor_add += 0x400;// deal with hardware wraparound
cursor_add -= screen_start;
gotoxy(cursor_add % 40 + 1, cursor_add / 40 + 1);
}
else { // if in a graphics mode
cursor_add = 0x100 * crt_regs[14] + crt_regs[15];
cursor_add <<= 3; // calculte the actual address
// deal with hardware wrap around
if (cursor_add >= 0x8000) cursor_add -= 0x8000 - ram_screen_start;
switch (vid_con_reg & 0x60) { // get the cursor width in bytes
case 0x60:
cursor_wid = 4;
break;
case 0x40:
cursor_wid = 2;
break;
case 0x20:
puts("Invalid Cursor");
exit(1);
break;
case 0x00:
cursor_wid = 1;
break;
}
switch (old_cursor_wid) { // remove the old cursor
case 4:
screen_byte_P(RAM[old_cursor_add + 0x1F], old_cursor_add + 0x1F);
screen_byte_P(RAM[old_cursor_add + 0x17], old_cursor_add + 0x17);
case 2:
screen_byte_P(RAM[old_cursor_add + 0x0F], old_cursor_add + 0x0F);
case 1:
screen_byte_P(RAM[old_cursor_add + 0x07], old_cursor_add + 0x07);
}
switch (cursor_wid) { // position the new cursor
case 4:
screen_byte_P(0xFF, cursor_add + 0x1F);
screen_byte_P(0xFF, cursor_add + 0x17);
case 2:
screen_byte_P(0xFF, cursor_add + 0x0F);
case 1:
screen_byte_P(0xFF, cursor_add + 0x07);
}
old_cursor_wid = cursor_wid; // store a copy of the current cursor
old_cursor_add = cursor_add; //
}
}
// The name says it all really, used to update
// the teletext screen after a hardware scroll
void update_full_text_screen(void) {
uint c;
uint d;
_setcursortype(_NOCURSOR); // turn off the cursor to stop flickering
c = screen_start;
for (d = 0; d < 999; d++, c++) { // work through every byte
if (c == 0x8000) c = 0x7C00; // deal with hardware wraparound
text_screen_byte(RAM[c], c); // output the current byte
}
_setcursortype(_NORMALCURSOR); // turn the cursor back on again
}
/*
This function does not really do anywork, it calls the relevant function
*/
void update_graphics_screen(void) {
switch (colour_bits) {
case 1:
mono_update();
break;
case 2:
four_update();
break;
case 4:
sixt_update();
break;
default:
puts("Error, unknown number of colours");
exit(1);
}
}
/*
Called upon a negative transition of the teletext
select bit in the video ULA Sheila Address 0xFE20
*/
void pixel_vid_init(void) {
setgraphmode(VGAMED); // Change mode from text to graphics
set_colour_bits(); // initialise for the relevant colour mode
set_screen_start(); // initialise the screen start
update_screen = update_graphics_screen; // point the screen update function
return;
}
/*
Called upon a positive transition of the teletext
select bit in the video ULA
*/
void teletext_init(void) {
restorecrtmode(); // Change to a text mode
ram_screen_start = 0x7C00; // Set screen start
screen_byte_P = text_screen_byte; // Point screen access function
update_screen = update_full_text_screen; // point screen update function
textcolor(WHITE); // set text to white colour
return;
}
/*
Called only once, during system initialisation
*/
void graphics_init(void) {
signed int errorcode;
printf("Init graphics system..."); // display pretty startup info
errorcode = registerfarbgidriver(EGAVGA_driver_far); // initialise the graphics
if (errorcode < 0) // system. check for error
{
printf("\nUnable to Initialise Graphics\n"); // if unable to init,
printf("This software requires VGA/EGA"); // print error
exit(1); // and exit
}
screen_byte_P = text_screen_byte; // point screen access function for text
printf("Done\n"); // display pretty startup info
}
void set_colour_bits(void) // initialise colour functions
{
if (!teletext) // only if in graphics mode
switch (colour_bits = crt_regs[1] / disp_chars) // calc bits per pixel
{
case 1:
screen_byte_P = screen_byte_1;
break; // point screen access func.
case 2:
screen_byte_P = screen_byte_2;
break;
case 4:
screen_byte_P = screen_byte_4;
break;
}
}
/*
Update ram screen start, used in putbyte() (to decide if output is directed
at the screen) and elsewhere
*/
void set_screen_start(void) {
ubyte screen_latch = 0;
screen_latch = s_via_latch[4] + (2 * s_via_latch[5]); // read from the system
// via latch
// There is a possibly bug here: the system via latch does not
// correspond to values given in the Advanced User Guide or the
// Advanced Master Series Guide.
// However, inaccuracies would probably have gone unnoticed, since
// these bits are only ever altered by the OS and cannot be read by the
// user
switch (screen_latch) {
case 0x000:
ram_screen_start = 0x4000;
break;
case 0x008:
ram_screen_start = 0x6000;
break;
case 0x018:
ram_screen_start = 0x5800;
break;
case 0x010:
ram_screen_start = 0x3000;
break;
default:
puts("Fatal error in detecting screen boundary");
exit(1);
}
}