From 1a5dc08e5b76b384ebadbdc47fe666dfdd929e71 Mon Sep 17 00:00:00 2001 From: John Bintz Date: Mon, 27 May 2024 07:15:18 -0400 Subject: [PATCH] Update for publishing --- .gitignore | 2 ++ README.md | 42 +++++++++++++++++++++++++++++- asmvga.asm | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 46 +++++++++++++++++++++++++++++++++ simple.c | 23 +++++++++++++++++ 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 asmvga.asm create mode 100644 simple.c diff --git a/.gitignore b/.gitignore index d16db97..d8528f9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ *.err *.exe .ccls-cache/ +ccls.log +capture/ diff --git a/README.md b/README.md index 25f7e61..2167d62 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,47 @@ -# VGA logic units in 256 colors and SVGA mode usage +# VGA and SVGA code examples Some code to exercise the four logic units of the VGA card in 256 color mode, as well as code that gets SVGA mode working. Most of this is in C, but some of it's in assembler to help me learn assembler better, as well as get comfortable with C/asm interop on x86. + +Check out the video I wrote all this code to support: +https://makertube.net/w/sQSZJcxh8CRuMZWVh8Q6aF + +Read more about my project The Industrious Rabbit at +https://theindustriousrabbit.com/ + +## Building + +You'll need [Open Watcom 2.0](https://open-watcom.github.io/). You can use +`wmake` on the `makefile` to build some of these, and +`wcl386 -q -bt=dos -l=dos4g ` for the others. All of these +run in 32-bit protected mode within a DPMI wrapper and in a flat memory space, +because I *really don't* want to deal with segment:offset addressing. + +## What's here + +### `main.c` and `vga.asm` + +C code that exercises a bunch of the VGA registers by transforming a colored +cube of all 256 VGA colors in different ways. The display is set to unchained +mode. Lots of latch copies and trasnforming data with stuff in the latches. +The core of the transformation code is in `vga.asm`, which is also where the +keyboard handler for exiting the program lives. + +### `svga.c`, `vesa.c`, `dpmi.c`, and `bmp.c` + +Display a bitmap in a 640x480x256 SVGA mode. Trying to find a fully working +SVGA, DOS Protected Mode Interface, and VESA example was tough, so hopefully +this will help you out if you're trying to do the same thing! + +### `simple.c` and `asmvga.asm` + +These both draw a single dot on the screen, but in different ways: + +* `simple.c` draws the dot directly to VGA memory +* `asmvga.asm` allocates a block of RAM, writes the pixel there, then + shovels the data from the RAM into the VGA card with `rep movsb`, which + is the procedure a game would use to draw to a non-VGA RAM buffer and then + copy when done. diff --git a/asmvga.asm b/asmvga.asm new file mode 100644 index 0000000..f7417ab --- /dev/null +++ b/asmvga.asm @@ -0,0 +1,75 @@ +.386 +.model flat,c +.STACK 100h + +.data +bufferPtr dword 0 +bufferHandleLow word 0 +bufferHandleHigh word 0 + +.code + +main PROC + ; we need es the same as ds for movsb + mov ax,ds + mov es,ax + + ; place to catch bpint + mov cx,0fh + mov dx,1 + mov ah,86h + int 15h + + ; reserve ram + mov ax,0501h + mov bx,0 + mov cx,64000 + int 31h + shl ebx,16 + mov bx,cx + mov bufferPtr,ebx + mov bufferHandleLow,di + mov bufferHandleHigh,si + + ; clear ram + mov ecx,64000 + mov edi,ebx + mov al,0 + rep stosb + + ; write pixel 15 at (10,10) + mov edi,ebx + add edi,320*10+10 + mov al,15 + stosb + + ; switch to 320x200 256 color chunky chained mode + mov ah,0h + mov al,13h + int 10h + + ; copy buffer to vga card + mov esi,bufferPtr + mov edi,0a0000h + mov ecx,320*200 + rep movsb + + ; wait 5s + mov cx,0fh + mov dx,5000 + mov ah,86h + int 15h + + ; free memory + mov ax,0502h + mov si,bufferHandleHigh + mov di,bufferHandleLow + int 31h + + ; terminate with return code + mov ah,4Ch + mov al,00h + int 21h +main ENDP + +END main diff --git a/main.c b/main.c index 7dae515..18449cb 100644 --- a/main.c +++ b/main.c @@ -47,7 +47,14 @@ void populateExampleCube(void) { } } +void forceReadVGA(char far *vga); +#pragma aux forceReadVGA = \ +"mov bl,BYTE PTR [eax]" \ +parm [ eax ] \ +modify [ bl ]; + int main(void) { + char a; // activate unchained vga mode // place some data into video memory to be latch copied // show off the following @@ -93,11 +100,50 @@ int main(void) { writeCube(10, 0x00, 0, 3); writeCube(15, 0x00, 3, 0); + outpw(0x3ce, 0x0000); + outpw(0x3ce, 0x0001); + outpw(0x3ce, 0x0002); + outpw(0x3ce, 0x0003); + /* + outpw(0x3ce, 0x0005); + */ + outpw(0x3ce, 0xff08); + outpw(0x3c4, 0x0f02); + /* + outp(0x3ce, 0x08); + outp(0x3cf, 0xff); + */ + + VGA[0] = 255; + // read the above. if you're reading the value and doing nothing with it, watcom will optimize it out + forceReadVGA(VGA); + + //outp(0x3cf, 0xff); + // all from latches + outpw(0x3ce, 0x0008); + + VGA[2] = 127; + + // all but the first bit from incoming data + outpw(0x3ce, 0xfe08); + + VGA[4] = 2; + + a = VGA[4]; + + /* + outp(0x3cf, 0x00); + + VGA[410] = 0; + */ + while (keyboardPressed == 0); _dos_setvect(9, int9Save); enableTextMode(); + printf("%d\n", a); + return 0; } diff --git a/simple.c b/simple.c new file mode 100644 index 0000000..dc6b138 --- /dev/null +++ b/simple.c @@ -0,0 +1,23 @@ +#include +#include +#include + +int main(void) { + union REGS regs; + + regs.w.ax = 0x13; + + int386(0x10, ®s, ®s); + + delay(5000); + + *((unsigned char far *)0xa0000 + (320 * 10) + 10) = 15; + + delay(2000); + + regs.w.ax = 0x03; + + int386(0x10, ®s, ®s); + + return 0; +}