aboutsummaryrefslogtreecommitdiff
path: root/src/vga.c
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-08-28 15:16:12 +0100
committerJuan J. Martinez <jjm@usebox.net>2023-08-28 15:30:25 +0100
commite35cff6d299a07d9b34f303717083a9299a37e82 (patch)
tree7204099ad4978dfc67e04bc11df29d0f366af851 /src/vga.c
downloaduboxlib-dos-e35cff6d299a07d9b34f303717083a9299a37e82.tar.gz
uboxlib-dos-e35cff6d299a07d9b34f303717083a9299a37e82.zip
Initial import
Diffstat (limited to 'src/vga.c')
-rw-r--r--src/vga.c235
1 files changed, 235 insertions, 0 deletions
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 <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <dpmi.h>
+#include <sys/nearptr.h>
+#include <pc.h>
+#include <dos.h>
+
+#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, &regs);
+ if (regs.h.al != 0x1a)
+ return 0;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.x.ax = mode;
+ __dpmi_int(0x10, &regs);
+
+ 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"
+ );
+}