From e94cfac0006ce5f8b3aa665d199d4de7d4ecee27 Mon Sep 17 00:00:00 2001 From: David Kuder Date: Fri, 28 Apr 2023 23:23:03 -0400 Subject: [PATCH] Video 7 support --- common/cfgtoken.h | 3 + common/config.c | 81 ++++++++++++++++++- common/main.c | 27 ++++--- vga/businterface.c | 26 ++++-- vga/render.c | 2 +- vga/render.h | 5 ++ vga/render_80col.c | 60 ++++++++++++-- vga/render_dgr.c | 8 +- vga/render_dhgr.c | 67 ++++++++++++---- vga/render_hires.c | 8 +- vga/render_lores.c | 8 +- vga/render_text.c | 193 ++++++++++++++++++++++++++++++++++++++++++++- 12 files changed, 419 insertions(+), 69 deletions(-) diff --git a/common/cfgtoken.h b/common/cfgtoken.h index e842b5d..a21d9b6 100644 --- a/common/cfgtoken.h +++ b/common/cfgtoken.h @@ -55,3 +55,6 @@ #define CFGTOKEN_TBCOLOR 0x00005456 // "VT\xXX\x00" Custom default TBCOLOR #define CFGTOKEN_BORDER 0x00004256 // "VB\xXX\x00" Custom default BORDER + +#define CFGTOKEN_VIDEO7 0x00003756 // "V7\xXX\x00" Video 7 Enable / Disable +#define CFGTOKEN_RGBCOLOR 0x00005043 // "CP\xXX\x04" RGB Palette Entry Override diff --git a/common/config.c b/common/config.c index fabb20a..6b90943 100644 --- a/common/config.c +++ b/common/config.c @@ -15,8 +15,10 @@ extern volatile uint8_t romx_changed; #include +#ifdef ANALOG_GS volatile compat_t cfg_machine = MACHINE_AUTO; volatile compat_t current_machine = MACHINE_AUTO; +#endif #ifdef FUNCTION_Z80 volatile usbmux_t usbmux; @@ -68,21 +70,29 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) { switch(config[i] & 0x0000FFFF) { case CFGTOKEN_HOST_AUTO: cfg_machine = MACHINE_AUTO; + internal_flags |= (IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); break; case CFGTOKEN_HOST_II: cfg_machine = MACHINE_II; + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); break; case CFGTOKEN_HOST_IIE: cfg_machine = MACHINE_IIE; + internal_flags |= IFLAGS_IIE_REGS; + internal_flags &= ~IFLAGS_IIGS_REGS; break; case CFGTOKEN_HOST_IIGS: cfg_machine = MACHINE_IIGS; + internal_flags &= ~IFLAGS_IIE_REGS; + internal_flags |= IFLAGS_IIGS_REGS; break; case CFGTOKEN_HOST_PRAVETZ: cfg_machine = MACHINE_PRAVETZ; + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); break; case CFGTOKEN_HOST_BASIS: cfg_machine = MACHINE_BASIS; + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); break; #ifdef FUNCTION_VGA case CFGTOKEN_FONT_00: @@ -98,6 +108,17 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) { case CFGTOKEN_BORDER: terminal_border = (config[i] >> 16) & 0xF; break; + case CFGTOKEN_RGBCOLOR: + lores_palette[(config[i] >> 16) & 0xF] = config[i+1]; + dhgr_palette[((config[i] >> 17) & 0x7) | ((config[i] >> 13) & 0x8)] = config[i+1]; + break; + case CFGTOKEN_VIDEO7: + if((config[i] >> 16) & 1) { + internal_flags |= IFLAGS_VIDEO7; + } else { + internal_flags &= ~IFLAGS_VIDEO7; + } + break; #elif defined(FUNCTION_Z80) case CFGTOKEN_MUX_LOOP: serialmux[(config[i] >> 16) & 1] = SERIAL_LOOP; @@ -172,7 +193,17 @@ void DELAYED_COPY_CODE(default_config)() { strcpy((char*)wifi_ssid, "V2RetroNet"); strcpy((char*)wifi_psk, "Analog"); #endif +#ifdef ANALOG_GS + cfg_machine = MACHINE_IIGS; + current_machine = MACHINE_IIGS; + internal_flags &= ~IFLAGS_IIE_REGS; + internal_flags |= IFLAGS_IIGS_REGS; +#else cfg_machine = MACHINE_AUTO; + current_machine = MACHINE_AUTO; + internal_flags |= (IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); +#endif + internal_flags |= IFLAGS_VIDEO7; } int DELAYED_COPY_CODE(make_config)(uint32_t rev) { @@ -277,6 +308,13 @@ int DELAYED_COPY_CODE(make_config)(uint32_t rev) { config_temp[i++] = CFGTOKEN_MONO_00 | ((mono_palette & 0xF) << 20); config_temp[i++] = CFGTOKEN_TBCOLOR | ((terminal_tbcolor & 0xFF) << 16); config_temp[i++] = CFGTOKEN_BORDER | ((terminal_border & 0xF) << 16); + + config_temp[i++] = CFGTOKEN_VIDEO7 | ((internal_flags & IFLAGS_VIDEO7) ? (1ul<<16) : 0); + + for(uint32_t j = 0; j < 16; j++) { + config_temp[i++] = CFGTOKEN_RGBCOLOR | (j << 16); + config_temp[i++] = lores_palette[j]; + } #endif config_temp[i++] = NEWCONFIG_EOF_MARKER; @@ -320,12 +358,14 @@ uint8_t DELAYED_COPY_CODE(get_config_rev)(uint32_t address) { // Every time we write the config we overwrite the older slot, // ensuring we don't leave the user without a configuration. // We increment the revision number each time, wrapping back to 0x00 from 0xFF. +#if 0 bool DELAYED_COPY_CODE(is_primary_config_newer)() { uint8_t a=get_config_rev(FLASH_CONFIG_PRIMARY); uint8_t b=get_config_rev(FLASH_CONFIG_SECONDARY); return ((int8_t)(a-b)) >= 0; } +#endif bool DELAYED_COPY_CODE(read_config)() { if(is_config_valid(FLASH_CONFIG_ONETIME)) { @@ -334,6 +374,13 @@ bool DELAYED_COPY_CODE(read_config)() { if(parse_config(FLASH_CONFIG_ONETIME)) return true; } + + if(is_config_valid(FLASH_CONFIG_PRIMARY)) { + if(parse_config(FLASH_CONFIG_PRIMARY)) + return true; + } + +#if 0 if(is_config_valid(FLASH_CONFIG_PRIMARY)) { if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) { if(parse_config(FLASH_CONFIG_PRIMARY)) @@ -344,6 +391,7 @@ bool DELAYED_COPY_CODE(read_config)() { if(parse_config(FLASH_CONFIG_SECONDARY)) return true; } +#endif default_config(); return false; @@ -359,6 +407,10 @@ bool DELAYED_COPY_CODE(write_config)(bool onetime) { vga_dpms_sleep(); #endif + write_secondary = false; + rev = get_config_rev(FLASH_CONFIG_PRIMARY); + +#if 0 if(is_config_valid(FLASH_CONFIG_PRIMARY) && is_config_valid(FLASH_CONFIG_SECONDARY)) { write_secondary = is_primary_config_newer(); rev = write_secondary ? get_config_rev(FLASH_CONFIG_PRIMARY) : get_config_rev(FLASH_CONFIG_SECONDARY); @@ -369,9 +421,9 @@ bool DELAYED_COPY_CODE(write_config)(bool onetime) { write_secondary = false; rev = get_config_rev(FLASH_CONFIG_SECONDARY); } +#endif if(make_config(rev + 1) <= CONFIG_SIZE) { - if(onetime) { flash_range_erase((FLASH_CONFIG_ONETIME-XIP_BASE), CONFIG_SIZE); flash_range_program((FLASH_CONFIG_ONETIME-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE); @@ -401,6 +453,7 @@ uint8_t DELAYED_COPY_CODE(get_config_block)() { last_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096; next_config_block = last_config_block; +#if 0 if(is_config_valid(FLASH_CONFIG_PRIMARY)) { if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) { last_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096; @@ -413,6 +466,7 @@ uint8_t DELAYED_COPY_CODE(get_config_block)() { last_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096; next_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096; } +#endif config_rpybuf[5] = (next_config_block >> 8) & 0xFF; config_rpybuf[4] = (next_config_block >> 0) & 0xFF; @@ -574,6 +628,31 @@ void DELAYED_COPY_CODE(config_handler)() { config_rpybuf[0] = REPLY_BUSY; switch(config_cmdbuf[0]) { + case 'P': + switch(config_cmdbuf[1]) { + default: + retval = REPLY_ECMD; + break; +#ifdef FUNCTION_VGA + case 'r': + memcpy((void *)cfbuf, lores_palette, 16*2); + cfptr = 0; + retval = REPLY_OK; + break; + case 'T': + for(uint j = 0; j < 16; j++) { +#ifdef ANALOG_GS + lores_palette[j] = ((uint16_t *)cfbuf)[j] & 0xFFF; +#else + lores_palette[j] = ((uint16_t *)cfbuf)[j] & 0x1FF; +#endif + } + cfptr = 0; + retval = REPLY_OK; + break; +#endif + } + break; case 'C': switch(config_cmdbuf[1]) { default: diff --git a/common/main.c b/common/main.c index 5087585..2b5c9b7 100644 --- a/common/main.c +++ b/common/main.c @@ -46,25 +46,25 @@ static void __noinline __time_critical_func(core1_loop)() { // Config memory in card slot-rom address space if(ACCESS_WRITE) { if((address & 0xFF) == 0xEC) { - apple_memory[address] = value; - cfptr = (cfptr & 0x0F00) | value; + apple_memory[address] = (value & 0xff); + cfptr = (cfptr & 0x0F00) | (value & 0xff); apple_memory[address+2] = cfbuf[cfptr]; // $CnEE apple_memory[address+3] = cfbuf[cfptr]; // $CnEF } if((address & 0xFF) == 0xED) { - apple_memory[address] = value & 0x0F; + apple_memory[address] = (value & 0x0F); cfptr = ((cfptr & 0xFF) | (((uint16_t)value) << 8)) & 0xFFF; apple_memory[address+1] = cfbuf[cfptr]; // $CnEE apple_memory[address+2] = cfbuf[cfptr]; // $CnEF } if((address & 0xFF) == 0xEF) { - cfbuf[cfptr] = value; + cfbuf[cfptr] = (value & 0xff); cfptr = (cfptr + 1) & 0x0FFF; apple_memory[address-1] = cfbuf[cfptr]; // $CnEE apple_memory[address] = cfbuf[cfptr]; // $CnEF } if((address & 0xFF) >= 0xF0) { - apple_memory[address] = value; + apple_memory[address] = (value & 0xff); } } else if((address & 0xFF) == 0xEE) { cfptr = (cfptr + 1) & 0x0FFF; @@ -76,7 +76,12 @@ static void __noinline __time_critical_func(core1_loop)() { } #ifdef FUNCTION_VGA } else if(current_machine == MACHINE_AUTO) { - if((apple_memory[0x404] == 0xE5) && (apple_memory[0x0403] == 0xD8)) { // ROMXe + if(value & 0x08000000) { + // Hardware jumpered for IIGS mode. + current_machine = MACHINE_IIGS; + internal_flags &= ~IFLAGS_IIE_REGS; + internal_flags |= IFLAGS_IIGS_REGS; + } else if((apple_memory[0x404] == 0xE5) && (apple_memory[0x0403] == 0xD8)) { // ROMXe current_machine = MACHINE_IIE; internal_flags |= IFLAGS_IIE_REGS; internal_flags &= ~IFLAGS_IIGS_REGS; @@ -108,25 +113,27 @@ static void __noinline __time_critical_func(core1_loop)() { #endif } else switch(reset_state) { case 0: - if((value & 0x3FFFF00) == ((0xFFFC << 10) | 0x300)) + if((value & 0x7FFFF00) == ((0xFFFC << 10) | 0x300)) reset_state++; break; case 1: - if((value & 0x3FFFF00) == ((0xFFFD << 10) | 0x300)) + if((value & 0x7FFFF00) == ((0xFFFD << 10) | 0x300)) reset_state++; else reset_state=0; break; case 2: - if((value & 0x3FFFF00) == ((0xFA62 << 10) | 0x300)) + if((value & 0x7FFFF00) == ((0xFA62 << 10) | 0x300)) reset_state++; else reset_state=0; break; case 3: #ifdef FUNCTION_VGA - soft_switches = SOFTSW_TEXT_MODE; + soft_switches |= SOFTSW_TEXT_MODE; soft_switches &= ~SOFTSW_80COL; + soft_switches &= ~SOFTSW_DGR; + internal_flags &= ~(IFLAGS_TERMINAL | IFLAGS_TEST | IFLAGS_V7_MODE3); #endif default: reset_state = 0; diff --git a/vga/businterface.c b/vga/businterface.c index 67e2189..06a3379 100644 --- a/vga/businterface.c +++ b/vga/businterface.c @@ -8,14 +8,14 @@ volatile uint8_t *terminal_page = terminal_memory; void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { - // Shadow parts of the Apple's memory by observing the bus write cycles - if((address < 0xC000) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { - // Apple IIgs: CARD_SELECT is pulled low by our CPLD when M2B0 is active and addr < $C000 #ifdef ANALOG_GS - if(CARD_SELECT) { + // Apple IIgs: Bit 27 is GS jumper closed, Bit 26 is M2B0 + if(value & 0x4000000) { + if(ACCESS_WRITE) { private_memory[address] = value & 0xff; - return; } + return; + } #endif // Shadow parts of the Apple's memory by observing the bus write cycles @@ -156,6 +156,11 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { } break; case 0x5f: + // Video 7 shift register + if(!soft_switches & SOFTSW_DGR) { + internal_flags = (internal_flags & 0xfffffffc) | ((internal_flags & 0x1) << 1) | ((soft_switches & SOFTSW_80COL) ? 1 : 0); + } + if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) { soft_switches &= ~SOFTSW_DGR; } @@ -239,11 +244,16 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { switch(address & 0x0F) { case 0x01: mono_palette = (value >> 4) & 0xF; - if(value & 0x8) { + if(value & 8) { internal_flags |= IFLAGS_OLDCOLOR; } else { internal_flags &= ~IFLAGS_OLDCOLOR; } + if(value & 4) { + internal_flags |= IFLAGS_VIDEO7; + } else { + internal_flags &= ~IFLAGS_VIDEO7; + } apple_memory[address] = value; break; case 0x02: @@ -255,10 +265,10 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { apple_memory[address] = terminal_border; break; case 0x08: - soft_switches &= ~SOFTSW_TERMINAL; + internal_flags &= ~IFLAGS_TERMINAL; break; case 0x09: - soft_switches |= SOFTSW_TERMINAL; + internal_flags |= IFLAGS_TERMINAL; break; case 0x0A: terminal_fifo[terminal_fifo_wrptr++] = (value & 0xFF); diff --git a/vga/render.c b/vga/render.c index 910cf25..2a02231 100644 --- a/vga/render.c +++ b/vga/render.c @@ -213,7 +213,7 @@ void DELAYED_COPY_CODE(render_loop)() { vga_prepare_frame(); render_shr(); #endif - } else if(soft_switches & SOFTSW_TERMINAL) { + } else if(internal_flags & IFLAGS_TERMINAL) { vga_prepare_frame(); render_terminal(); } else { diff --git a/vga/render.h b/vga/render.h index a33c7c4..b6a16b0 100644 --- a/vga/render.h +++ b/vga/render.h @@ -6,6 +6,8 @@ #define RENDER_TEST_PATTERN extern uint16_t lores_palette[16]; +extern uint16_t dhgr_palette[16]; + extern uint16_t text_fore, text_back, text_border; extern uint8_t status_line[81]; extern bool mono_rendering; @@ -25,8 +27,11 @@ extern void render_test_sleep(); extern void update_text_flasher(); extern void render_text(); +extern void render_mixed_text(); extern void render_text40_line(bool p2, unsigned int line); extern void render_text80_line(bool p2, unsigned int line); +extern void render_color_text40_line(unsigned int line); +extern void render_color_text80_line(unsigned int line); extern void render_status_line(); extern void render_terminal(); diff --git a/vga/render_80col.c b/vga/render_80col.c index 976e989..3b8d018 100644 --- a/vga/render_80col.c +++ b/vga/render_80col.c @@ -9,6 +9,7 @@ uint8_t terminal_jsoffset = 0; uint8_t terminal_ssoffset = 0; +bool terminal_inverse = 0; bool terminal_esc = 0; bool terminal_esc_crz = 0; int terminal_esc_pos = 0; @@ -26,15 +27,19 @@ static inline uint_fast8_t char_terminal_bits(uint_fast8_t ch, uint_fast8_t glyp return (bits & 0x7f); } +static void DELAYED_COPY_CODE(terminal_scroll)() { + // Clear the next text buffer line (using dma if possible) + memset((void*)(terminal_memory+(((terminal_height+terminal_jsoffset) * 128) & 0xFFF)), ' ', 128); + + // Smooth scroll then increment jsoffset + terminal_ssoffset = 1; +} + static void DELAYED_COPY_CODE(terminal_linefeed)() { if(terminal_row < (terminal_height-1)) { terminal_row++; } else { - // Clear the next text buffer line (using dma if possible) - memset((void*)(terminal_memory+(((terminal_row+1+terminal_jsoffset) * 128) & 0xFFF)), ' ', 128); - - // Smooth scroll then increment jsoffset - terminal_ssoffset = 1; + terminal_scroll(); } } @@ -89,7 +94,7 @@ void DELAYED_COPY_CODE(terminal_process_input)() { terminal_clear_screen(); break; case '1': - soft_switches &= ~SOFTSW_TERMINAL; + internal_flags &= ~IFLAGS_TERMINAL; break; case '2': terminal_charset = 0; @@ -104,17 +109,30 @@ void DELAYED_COPY_CODE(terminal_process_input)() { } terminal_esc_crz = false; } else if(terminal_esc) { + terminal_esc = false; switch(ch) { + case 'K': + case '>': + terminal_esc = true; case 'A': terminal_advance_cursor(); break; + case 'J': + case '<': + terminal_esc = true; case 'B': if(terminal_col > 0) terminal_col--; break; + case 'M': + case 'v': + terminal_esc = true; case 'C': terminal_linefeed(); break; + case 'I': + case '^': + terminal_esc = true; case 'D': // Reverse Linefeed if(terminal_row > 0) terminal_row--; @@ -128,14 +146,25 @@ void DELAYED_COPY_CODE(terminal_process_input)() { case '@': // Clear screen terminal_clear_screen(); break; + case '4': + internal_flags &= ~IFLAGS_TERMINAL; + break; + case '8': + internal_flags |= IFLAGS_TERMINAL; + break; default: terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch; terminal_advance_cursor(); break; } - terminal_esc = false; } else switch(ch) { + case 0x07: + break; + case 0x08: + if(terminal_col > 0) + terminal_col--; + break; case 0x0A: // Line Feed terminal_linefeed(); break; @@ -148,10 +177,25 @@ void DELAYED_COPY_CODE(terminal_process_input)() { case 0x0D: // Ctrl-M: Carriage Return terminal_col = 0; break; + case 0x0E: // Normal Text + terminal_inverse = false; + break; + case 0x0F: // Inverse Text + terminal_inverse = true; + break; + case 0x11: + internal_flags &= ~IFLAGS_TERMINAL; + break; + case 0x12: + internal_flags |= IFLAGS_TERMINAL; + break; case 0x13: // Ctrl-S: Xon/Xoff (unimplemented) break; case 0x15: // Ctrl-U: Copy (unimplemented) break; + case 0x17: // Ctrl-W: Scroll one line without moving cursor + terminal_scroll(); + break; case 0x19: // Ctrl-Y: Home Cursor terminal_row = 0; terminal_col = 0; @@ -176,7 +220,7 @@ void DELAYED_COPY_CODE(terminal_process_input)() { terminal_row--; break; default: - terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch; + terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch ^ (terminal_inverse ? 0x80 : 0x00); terminal_advance_cursor(); break; } diff --git a/vga/render_dgr.c b/vga/render_dgr.c index 94d5f5f..990a05a 100644 --- a/vga/render_dgr.c +++ b/vga/render_dgr.c @@ -30,13 +30,7 @@ void DELAYED_COPY_CODE(render_mixed_dgr)() { render_dgr_line(PAGE2SEL, line); } - for(uint line=20; line < 24; line++) { - if(soft_switches & SOFTSW_80COL) { - render_text80_line(PAGE2SEL, line); - } else { - render_text40_line(PAGE2SEL, line); - } - } + render_mixed_text(); } diff --git a/vga/render_dhgr.c b/vga/render_dhgr.c index 2d17516..3dd623a 100644 --- a/vga/render_dhgr.c +++ b/vga/render_dhgr.c @@ -25,27 +25,25 @@ static inline uint dhgr_line_to_mem_offset(uint line) { void DELAYED_COPY_CODE(render_dhgr)() { + if((internal_flags & IFLAGS_VIDEO7) && (internal_flags & IFLAGS_V7_MODE3 == IFLAGS_V7_MODE3)) { + mono_rendering = true; + } for(uint line=0; line < 192; line++) { render_dhgr_line(PAGE2SEL, line); } } - void DELAYED_COPY_CODE(render_mixed_dhgr)() { + if((internal_flags & IFLAGS_VIDEO7) && (internal_flags & IFLAGS_V7_MODE3 == IFLAGS_V7_MODE3)) { + mono_rendering = true; + } for(uint line=0; line < 160; line++) { render_dhgr_line(PAGE2SEL, line); } - for(uint line=20; line < 24; line++) { - if(soft_switches & SOFTSW_80COL) { - render_text80_line(PAGE2SEL, line); - } else { - render_text40_line(PAGE2SEL, line); - } - } + render_mixed_text(); } - static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) { struct vga_scanline *sl = vga_prepare_scanline(); uint sl_pos = 0; @@ -54,10 +52,17 @@ static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) { const uint8_t *line_mema = (const uint8_t *)((p2 ? hgr_p2 : hgr_p1) + dhgr_line_to_mem_offset(line)); const uint8_t *line_memb = (const uint8_t *)((p2 ? hgr_p4 : hgr_p3) + dhgr_line_to_mem_offset(line)); - // Pad 40 pixels on the left to center horizontally - sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word - sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word - sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word + if((internal_flags & IFLAGS_VIDEO7) && ((internal_flags & IFLAGS_V7_MODE3) == IFLAGS_V7_MODE1)) { + // Pad 30 pixels on the left to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_7) << 16); // 12 pixels per word + sl->data[sl_pos++] = (text_border) | ((text_border) << 16); // 2 pixels per word + } else { + // Pad 40 pixels on the left to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word + } // DHGR is weird. Nuff said. uint32_t dots = 0; @@ -86,6 +91,27 @@ static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) { dotc -= 2; } } + } else if((internal_flags & IFLAGS_VIDEO7) && ((internal_flags & IFLAGS_V7_MODE3) == IFLAGS_V7_MODE1)) { + while(i < 40) { + // Load in as many subpixels as possible + while((dotc <= 18) && (i < 40)) { + dots |= (line_memb[i] & 0xff) << dotc; + dotc += 8; + dots |= (line_mema[i] & 0xff) << dotc; + dotc += 8; + i++; + } + + // Consume pixels + while(dotc >= 8) { + pixeldata = (dhgr_palette[dots & 0xf] | THEN_EXTEND_3); + dots >>= 4; + pixeldata |= (dhgr_palette[dots & 0xf] | THEN_EXTEND_3) << 16; + dots >>= 4; + sl->data[sl_pos++] = pixeldata; + dotc -= 8; + } + } } else if(internal_flags & IFLAGS_OLDCOLOR) { while(i < 40) { // Load in as many subpixels as possible @@ -149,10 +175,17 @@ static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) { sl->data[sl_pos++] = pixeldata; } - // Pad 40 pixels on the right to center horizontally - sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word - sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word - sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word + if((internal_flags & IFLAGS_VIDEO7) && ((internal_flags & IFLAGS_V7_MODE3) == IFLAGS_V7_MODE1)) { + // Pad 30 pixels on the right to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_7) << 16); // 12 pixels per word + sl->data[sl_pos++] = (text_border) | ((text_border) << 16); // 2 pixels per word + } else { + // Pad 40 pixels on the right to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word + } sl->length = sl_pos; sl->repeat_count = 1; diff --git a/vga/render_hires.c b/vga/render_hires.c index 676d8a0..18e5656 100644 --- a/vga/render_hires.c +++ b/vga/render_hires.c @@ -29,13 +29,7 @@ void DELAYED_COPY_CODE(render_mixed_hires)() { render_hires_line(PAGE2SEL, line); } - for(uint line=20; line < 24; line++) { - if(soft_switches & SOFTSW_80COL) { - render_text80_line(PAGE2SEL, line); - } else { - render_text40_line(PAGE2SEL, line); - } - } + render_mixed_text(); } static void DELAYED_COPY_CODE(render_hires_line)(bool p2, uint line) { diff --git a/vga/render_lores.c b/vga/render_lores.c index 5d105f4..c76501b 100644 --- a/vga/render_lores.c +++ b/vga/render_lores.c @@ -48,13 +48,7 @@ void DELAYED_COPY_CODE(render_mixed_lores)() { render_lores_line(PAGE2SEL, line); } - for(uint line=20; line < 24; line++) { - if(soft_switches & SOFTSW_80COL) { - render_text80_line(PAGE2SEL, line); - } else { - render_text40_line(PAGE2SEL, line); - } - } + render_mixed_text(); } diff --git a/vga/render_text.c b/vga/render_text.c index 30f4115..bb93662 100644 --- a/vga/render_text.c +++ b/vga/render_text.c @@ -4,6 +4,8 @@ #include "vga/render.h" #include "vga/vgaout.h" +extern uint16_t lores_palette[16]; + //#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2)) #define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2) @@ -48,11 +50,53 @@ static inline uint_fast8_t char_text_bits(uint_fast8_t ch, uint_fast8_t glyph_li } void DELAYED_COPY_CODE(render_text)() { - for(uint line=0; line < 24; line++) { + uint line; + + if((internal_flags & IFLAGS_VIDEO7) && !(soft_switches & SOFTSW_DGR)) { if(soft_switches & SOFTSW_80COL) { - render_text80_line(PAGE2SEL, line); + for(line=0; line < 24; line++) { + render_color_text80_line(line); + } } else { - render_text40_line(PAGE2SEL, line); + for(line=0; line < 24; line++) { + render_color_text40_line(line); + } + } + } else { + if(soft_switches & SOFTSW_80COL) { + for(line=0; line < 24; line++) { + render_text80_line(PAGE2SEL, line); + } + } else { + for(line=0; line < 24; line++) { + render_text40_line(PAGE2SEL, line); + } + } + } +} + +void DELAYED_COPY_CODE(render_mixed_text)() { + uint line; + + if((internal_flags & IFLAGS_VIDEO7) && !(soft_switches & SOFTSW_DGR)) { + if(soft_switches & SOFTSW_80COL) { + for(line=20; line < 24; line++) { + render_color_text80_line(line); + } + } else { + for(line=20; line < 24; line++) { + render_color_text40_line(line); + } + } + } else { + if(soft_switches & SOFTSW_80COL) { + for(line=20; line < 24; line++) { + render_text80_line(PAGE2SEL, line); + } + } else { + for(line=20; line < 24; line++) { + render_text40_line(PAGE2SEL, line); + } } } } @@ -150,3 +194,146 @@ void DELAYED_COPY_CODE(render_text80_line)(bool p2, unsigned int line) { } } +void DELAYED_COPY_CODE(render_color_text40_line)(unsigned int line) { + const uint8_t *line_buf = (const uint8_t *)(text_p1 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); + const uint8_t *color_buf = (const uint8_t *)(text_p3 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); + + for(uint glyph_line=0; glyph_line < 8; glyph_line++) { + struct vga_scanline *sl = vga_prepare_scanline(); + uint sl_pos = 0; + + // Pad 40 pixels on the left to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word + + for(uint col=0; col < 40; ) { + // Grab 14 pixels from the next two characters + uint32_t bits_a = char_text_bits(line_buf[col], glyph_line); + uint16_t color1 = lores_palette[(color_buf[col] >> 4) & 0xf]; + uint16_t color2 = lores_palette[color_buf[col] & 0xf]; + col++; + uint32_t bits_b = char_text_bits(line_buf[col], glyph_line); + uint16_t color3 = lores_palette[(color_buf[col] >> 4) & 0xf]; + uint16_t color4 = lores_palette[color_buf[col] & 0xf]; + col++; + + uint32_t bits = (bits_a << 7) | bits_b; + uint32_t pixeldata; + + // Translate each pair of bits into a pair of pixels + for(int i=0; i < 3; i++) { + pixeldata = (bits & 0x2000) ? (color2|THEN_EXTEND_1) : (color1|THEN_EXTEND_1); + pixeldata |= (bits & 0x1000) ? + (uint32_t)(color2|THEN_EXTEND_1) << 16 : + (uint32_t)(color1|THEN_EXTEND_1) << 16; + bits <<= 2; + + sl->data[sl_pos] = pixeldata; + sl_pos++; + } + + pixeldata = (bits & 0x2000) ? (color2|THEN_EXTEND_1) : (color1|THEN_EXTEND_1); + pixeldata |= (bits & 0x1000) ? + (uint32_t)(color4|THEN_EXTEND_1) << 16 : + (uint32_t)(color3|THEN_EXTEND_1) << 16; + bits <<= 2; + + sl->data[sl_pos] = pixeldata; + sl_pos++; + + for(int i=4; i < 7; i++) { + pixeldata = (bits & 0x2000) ? (color4|THEN_EXTEND_1) : (color3|THEN_EXTEND_1); + pixeldata |= (bits & 0x1000) ? + (uint32_t)(color4|THEN_EXTEND_1) << 16 : + (uint32_t)(color3|THEN_EXTEND_1) << 16; + bits <<= 2; + + sl->data[sl_pos] = pixeldata; + sl_pos++; + } + } + + // Pad 40 pixels on the right to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word + + sl->length = sl_pos; + sl->repeat_count = 1; + vga_submit_scanline(sl); + } +} + +void DELAYED_COPY_CODE(render_color_text80_line)(unsigned int line) { + const uint8_t *line_buf_a = (const uint8_t *)(text_p1 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); + const uint8_t *line_buf_b = (const uint8_t *)(text_p3 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); + const uint8_t *color_buf_a = (const uint8_t *)(text_p2 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); + const uint8_t *color_buf_b = (const uint8_t *)(text_p4 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); + + for(uint glyph_line=0; glyph_line < 8; glyph_line++) { + struct vga_scanline *sl = vga_prepare_scanline(); + uint sl_pos = 0; + + // Pad 40 pixels on the left to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word + + for(uint col=0; col < 40; ) { + // Grab 14 pixels from the next two characters + uint32_t bits_a = char_text_bits(line_buf_a[col], glyph_line); + uint32_t bits_b = char_text_bits(line_buf_b[col], glyph_line); + uint16_t color1 = lores_palette[color_buf_a[col] >> 4]; + uint16_t color2 = lores_palette[color_buf_a[col] & 0xF]; + uint16_t color3 = lores_palette[color_buf_b[col] >> 4]; + uint16_t color4 = lores_palette[color_buf_b[col] & 0xF]; + col++; + + uint32_t bits = (bits_b << 7) | bits_a; + uint32_t pixeldata; + + // Translate each pair of bits into a pair of pixels + for(int i=0; i < 3; i++) { + pixeldata = (bits & 0x2000) ? (color2) : (color1); + pixeldata |= (bits & 0x1000) ? + (uint32_t)(color2) << 16 : + (uint32_t)(color1) << 16; + bits <<= 2; + + sl->data[sl_pos] = pixeldata; + sl_pos++; + } + + pixeldata = (bits & 0x2000) ? (color2) : (color1); + pixeldata |= (bits & 0x1000) ? + (uint32_t)(color4) << 16 : + (uint32_t)(color3) << 16; + bits <<= 2; + + sl->data[sl_pos] = pixeldata; + sl_pos++; + + for(int i=4; i < 7; i++) { + pixeldata = (bits & 0x2000) ? (color4) : (color3); + pixeldata |= (bits & 0x1000) ? + (uint32_t)(color4) << 16 : + (uint32_t)(color3) << 16; + bits <<= 2; + + sl->data[sl_pos] = pixeldata; + sl_pos++; + } + } + + // Pad 40 pixels on the right to center horizontally + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word + sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word + + sl->length = sl_pos; + sl->repeat_count = 1; + vga_submit_scanline(sl); + } +} +