diff --git a/vga/businterface.c b/vga/businterface.c index fd8494b..0ad160f 100644 --- a/vga/businterface.c +++ b/vga/businterface.c @@ -224,17 +224,14 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { apple_memory[address] = terminal_border; break; case 0x08: - terminal_row = (value < 24) ? value : 23; - apple_memory[address] = terminal_row; - apple_memory[address+2] = terminal_memory[terminal_row*80+terminal_col]; + soft_switches &= ~SOFTSW_TERMINAL; break; case 0x09: - terminal_col = (value < 80) ? value : 79; - apple_memory[address] = terminal_col; - apple_memory[address+1] = terminal_memory[terminal_row*80+terminal_col]; + soft_switches |= SOFTSW_TERMINAL; break; case 0x0A: - terminal_memory[terminal_row*80+terminal_col] = value; + terminal_fifo[terminal_fifo_wrptr++] = (value & 0xFF); + apple_memory[address] = (terminal_fifo_rdptr - terminal_fifo_wrptr); break; case 0x0B: if((value & 0xFF) <= 0x27) { @@ -244,5 +241,10 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { break; } } + } else if(CARD_SELECT && CARD_DEVSEL) { + if((address & 0x0F) == 0x0A) { + apple_memory[address] = (terminal_fifo_rdptr - terminal_fifo_wrptr); + } } + } diff --git a/vga/render.c b/vga/render.c index e699feb..010c9a5 100644 --- a/vga/render.c +++ b/vga/render.c @@ -115,6 +115,8 @@ void DELAYED_COPY_CODE(render_init)() { memcpy(terminal_character_rom, (void*)FLASH_FONT_APPLE_IIE, 4096); memset(status_line, 0, sizeof(status_line)); + terminal_clear_screen(); + render_test_init(); } @@ -124,7 +126,7 @@ void DELAYED_COPY_CODE(render_border)(uint count) { uint sl_pos = 0; while(sl_pos < VGA_WIDTH/16) { - sl->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 8 pixels per word + sl->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word sl_pos++; } @@ -203,8 +205,6 @@ void DELAYED_COPY_CODE(render_loop)() { testdone = 1; render_about_init(); } - } else if(soft_switches & SOFTSW_TERMINAL) { - render_terminal(); #if defined(ANALOG_GS) || defined(OVERCLOCKED) } else if(soft_switches & SOFTSW_SHR) { render_shr(); @@ -220,6 +220,9 @@ void DELAYED_COPY_CODE(render_loop)() { render_border(32); } + if(soft_switches & SOFTSW_TERMINAL) { + render_terminal(); + } else switch(soft_switches & SOFTSW_MODE_MASK) { case 0: if(soft_switches & SOFTSW_DGR) { diff --git a/vga/render.h b/vga/render.h index e461e70..e10143a 100644 --- a/vga/render.h +++ b/vga/render.h @@ -9,6 +9,8 @@ extern uint16_t lores_palette[16]; extern uint16_t text_fore, text_back, text_border; extern uint8_t status_line[81]; +extern void terminal_clear_screen(); + extern void update_status_left(const char *str); extern void update_status_right(const char *str); @@ -27,7 +29,6 @@ extern void render_text80_line(bool p2, unsigned int line); extern void render_status_line(); extern void render_terminal(); -extern void render_terminal_line(unsigned int line); extern void render_border(uint count); diff --git a/vga/render_80col.c b/vga/render_80col.c index 1a433dc..c289f52 100644 --- a/vga/render_80col.c +++ b/vga/render_80col.c @@ -1,76 +1,241 @@ +#include #include #include "common/config.h" +#include "common/dmacopy.h" + #include "vga/vgabuf.h" #include "vga/render.h" #include "vga/vgaout.h" -static inline uint_fast8_t char_terminal_bits(uint_fast8_t ch, uint_fast8_t glyph_line) { - uint_fast8_t bits = terminal_character_rom[((uint_fast16_t)ch << 3) | glyph_line]; - if(ch & 0x80) { - // normal character - return bits & 0x7f; - } +uint8_t terminal_jsoffset = 0; +uint8_t terminal_ssoffset = 0; +bool terminal_esc = 0; +bool terminal_esc_crz = 0; +int terminal_esc_pos = 0; +uint16_t terminal_charset = 0; +uint8_t terminal_width = 80; +uint8_t terminal_height = 24; - if((bits & 0x80) == 0) { - // inverse character - return bits ^ 0x7f; +static inline uint_fast8_t char_terminal_bits(uint_fast8_t ch, uint_fast8_t glyph_line) { + uint_fast8_t bits = terminal_character_rom[terminal_charset | (((uint_fast16_t)ch & 0x7f) << 3) | glyph_line]; + + if(ch & 0x80) { + return (bits & 0x7f) ^ 0x7f; + } + return (bits & 0x7f); +} + +static void DELAYED_COPY_CODE(terminal_linefeed)() { + if(terminal_row < (terminal_height-1)) { + terminal_row++; } else { - // flashing character - return (bits ^ text_flasher_mask) & 0x7f; + // 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; } } +static void DELAYED_COPY_CODE(terminal_advance_cursor)() { + terminal_col++; + if(terminal_col >= terminal_width) { + terminal_col = 0; + terminal_linefeed(); + } +} + +void DELAYED_COPY_CODE(terminal_clear_screen)() { + // Clear screen (using dma) + memset((void*)terminal_memory, ' ', 4096); + terminal_jsoffset = 0; + terminal_row = 0; + terminal_col = 0; +} + +static void DELAYED_COPY_CODE(terminal_clear_to_line_end)() { + // Clear to end of line first + memset((void*)(terminal_memory+((((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF)), ' ', 128-terminal_col); +} + +static void DELAYED_COPY_CODE(terminal_clear_to_screen_end)() { + // Clear to end of line first + memset((void*)(terminal_memory+((((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF)), ' ', 128-terminal_col); + + // Then clear remaining lines on the screen + for(uint i = terminal_row; i < terminal_height; i++) + memset((void*)(terminal_memory+(((i+terminal_jsoffset) * 128) & 0xFFF)), ' ', 128); +} + +void DELAYED_COPY_CODE(terminal_process_input)() { + if(terminal_ssoffset > 0) return; + + if(terminal_fifo_rdptr != terminal_fifo_wrptr) { + char ch = terminal_fifo[terminal_fifo_rdptr++]; + if(terminal_esc_pos == 1) { + terminal_col = (ch - 32); + if(terminal_col >= terminal_width) + terminal_col = terminal_width - 1; + terminal_esc_pos = 2; + } else if(terminal_esc_pos == 2) { + terminal_row = (ch - 32); + if(terminal_row >= terminal_height) + terminal_row = terminal_height - 1; + terminal_esc_pos = 0; + } else if(terminal_esc_crz) { + switch(ch) { + case '0': // Clear Screen + terminal_clear_screen(); + break; + case '1': + soft_switches &= ~SOFTSW_TERMINAL; + break; + case '2': + terminal_charset = 0; + break; + case '3': + terminal_charset = 2048; + break; + default: + terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch; + terminal_advance_cursor(); + break; + } + terminal_esc_crz = false; + } else if(terminal_esc) { + switch(ch) { + case 'A': + terminal_advance_cursor(); + break; + case 'B': + if(terminal_col > 0) + terminal_col--; + break; + case 'C': + terminal_linefeed(); + break; + case 'D': // Reverse Linefeed + if(terminal_row > 0) + terminal_row--; + break; + case 'E': // Clear to end of line + terminal_clear_to_line_end(); + break; + case 'F': // Clear to end of screen + terminal_clear_to_screen_end(); + break; + case '@': // Clear screen + terminal_clear_screen(); + break; + default: + terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch; + terminal_advance_cursor(); + break; + } + terminal_esc = false; + } else + switch(ch) { + case 0x0A: // Line Feed + terminal_linefeed(); + break; + case 0x0B: // Ctrl-K: Clear to End of Screen + terminal_clear_to_screen_end(); + break; + case 0x0C: // Ctrl-L: Form Feed + terminal_clear_screen(); + break; + case 0x0D: // Ctrl-M: Carriage Return + terminal_col = 0; + break; + case 0x13: // Ctrl-S: Xon/Xoff (unimplemented) + break; + case 0x15: // Ctrl-U: Copy (unimplemented) + break; + case 0x19: // Ctrl-Y: Home Cursor + terminal_row = 0; + terminal_col = 0; + break; + case 0x1A: // Ctrl-Z + terminal_esc_crz = true; + break; + case 0x1B: // Escape + terminal_esc = true; + break; + case 0x1C: // Forward Space + terminal_advance_cursor(); + break; + case 0x1D: // Clear to end of line + terminal_clear_to_line_end(); + break; + case 0x1E: // Position Cursor + terminal_esc_pos = 1; + break; + case 0x1F: // Reverse Linefeed + if(terminal_row > 0) + terminal_row--; + break; + default: + terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch; + terminal_advance_cursor(); + break; + } + } +} + +static void DELAYED_COPY_CODE(render_terminal_line)(uint16_t line) { + uint glyph_line = line & 0x7; + const uint8_t *line_buf = (const uint8_t *)terminal_memory + (((line>>3) * 128) & 0xFFF); + bool cursor_row = ((((terminal_row+terminal_jsoffset) * 128) & 0xFFF) == (((line>>3) * 128) & 0xFFF)); + + 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 < 80; ) { + // Grab 14 pixels from the next two characters + uint32_t bits_a = char_terminal_bits(line_buf[col], glyph_line) ^ ((cursor_row && (col==terminal_col)) ? text_flasher_mask : 0x00); + col++; + uint32_t bits_b = char_terminal_bits(line_buf[col], glyph_line) ^ ((cursor_row && (col==terminal_col)) ? text_flasher_mask : 0x00); + col++; + + uint32_t bits = (bits_a << 7) | bits_b; + + // Translate each pair of bits into a pair of pixels + for(int i=0; i < 7; i++) { + uint32_t pixeldata = (bits & 0x2000) ? (text_fore) : (text_back); + pixeldata |= (bits & 0x1000) ? + (((uint32_t)text_fore) << 16) : + (((uint32_t)text_back) << 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_terminal)() { - for(int line=0; line < 24; line++) { - render_terminal_line(line); + for(uint line=0; line < 192; line++) { + render_terminal_line((terminal_jsoffset<<3)+line+terminal_ssoffset); } -} - - -void DELAYED_COPY_CODE(render_terminal_line)(unsigned int line) { - const uint8_t *page = (const uint8_t *)terminal_memory; - const uint8_t *line_buf = page + (line * 80); - - 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); // 16 pixels per word - - for(uint col=0; col < 80; ) { - // Grab 14 pixels from the next two characters - uint32_t bits_a = char_terminal_bits(line_buf[col], glyph_line); - col++; - uint32_t bits_b = char_terminal_bits(line_buf[col], glyph_line); - col++; - - uint32_t bits = (bits_a << 7) | bits_b; - - // Translate each pair of bits into a pair of pixels - for(int i=0; i < 7; i++) { - uint32_t pixeldata = (bits & 0x2000) ? (text_fore) : (text_back); - pixeldata |= (bits & 0x1000) ? - (((uint32_t)text_fore) << 16) : - (((uint32_t)text_back) << 16); - bits <<= 2; - - sl->data[sl_pos] = pixeldata; - sl_pos++; - } + if(terminal_ssoffset > 0) { + terminal_ssoffset++; + if(terminal_ssoffset >= 8) { + terminal_ssoffset = 0; + terminal_jsoffset++; } - - // 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; - vga_submit_scanline(sl); } } - diff --git a/vga/vgabuf.c b/vga/vgabuf.c index eadccf8..7310e58 100644 --- a/vga/vgabuf.c +++ b/vga/vgabuf.c @@ -7,6 +7,10 @@ volatile uint32_t mono_palette = 0; uint8_t __attribute__((section(".uninitialized_data."))) character_rom[4096]; uint8_t __attribute__((section(".uninitialized_data."))) terminal_character_rom[4096]; +uint8_t __attribute__((section(".uninitialized_data."))) terminal_fifo[256]; +uint8_t terminal_fifo_wrptr = 0; +uint8_t terminal_fifo_rdptr = 0; + volatile uint8_t terminal_row = 0; volatile uint8_t terminal_col = 0; diff --git a/vga/vgabuf.h b/vga/vgabuf.h index 11a8678..7ddc13e 100644 --- a/vga/vgabuf.h +++ b/vga/vgabuf.h @@ -10,6 +10,10 @@ extern uint8_t character_rom[4096]; extern uint8_t terminal_character_rom[4096]; +extern uint8_t terminal_fifo[256]; +extern uint8_t terminal_fifo_wrptr; +extern uint8_t terminal_fifo_rdptr; + extern volatile uint8_t terminal_row; extern volatile uint8_t terminal_col; diff --git a/vga/vgaout.c b/vga/vgaout.c index ddff696..5649a9b 100644 --- a/vga/vgaout.c +++ b/vga/vgaout.c @@ -235,7 +235,8 @@ struct vga_scanline * DELAYED_COPY_CODE(vga_prepare_scanline)() { // Wait for the scanline buffer to become available again while(scanline->_flags & FLAG_BUSY) - tight_loop_contents(); + terminal_process_input(); + //tight_loop_contents(); // Reinitialize the scanline struct for reuse scanline->length = 0;