From e35cff6d299a07d9b34f303717083a9299a37e82 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Mon, 28 Aug 2023 15:16:12 +0100 Subject: Initial import --- src/vga.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/vga.c (limited to 'src/vga.c') diff --git a/src/vga.c b/src/vga.c new file mode 100644 index 0000000..a9f5a18 --- /dev/null +++ b/src/vga.c @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "ubox_vga.h" + +static uint8_t buffer[320 * 200]; +static uint8_t *screen = NULL; +static uint8_t *target = NULL; + +uint8_t ubox_open_framebuffer() +{ + if (__djgpp_nearptr_enable() == 0) + return 0; + + target = screen = (uint8_t *)(0xa0000 + __djgpp_conventional_base); + return 1; +} + +void ubox_blit_target(uint8_t t) +{ + target = t ? buffer : screen; +} + +void ubox_close_framebuffer() +{ + __djgpp_nearptr_disable(); +} + +uint8_t ubox_set_mode(uint8_t mode) +{ + __dpmi_regs regs = { 0 }; + + /* detect VGA card */ + regs.x.ax = 0x1a00; + __dpmi_int(0x10, ®s); + if (regs.h.al != 0x1a) + return 0; + + memset(®s, 0, sizeof(regs)); + regs.x.ax = mode; + __dpmi_int(0x10, ®s); + + if (mode == 0x13) + { + /* setup the VGA: 320x200 @ 60Hz */ + /* from: https://gist.github.com/juj/34306e6da02a8a7043e393f01e013f24 */ + disable(); + + /* XXX: probably not neeed */ + ubox_wait_vsync(); + + outportw(0x3d4, 0x0011); /* Turn off write protect to CRTC registers */ + outportw(0x3d4, 0x0b06); /* New vertical total=525 lines, bits 0-7 */ + outportw(0x3d4, 0x3e07); /* New vertical total=525 lines, bits 8-9 */ + + outportw(0x3d4, 0xb910); /* Vsync start=scanline 185 */ + outportw(0x3d4, 0x8f12); /* Vertical display end=scanline 399, bits 0-7 */ + outportw(0x3d4, 0xb815); /* Vertical blanking start=scanline 440, bits 0-7 */ + outportw(0x3d4, 0xe216); /* Adjust vblank end position */ + outportw(0x3d4, 0x8511); /* Vsync length=2 lines + turn write protect back on */ + + /* XXX: probably not neeed */ + ubox_wait_vsync(); + + outportw(0x3d4, 0x2813); /* 8 pixel chars */ + outportw(0x3d4, 0x8e11); /* restore retrace */ + enable(); + } + + return 1; +} + +void ubox_wait_vsync() +{ + while (inportb(0x3da) & 8); + while (!(inportb(0x3da) & 8)); +} + +void ubox_wait_frames(uint16_t frames) +{ + /* wait some time */ + while (frames--) + ubox_wait_vsync(); +} + +void ubox_set_palette(const uint8_t *palette) +{ + outportb(0x3c8, 0); + for (int i = 0; i < 768; i++) + outportb(0x3c9, palette[i] >> 2); +} + +void ubox_blit(const uint8_t *sprite, const ubox_rect *dst) +{ + uint8_t b; + uint8_t *dtarget = target + dst->x + dst->y * 320; + const uint16_t inc = 320 - dst->w; + + for (uint16_t j = dst->h; j > 0; j--) + { + for (uint16_t i = dst->w; i > 0; i--) + { + b = *sprite++; + + /* transparent */ + if (b == UBOX_TRANSPARENT) + { + dtarget++; + continue; + } + + *dtarget++ = b; + } + dtarget += inc; + } +} + +void ubox_blit_c(const uint8_t *sprite, const ubox_rect *dst, uint8_t c) +{ + uint8_t *dtarget = target + dst->x + dst->y * 320; + + asm volatile ( + "movl $320, %%ebp\n\t" + "subl %%ecx, %%ebp\n\t" + "blit_c_w:\n\t" + "movl %%ecx, %%eax\n\t" + "blit_c_w_loop:\n\t" + "movb (%%esi), %%ah\n\t" + "cmpb $%p5, %%ah\n\t" + "je blitrc_tr\n\t" + "orb %%ah, %%ah\n\t" + "je blit_c_store\n\t" + "movb %%dl, %%ah\n\t" + "blit_c_store:\n\t" + "movb %%ah, (%%edi)\n\t" + "blit_c_tr:\n\t" + "incl %%esi\n\t" + "incl %%edi\n\t" + "decb %%al\n\t" + "jne blit_c_w_loop\n\t" + "addl %%ebp, %%edi\n\t" + "decl %%ebx\n\t" + "jne blit_c_w\n\t" + : /*no output */ + : "S" (sprite), "D" (dtarget), + "b" ((uint32_t)dst->h), "d" ((uint32_t)c), + "c" ((uint32_t)dst->w), "i" (UBOX_TRANSPARENT) + : "eax", "ebp" + ); +} + +void ubox_blitrc(const uint8_t *sprite, const ubox_rect *src, const ubox_rect *dst) +{ + uint8_t *dtarget = target + dst->x + dst->y * 320; + + sprite += src->x + src->y * src->w; + + asm volatile ( + "movl $320, %%ebp\n\t" + "subl %%ecx, %%ebp\n\t" + "blitrc_w:\n\t" + "movl %%ecx, %%eax\n\t" + "blitrc_w_loop:\n\t" + "movb (%%esi), %%ah\n\t" + "cmpb $%p5, %%ah\n\t" + "je blitrc_tr\n\t" + "movb %%ah, (%%edi)\n\t" + "blitrc_tr:\n\t" + "incl %%esi\n\t" + "incl %%edi\n\t" + "decb %%al\n\t" + "jne blitrc_w_loop\n\t" + "addl %%edx, %%esi\n\t" + "addl %%ebp, %%edi\n\t" + "decl %%ebx\n\t" + "jne blitrc_w\n\t" + : /*no output */ + : "S" (sprite), "D" (dtarget), + "b" ((uint32_t)dst->h), "d" ((uint32_t)(src->w - dst->w)), + "c" ((uint32_t)dst->w), "i" (UBOX_TRANSPARENT) + : "eax", "ebp" + ); +} + +void ubox_blit_erase(uint8_t c) +{ + memset(target, c, 320 * 200); +} + +void ubox_blit_copy_all() +{ + memcpy(screen, buffer, 320 * 200); +} + +void ubox_blit_copy(const ubox_rect *dst) +{ + uint8_t *src = buffer + dst->x + dst->y * 320; + uint8_t *dtarget = screen + dst->x + dst->y * 320; + + for (uint16_t j = dst->h; j > 0; j--) + { + memcpy(dtarget, src, dst->w); + src += 320; + dtarget += 320; + } +} + +void ubox_blit_copy16(const ubox_rect *dst) +{ + uint8_t *src = buffer + dst->x + dst->y * 320; + uint8_t *dtarget = screen + dst->x + dst->y * 320; + + asm volatile ( + "movl $0x130, %%ebx\n\t" + "cld\n\t" + "blit_copy16_loop:\n\t" + "movsl\n\t" + "movsl\n\t" + "movsl\n\t" + "movsl\n\t" + "addl %%ebx, %%esi\n\t" + "addl %%ebx, %%edi\n\t" + "decl %%eax\n\t" + "orl %%eax, %%eax\n\t" + "jne blit_copy16_loop\n\t" + : /* no output */ + : "S" (src), "D" (dtarget), "a" ((uint32_t)dst->h) + : "ecx", "ebx" + ); +} -- cgit v1.2.3