9
VGA_BANK_SIZE = 64 * 1024,
22
var VGA_LFB_ADDRESS = 0xE0000000;
29
var VGA_PIXEL_BUFFER_SIZE = 8 * VGA_BANK_SIZE;
32
var VGA_MIN_MEMORY_SIZE = 4 * VGA_BANK_SIZE;
38
var VGA_HOST_MEMORY_SPACE_START = Uint32Array.from([
49
var VGA_HOST_MEMORY_SPACE_SIZE = Uint32Array.from([
62
function VGAScreen(cpu, bus, vga_memory_size)
69
this.vga_memory_size = vga_memory_size;
72
this.cursor_address = 0;
75
this.cursor_scanline_start = 0xE;
78
this.cursor_scanline_end = 0xF;
96
this.screen_width = 0;
102
this.screen_height = 0;
108
this.virtual_width = 0;
114
this.virtual_height = 0;
127
this.start_address = 0;
134
this.start_address_latched = 0;
139
this.crtc = new Uint8Array(0x19);
147
this.horizontal_display_enable_end = 0;
150
this.horizontal_blank_start = 0;
153
this.vertical_display_enable_end = 0;
156
this.vertical_blank_start = 0;
159
this.underline_location_register = 0;
162
this.preset_row_scan = 0;
165
this.offset_register = 0;
168
this.line_compare = 0;
176
this.graphical_mode_is_linear = true;
179
this.graphical_mode = false;
180
setTimeout(() => { bus.send("screen-set-mode", this.graphical_mode); }, 0);
186
this.vga256_palette = new Int32Array(256);
192
this.latch_dword = 0;
198
this.svga_height = 0;
200
this.svga_enabled = false;
206
this.svga_bank_offset = 0;
213
this.svga_offset = 0;
218
0x34, 0x12, 0x11, 0x11, 0x03, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
219
0x08, VGA_LFB_ADDRESS >>> 8, VGA_LFB_ADDRESS >>> 16, VGA_LFB_ADDRESS >>> 24,
220
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xfe, 0x00, 0x00, 0x00, 0x00,
221
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x1a, 0x00, 0x11,
222
0x00, 0x00, 0xbe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224
this.pci_id = 0x12 << 3;
227
size: vga_memory_size,
238
this.pci_rom_size = 0x10000;
239
this.pci_rom_address = 0xFEB00000;
253
this.dac_color_index_write = 0;
254
this.dac_color_index_read = 0;
257
this.dac_map = new Uint8Array(0x10);
259
this.attribute_controller_index = -1;
260
this.palette_source = 0x20;
261
this.attribute_mode = 0;
262
this.color_plane_enable = 0;
263
this.horizontal_panning = 0;
264
this.color_select = 0;
266
this.sequencer_index = -1;
269
this.plane_write_bm = 0xF;
270
this.sequencer_memory_mode = 0;
271
this.clocking_mode = 0;
272
this.graphics_index = -1;
275
this.planar_mode = 0;
276
this.planar_rotate_reg = 0;
277
this.planar_bitmap = 0xFF;
278
this.planar_setreset = 0;
279
this.planar_setreset_enable = 0;
280
this.miscellaneous_graphics_register = 0;
282
this.color_compare = 0;
283
this.color_dont_care = 0;
285
this.max_scan_line = 0;
287
this.miscellaneous_output_register = 0xff;
288
this.port_3DA_value = 0xFF;
293
io.register_write(0x3C0, this, this.port3C0_write);
294
io.register_read(0x3C0, this, this.port3C0_read, this.port3C0_read16);
296
io.register_read(0x3C1, this, this.port3C1_read);
297
io.register_write(0x3C2, this, this.port3C2_write);
299
io.register_write_consecutive(0x3C4, this, this.port3C4_write, this.port3C5_write);
301
io.register_read(0x3C4, this, this.port3C4_read);
302
io.register_read(0x3C5, this, this.port3C5_read);
304
io.register_write_consecutive(0x3CE, this, this.port3CE_write, this.port3CF_write);
306
io.register_read(0x3CE, this, this.port3CE_read);
307
io.register_read(0x3CF, this, this.port3CF_read);
309
io.register_write(0x3C7, this, this.port3C7_write);
310
io.register_read(0x3C7, this, this.port3C7_read);
311
io.register_write(0x3C8, this, this.port3C8_write);
312
io.register_read(0x3C8, this, this.port3C8_read);
313
io.register_write(0x3C9, this, this.port3C9_write);
314
io.register_read(0x3C9, this, this.port3C9_read);
316
io.register_read(0x3CC, this, this.port3CC_read);
318
io.register_write_consecutive(0x3D4, this, this.port3D4_write, this.port3D5_write);
319
io.register_read(0x3D4, this, this.port3D4_read);
320
io.register_read(0x3D5, this, this.port3D5_read, () => {
321
dbg_log("Warning: 16-bit read from 3D5", LOG_VGA);
322
return this.port3D5_read();
325
io.register_read(0x3CA, this, function() { dbg_log("3CA read", LOG_VGA); return 0; });
327
io.register_read(0x3DA, this, this.port3DA_read);
328
io.register_read(0x3BA, this, this.port3DA_read);
333
this.dispi_index = -1;
334
this.dispi_enable_value = 0;
336
io.register_write(0x1CE, this, undefined, this.port1CE_write);
338
io.register_write(0x1CF, this, undefined, this.port1CF_write);
339
io.register_read(0x1CF, this, undefined, this.port1CF_read);
341
if(this.vga_memory_size === undefined || this.vga_memory_size < VGA_MIN_MEMORY_SIZE)
343
this.vga_memory_size = VGA_MIN_MEMORY_SIZE;
344
dbg_log("vga memory size rounded up to " + this.vga_memory_size, LOG_VGA);
346
else if(this.vga_memory_size & (VGA_BANK_SIZE - 1))
349
this.vga_memory_size |= VGA_BANK_SIZE - 1;
350
this.vga_memory_size++;
354
const vga_offset = cpu.svga_allocate_memory(this.vga_memory_size);
355
this.svga_memory = v86util.view(Uint8Array, cpu.wasm_memory, vga_offset, this.vga_memory_size);
357
this.diff_addr_min = this.vga_memory_size;
358
this.diff_addr_max = 0;
359
this.diff_plot_min = this.vga_memory_size;
360
this.diff_plot_max = 0;
362
this.image_data = null;
364
bus.register("screen-fill-buffer", function()
366
this.screen_fill_buffer();
369
this.vga_memory = new Uint8Array(4 * VGA_BANK_SIZE);
370
this.plane0 = new Uint8Array(this.vga_memory.buffer, 0 * VGA_BANK_SIZE, VGA_BANK_SIZE);
371
this.plane1 = new Uint8Array(this.vga_memory.buffer, 1 * VGA_BANK_SIZE, VGA_BANK_SIZE);
372
this.plane2 = new Uint8Array(this.vga_memory.buffer, 2 * VGA_BANK_SIZE, VGA_BANK_SIZE);
373
this.plane3 = new Uint8Array(this.vga_memory.buffer, 3 * VGA_BANK_SIZE, VGA_BANK_SIZE);
374
this.pixel_buffer = new Uint8Array(VGA_PIXEL_BUFFER_SIZE);
377
io.mmap_register(0xA0000, 0x20000,
378
function(addr) { return me.vga_memory_read(addr); },
379
function(addr, value) { me.vga_memory_write(addr, value); }
382
cpu.devices.pci.register_device(this);
385
VGAScreen.prototype.get_state = function()
389
state[0] = this.vga_memory_size;
390
state[1] = this.cursor_address;
391
state[2] = this.cursor_scanline_start;
392
state[3] = this.cursor_scanline_end;
393
state[4] = this.max_cols;
394
state[5] = this.max_rows;
395
state[6] = this.vga_memory;
396
state[7] = this.dac_state;
397
state[8] = this.start_address;
398
state[9] = this.graphical_mode;
399
state[10] = this.vga256_palette;
400
state[11] = this.latch_dword;
401
state[12] = this.color_compare;
402
state[13] = this.color_dont_care;
403
state[14] = this.miscellaneous_graphics_register;
404
state[15] = this.svga_width;
405
state[16] = this.svga_height;
406
state[17] = this.crtc_mode;
407
state[18] = this.svga_enabled;
408
state[19] = this.svga_bpp;
409
state[20] = this.svga_bank_offset;
410
state[21] = this.svga_offset;
411
state[22] = this.index_crtc;
412
state[23] = this.dac_color_index_write;
413
state[24] = this.dac_color_index_read;
414
state[25] = this.dac_map;
415
state[26] = this.sequencer_index;
416
state[27] = this.plane_write_bm;
417
state[28] = this.sequencer_memory_mode;
418
state[29] = this.graphics_index;
419
state[30] = this.plane_read;
420
state[31] = this.planar_mode;
421
state[32] = this.planar_rotate_reg;
422
state[33] = this.planar_bitmap;
423
state[34] = this.max_scan_line;
424
state[35] = this.miscellaneous_output_register;
425
state[36] = this.port_3DA_value;
426
state[37] = this.dispi_index;
427
state[38] = this.dispi_enable_value;
428
state[39] = this.svga_memory;
429
state[40] = this.graphical_mode_is_linear;
430
state[41] = this.attribute_controller_index;
431
state[42] = this.offset_register;
432
state[43] = this.planar_setreset;
433
state[44] = this.planar_setreset_enable;
434
state[45] = this.start_address_latched;
435
state[46] = this.crtc;
436
state[47] = this.horizontal_display_enable_end;
437
state[48] = this.horizontal_blank_start;
438
state[49] = this.vertical_display_enable_end;
439
state[50] = this.vertical_blank_start;
440
state[51] = this.underline_location_register;
441
state[52] = this.preset_row_scan;
442
state[53] = this.offset_register;
443
state[54] = this.palette_source;
444
state[55] = this.attribute_mode;
445
state[56] = this.color_plane_enable;
446
state[57] = this.horizontal_panning;
447
state[58] = this.color_select;
448
state[59] = this.clocking_mode;
449
state[60] = this.line_compare;
450
state[61] = this.pixel_buffer;
455
VGAScreen.prototype.set_state = function(state)
457
this.vga_memory_size = state[0];
458
this.cursor_address = state[1];
459
this.cursor_scanline_start = state[2];
460
this.cursor_scanline_end = state[3];
461
this.max_cols = state[4];
462
this.max_rows = state[5];
463
state[6] && this.vga_memory.set(state[6]);
464
this.dac_state = state[7];
465
this.start_address = state[8];
466
this.graphical_mode = state[9];
467
this.vga256_palette = state[10];
468
this.latch_dword = state[11];
469
this.color_compare = state[12];
470
this.color_dont_care = state[13];
471
this.miscellaneous_graphics_register = state[14];
472
this.svga_width = state[15];
473
this.svga_height = state[16];
474
this.crtc_mode = state[17];
475
this.svga_enabled = state[18];
476
this.svga_bpp = state[19];
477
this.svga_bank_offset = state[20];
478
this.svga_offset = state[21];
479
this.index_crtc = state[22];
480
this.dac_color_index_write = state[23];
481
this.dac_color_index_read = state[24];
482
this.dac_map = state[25];
483
this.sequencer_index = state[26];
484
this.plane_write_bm = state[27];
485
this.sequencer_memory_mode = state[28];
486
this.graphics_index = state[29];
487
this.plane_read = state[30];
488
this.planar_mode = state[31];
489
this.planar_rotate_reg = state[32];
490
this.planar_bitmap = state[33];
491
this.max_scan_line = state[34];
492
this.miscellaneous_output_register = state[35];
493
this.port_3DA_value = state[36];
494
this.dispi_index = state[37];
495
this.dispi_enable_value = state[38];
496
this.svga_memory.set(state[39]);
497
this.graphical_mode_is_linear = state[40];
498
this.attribute_controller_index = state[41];
499
this.offset_register = state[42];
500
this.planar_setreset = state[43];
501
this.planar_setreset_enable = state[44];
502
this.start_address_latched = state[45];
503
this.crtc.set(state[46]);
504
this.horizontal_display_enable_end = state[47];
505
this.horizontal_blank_start = state[48];
506
this.vertical_display_enable_end = state[49];
507
this.vertical_blank_start = state[50];
508
this.underline_location_register = state[51];
509
this.preset_row_scan = state[52];
510
this.offset_register = state[53];
511
this.palette_source = state[54];
512
this.attribute_mode = state[55];
513
this.color_plane_enable = state[56];
514
this.horizontal_panning = state[57];
515
this.color_select = state[58];
516
this.clocking_mode = state[59];
517
this.line_compare = state[60];
518
state[61] && this.pixel_buffer.set(state[61]);
520
this.bus.send("screen-set-mode", this.graphical_mode);
522
if(this.graphical_mode)
525
this.screen_width = 0;
526
this.screen_height = 0;
528
if(this.svga_enabled)
530
this.set_size_graphical(this.svga_width, this.svga_height,
531
this.svga_bpp, this.svga_width, this.svga_height);
532
this.update_layers();
536
this.update_vga_size();
537
this.update_layers();
538
this.complete_replot();
543
this.set_size_text(this.max_cols, this.max_rows);
544
this.update_cursor_scanline();
545
this.update_cursor();
547
this.complete_redraw();
550
VGAScreen.prototype.vga_memory_read = function(addr)
552
if(this.svga_enabled && this.graphical_mode_is_linear)
554
return this.cpu.read8((addr - 0xA0000 | this.svga_bank_offset) + VGA_LFB_ADDRESS | 0);
557
var memory_space_select = this.miscellaneous_graphics_register >> 2 & 0x3;
558
addr -= VGA_HOST_MEMORY_SPACE_START[memory_space_select];
561
if(addr < 0 || addr >= VGA_HOST_MEMORY_SPACE_SIZE[memory_space_select])
563
dbg_log("vga read outside memory space: addr:" + h(addr), LOG_VGA);
567
this.latch_dword = this.plane0[addr];
568
this.latch_dword |= this.plane1[addr] << 8;
569
this.latch_dword |= this.plane2[addr] << 16;
570
this.latch_dword |= this.plane3[addr] << 24;
572
if(this.planar_mode & 0x08)
577
if(this.color_dont_care & 0x1)
579
reading &= this.plane0[addr] ^ ~(this.color_compare & 0x1 ? 0xFF : 0x00);
581
if(this.color_dont_care & 0x2)
583
reading &= this.plane1[addr] ^ ~(this.color_compare & 0x2 ? 0xFF : 0x00);
585
if(this.color_dont_care & 0x4)
587
reading &= this.plane2[addr] ^ ~(this.color_compare & 0x4 ? 0xFF : 0x00);
589
if(this.color_dont_care & 0x8)
591
reading &= this.plane3[addr] ^ ~(this.color_compare & 0x8 ? 0xFF : 0x00);
600
var plane = this.plane_read;
601
if(!this.graphical_mode)
606
else if(this.sequencer_memory_mode & 0x8)
612
else if(this.planar_mode & 0x10)
618
return this.vga_memory[plane << 16 | addr];
622
VGAScreen.prototype.vga_memory_write = function(addr, value)
624
if(this.svga_enabled && this.graphical_mode && this.graphical_mode_is_linear)
627
this.cpu.write8((addr - 0xA0000 | this.svga_bank_offset) + VGA_LFB_ADDRESS | 0, value);
631
var memory_space_select = this.miscellaneous_graphics_register >> 2 & 0x3;
632
addr -= VGA_HOST_MEMORY_SPACE_START[memory_space_select];
634
if(addr < 0 || addr >= VGA_HOST_MEMORY_SPACE_SIZE[memory_space_select])
636
dbg_log("vga write outside memory space: addr:" + h(addr) + ", value:" + h(value), LOG_VGA);
640
if(this.graphical_mode)
642
this.vga_memory_write_graphical(addr, value);
646
if(!(this.plane_write_bm & 0x3))
651
this.vga_memory_write_text_mode(addr, value);
655
VGAScreen.prototype.vga_memory_write_graphical = function(addr, value)
658
var write_mode = this.planar_mode & 3;
659
var bitmask = this.apply_feed(this.planar_bitmap);
660
var setreset_dword = this.apply_expand(this.planar_setreset);
661
var setreset_enable_dword = this.apply_expand(this.planar_setreset_enable);
667
value = this.apply_rotate(value);
668
plane_dword = this.apply_feed(value);
669
plane_dword = this.apply_setreset(plane_dword, setreset_enable_dword);
670
plane_dword = this.apply_logical(plane_dword, this.latch_dword);
671
plane_dword = this.apply_bitmask(plane_dword, bitmask);
674
plane_dword = this.latch_dword;
677
plane_dword = this.apply_expand(value);
678
plane_dword = this.apply_logical(plane_dword, this.latch_dword);
679
plane_dword = this.apply_bitmask(plane_dword, bitmask);
682
value = this.apply_rotate(value);
683
bitmask &= this.apply_feed(value);
684
plane_dword = setreset_dword;
685
plane_dword = this.apply_bitmask(plane_dword, bitmask);
689
var plane_select = 0xF;
691
switch(this.sequencer_memory_mode & 0xC)
695
plane_select = 0x5 << (addr & 0x1);
705
plane_select = 1 << (addr & 0x3);
712
plane_select &= this.plane_write_bm;
714
if(plane_select & 0x1) this.plane0[addr] = (plane_dword >> 0) & 0xFF;
715
if(plane_select & 0x2) this.plane1[addr] = (plane_dword >> 8) & 0xFF;
716
if(plane_select & 0x4) this.plane2[addr] = (plane_dword >> 16) & 0xFF;
717
if(plane_select & 0x8) this.plane3[addr] = (plane_dword >> 24) & 0xFF;
719
var pixel_addr = this.vga_addr_to_pixel(addr);
720
this.partial_replot(pixel_addr, pixel_addr + 7);
729
VGAScreen.prototype.apply_feed = function(data_byte)
731
var dword = data_byte;
732
dword |= data_byte << 8;
733
dword |= data_byte << 16;
734
dword |= data_byte << 24;
744
VGAScreen.prototype.apply_expand = function(data_byte)
746
var dword = data_byte & 0x1 ? 0xFF : 0x00;
747
dword |= (data_byte & 0x2 ? 0xFF : 0x00) << 8;
748
dword |= (data_byte & 0x4 ? 0xFF : 0x00) << 16;
749
dword |= (data_byte & 0x8 ? 0xFF : 0x00) << 24;
760
VGAScreen.prototype.apply_rotate = function(data_byte)
762
var wrapped = data_byte | (data_byte << 8);
763
var count = this.planar_rotate_reg & 0x7;
764
var shifted = wrapped >>> count;
765
return shifted & 0xFF;
776
VGAScreen.prototype.apply_setreset = function(data_dword, enable_dword)
778
var setreset_dword = this.apply_expand(this.planar_setreset);
779
data_dword |= enable_dword & setreset_dword;
780
data_dword &= ~enable_dword | setreset_dword;
792
VGAScreen.prototype.apply_logical = function(data_dword, latch_dword)
794
switch(this.planar_rotate_reg & 0x18)
797
return data_dword & latch_dword;
799
return data_dword | latch_dword;
801
return data_dword ^ latch_dword;
814
VGAScreen.prototype.apply_bitmask = function(data_dword, bitmask_dword)
816
var plane_dword = bitmask_dword & data_dword;
817
plane_dword |= ~bitmask_dword & this.latch_dword;
821
VGAScreen.prototype.text_mode_redraw = function()
823
var addr = this.start_address << 1,
827
for(var row = 0; row < this.max_rows; row++)
829
for(var col = 0; col < this.max_cols; col++)
831
chr = this.vga_memory[addr];
832
color = this.vga_memory[addr | 1];
834
this.bus.send("screen-put-char", [row, col, chr,
835
this.vga256_palette[color >> 4 & 0xF], this.vga256_palette[color & 0xF]]);
842
VGAScreen.prototype.vga_memory_write_text_mode = function(addr, value)
844
var memory_start = (addr >> 1) - this.start_address,
845
row = memory_start / this.max_cols | 0,
846
col = memory_start % this.max_cols,
854
chr = this.vga_memory[addr & ~1];
859
color = this.vga_memory[addr | 1];
862
this.bus.send("screen-put-char", [row, col, chr,
863
this.vga256_palette[color >> 4 & 0xF], this.vga256_palette[color & 0xF]]);
865
this.vga_memory[addr] = value;
868
VGAScreen.prototype.update_cursor = function()
870
var row = (this.cursor_address - this.start_address) / this.max_cols | 0,
871
col = (this.cursor_address - this.start_address) % this.max_cols;
873
row = Math.min(this.max_rows - 1, row);
875
this.bus.send("screen-update-cursor", [row, col]);
878
VGAScreen.prototype.complete_redraw = function()
880
dbg_log("complete redraw", LOG_VGA);
882
if(this.graphical_mode)
884
if(this.svga_enabled)
886
this.cpu.svga_mark_dirty();
890
this.diff_addr_min = 0;
891
this.diff_addr_max = VGA_PIXEL_BUFFER_SIZE;
896
this.text_mode_redraw();
900
VGAScreen.prototype.complete_replot = function()
902
dbg_log("complete replot", LOG_VGA);
904
if(!this.graphical_mode || this.svga_enabled)
909
this.diff_plot_min = 0;
910
this.diff_plot_max = VGA_PIXEL_BUFFER_SIZE;
912
this.complete_redraw();
915
VGAScreen.prototype.partial_redraw = function(min, max)
917
if(min < this.diff_addr_min) this.diff_addr_min = min;
918
if(max > this.diff_addr_max) this.diff_addr_max = max;
921
VGAScreen.prototype.partial_replot = function(min, max)
923
if(min < this.diff_plot_min) this.diff_plot_min = min;
924
if(max > this.diff_plot_max) this.diff_plot_max = max;
926
this.partial_redraw(min, max);
929
VGAScreen.prototype.reset_diffs = function()
931
this.diff_addr_min = this.vga_memory_size;
932
this.diff_addr_max = 0;
933
this.diff_plot_min = this.vga_memory_size;
934
this.diff_plot_max = 0;
937
VGAScreen.prototype.destroy = function()
942
VGAScreen.prototype.vga_bytes_per_line = function()
944
var bytes_per_line = this.offset_register << 2;
945
if(this.underline_location_register & 0x40) bytes_per_line <<= 1;
946
else if(this.crtc_mode & 0x40) bytes_per_line >>>= 1;
947
return bytes_per_line;
950
VGAScreen.prototype.vga_addr_shift_count = function()
954
var shift_count = 0x80;
957
shift_count += ~this.underline_location_register & this.crtc_mode & 0x40;
960
shift_count -= this.underline_location_register & 0x40;
963
shift_count -= this.attribute_mode & 0x40;
965
return shift_count >>> 6;
968
VGAScreen.prototype.vga_addr_to_pixel = function(addr)
970
var shift_count = this.vga_addr_shift_count();
977
if(~this.crtc_mode & 0x3)
979
var pixel_addr = addr - this.start_address;
982
pixel_addr &= this.crtc_mode << 13 | ~0x6000;
985
pixel_addr <<= shift_count;
988
var row = pixel_addr / this.virtual_width | 0;
989
var col = pixel_addr % this.virtual_width;
991
switch(this.crtc_mode & 0x3)
996
row = row << 1 | (addr >> 13 & 0x1);
1001
row = row << 1 | (addr >> 14 & 0x1);
1006
row = row << 2 | (addr >> 13 & 0x3);
1011
return row * this.virtual_width + col + (this.start_address << shift_count);
1016
return addr << shift_count;
1020
VGAScreen.prototype.scan_line_to_screen_row = function(scan_line)
1024
if(this.max_scan_line & 0x80)
1031
var repeat_factor = 1 + (this.max_scan_line & 0x1F);
1032
scan_line = Math.ceil(scan_line / repeat_factor);
1040
if(!(this.crtc_mode & 0x1))
1050
if(!(this.crtc_mode & 0x2))
1062
VGAScreen.prototype.set_size_text = function(cols_count, rows_count)
1064
this.max_cols = cols_count;
1065
this.max_rows = rows_count;
1067
this.bus.send("screen-set-size-text", [cols_count, rows_count]);
1070
VGAScreen.prototype.set_size_graphical = function(width, height, bpp, virtual_width, virtual_height)
1072
var needs_update = !this.stats.is_graphical ||
1073
this.stats.bpp !== bpp ||
1074
this.screen_width !== width ||
1075
this.screen_height !== height ||
1076
this.virtual_width !== virtual_width ||
1077
this.virtual_height !== virtual_height;
1081
this.screen_width = width;
1082
this.screen_height = height;
1083
this.virtual_width = virtual_width;
1084
this.virtual_height = virtual_height;
1086
this.stats.bpp = bpp;
1087
this.stats.is_graphical = true;
1088
this.stats.res_x = width;
1089
this.stats.res_y = height;
1091
if (typeof ImageData !== "undefined")
1093
const size = virtual_width * virtual_height;
1094
const offset = this.cpu.svga_allocate_dest_buffer(size) >>> 0;
1096
this.dest_buffet_offset = offset;
1097
this.image_data = new ImageData(new Uint8ClampedArray(this.cpu.wasm_memory.buffer, offset, 4 * size), virtual_width, virtual_height);
1099
this.cpu.svga_mark_dirty();
1106
this.bus.send("screen-set-size-graphical", [width, height, virtual_width, virtual_height, bpp]);
1110
VGAScreen.prototype.update_vga_size = function()
1112
if(this.svga_enabled)
1117
var horizontal_characters = Math.min(1 + this.horizontal_display_enable_end,
1118
this.horizontal_blank_start);
1119
var vertical_scans = Math.min(1 + this.vertical_display_enable_end,
1120
this.vertical_blank_start);
1122
if(!horizontal_characters || !vertical_scans)
1129
if(this.graphical_mode)
1131
var screen_width = horizontal_characters << 3;
1138
var virtual_width = this.offset_register << 4;
1141
if(this.attribute_mode & 0x40)
1143
screen_width >>>= 1;
1144
virtual_width >>>= 1;
1147
var screen_height = this.scan_line_to_screen_row(vertical_scans);
1155
var available_bytes = VGA_HOST_MEMORY_SPACE_SIZE[0];
1157
var virtual_height = Math.ceil(available_bytes / this.vga_bytes_per_line());
1159
this.set_size_graphical(screen_width, screen_height, 8,
1160
virtual_width, virtual_height);
1162
this.update_vertical_retrace();
1163
this.update_layers();
1167
if(this.max_scan_line & 0x80)
1171
vertical_scans >>>= 1;
1174
var height = vertical_scans / (1 + (this.max_scan_line & 0x1F)) | 0;
1176
if(horizontal_characters && height)
1178
this.set_size_text(horizontal_characters, height);
1183
VGAScreen.prototype.update_layers = function()
1185
if(!this.graphical_mode)
1187
this.text_mode_redraw();
1190
if(this.svga_enabled)
1196
if(!this.virtual_width || !this.screen_width)
1202
if(!this.palette_source || (this.clocking_mode & 0x20))
1208
this.bus.send("screen-clear");
1212
var start_addr = this.start_address_latched;
1214
var pixel_panning = this.horizontal_panning;
1215
if(this.attribute_mode & 0x40)
1217
pixel_panning >>>= 1;
1220
var byte_panning = this.preset_row_scan >> 5 & 0x3;
1221
var pixel_addr_start = this.vga_addr_to_pixel(start_addr + byte_panning);
1223
var start_buffer_row = pixel_addr_start / this.virtual_width | 0;
1224
var start_buffer_col = pixel_addr_start % this.virtual_width + pixel_panning;
1226
var split_screen_row = this.scan_line_to_screen_row(1 + this.line_compare);
1227
split_screen_row = Math.min(split_screen_row, this.screen_height);
1229
var split_buffer_height = this.screen_height - split_screen_row;
1233
for(var x = -start_buffer_col, y = 0; x < this.screen_width; x += this.virtual_width, y++)
1236
image_data: this.image_data,
1240
buffer_y: start_buffer_row + y,
1241
buffer_width: this.virtual_width,
1242
buffer_height: split_screen_row,
1246
var start_split_col = 0;
1247
if(!(this.attribute_mode & 0x20))
1250
start_split_col = this.vga_addr_to_pixel(byte_panning) + pixel_panning;
1253
for(var x = -start_split_col, y = 0; x < this.screen_width; x += this.virtual_width, y++)
1256
image_data: this.image_data,
1258
screen_y: split_screen_row,
1261
buffer_width: this.virtual_width,
1262
buffer_height: split_buffer_height,
1267
VGAScreen.prototype.update_vertical_retrace = function()
1270
this.port_3DA_value |= 0x8;
1271
if(this.start_address_latched !== this.start_address)
1273
this.start_address_latched = this.start_address;
1274
this.update_layers();
1278
VGAScreen.prototype.update_cursor_scanline = function()
1280
this.bus.send("screen-update-cursor-scanline", [this.cursor_scanline_start, this.cursor_scanline_end]);
1289
VGAScreen.prototype.port3C0_write = function(value)
1291
if(this.attribute_controller_index === -1)
1293
dbg_log("attribute controller index register: " + h(value), LOG_VGA);
1294
this.attribute_controller_index = value & 0x1F;
1295
dbg_log("attribute actual index: " + h(this.attribute_controller_index), LOG_VGA);
1297
if(this.palette_source !== (value & 0x20))
1301
this.palette_source = value & 0x20;
1302
this.update_layers();
1307
if(this.attribute_controller_index < 0x10)
1309
dbg_log("internal palette: " + h(this.attribute_controller_index) + " -> " + h(value), LOG_VGA);
1310
this.dac_map[this.attribute_controller_index] = value;
1312
if(!(this.attribute_mode & 0x40))
1314
this.complete_redraw();
1318
switch(this.attribute_controller_index)
1321
dbg_log("3C0 / attribute mode control: " + h(value), LOG_VGA);
1322
if(this.attribute_mode !== value)
1324
var previous_mode = this.attribute_mode;
1325
this.attribute_mode = value;
1327
var is_graphical = (value & 0x1) > 0;
1328
if(!this.svga_enabled && this.graphical_mode !== is_graphical)
1330
this.graphical_mode = is_graphical;
1331
this.bus.send("screen-set-mode", this.graphical_mode);
1334
if((previous_mode ^ value) & 0x40)
1337
this.complete_replot();
1340
this.update_vga_size();
1343
this.complete_redraw();
1347
dbg_log("3C0 / color plane enable: " + h(value), LOG_VGA);
1348
if(this.color_plane_enable !== value)
1350
this.color_plane_enable = value;
1353
this.complete_redraw();
1357
dbg_log("3C0 / horizontal panning: " + h(value), LOG_VGA);
1358
if(this.horizontal_panning !== value)
1360
this.horizontal_panning = value & 0xF;
1361
this.update_layers();
1365
dbg_log("3C0 / color select: " + h(value), LOG_VGA);
1366
if(this.color_select !== value)
1368
this.color_select = value;
1371
this.complete_redraw();
1375
dbg_log("3C0 / attribute controller write " + h(this.attribute_controller_index) + ": " + h(value), LOG_VGA);
1378
this.attribute_controller_index = -1;
1382
VGAScreen.prototype.port3C0_read = function()
1384
dbg_log("3C0 read", LOG_VGA);
1385
var result = this.attribute_controller_index | this.palette_source;
1389
VGAScreen.prototype.port3C0_read16 = function()
1391
dbg_log("3C0 read16", LOG_VGA);
1392
return this.port3C0_read() & 0xFF | this.port3C1_read() << 8 & 0xFF00;
1395
VGAScreen.prototype.port3C1_read = function()
1397
if(this.attribute_controller_index < 0x10)
1399
dbg_log("3C1 / internal palette read: " + h(this.attribute_controller_index) +
1400
" -> " + h(this.dac_map[this.attribute_controller_index]), LOG_VGA);
1401
return this.dac_map[this.attribute_controller_index] & 0xFF;
1404
switch(this.attribute_controller_index)
1407
dbg_log("3C1 / attribute mode read: " + h(this.attribute_mode), LOG_VGA);
1408
return this.attribute_mode;
1410
dbg_log("3C1 / color plane enable read: " + h(this.color_plane_enable), LOG_VGA);
1411
return this.color_plane_enable;
1413
dbg_log("3C1 / horizontal panning read: " + h(this.horizontal_panning), LOG_VGA);
1414
return this.horizontal_panning;
1416
dbg_log("3C1 / color select read: " + h(this.color_select), LOG_VGA);
1417
return this.color_select;
1419
dbg_log("3C1 / attribute controller read " + h(this.attribute_controller_index), LOG_VGA);
1425
VGAScreen.prototype.port3C2_write = function(value)
1427
dbg_log("3C2 / miscellaneous output register = " + h(value), LOG_VGA);
1428
this.miscellaneous_output_register = value;
1431
VGAScreen.prototype.port3C4_write = function(value)
1433
this.sequencer_index = value;
1436
VGAScreen.prototype.port3C4_read = function()
1438
return this.sequencer_index;
1447
VGAScreen.prototype.port3C5_write = function(value)
1449
switch(this.sequencer_index)
1452
dbg_log("clocking mode: " + h(value), LOG_VGA);
1453
var previous_clocking_mode = this.clocking_mode;
1454
this.clocking_mode = value;
1455
if((previous_clocking_mode ^ value) & 0x20)
1458
this.update_layers();
1462
dbg_log("plane write mask: " + h(value), LOG_VGA);
1463
this.plane_write_bm = value;
1466
dbg_log("sequencer memory mode: " + h(value), LOG_VGA);
1467
this.sequencer_memory_mode = value;
1470
dbg_log("3C5 / sequencer write " + h(this.sequencer_index) + ": " + h(value), LOG_VGA);
1474
VGAScreen.prototype.port3C5_read = function()
1476
dbg_log("3C5 / sequencer read " + h(this.sequencer_index), LOG_VGA);
1478
switch(this.sequencer_index)
1481
return this.clocking_mode;
1483
return this.plane_write_bm;
1485
return this.sequencer_memory_mode;
1493
VGAScreen.prototype.port3C7_write = function(index)
1496
dbg_log("3C7 write: " + h(index), LOG_VGA);
1497
this.dac_color_index_read = index * 3;
1498
this.dac_state &= 0x0;
1501
VGAScreen.prototype.port3C7_read = function()
1504
return this.dac_state;
1507
VGAScreen.prototype.port3C8_write = function(index)
1509
this.dac_color_index_write = index * 3;
1510
this.dac_state |= 0x3;
1513
VGAScreen.prototype.port3C8_read = function()
1515
return this.dac_color_index_write / 3 & 0xFF;
1524
VGAScreen.prototype.port3C9_write = function(color_byte)
1526
var index = this.dac_color_index_write / 3 | 0,
1527
offset = this.dac_color_index_write % 3,
1528
color = this.vga256_palette[index];
1530
color_byte = (color_byte & 0x3F) * 255 / 63 | 0;
1534
color = color & ~0xFF0000 | color_byte << 16;
1536
else if(offset === 1)
1538
color = color & ~0xFF00 | color_byte << 8;
1542
color = color & ~0xFF | color_byte;
1543
dbg_log("dac set color, index=" + h(index) + " value=" + h(color), LOG_VGA);
1546
if(this.vga256_palette[index] !== color)
1548
this.vga256_palette[index] = color;
1549
this.complete_redraw();
1551
this.dac_color_index_write++;
1554
VGAScreen.prototype.port3C9_read = function()
1556
dbg_log("3C9 read", LOG_VGA);
1558
var index = this.dac_color_index_read / 3 | 0;
1559
var offset = this.dac_color_index_read % 3;
1560
var color = this.vga256_palette[index];
1562
this.dac_color_index_read++;
1563
return (color >> (2 - offset) * 8 & 0xFF) / 255 * 63 | 0;
1566
VGAScreen.prototype.port3CC_read = function()
1568
dbg_log("3CC read", LOG_VGA);
1569
return this.miscellaneous_output_register;
1572
VGAScreen.prototype.port3CE_write = function(value)
1574
this.graphics_index = value;
1577
VGAScreen.prototype.port3CE_read = function()
1579
return this.graphics_index;
1588
VGAScreen.prototype.port3CF_write = function(value)
1590
switch(this.graphics_index)
1593
this.planar_setreset = value;
1594
dbg_log("plane set/reset: " + h(value), LOG_VGA);
1597
this.planar_setreset_enable = value;
1598
dbg_log("plane set/reset enable: " + h(value), LOG_VGA);
1601
this.color_compare = value;
1602
dbg_log("color compare: " + h(value), LOG_VGA);
1605
this.planar_rotate_reg = value;
1606
dbg_log("plane rotate: " + h(value), LOG_VGA);
1609
this.plane_read = value;
1610
dbg_log("plane read: " + h(value), LOG_VGA);
1613
var previous_planar_mode = this.planar_mode;
1614
this.planar_mode = value;
1615
dbg_log("planar mode: " + h(value), LOG_VGA);
1616
if((previous_planar_mode ^ value) & 0x60)
1619
this.complete_replot();
1623
dbg_log("miscellaneous graphics register: " + h(value), LOG_VGA);
1624
if(this.miscellaneous_graphics_register !== value)
1626
this.miscellaneous_graphics_register = value;
1627
this.update_vga_size();
1631
this.color_dont_care = value;
1632
dbg_log("color don't care: " + h(value), LOG_VGA);
1635
this.planar_bitmap = value;
1636
dbg_log("planar bitmap: " + h(value), LOG_VGA);
1639
dbg_log("3CF / graphics write " + h(this.graphics_index) + ": " + h(value), LOG_VGA);
1643
VGAScreen.prototype.port3CF_read = function()
1645
dbg_log("3CF / graphics read " + h(this.graphics_index), LOG_VGA);
1647
switch(this.graphics_index)
1650
return this.planar_setreset;
1652
return this.planar_setreset_enable;
1654
return this.color_compare;
1656
return this.planar_rotate_reg;
1658
return this.plane_read;
1660
return this.planar_mode;
1662
return this.miscellaneous_graphics_register;
1664
return this.color_dont_care;
1666
return this.planar_bitmap;
1672
VGAScreen.prototype.port3D4_write = function(register)
1674
dbg_log("3D4 / crtc index: " + register, LOG_VGA);
1675
this.index_crtc = register;
1678
VGAScreen.prototype.port3D4_read = function()
1680
dbg_log("3D4 read / crtc index: " + this.index_crtc, LOG_VGA);
1681
return this.index_crtc;
1690
VGAScreen.prototype.port3D5_write = function(value)
1692
switch(this.index_crtc)
1695
dbg_log("3D5 / hdisp enable end write: " + h(value), LOG_VGA);
1696
if(this.horizontal_display_enable_end !== value)
1698
this.horizontal_display_enable_end = value;
1699
this.update_vga_size();
1703
if(this.horizontal_blank_start !== value)
1705
this.horizontal_blank_start = value;
1706
this.update_vga_size();
1710
dbg_log("3D5 / overflow register write: " + h(value), LOG_VGA);
1711
var previous_vertical_display_enable_end = this.vertical_display_enable_end;
1712
this.vertical_display_enable_end &= 0xFF;
1713
this.vertical_display_enable_end |= (value << 3 & 0x200) | (value << 7 & 0x100);
1714
if(previous_vertical_display_enable_end != this.vertical_display_enable_end)
1716
this.update_vga_size();
1718
this.line_compare = (this.line_compare & 0x2FF) | (value << 4 & 0x100);
1720
var previous_vertical_blank_start = this.vertical_blank_start;
1721
this.vertical_blank_start = (this.vertical_blank_start & 0x2FF) | (value << 5 & 0x100);
1722
if(previous_vertical_blank_start !== this.vertical_blank_start)
1724
this.update_vga_size();
1726
this.update_layers();
1729
dbg_log("3D5 / preset row scan write: " + h(value), LOG_VGA);
1730
this.preset_row_scan = value;
1731
this.update_layers();
1734
dbg_log("3D5 / max scan line write: " + h(value), LOG_VGA);
1735
this.max_scan_line = value;
1736
this.line_compare = (this.line_compare & 0x1FF) | (value << 3 & 0x200);
1738
var previous_vertical_blank_start = this.vertical_blank_start;
1739
this.vertical_blank_start = (this.vertical_blank_start & 0x1FF) | (value << 4 & 0x200);
1740
if(previous_vertical_blank_start !== this.vertical_blank_start)
1742
this.update_vga_size();
1745
this.update_layers();
1748
dbg_log("3D5 / cursor scanline start write: " + h(value), LOG_VGA);
1749
this.cursor_scanline_start = value;
1750
this.update_cursor_scanline();
1753
dbg_log("3D5 / cursor scanline end write: " + h(value), LOG_VGA);
1754
this.cursor_scanline_end = value;
1755
this.update_cursor_scanline();
1758
if((this.start_address >> 8 & 0xFF) !== value)
1760
this.start_address = this.start_address & 0xff | value << 8;
1761
this.update_layers();
1762
if(~this.crtc_mode & 0x3)
1766
this.complete_replot();
1769
dbg_log("3D5 / start addr hi write: " + h(value) + " -> " + h(this.start_address, 4), LOG_VGA);
1772
if((this.start_address & 0xFF) !== value)
1774
this.start_address = this.start_address & 0xff00 | value;
1775
this.update_layers();
1776
if(~this.crtc_mode & 0x3)
1780
this.complete_replot();
1783
dbg_log("3D5 / start addr lo write: " + h(value) + " -> " + h(this.start_address, 4), LOG_VGA);
1786
dbg_log("3D5 / cursor address hi write: " + h(value), LOG_VGA);
1787
this.cursor_address = this.cursor_address & 0xFF | value << 8;
1788
this.update_cursor();
1791
dbg_log("3D5 / cursor address lo write: " + h(value), LOG_VGA);
1792
this.cursor_address = this.cursor_address & 0xFF00 | value;
1793
this.update_cursor();
1796
dbg_log("3D5 / vdisp enable end write: " + h(value), LOG_VGA);
1797
if((this.vertical_display_enable_end & 0xFF) !== value)
1799
this.vertical_display_enable_end = (this.vertical_display_enable_end & 0x300) | value;
1800
this.update_vga_size();
1804
dbg_log("3D5 / offset register write: " + h(value), LOG_VGA);
1805
if(this.offset_register !== value)
1807
this.offset_register = value;
1808
this.update_vga_size();
1810
if(~this.crtc_mode & 0x3)
1814
this.complete_replot();
1819
dbg_log("3D5 / underline location write: " + h(value), LOG_VGA);
1820
if(this.underline_location_register !== value)
1822
var previous_underline = this.underline_location_register;
1824
this.underline_location_register = value;
1825
this.update_vga_size();
1827
if((previous_underline ^ value) & 0x40)
1830
this.complete_replot();
1835
dbg_log("3D5 / vertical blank start write: " + h(value), LOG_VGA);
1836
if((this.vertical_blank_start & 0xFF) !== value)
1838
this.vertical_blank_start = (this.vertical_blank_start & 0x300) | value;
1839
this.update_vga_size();
1843
dbg_log("3D5 / crtc mode write: " + h(value), LOG_VGA);
1844
if(this.crtc_mode !== value)
1846
var previous_mode = this.crtc_mode;
1848
this.crtc_mode = value;
1849
this.update_vga_size();
1851
if((previous_mode ^ value) & 0x43)
1855
this.complete_replot();
1860
dbg_log("3D5 / line compare write: " + h(value), LOG_VGA);
1861
this.line_compare = (this.line_compare & 0x300) | value;
1862
this.update_layers();
1865
if(this.index_crtc < this.crtc.length)
1867
this.crtc[this.index_crtc] = value;
1869
dbg_log("3D5 / CRTC write " + h(this.index_crtc) + ": " + h(value), LOG_VGA);
1874
VGAScreen.prototype.port3D5_read = function()
1876
dbg_log("3D5 read " + h(this.index_crtc), LOG_VGA);
1878
switch(this.index_crtc)
1881
return this.horizontal_display_enable_end;
1883
return this.horizontal_blank_start;
1885
return (this.vertical_display_enable_end >> 7 & 0x2) |
1886
(this.vertical_blank_start >> 5 & 0x8) |
1887
(this.line_compare >> 4 & 0x10) |
1888
(this.vertical_display_enable_end >> 3 & 0x40);
1890
return this.preset_row_scan;
1892
return this.max_scan_line;
1894
return this.cursor_scanline_start;
1896
return this.cursor_scanline_end;
1898
return this.start_address & 0xFF;
1900
return this.start_address >> 8;
1902
return this.cursor_address >> 8;
1904
return this.cursor_address & 0xFF;
1906
return this.vertical_display_enable_end & 0xFF;
1908
return this.offset_register;
1910
return this.underline_location_register;
1912
return this.vertical_blank_start & 0xFF;
1914
return this.crtc_mode;
1916
return this.line_compare & 0xFF;
1919
if(this.index_crtc < this.crtc.length)
1921
return this.crtc[this.index_crtc];
1929
VGAScreen.prototype.port3DA_read = function()
1931
dbg_log("3DA read - status 1 and clear attr index", LOG_VGA);
1933
var value = this.port_3DA_value;
1937
if(!this.graphical_mode)
1941
if(this.port_3DA_value & 1)
1943
this.port_3DA_value ^= 8;
1945
this.port_3DA_value ^= 1;
1949
this.port_3DA_value ^= 1;
1950
this.port_3DA_value &= 1;
1952
this.attribute_controller_index = -1;
1956
VGAScreen.prototype.port1CE_write = function(value)
1958
this.dispi_index = value;
1961
VGAScreen.prototype.port1CF_write = function(value)
1963
dbg_log("1CF / dispi write " + h(this.dispi_index) + ": " + h(value), LOG_VGA);
1965
switch(this.dispi_index)
1968
this.svga_width = value;
1969
if(this.svga_width > MAX_XRES)
1971
dbg_log("svga_width reduced from " + this.svga_width + " to " + MAX_XRES, LOG_VGA);
1972
this.svga_width = MAX_XRES;
1976
this.svga_height = value;
1977
if(this.svga_height > MAX_YRES)
1979
dbg_log("svga_height reduced from " + this.svga_height + " to " + MAX_YRES, LOG_VGA);
1980
this.svga_height = MAX_YRES;
1984
this.svga_bpp = value;
1988
this.svga_enabled = (value & 1) === 1;
1989
this.dispi_enable_value = value;
1992
dbg_log("SVGA bank offset: " + h(value << 16));
1993
this.svga_bank_offset = value << 16;
1997
const offset = value * this.svga_width;
1998
dbg_log("SVGA offset: " + h(offset) + " y=" + h(value), LOG_VGA);
1999
if(this.svga_offset !== offset)
2001
this.svga_offset = offset;
2002
this.complete_redraw();
2008
if(this.svga_enabled && (!this.svga_width || !this.svga_height))
2010
dbg_log("SVGA: disabled because of invalid width/height: " + this.svga_width + "x" + this.svga_height, LOG_VGA);
2011
this.svga_enabled = false;
2014
dbg_assert(this.svga_bpp !== 4, "unimplemented svga bpp: 4");
2015
dbg_assert(this.svga_bpp === 4 || this.svga_bpp === 8 ||
2016
this.svga_bpp === 15 || this.svga_bpp === 16 ||
2017
this.svga_bpp === 24 || this.svga_bpp === 32,
2018
"unexpected svga bpp: " + this.svga_bpp);
2020
dbg_log("SVGA: enabled=" + this.svga_enabled + ", " + this.svga_width + "x" + this.svga_height + "x" + this.svga_bpp, LOG_VGA);
2022
if(this.svga_enabled && this.dispi_index === 4)
2024
this.set_size_graphical(this.svga_width, this.svga_height, this.svga_bpp, this.svga_width, this.svga_height);
2025
this.bus.send("screen-set-mode", true);
2026
this.graphical_mode = true;
2027
this.graphical_mode_is_linear = true;
2030
if(!this.svga_enabled)
2032
this.svga_bank_offset = 0;
2035
this.update_layers();
2038
VGAScreen.prototype.port1CF_read = function()
2040
dbg_log("1CF / dispi read " + h(this.dispi_index), LOG_VGA);
2041
return this.svga_register_read(this.dispi_index);
2044
VGAScreen.prototype.svga_register_read = function(n)
2052
return this.dispi_enable_value & 2 ? MAX_XRES : this.svga_width;
2054
return this.dispi_enable_value & 2 ? MAX_YRES : this.svga_height;
2056
return this.dispi_enable_value & 2 ? MAX_BPP : this.svga_bpp;
2058
return this.dispi_enable_value;
2060
return this.svga_bank_offset >>> 16;
2063
if(this.screen_width)
2065
return this.screen_width;
2078
return this.vga_memory_size / VGA_BANK_SIZE | 0;
2089
VGAScreen.prototype.vga_replot = function()
2092
var start = this.diff_plot_min & ~0xF;
2093
var end = Math.min((this.diff_plot_max | 0xF), VGA_PIXEL_BUFFER_SIZE - 1);
2095
var addr_shift = this.vga_addr_shift_count();
2096
var addr_substitution = ~this.crtc_mode & 0x3;
2098
var shift_mode = this.planar_mode & 0x60;
2099
var pel_width = this.attribute_mode & 0x40;
2101
for(var pixel_addr = start; pixel_addr <= end;)
2103
var addr = pixel_addr >>> addr_shift;
2104
if(addr_substitution)
2106
var row = pixel_addr / this.virtual_width | 0;
2107
var col = pixel_addr - this.virtual_width * row;
2109
switch(addr_substitution)
2114
addr = (row & 0x1) << 13;
2120
addr = (row & 0x1) << 14;
2126
addr = (row & 0x3) << 13;
2131
addr |= (row * this.virtual_width + col >>> addr_shift) + this.start_address;
2134
var byte0 = this.plane0[addr];
2135
var byte1 = this.plane1[addr];
2136
var byte2 = this.plane2[addr];
2137
var byte3 = this.plane3[addr];
2139
var shift_loads = new Uint8Array(8);
2152
for(var i = 7; i >= 0; i--)
2154
shift_loads[7 - i] =
2165
shift_loads[0] = (byte0 >> 6 & 0x3) | (byte2 >> 4 & 0xC);
2166
shift_loads[1] = (byte0 >> 4 & 0x3) | (byte2 >> 2 & 0xC);
2167
shift_loads[2] = (byte0 >> 2 & 0x3) | (byte2 >> 0 & 0xC);
2168
shift_loads[3] = (byte0 >> 0 & 0x3) | (byte2 << 2 & 0xC);
2170
shift_loads[4] = (byte1 >> 6 & 0x3) | (byte3 >> 4 & 0xC);
2171
shift_loads[5] = (byte1 >> 4 & 0x3) | (byte3 >> 2 & 0xC);
2172
shift_loads[6] = (byte1 >> 2 & 0x3) | (byte3 >> 0 & 0xC);
2173
shift_loads[7] = (byte1 >> 0 & 0x3) | (byte3 << 2 & 0xC);
2180
shift_loads[0] = byte0 >> 4 & 0xF;
2181
shift_loads[1] = byte0 >> 0 & 0xF;
2182
shift_loads[2] = byte1 >> 4 & 0xF;
2183
shift_loads[3] = byte1 >> 0 & 0xF;
2184
shift_loads[4] = byte2 >> 4 & 0xF;
2185
shift_loads[5] = byte2 >> 0 & 0xF;
2186
shift_loads[6] = byte3 >> 4 & 0xF;
2187
shift_loads[7] = byte3 >> 0 & 0xF;
2194
for(var i = 0, j = 0; i < 4; i++, pixel_addr++, j += 2)
2196
this.pixel_buffer[pixel_addr] = (shift_loads[j] << 4) | shift_loads[j + 1];
2201
for(var i = 0; i < 8; i++, pixel_addr++)
2203
this.pixel_buffer[pixel_addr] = shift_loads[i];
2215
VGAScreen.prototype.vga_redraw = function()
2217
var start = this.diff_addr_min;
2218
var end = Math.min(this.diff_addr_max, VGA_PIXEL_BUFFER_SIZE - 1);
2219
const buffer = new Int32Array(this.cpu.wasm_memory.buffer, this.dest_buffet_offset, this.virtual_width * this.virtual_height);
2222
var colorset = 0x00;
2223
if(this.attribute_mode & 0x80)
2227
colorset |= this.color_select << 4 & 0x30;
2230
if(this.attribute_mode & 0x40)
2234
for(var pixel_addr = start; pixel_addr <= end; pixel_addr++)
2236
var color256 = (this.pixel_buffer[pixel_addr] & mask) | colorset;
2237
var color = this.vga256_palette[color256];
2239
buffer[pixel_addr] = color & 0xFF00 | color << 16 | color >> 16 | 0xFF000000;
2248
colorset |= this.color_select << 4 & 0xC0;
2250
for(var pixel_addr = start; pixel_addr <= end; pixel_addr++)
2252
var color16 = this.pixel_buffer[pixel_addr] & this.color_plane_enable;
2253
var color256 = (this.dac_map[color16] & mask) | colorset;
2254
var color = this.vga256_palette[color256];
2256
buffer[pixel_addr] = color & 0xFF00 | color << 16 | color >> 16 | 0xFF000000;
2261
VGAScreen.prototype.screen_fill_buffer = function()
2263
if(!this.graphical_mode)
2268
this.update_vertical_retrace();
2272
if(this.image_data.data.byteLength === 0)
2275
const buffer = new Uint8ClampedArray(this.cpu.wasm_memory.buffer, this.dest_buffet_offset, 4 * this.virtual_width * this.virtual_height);
2276
this.image_data = new ImageData(buffer, this.virtual_width, this.virtual_height);
2277
this.update_layers();
2280
if(this.svga_enabled)
2283
let max_y = this.svga_height;
2285
if(this.svga_bpp === 8)
2289
const buffer = new Int32Array(this.cpu.wasm_memory.buffer, this.dest_buffet_offset, this.screen_width * this.screen_height);
2290
const svga_memory = new Uint8Array(this.cpu.wasm_memory.buffer, this.svga_memory.byteOffset, this.vga_memory_size);
2292
for(var i = 0; i < buffer.length; i++)
2294
var color = this.vga256_palette[svga_memory[i]];
2295
buffer[i] = color & 0xFF00 | color << 16 | color >> 16 | 0xFF000000;
2300
this.cpu.svga_fill_pixel_buffer(this.svga_bpp, this.svga_offset);
2302
const bytes_per_pixel = this.svga_bpp === 15 ? 2 : this.svga_bpp / 8;
2303
min_y = (((this.cpu.svga_dirty_bitmap_min_offset[0] / bytes_per_pixel | 0) - this.svga_offset) / this.svga_width | 0);
2304
max_y = (((this.cpu.svga_dirty_bitmap_max_offset[0] / bytes_per_pixel | 0) - this.svga_offset) / this.svga_width | 0) + 1;
2309
min_y = Math.max(min_y, 0);
2310
max_y = Math.min(max_y, this.svga_height);
2312
this.bus.send("screen-fill-buffer-end", [{
2313
image_data: this.image_data,
2314
screen_x: 0, screen_y: min_y,
2315
buffer_x: 0, buffer_y: min_y,
2316
buffer_width: this.svga_width,
2317
buffer_height: max_y - min_y,
2325
this.bus.send("screen-fill-buffer-end", this.layers);
2329
this.update_vertical_retrace();