Getting to vesa/svga modes from v8086

I'm working on a game that is supposed to work on old pcs. It runs on my 166mhz Pentium mmx, but only about 30 fps. This is 640x480 game with 8 bit colour, so I thought of using the vesa modes directly. Windows 9x has the v8086 monitor, that's what allows it to run dos programs. Dos games that use vesa/svga modes work fine from win9x, so I tried... And it doesn't really work. If I code some 16 bit assembly (for example in a com file) I can enter any video mode and display something, but if I have that code in my 32 bit game exe, the system hangs. I get a black screen, so I guess I do enter the graphics mode, but nothing else happens.

While looking for some help I came across svga lib for linux and it seems that SDL1 supports that driver. The question is, is there a linux distro that could run on such old computer ? I tried damn small linux and it works, but it feels like it's swapping all the time (48mb of ram) and there's no /dev/svga so how to install that ?

Other urls found in this thread:

delorie.com/djgpp/
youtu.be/Cqy-WKZURbM
twitter.com/SFWRedditImages

Could you be trying to call the VBE Mode from Protected Mode? That will not Work, you have to initialize the Video Mode from Real Mode ( Windows does some tricks in v8086 ). For a Linux Distribution you could try using Alpine Linux, probably the slimmest modern Linux. Another Option if you want to go really low level might be to use Grub as a Bootloader which can Initialize a Vesa LFB for you and even load/execute a normal ELF executable for you ( of course without any c stdlib ).

Gentoo, but give up on having an X server.

32 bit in DOS was tricky. It involved several tiers of bootstrapping and callbacks, garbage like DPMI and slightly less awful VCPI, etc.. That was the era where most game devs wound up using dos4gw because doing things by hand was pretty messy. Try going that route if you just want Windows compatibility without having to understand a lot of obsolete tech.
It sounds like there's some open source clone now called dos/32, by the way.

I know about dos extenders and considered them, but it's not an ideal option, because then I don't have any windows driver (for the sound for example) although I could theoretically just assume that people have sound blaster and cover 99% of people.

All soundcards from that era included Soundblaster emulation, and Windows 9x allows DOS programs direct access to sound hardware (so it will work both under Windows and bare DOS).

Ok then, I guess I'll have to go the way of dos extenders. One more issue. This game works both and new hardware (uses sdl1 or sdl2) , is there a nice way of having the same source compile to dos with an extender? And is it possible to compile such executable from linux or do I have to wipe out turbo c++ in dosbox ? For example I compile the win98 version on my linux box using mingw 3.x (don't remember which exactly now but the last to generate executable that will work below win xp)

Btw, the reason I want this direct access to the transmitted is because I believe windows is slowing things down a lot. While I use my own blit functions I still use sdl for input and creating a window. Them I give it a ready frame and make it display that frame. If I instead of asking ask to display my frame just copy my frame once again to some buffer I ram suddenly I get 75fps (I can't see anything of course, but all pixel manipulations are still going on).

BIOS functions can be called only from real mode. If you're running in protected mode, you need to jump back to real mode before executing one.


You need a compiler that targets the DOS+DPMI platform. Check out DJGPP:
delorie.com/djgpp/
Sure, DJGPP is basically a GCC port. You can compile it for linux if you want (no binaries provided though).

Windows 9x is a protected mode os and yet it can run dos programs that use interrupts thanks to v8086

Do you set a proper fullscreen video mode? Unless you set a fullscreen mode with the exact same format as your back buffer surface, Windows has to convert your frame to whatever format the screen uses (probably 24-bit RGB) on each flip, which is costly.

Virtual mode is basically a CPU emulation mode for real mode code. You still need to explicitly switch to it before calling any real mode code (like BIOS interrupts).

Well I use SDL1 so I assume it does it right. I ask for [email protected]/* */ and that's the resolution and colour depth I have on windows98. Still, the performance is exactly the same whether I have a window or fullscreen

It only does it right if you ask it right. How do you create the window and set video mode? How do you put your frame onto the screen?

gFrameBuffer = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE | SDL_FULLSCREEN);

Then the game draws shit into gFrameBuffer and at the end

SDL_Flip(gFrameBuffer);

If I replace SDL_Flip with simple memcpy to some buffer in ram it works about 2 times faster. I looked up the SDL1 source and it doesn't seem to do anything bad, it just uses the window API to put the stuff on the screen which seems to slow things down.

Then don't use Windows at all, do it pure DOS. You're coming at this from a modern mindset where everything needs a driver, but back then the hardware was the API. If you're using VESA BIOS and the original SoundBlaster then you don't need anything other than disk access. The additional effort in DOS extenders was staying compatible with other software like Windows, it was literally harder than not bothering with compatibility (see: Ultima 7).
But it sounds like you'd be /way/ better off with SDL on Linux if there's not a reason you absolutely needed DOS or Windows. You could even have the whole 'distro' packaged as an executable that bootstraps from DOS using loadlin. I did that a long time ago for a demo using svgalib and mikmod. IIRC I had it boot directly to my code rather than init so I was the only program running.

I wanted to do something like that. Can you say some more ? I want the svga lib since sdl supports that. Would I get .mod playback?

Start by getting a feel for Linux. A basic Debian install with no X11 for example. You'd be doing video through SDL/svgalib which is pretty direct and will map the ram for you. Audio would be through ALSA and is again pretty direct. You could either mix it yourself like in DOS or use a library that takes care of the mixing. You might like OpenAL as the interface is very much like doing SoundBlaster coding but with two buffers rather than autoinit DMA and it's low faggotry unlike gstreamer. If doing it yourself, be aware that mixing well is a surprisingly difficult math problem and you might be surprised how far away from the quality you expect today your own efforts will be.
Next make a stripped down Linux distro that just includes your program and dependencies. Embedded tutorials will help but getting it really small is a dark art. But you probably don't need really small anyway - a 64MiB squashfs partition is enough for a full debootstrap without stripping anything. Just make sure it's not running other services that could steal your CPU time.
Then look into booting the resulting blob via loadlin. I last did that like 20 years ago so you'll need to look into it. Note that you'll need to reboot afterwards as it completely replaces DOS but that's probably fine for you.

Btw, the advantage is that you'll have an entirely modern 'stack' and toolset to do programs for old computers. Doing real DOS development is not nearly as easy. I'm 39 and used to do some demoscene stuff back then and had a lot of fun, but holy shit are you guys spoiled today with the stuff you have available.

Let's pretend someone booted freeDOS. How would you go about finding hardware memory adresses for components like a ssd or a special hard disk? To write a driver that is.

DOS relied on BIOS for disk access, it knows how to access them and you query BIOS to know what it knows about them (this is how grub loads stage 1 and why it's so awkward to configure). You're in the wrong mindset with drivers. BIOS was a big deal back then and was the driver layer at runtime for early OSes like DOS. There was also a VESA BIOS doing the same thing for video but it was highly restrictive (read: shit) so we often coded against the cards directly which was easy until SVGA fucked everything up. And the SoundBlaster had a standard interface everyone copied you'd just ask the user where they jumpered it to, there was no driver. Even if you were doing AWE32, you built the 'driver' into your code, you were programming directly against the hardware, and you'd ask the user where to find it. That was the misery of ISA, having to jumper everything to resolve conflicts by hand and having to remember where you put your hardware.
I never did BIOS disk operations directly as I was terrified of wrecking my filesystem (they've very easy to do, though), I did all I/O through DOS. I did my own protected mode code though which was 32 bit with a flat memory model. To re-use DOS for disk access while running like that, I routed the disk interrupt back to DOS via 'v86' mode which was this funny 386 thing where you could have an ISR bounce into 16 bit real mode then use a trampoline to return to your protected mode code. I could then call DOS from v86 mode and it'd service the interrupt like it was still in real mode and I'd get the result in my protected mode code. I expect dos4gw did it this way too but I never checked, it was great as it retained compatibility with all the weird TSR bullshit people might be running (stacker, for example, which would transparently compress a drive).

There's your problem. Use SDL_HWSURFACE.

But then drawing directly to the screen surface will be slow as fuck if everything works correctly. Since you said you're implementing your own software blitters instead of using SDL drawing primitives, you need a back buffer in system memory. You have two approaches to do it:
1) malloc yourself a back buffer, draw there, then hand-blit to screen:
SDL_LockSurface(gFrameBuffer);for(int y=0; y

It shouldn't be that slow if you're careful about how you draw and avoid reads. We didn't use buffering back in the 386 days as it was impossible to blit the full screen at monitor refresh let alone draw anything.

Yeah, shit changed in the Pentium era. Directly accessing memory-mapped hardware addresses got really slow compared to normal memory. You want to write there only contiguous, cache-aligned blocks of at least few hundred bytes each to take advantage of write combining. Plain memcopies became fast though, so that extra copy will not cost much.

I did things in the pentium era. It was fine without a buffer. It worked the same as back in the VGA days where we'd split the planes but always write each plane in order for performance. Draw routines were optimized to do this kind of weird draw, and to never read (convolution effects were done in a buffer).
Funny story, I once worked on a network card driver (funnier story: it was for PRISM) where write combining was bugged and could crash it so all writes had to be done backwards. The code was like looking at a funhouse mirror.

You seriously expect OP to know how to do that? I'm trying to set him up so that things just work for him without excessive autism.
Also, you don't get that kind of low-level control under Windows. All you get is a damn memory-mapped framebuffer with MTRRs set to WC.

DPMI lets you call BIOS and DOS interrupts and takes care of all the ugly details of bouncing to virtual mode and back. Anyway, you don't need to mess with that directly either, since DJGPP implements the full standard libc on top of DPMI and DOS.

I'm drawing every frame from scratch. I know you can use vga registers to scroll the image around and other stuff but that's not guaranteed to work on all hardware. It's fun to to read all your details about this, I'm a C64 guy.

Just as I thought, it's even slower when doing that. If you have HW surface SDL will try to do the blits with HW, so if I still do everything in software and then just copy a frame toa HW surface... doesn't make any difference besides adding yet another memcpy. I'm on a laptop with 2 MB VRAM, I'm pretty sure it can't do shit other than have the framebuffer.


DOS has a syscall (is that what you call it ?) under interrupt 0x21. So if you want for example to open a file you put a function number X in AH register, pointer to a string with a name in ES:DI register and do int 0x21. Or you can read the disk directly with a BIOS interrupt 0x13 I think. You have to provide the track and sector number and it will give you the sector (512 bytes). I know that much because I wrote a small bare metal thing some time ago for shit and giggle. I even had a thread about it here so maybe someone remembers. Nothing worth bragging about but hey it's something.

I started out on a C64 but I was too young at the time and only wrote code in BASIC and did 'basic' sprite manipulation and bland beepy music, no fun assembly stuff or tracking. Started doing assembly when we got an XT, and then went nuts when the 386 came out and did everything, then went to Linux.

I'm a youngster, my first computer was a pc already And so most of my coding was also done on pc, but when I found the C64 I fell in love with it. I think it's the ultimate demo machine, that is, it has the most hidden/unintentional features. The ratio of what it's supposed to do and what it can actually do is much greater than other platforms.

youtu.be/Cqy-WKZURbM