eobish

changeset 7:6a350c554e46

started DOS port
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 19 Jan 2015 15:49:14 +0200
parents 0baf4e98315e
children c0e8bbf96849
files Makefile.wat dos4gw.exe src/dos/dpmi.c src/dos/dpmi.h src/dos/inttypes.h src/dos/keyb.c src/dos/keyb.h src/dos/mouse.c src/dos/mouse.h src/dos/pit8254.h src/dos/scancode.h src/dos/timer.c src/dos/timer.h src/dos/vbe.c src/dos/vbe.h src/dos/vbegfx.c src/dos/vbegfx.h src/fblib.c src/fblibdos.c src/fblibsdl.c src/level.c src/tileset.c
diffstat 22 files changed, 1243 insertions(+), 15 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile.wat	Mon Jan 19 15:49:14 2015 +0200
     1.3 @@ -0,0 +1,39 @@
     1.4 +gameobj = main.obj player.obj level.obj rend.obj tileset.obj image.obj
     1.5 +fblibobj = fblib.obj
     1.6 +sysobj = vbe.obj dpmi.obj timer.obj mouse.obj keyb.obj
     1.7 +obj = $(gameobj) $(fblibobj) $(sysobj)
     1.8 +bin = eobish.exe
     1.9 +
    1.10 +def = -dFBLIB_VBE=1
    1.11 +opt = -5 -fp5 -otexan
    1.12 +dbg = -d1
    1.13 +
    1.14 +AS = nasm
    1.15 +CC = wcc386
    1.16 +CXX = wpp386
    1.17 +ASFLAGS = -fobj
    1.18 +CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -Isrc\dos
    1.19 +CXXFLAGS = $(CFLAGS)
    1.20 +LD = wlink
    1.21 +
    1.22 +$(bin): $(obj)
    1.23 +	%write objects.lnk file { $(obj) }
    1.24 +	$(LD) debug all name $@ @objects $(LDFLAGS)
    1.25 +
    1.26 +.c: src
    1.27 +.c: src\dos
    1.28 +.cc: src
    1.29 +.asm: src
    1.30 +
    1.31 +.c.obj: .autodepend
    1.32 +	$(CC) $(CFLAGS) $[*
    1.33 +
    1.34 +.cc.obj: .autodepend
    1.35 +	$(CXX) $(CXXFLAGS) $[*
    1.36 +
    1.37 +.asm.obj:
    1.38 +	$(AS) $(ASFLAGS) -o $@ $[*.asm
    1.39 +
    1.40 +clean: .symbolic
    1.41 +	del *.obj
    1.42 +	del $(bin)
     2.1 Binary file dos4gw.exe has changed
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/dos/dpmi.c	Mon Jan 19 15:49:14 2015 +0200
     3.3 @@ -0,0 +1,55 @@
     3.4 +#include "dpmi.h"
     3.5 +
     3.6 +void dpmi_real_int(int inum, struct dpmi_real_regs *regs)
     3.7 +{
     3.8 +	unsigned char int_num = (unsigned char)inum;
     3.9 +	__asm {
    3.10 +		mov eax, 0x300
    3.11 +		mov edi, regs
    3.12 +		mov bl, int_num
    3.13 +		mov bh, 0
    3.14 +		xor ecx, ecx
    3.15 +		int 0x31
    3.16 +	}
    3.17 +}
    3.18 +
    3.19 +void *dpmi_mmap(uint32_t phys_addr, unsigned int size)
    3.20 +{
    3.21 +	uint16_t mem_high, mem_low;
    3.22 +	uint16_t phys_high = phys_addr >> 16;
    3.23 +	uint16_t phys_low = phys_addr & 0xffff;
    3.24 +	uint16_t size_high = size >> 16;
    3.25 +	uint16_t size_low = size & 0xffff;
    3.26 +	unsigned int err, res = 0;
    3.27 +
    3.28 +	__asm {
    3.29 +		mov eax, 0x800
    3.30 +		mov bx, phys_high
    3.31 +		mov cx, phys_low
    3.32 +		mov si, size_high
    3.33 +		mov di, size_low
    3.34 +		int 0x31
    3.35 +		add res, 1
    3.36 +		mov err, eax
    3.37 +		mov mem_high, bx
    3.38 +		mov mem_low, cx
    3.39 +	}
    3.40 +
    3.41 +	if(res == 2) {
    3.42 +		return 0;
    3.43 +	}
    3.44 +	return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low));
    3.45 +}
    3.46 +
    3.47 +void dpmi_munmap(void *addr)
    3.48 +{
    3.49 +	uint16_t mem_high = (uint32_t)addr >> 16;
    3.50 +	uint16_t mem_low = (uint16_t)addr;
    3.51 +
    3.52 +	__asm {
    3.53 +		mov eax, 0x801
    3.54 +		mov bx, mem_high
    3.55 +		mov cx, mem_low
    3.56 +		int 0x31
    3.57 +	}
    3.58 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/dos/dpmi.h	Mon Jan 19 15:49:14 2015 +0200
     4.3 @@ -0,0 +1,26 @@
     4.4 +#ifndef DPMI_H_
     4.5 +#define DPMI_H_
     4.6 +
     4.7 +#include "inttypes.h"
     4.8 +
     4.9 +struct dpmi_real_regs {
    4.10 +	uint32_t edi, esi, ebp;
    4.11 +	uint32_t reserved;
    4.12 +	uint32_t ebx, edx, ecx, eax;
    4.13 +	uint16_t flags;
    4.14 +	uint16_t es, ds, fs, gs;
    4.15 +	uint16_t ip, cs, sp, ss;
    4.16 +};
    4.17 +
    4.18 +unsigned short dpmi_alloc(unsigned int par);
    4.19 +#pragma aux dpmi_alloc = \
    4.20 +		"mov eax, 0x100" \
    4.21 +		"int 0x31" \
    4.22 +		value[ax] parm[ebx];
    4.23 +
    4.24 +void dpmi_real_int(int inum, struct dpmi_real_regs *regs);
    4.25 +
    4.26 +void *dpmi_mmap(uint32_t phys_addr, unsigned int size);
    4.27 +void dpmi_munmap(void *addr);
    4.28 +
    4.29 +#endif	/* DPMI_H_ */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/dos/inttypes.h	Mon Jan 19 15:49:14 2015 +0200
     5.3 @@ -0,0 +1,18 @@
     5.4 +#ifndef INT_TYPES_H_
     5.5 +#define INT_TYPES_H_
     5.6 +
     5.7 +#if defined(__DOS__) || defined(WIN32)
     5.8 +typedef char int8_t;
     5.9 +typedef short int16_t;
    5.10 +typedef long int32_t;
    5.11 +
    5.12 +typedef unsigned char uint8_t;
    5.13 +typedef unsigned short uint16_t;
    5.14 +typedef unsigned long uint32_t;
    5.15 +
    5.16 +typedef unsigned long intptr_t;
    5.17 +#else
    5.18 +#include <stdint.h>
    5.19 +#endif
    5.20 +
    5.21 +#endif	/* INT_TYPES_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/dos/keyb.c	Mon Jan 19 15:49:14 2015 +0200
     6.3 @@ -0,0 +1,201 @@
     6.4 +/*
     6.5 +DOS interrupt-based keyboard driver.
     6.6 +Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
     6.7 +
     6.8 +This program is free software: you can redistribute it and/or modify
     6.9 +it under the terms of the GNU General Public License as published by
    6.10 +the Free Software Foundation, either version 3 of the License, or
    6.11 +(at your option) any later version.
    6.12 +
    6.13 +This program is distributed in the hope that it will be useful,
    6.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    6.16 +GNU General Public License  for more details.
    6.17 +
    6.18 +You should have received a copy of the GNU General Public License
    6.19 +along with the program. If not, see <http://www.gnu.org/licenses/>
    6.20 +*/
    6.21 +#define KEYB_C_
    6.22 +
    6.23 +#include <stdio.h>
    6.24 +#include <stdlib.h>
    6.25 +#include <string.h>
    6.26 +#include <conio.h>
    6.27 +#include <dos.h>
    6.28 +#include <i86.h>
    6.29 +#include "keyb.h"
    6.30 +#include "scancode.h"
    6.31 +
    6.32 +#define KB_INTR		0x9
    6.33 +#define KB_PORT		0x60
    6.34 +
    6.35 +#define PIC1_CMD_PORT	0x20
    6.36 +#define OCW2_EOI		(1 << 5)
    6.37 +
    6.38 +#define DONE_INIT	(prev_handler)
    6.39 +
    6.40 +static void __interrupt __far kbintr();
    6.41 +
    6.42 +static void (__interrupt __far *prev_handler)();
    6.43 +
    6.44 +static int *buffer;
    6.45 +static int buffer_size, buf_ridx, buf_widx;
    6.46 +static int last_key;
    6.47 +
    6.48 +static unsigned int num_pressed;
    6.49 +static unsigned char keystate[256];
    6.50 +
    6.51 +#define ADVANCE(x)	((x) = ((x) + 1) % buffer_size)
    6.52 +
    6.53 +int kb_init(int bufsz)
    6.54 +{
    6.55 +	if(DONE_INIT) {
    6.56 +		fprintf(stderr, "keyboard driver already initialized!\n");
    6.57 +		return 0;
    6.58 +	}
    6.59 +
    6.60 +	buffer_size = bufsz;
    6.61 +	if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) {
    6.62 +		fprintf(stderr, "failed to allocate input buffer, continuing without\n");
    6.63 +		buffer_size = 0;
    6.64 +	}
    6.65 +	buf_ridx = buf_widx = 0;
    6.66 +	last_key = -1;
    6.67 +
    6.68 +	memset(keystate, 0, sizeof keystate);
    6.69 +	num_pressed = 0;
    6.70 +
    6.71 +	/* set our interrupt handler */
    6.72 +	_disable();
    6.73 +	prev_handler = _dos_getvect(KB_INTR);
    6.74 +	_dos_setvect(KB_INTR, kbintr);
    6.75 +	_enable();
    6.76 +
    6.77 +	return 0;
    6.78 +}
    6.79 +
    6.80 +void kb_shutdown(void)
    6.81 +{
    6.82 +	if(!DONE_INIT) {
    6.83 +		return;
    6.84 +	}
    6.85 +
    6.86 +	/* restore the original interrupt handler */
    6.87 +	_disable();
    6.88 +	_dos_setvect(KB_INTR, prev_handler);
    6.89 +	_enable();
    6.90 +
    6.91 +	free(buffer);
    6.92 +}
    6.93 +
    6.94 +int kb_isdown(int key)
    6.95 +{
    6.96 +	switch(key) {
    6.97 +	case KB_ANY:
    6.98 +		return num_pressed;
    6.99 +
   6.100 +	case KB_ALT:
   6.101 +		return keystate[KB_LALT] + keystate[KB_RALT];
   6.102 +
   6.103 +	case KB_CTRL:
   6.104 +		return keystate[KB_LCTRL] + keystate[KB_RCTRL];
   6.105 +	}
   6.106 +	return keystate[key];
   6.107 +}
   6.108 +
   6.109 +void kb_wait(void)
   6.110 +{
   6.111 +	int key;
   6.112 +	while((key = kb_getkey()) == -1) {
   6.113 +		/* put the processor to sleep while waiting for keypresses, but first
   6.114 +		 * make sure interrupts are enabled, or we'll sleep forever
   6.115 +		 */
   6.116 +		__asm {
   6.117 +			sti
   6.118 +			hlt
   6.119 +		}
   6.120 +	}
   6.121 +	kb_putback(key);
   6.122 +}
   6.123 +
   6.124 +int kb_getkey(void)
   6.125 +{
   6.126 +	int res;
   6.127 +
   6.128 +	if(buffer) {
   6.129 +		if(buf_ridx == buf_widx) {
   6.130 +			return -1;
   6.131 +		}
   6.132 +		res = buffer[buf_ridx];
   6.133 +		ADVANCE(buf_ridx);
   6.134 +	} else {
   6.135 +		res = last_key;
   6.136 +		last_key = -1;
   6.137 +	}
   6.138 +	return res;
   6.139 +}
   6.140 +
   6.141 +void kb_putback(int key)
   6.142 +{
   6.143 +	if(buffer) {
   6.144 +		/* go back a place */
   6.145 +		if(--buf_ridx < 0) {
   6.146 +			buf_ridx += buffer_size;
   6.147 +		}
   6.148 +
   6.149 +		/* if the write end hasn't caught up with us, go back one place
   6.150 +		 * and put it there, otherwise just overwrite the oldest key which
   6.151 +		 * is right where we were.
   6.152 +		 */
   6.153 +		if(buf_ridx == buf_widx) {
   6.154 +			ADVANCE(buf_ridx);
   6.155 +		}
   6.156 +
   6.157 +		buffer[buf_ridx] = key;
   6.158 +	} else {
   6.159 +		last_key = key;
   6.160 +	}
   6.161 +}
   6.162 +
   6.163 +static void __interrupt __far kbintr()
   6.164 +{
   6.165 +	unsigned char code;
   6.166 +	int key, press;
   6.167 +
   6.168 +	code = inp(KB_PORT);
   6.169 +
   6.170 +	if(code >= 128) {
   6.171 +		press = 0;
   6.172 +		code -= 128;
   6.173 +
   6.174 +		if(num_pressed > 0) {
   6.175 +			num_pressed--;
   6.176 +		}
   6.177 +	} else {
   6.178 +		press = 1;
   6.179 +
   6.180 +		num_pressed++;
   6.181 +	}
   6.182 +
   6.183 +	key = scantbl[code];
   6.184 +
   6.185 +	if(press) {
   6.186 +		/* append to buffer */
   6.187 +		last_key = key;
   6.188 +		if(buffer_size > 0) {
   6.189 +			buffer[buf_widx] = key;
   6.190 +			ADVANCE(buf_widx);
   6.191 +			/* if the write end overtook the read end, advance the read end
   6.192 +			 * too, to discard the oldest keypress from the buffer
   6.193 +			 */
   6.194 +			if(buf_widx == buf_ridx) {
   6.195 +				ADVANCE(buf_ridx);
   6.196 +			}
   6.197 +		}
   6.198 +	}
   6.199 +
   6.200 +	/* and update keystate table */
   6.201 +	keystate[key] = press;
   6.202 +
   6.203 +	outp(PIC1_CMD_PORT, OCW2_EOI);	/* send end-of-interrupt */
   6.204 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/dos/keyb.h	Mon Jan 19 15:49:14 2015 +0200
     7.3 @@ -0,0 +1,69 @@
     7.4 +/*
     7.5 +DOS interrupt-based keyboard driver.
     7.6 +Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
     7.7 +
     7.8 +This program is free software: you can redistribute it and/or modify
     7.9 +it under the terms of the GNU General Public License as published by
    7.10 +the Free Software Foundation, either version 3 of the License, or
    7.11 +(at your option) any later version.
    7.12 +
    7.13 +This program is distributed in the hope that it will be useful,
    7.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    7.16 +GNU General Public License  for more details.
    7.17 +
    7.18 +You should have received a copy of the GNU General Public License
    7.19 +along with the program. If not, see <http://www.gnu.org/licenses/>
    7.20 +*/
    7.21 +#ifndef KEYB_H_
    7.22 +#define KEYB_H_
    7.23 +
    7.24 +#define KB_ANY		(-1)
    7.25 +#define KB_ALT		(-2)
    7.26 +#define KB_CTRL		(-3)
    7.27 +#define KB_SHIFT	(-4)
    7.28 +
    7.29 +/* special keys */
    7.30 +enum {
    7.31 +	KB_LALT, KB_RALT,
    7.32 +	KB_LCTRL, KB_RCTRL,
    7.33 +	KB_LSHIFT, KB_RSHIFT,
    7.34 +	KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6,
    7.35 +	KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12,
    7.36 +	KB_CAPSLK, KB_NUMLK, KB_SCRLK, KB_SYSRQ,
    7.37 +	KB_ESC = 27,
    7.38 +	KB_INSERT, KB_DEL, KB_HOME, KB_END, KB_PGUP, KB_PGDN,
    7.39 +	KB_LEFT, KB_RIGHT, KB_UP, KB_DOWN,
    7.40 +	KB_NUM_DOT, KB_NUM_ENTER, KB_NUM_PLUS, KB_NUM_MINUS, KB_NUM_MUL, KB_NUM_DIV,
    7.41 +	KB_NUM_0, KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_4,
    7.42 +	KB_NUM_5, KB_NUM_6, KB_NUM_7, KB_NUM_8, KB_NUM_9,
    7.43 +	KB_BACKSP = 127
    7.44 +};
    7.45 +
    7.46 +
    7.47 +#ifdef __cplusplus
    7.48 +extern "C" {
    7.49 +#endif
    7.50 +
    7.51 +int kb_init(int bufsz);	/* bufsz can be 0 for no buffered keys */
    7.52 +void kb_shutdown(void); /* don't forget to call this at the end! */
    7.53 +
    7.54 +/* Boolean predicate for testing the current state of a particular key.
    7.55 + * You may also pass KB_ANY to test if any key is held down.
    7.56 + */
    7.57 +int kb_isdown(int key);
    7.58 +
    7.59 +/* waits for any keypress */
    7.60 +void kb_wait(void);
    7.61 +
    7.62 +/* removes and returns a single key from the input buffer.
    7.63 + * If buffering is disabled (initialized with kb_init(0)), then it always
    7.64 + * returns the last key pressed.
    7.65 + */
    7.66 +int kb_getkey(void);
    7.67 +
    7.68 +#ifdef __cplusplus
    7.69 +}
    7.70 +#endif
    7.71 +
    7.72 +#endif	/* KEYB_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/dos/mouse.c	Mon Jan 19 15:49:14 2015 +0200
     8.3 @@ -0,0 +1,93 @@
     8.4 +#include "mouse.h"
     8.5 +#include "inttypes.h"
     8.6 +
     8.7 +#define INTR	0x33
     8.8 +
     8.9 +#define QUERY	0
    8.10 +#define SHOW	1
    8.11 +#define HIDE	2
    8.12 +#define READ	3
    8.13 +#define WRITE	4
    8.14 +#define PIXRATE	0xf
    8.15 +
    8.16 +#define XLIM	7
    8.17 +#define YLIM	8
    8.18 +
    8.19 +int have_mouse(void)
    8.20 +{
    8.21 +	uint16_t res = 0;
    8.22 +	_asm {
    8.23 +		mov eax, QUERY
    8.24 +		int INTR
    8.25 +		mov res, ax
    8.26 +	}
    8.27 +	return res;
    8.28 +}
    8.29 +
    8.30 +void show_mouse(int show)
    8.31 +{
    8.32 +	uint16_t cmd = show ? SHOW : HIDE;
    8.33 +	_asm {
    8.34 +		mov ax, cmd
    8.35 +		int INTR
    8.36 +	}
    8.37 +}
    8.38 +
    8.39 +int read_mouse(int *xp, int *yp)
    8.40 +{
    8.41 +	uint16_t x, y, state;
    8.42 +	_asm {
    8.43 +		mov eax, READ
    8.44 +		int INTR
    8.45 +		mov state, bx
    8.46 +		mov x, cx
    8.47 +		mov y, dx
    8.48 +	}
    8.49 +
    8.50 +	if(xp) *xp = x;
    8.51 +	if(yp) *yp = y;
    8.52 +	return state;
    8.53 +}
    8.54 +
    8.55 +void set_mouse(int x, int y)
    8.56 +{
    8.57 +	_asm {
    8.58 +		mov eax, WRITE
    8.59 +		mov ecx, x
    8.60 +		mov edx, y
    8.61 +		int INTR
    8.62 +	}
    8.63 +}
    8.64 +
    8.65 +void set_mouse_limits(int xmin, int ymin, int xmax, int ymax)
    8.66 +{
    8.67 +	_asm {
    8.68 +		mov eax, XLIM
    8.69 +		mov ecx, xmin
    8.70 +		mov edx, xmax
    8.71 +		int INTR
    8.72 +		mov eax, YLIM
    8.73 +		mov ecx, ymin
    8.74 +		mov edx, ymax
    8.75 +		int INTR
    8.76 +	}
    8.77 +}
    8.78 +
    8.79 +void set_mouse_rate(int xrate, int yrate)
    8.80 +{
    8.81 +	_asm {
    8.82 +		mov ax, PIXRATE
    8.83 +		mov ecx, xrate
    8.84 +		mov edx, yrate
    8.85 +		int INTR
    8.86 +	}
    8.87 +}
    8.88 +
    8.89 +void set_mouse_mode(enum mouse_mode mode)
    8.90 +{
    8.91 +	if(mode == MOUSE_GFX) {
    8.92 +		set_mouse_rate(1, 1);
    8.93 +	} else {
    8.94 +		set_mouse_rate(8, 16);
    8.95 +	}
    8.96 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/dos/mouse.h	Mon Jan 19 15:49:14 2015 +0200
     9.3 @@ -0,0 +1,31 @@
     9.4 +#ifndef MOUSE_H_
     9.5 +#define MOUSE_H_
     9.6 +
     9.7 +enum {
     9.8 +	MOUSE_LEFT		= 1,
     9.9 +	MOUSE_RIGHT		= 2,
    9.10 +	MOUSE_MIDDLE	= 4
    9.11 +};
    9.12 +
    9.13 +enum mouse_mode {
    9.14 +	MOUSE_GFX,
    9.15 +	MOUSE_TEXT
    9.16 +};
    9.17 +
    9.18 +#ifdef __cplusplus
    9.19 +extern "C" {
    9.20 +#endif
    9.21 +
    9.22 +int have_mouse(void);
    9.23 +void show_mouse(int show);
    9.24 +int read_mouse(int *xp, int *yp);
    9.25 +void set_mouse(int x, int y);
    9.26 +void set_mouse_limits(int xmin, int ymin, int xmax, int ymax);
    9.27 +void set_mouse_rate(int xrate, int yrate);
    9.28 +void set_mouse_mode(enum mouse_mode mode);
    9.29 +
    9.30 +#ifdef __cplusplus
    9.31 +}
    9.32 +#endif
    9.33 +
    9.34 +#endif	/* MOUSE_H_ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/dos/pit8254.h	Mon Jan 19 15:49:14 2015 +0200
    10.3 @@ -0,0 +1,34 @@
    10.4 +#ifndef PIT8254_H_
    10.5 +#define PIT8254_H_
    10.6 +
    10.7 +/* frequency of the oscillator driving the 8254 timer */
    10.8 +#define OSC_FREQ_HZ		1193182
    10.9 +
   10.10 +/* I/O ports connected to the 8254 */
   10.11 +#define PORT_DATA0	0x40
   10.12 +#define PORT_DATA1	0x41
   10.13 +#define PORT_DATA2	0x42
   10.14 +#define PORT_CMD	0x43
   10.15 +
   10.16 +/* command bits */
   10.17 +#define CMD_CHAN0			0
   10.18 +#define CMD_CHAN1			(1 << 6)
   10.19 +#define CMD_CHAN2			(2 << 6)
   10.20 +#define CMD_RDBACK			(3 << 6)
   10.21 +
   10.22 +#define CMD_LATCH			0
   10.23 +#define CMD_ACCESS_LOW		(1 << 4)
   10.24 +#define CMD_ACCESS_HIGH		(2 << 4)
   10.25 +#define CMD_ACCESS_BOTH		(3 << 4)
   10.26 +
   10.27 +#define CMD_OP_INT_TERM		0
   10.28 +#define CMD_OP_ONESHOT		(1 << 1)
   10.29 +#define CMD_OP_RATE			(2 << 1)
   10.30 +#define CMD_OP_SQWAVE		(3 << 1)
   10.31 +#define CMD_OP_SW_STROBE	(4 << 1)
   10.32 +#define CMD_OP_HW_STROBE	(5 << 1)
   10.33 +
   10.34 +#define CMD_MODE_BIN		0
   10.35 +#define CMD_MODE_BCD		1
   10.36 +
   10.37 +#endif	/* PIT8254_H_ */
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/dos/scancode.h	Mon Jan 19 15:49:14 2015 +0200
    11.3 @@ -0,0 +1,17 @@
    11.4 +#ifndef KEYB_C_
    11.5 +#error "do not include scancode.h anywhere..."
    11.6 +#endif
    11.7 +
    11.8 +/* table with rough translations from set 1 scancodes to ASCII-ish */
    11.9 +static int scantbl[] = {
   11.10 +	0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',		/* 0 - e */
   11.11 +	'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',			/* f - 1c */
   11.12 +	KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',				/* 1d - 29 */
   11.13 +	KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT,			/* 2a - 36 */
   11.14 +	KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,			/* 37 - 44 */
   11.15 +	KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,	/* 45 - 4e */
   11.16 +	KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,						/* 4d - 58 */
   11.17 +	0, 0, 0, 0, 0, 0, 0,															/* 59 - 5f */
   11.18 +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,									/* 60 - 6f */
   11.19 +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0									/* 70 - 7f */
   11.20 +};
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/dos/timer.c	Mon Jan 19 15:49:14 2015 +0200
    12.3 @@ -0,0 +1,131 @@
    12.4 +/*
    12.5 +256-color 3D graphics hack for real-mode DOS.
    12.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
    12.7 +
    12.8 +This program is free software: you can redistribute it and/or modify
    12.9 +it under the terms of the GNU General Public License as published by
   12.10 +the Free Software Foundation, either version 3 of the License, or
   12.11 +(at your option) any later version.
   12.12 +
   12.13 +This program is distributed in the hope that it will be useful,
   12.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   12.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12.16 +GNU General Public License for more details.
   12.17 +
   12.18 +You should have received a copy of the GNU General Public License
   12.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   12.20 +*/
   12.21 +#include <stdio.h>
   12.22 +#include <stdlib.h>
   12.23 +#include <conio.h>
   12.24 +#include <dos.h>
   12.25 +#include <i86.h>
   12.26 +#include "pit8254.h"
   12.27 +
   12.28 +#define PIT_TIMER_INTR	8
   12.29 +#define DOS_TIMER_INTR	0x1c
   12.30 +
   12.31 +/* macro to divide and round to the nearest integer */
   12.32 +#define DIV_ROUND(a, b) \
   12.33 +	((a) / (b) + ((a) % (b)) / ((b) / 2))
   12.34 +
   12.35 +static void set_timer_reload(int reload_val);
   12.36 +static void cleanup(void);
   12.37 +static void __interrupt __far timer_irq();
   12.38 +static void __interrupt __far dos_timer_intr();
   12.39 +
   12.40 +static void (__interrupt __far *prev_timer_intr)();
   12.41 +
   12.42 +static unsigned long ticks;
   12.43 +static unsigned long tick_interval, ticks_per_dos_intr;
   12.44 +static int inum;
   12.45 +
   12.46 +void init_timer(int res_hz)
   12.47 +{
   12.48 +	_disable();
   12.49 +
   12.50 +	if(res_hz > 0) {
   12.51 +		int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz);
   12.52 +		set_timer_reload(reload_val);
   12.53 +
   12.54 +		tick_interval = DIV_ROUND(1000, res_hz);
   12.55 +		ticks_per_dos_intr = DIV_ROUND(65535L, reload_val);
   12.56 +
   12.57 +		inum = PIT_TIMER_INTR;
   12.58 +		prev_timer_intr = _dos_getvect(inum);
   12.59 +		_dos_setvect(inum, timer_irq);
   12.60 +	} else {
   12.61 +		tick_interval = 55;
   12.62 +
   12.63 +		inum = DOS_TIMER_INTR;
   12.64 +		prev_timer_intr = _dos_getvect(inum);
   12.65 +		_dos_setvect(inum, dos_timer_intr);
   12.66 +	}
   12.67 +	_enable();
   12.68 +
   12.69 +	atexit(cleanup);
   12.70 +}
   12.71 +
   12.72 +static void cleanup(void)
   12.73 +{
   12.74 +	if(!prev_timer_intr) {
   12.75 +		return; /* init hasn't ran, there's nothing to cleanup */
   12.76 +	}
   12.77 +
   12.78 +	_disable();
   12.79 +	if(inum == PIT_TIMER_INTR) {
   12.80 +		/* restore the original timer frequency */
   12.81 +		set_timer_reload(65535);
   12.82 +	}
   12.83 +
   12.84 +	/* restore the original interrupt handler */
   12.85 +	_dos_setvect(inum, prev_timer_intr);
   12.86 +	_enable();
   12.87 +}
   12.88 +
   12.89 +void reset_timer(void)
   12.90 +{
   12.91 +	ticks = 0;
   12.92 +}
   12.93 +
   12.94 +unsigned long get_msec(void)
   12.95 +{
   12.96 +	return ticks * tick_interval;
   12.97 +}
   12.98 +
   12.99 +static void set_timer_reload(int reload_val)
  12.100 +{
  12.101 +	outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE);
  12.102 +	outp(PORT_DATA0, reload_val & 0xff);
  12.103 +	outp(PORT_DATA0, (reload_val >> 8) & 0xff);
  12.104 +}
  12.105 +
  12.106 +static void __interrupt __far dos_timer_intr()
  12.107 +{
  12.108 +	ticks++;
  12.109 +	_chain_intr(prev_timer_intr);	/* DOES NOT RETURN */
  12.110 +}
  12.111 +
  12.112 +/* first PIC command port */
  12.113 +#define PIC1_CMD	0x20
  12.114 +/* end of interrupt control word */
  12.115 +#define OCW2_EOI	(1 << 5)
  12.116 +
  12.117 +static void __interrupt __far timer_irq()
  12.118 +{
  12.119 +	static unsigned long dos_ticks;
  12.120 +
  12.121 +	ticks++;
  12.122 +
  12.123 +	if(++dos_ticks >= ticks_per_dos_intr) {
  12.124 +		/* I suppose the dos irq handler does the EOI so I shouldn't
  12.125 +		 * do it if I am to call the previous function
  12.126 +		 */
  12.127 +		dos_ticks = 0;
  12.128 +		_chain_intr(prev_timer_intr);	/* XXX DOES NOT RETURN */
  12.129 +		return;	/* just for clarity */
  12.130 +	}
  12.131 +
  12.132 +	/* send EOI to the PIC */
  12.133 +	outp(PIC1_CMD, OCW2_EOI);
  12.134 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/dos/timer.h	Mon Jan 19 15:49:14 2015 +0200
    13.3 @@ -0,0 +1,37 @@
    13.4 +/*
    13.5 +256-color 3D graphics hack for real-mode DOS.
    13.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
    13.7 +
    13.8 +This program is free software: you can redistribute it and/or modify
    13.9 +it under the terms of the GNU General Public License as published by
   13.10 +the Free Software Foundation, either version 3 of the License, or
   13.11 +(at your option) any later version.
   13.12 +
   13.13 +This program is distributed in the hope that it will be useful,
   13.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   13.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13.16 +GNU General Public License for more details.
   13.17 +
   13.18 +You should have received a copy of the GNU General Public License
   13.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   13.20 +*/
   13.21 +#ifndef TIMER_H_
   13.22 +#define TIMER_H_
   13.23 +
   13.24 +#ifdef __cplusplus
   13.25 +extern "C" {
   13.26 +#endif
   13.27 +
   13.28 +/* expects the required timer resolution in hertz
   13.29 + * if res_hz is 0, the current resolution is retained
   13.30 + */
   13.31 +void init_timer(int res_hz);
   13.32 +
   13.33 +void reset_timer(void);
   13.34 +unsigned long get_msec(void);
   13.35 +
   13.36 +#ifdef __cplusplus
   13.37 +}
   13.38 +#endif
   13.39 +
   13.40 +#endif	/* TIMER_H_ */
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/dos/vbe.c	Mon Jan 19 15:49:14 2015 +0200
    14.3 @@ -0,0 +1,153 @@
    14.4 +#include <stdio.h>
    14.5 +#include <string.h>
    14.6 +#include "vbe.h"
    14.7 +#include "dpmi.h"
    14.8 +
    14.9 +/* VGA DAC registers used for palette setting in 8bpp modes */
   14.10 +#define VGA_DAC_STATE		0x3c7
   14.11 +#define VGA_DAC_ADDR_RD		0x3c7
   14.12 +#define VGA_DAC_ADDR_WR		0x3c8
   14.13 +#define VGA_DAC_DATA		0x3c9
   14.14 +
   14.15 +#define MODE_LFB	(1 << 14)
   14.16 +
   14.17 +
   14.18 +struct vbe_info *vbe_get_info(void)
   14.19 +{
   14.20 +	static unsigned short info_block_seg;
   14.21 +	static struct vbe_info *info;
   14.22 +	struct dpmi_real_regs regs;
   14.23 +
   14.24 +	if(!info) {
   14.25 +		/* allocate 32 paragraphs (512 bytes) */
   14.26 +		info_block_seg = dpmi_alloc(32);
   14.27 +		info = (struct vbe_info*)(info_block_seg << 4);
   14.28 +	}
   14.29 +
   14.30 +	memcpy(info->sig, "VBE2", 4);
   14.31 +
   14.32 +	memset(&regs, 0, sizeof regs);
   14.33 +	regs.es = info_block_seg;
   14.34 +	regs.eax = 0x4f00;
   14.35 +
   14.36 +	dpmi_real_int(0x10, &regs);
   14.37 +
   14.38 +	return info;
   14.39 +}
   14.40 +
   14.41 +struct vbe_mode_info *vbe_get_mode_info(int mode)
   14.42 +{
   14.43 +	static unsigned short mode_info_seg;
   14.44 +	static struct vbe_mode_info *mi;
   14.45 +	struct dpmi_real_regs regs;
   14.46 +
   14.47 +	if(!mi) {
   14.48 +		/* allocate 16 paragraphs (256 bytes) */
   14.49 +		mode_info_seg = dpmi_alloc(16);
   14.50 +		mi = (struct vbe_mode_info*)(mode_info_seg << 4);
   14.51 +	}
   14.52 +
   14.53 +	memset(&regs, 0, sizeof regs);
   14.54 +	regs.es = mode_info_seg;
   14.55 +	regs.eax = 0x4f01;
   14.56 +	regs.ecx = mode;
   14.57 +	regs.es = mode_info_seg;
   14.58 +
   14.59 +	dpmi_real_int(0x10, &regs);
   14.60 +	if(regs.eax & 0xff00) {
   14.61 +		return 0;
   14.62 +	}
   14.63 +
   14.64 +	return mi;
   14.65 +}
   14.66 +
   14.67 +int vbe_set_mode(int mode)
   14.68 +{
   14.69 +	struct dpmi_real_regs regs;
   14.70 +
   14.71 +	memset(&regs, 0, sizeof regs);
   14.72 +	regs.eax = 0x4f02;
   14.73 +	regs.ebx = mode;
   14.74 +	dpmi_real_int(0x10, &regs);
   14.75 +
   14.76 +	if(regs.eax == 0x100) {
   14.77 +		return -1;
   14.78 +	}
   14.79 +	return 0;
   14.80 +}
   14.81 +
   14.82 +int vbe_set_palette_bits(int bits)
   14.83 +{
   14.84 +	struct dpmi_real_regs regs;
   14.85 +
   14.86 +	memset(&regs, 0, sizeof regs);
   14.87 +	regs.eax = 0x4f08;
   14.88 +	regs.ebx = bits << 8;	/* bits in bh */
   14.89 +	dpmi_real_int(0x10, &regs);
   14.90 +
   14.91 +	if((regs.eax >> 8) & 0xff == 3) {
   14.92 +		return -1;
   14.93 +	}
   14.94 +	return regs.ebx >> 8 & 0xff;	/* new color bits in bh */
   14.95 +}
   14.96 +
   14.97 +/* TODO: implement palette setting through the VBE2 interface for
   14.98 + * non-VGA displays (actually don't).
   14.99 + */
  14.100 +void vbe_set_palette(int idx, int *col, int count, int bits)
  14.101 +{
  14.102 +	int i, shift = 8 - bits;
  14.103 +
  14.104 +	__asm {
  14.105 +		mov dx, VGA_DAC_ADDR_WR
  14.106 +		mov eax, idx
  14.107 +		out dx, al
  14.108 +	}
  14.109 +
  14.110 +	for(i=0; i<count; i++) {
  14.111 +		unsigned char r = *col++;
  14.112 +		unsigned char g = *col++;
  14.113 +		unsigned char b = *col++;
  14.114 +
  14.115 +		if(shift) {
  14.116 +			r >>= shift;
  14.117 +			g >>= shift;
  14.118 +			b >>= shift;
  14.119 +		}
  14.120 +
  14.121 +		__asm {
  14.122 +			mov dx, VGA_DAC_DATA
  14.123 +			mov al, r
  14.124 +			out dx, al
  14.125 +			mov al, g
  14.126 +			out dx, al
  14.127 +			mov al, b
  14.128 +			out dx, al
  14.129 +		}
  14.130 +	}
  14.131 +}
  14.132 +
  14.133 +static unsigned int get_mask(int sz, int pos)
  14.134 +{
  14.135 +	unsigned int i, mask = 0;
  14.136 +
  14.137 +	for(i=0; i<sz; i++) {
  14.138 +		mask |= 1 << i;
  14.139 +	}
  14.140 +	return mask << pos;
  14.141 +}
  14.142 +
  14.143 +void print_mode_info(FILE *fp, struct vbe_mode_info *mi)
  14.144 +{
  14.145 +	fprintf(fp, "resolution: %dx%d\n", mi->xres, mi->yres);
  14.146 +	fprintf(fp, "color depth: %d\n", mi->bpp);
  14.147 +	fprintf(fp, "mode attributes: %x\n", mi->mode_attr);
  14.148 +	fprintf(fp, "bytes per scanline: %d\n", mi->scanline_bytes);
  14.149 +	fprintf(fp, "number of planes: %d\n", (int)mi->num_planes);
  14.150 +	fprintf(fp, "number of banks: %d\n", (int)mi->num_banks);
  14.151 +	fprintf(fp, "mem model: %d\n", (int)mi->mem_model);
  14.152 +	fprintf(fp, "red bits: %d (mask: %x)\n", (int)mi->rmask_size, get_mask(mi->rmask_size, mi->rpos));
  14.153 +	fprintf(fp, "green bits: %d (mask: %x)\n", (int)mi->gmask_size, get_mask(mi->gmask_size, mi->gpos));
  14.154 +	fprintf(fp, "blue bits: %d (mask: %x)\n", (int)mi->bmask_size, get_mask(mi->bmask_size, mi->bpos));
  14.155 +	fprintf(fp, "framebuffer address: %x\n", mi->fb_addr);
  14.156 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/dos/vbe.h	Mon Jan 19 15:49:14 2015 +0200
    15.3 @@ -0,0 +1,70 @@
    15.4 +#ifndef VBE_H_
    15.5 +#define VBE_H_
    15.6 +
    15.7 +#include "inttypes.h"
    15.8 +
    15.9 +#define VBE_ATTR_LFB	(1 << 7)
   15.10 +#define VBE_MODE_LFB	(1 << 14)
   15.11 +
   15.12 +#pragma pack (push, 0)
   15.13 +struct vbe_info {
   15.14 +	uint8_t sig[4];
   15.15 +	uint16_t version;
   15.16 +	uint32_t oem_str_ptr;
   15.17 +	uint8_t caps[4];			/* capabilities */
   15.18 +	uint32_t vid_mode_ptr;		/* vbefarptr to video mode list */
   15.19 +	uint16_t total_mem;			/* num of 64k mem blocks */
   15.20 +	uint16_t oem_sw_rev;		/* VBE implementation software revision */
   15.21 +	uint32_t oem_vendor_name_ptr;
   15.22 +	uint32_t oem_product_name_ptr;
   15.23 +	uint32_t oem_product_rev_ptr;
   15.24 +	uint8_t reserved[222];
   15.25 +	uint8_t oem_data[256];
   15.26 +};
   15.27 +
   15.28 +struct vbe_mode_info {
   15.29 +	uint16_t mode_attr;
   15.30 +	uint8_t wina_attr, winb_attr;
   15.31 +	uint16_t win_gran, win_size;
   15.32 +	uint16_t wina_seg, winb_seg;
   15.33 +	uint32_t win_func;
   15.34 +	uint16_t scanline_bytes;
   15.35 +
   15.36 +	/* VBE 1.2 and above */
   15.37 +	uint16_t xres, yres;
   15.38 +	uint8_t xcharsz, ycharsz;
   15.39 +	uint8_t num_planes;
   15.40 +	uint8_t bpp;
   15.41 +	uint8_t num_banks;
   15.42 +	uint8_t mem_model;
   15.43 +	uint8_t bank_size;		/* bank size in KB */
   15.44 +	uint8_t num_img_pages;
   15.45 +	uint8_t reserved1;
   15.46 +
   15.47 +	/* direct color fields */
   15.48 +	uint8_t rmask_size, rpos;
   15.49 +	uint8_t gmask_size, gpos;
   15.50 +	uint8_t bmask_size, bpos;
   15.51 +	uint8_t xmask_size, xpos;
   15.52 +	uint8_t cmode_info;		/* direct color mode attributes */
   15.53 +
   15.54 +	/* VBE 2.0 and above */
   15.55 +	uint32_t fb_addr;		/* physical address of the linear framebuffer */
   15.56 +	uint32_t reserved2;
   15.57 +	uint16_t reserved3;
   15.58 +
   15.59 +	uint8_t reserved4[206];
   15.60 +};
   15.61 +#pragma pack (pop)
   15.62 +
   15.63 +struct vbe_info *vbe_get_info(void);
   15.64 +struct vbe_mode_info *vbe_get_mode_info(unsigned int mode);
   15.65 +
   15.66 +int vbe_set_mode(unsigned int mode);
   15.67 +
   15.68 +int vbe_set_palette_bits(int bits);
   15.69 +void vbe_set_palette(int idx, int *col, int count, int bits);
   15.70 +
   15.71 +void print_mode_info(FILE *fp, struct vbe_mode_info *modei);
   15.72 +
   15.73 +#endif	/* VBE_H_ */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/dos/vbegfx.c	Mon Jan 19 15:49:14 2015 +0200
    16.3 @@ -0,0 +1,158 @@
    16.4 +#ifndef GFX_H_
    16.5 +#define GFX_H_
    16.6 +
    16.7 +#include <stdio.h>
    16.8 +#include <stdlib.h>
    16.9 +#include <string.h>
   16.10 +#include "vbe.h"
   16.11 +#include "logger.h"
   16.12 +
   16.13 +#define REALPTR(s, o)	(void*)(((uint32_t)(s) << 4) + (uint32_t)(o))
   16.14 +#define VBEPTR(x)		REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff)
   16.15 +#define VBEPTR_SEG(x)	(((x) & 0xffff0000) >> 16)
   16.16 +#define VBEPTR_OFF(x)	((x) & 0xffff)
   16.17 +
   16.18 +#define SAME_BPP(a, b)	\
   16.19 +	((a) == (b) || (a) == 16 && (b) == 15 || (a) == 15 && (b) == 16 || (a) == 32 && (b) == 24 || (a) == 24 && (b) == 32)
   16.20 +
   16.21 +static unsigned int make_mask(int sz, int pos);
   16.22 +
   16.23 +static struct vbe_info *vbe_info;
   16.24 +static struct vbe_mode_info *mode_info;
   16.25 +static int pal_bits = 6;
   16.26 +
   16.27 +void *set_video_mode(int xsz, int ysz, int bpp)
   16.28 +{
   16.29 +	int i;
   16.30 +	uint16_t *modes, best = 0;
   16.31 +	unsigned int fbsize;
   16.32 +
   16.33 +	/* check for VBE2 support and output some info */
   16.34 +	if(!vbe_info) {
   16.35 +		if(!(vbe_info = vbe_get_info())) {
   16.36 +			fprintf(stderr, "VESA BIOS Extensions not available\n");
   16.37 +			return 0;
   16.38 +		}
   16.39 +
   16.40 +		printlog("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff);
   16.41 +		if(vbe_info->version < 0x200) {
   16.42 +			fprintf(stderr, "This program requires VBE 2.0 or greater. Try running UniVBE\n");
   16.43 +			return 0;
   16.44 +		}
   16.45 +
   16.46 +		printlog("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr),
   16.47 +				VBEPTR(vbe_info->oem_product_name_ptr), VBEPTR(vbe_info->oem_product_rev_ptr));
   16.48 +		printlog("Video memory: %dmb\n", vbe_info->total_mem << 6);
   16.49 +
   16.50 +		modes = VBEPTR(vbe_info->vid_mode_ptr);
   16.51 +	}
   16.52 +
   16.53 +	for(i=0; i<1024; i++) {	/* impose an upper limit to avoid inf-loops */
   16.54 +		if(modes[i] == 0xffff) {
   16.55 +			break;	/* reached the end */
   16.56 +		}
   16.57 +
   16.58 +		mode_info = vbe_get_mode_info(modes[i] | VBE_MODE_LFB);
   16.59 +		if(!mode_info || mode_info->xres != xsz || mode_info->yres != ysz) {
   16.60 +			continue;
   16.61 +		}
   16.62 +		if(SAME_BPP(mode_info->bpp, bpp)) {
   16.63 +			best = modes[i];
   16.64 +		}
   16.65 +	}
   16.66 +
   16.67 +	if(best) {
   16.68 +		mode_info = vbe_get_mode_info(best);
   16.69 +	} else {
   16.70 +		fprintf(stderr, "Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp);
   16.71 +		return 0;
   16.72 +	}
   16.73 +
   16.74 +	if(vbe_set_mode(best | VBE_MODE_LFB) == -1) {
   16.75 +		fprintf(stderr, "Failed to set video mode %dx%d %dbpp\n", mode_info->xres, mode_info->yres, mode_info->bpp);
   16.76 +		return 0;
   16.77 +	}
   16.78 +
   16.79 +	/* attempt to set 8 bits of color per component in palettized modes */
   16.80 +	if(bpp <= 8) {
   16.81 +		pal_bits = vbe_set_palette_bits(8);
   16.82 +		printlog("palette bits per color primary: %d\n", pal_bits);
   16.83 +	}
   16.84 +
   16.85 +	fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT);
   16.86 +	return (void*)dpmi_mmap(mode_info->fb_addr, fbsize);
   16.87 +}
   16.88 +
   16.89 +int set_text_mode(void)
   16.90 +{
   16.91 +	vbe_set_mode(0x3);
   16.92 +	return 0;
   16.93 +}
   16.94 +
   16.95 +int get_color_depth(void)
   16.96 +{
   16.97 +	if(!mode_info) {
   16.98 +		return -1;
   16.99 +	}
  16.100 +	return mode_info->bpp;
  16.101 +}
  16.102 +
  16.103 +int get_color_bits(int *rbits, int *gbits, int *bbits)
  16.104 +{
  16.105 +	if(!mode_info) {
  16.106 +		return -1;
  16.107 +	}
  16.108 +	*rbits = mode_info->rmask_size;
  16.109 +	*gbits = mode_info->gmask_size;
  16.110 +	*bbits = mode_info->bmask_size;
  16.111 +	return 0;
  16.112 +}
  16.113 +
  16.114 +int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask)
  16.115 +{
  16.116 +	if(!mode_info) {
  16.117 +		return -1;
  16.118 +	}
  16.119 +	*rmask = make_mask(mode_info->rmask_size, mode_info->rpos);
  16.120 +	*gmask = make_mask(mode_info->gmask_size, mode_info->gpos);
  16.121 +	*bmask = make_mask(mode_info->bmask_size, mode_info->bpos);
  16.122 +	return 0;
  16.123 +}
  16.124 +
  16.125 +int get_color_shift(int *rshift, int *gshift, int *bshift)
  16.126 +{
  16.127 +	if(!mode_info) {
  16.128 +		return -1;
  16.129 +	}
  16.130 +	*rshift = mode_info->rpos;
  16.131 +	*gshift = mode_info->gpos;
  16.132 +	*bshift = mode_info->bpos;
  16.133 +	return 0;
  16.134 +}
  16.135 +
  16.136 +void set_palette(int idx, int r, int g, int b)
  16.137 +{
  16.138 +	int col[3];
  16.139 +	col[0] = r;
  16.140 +	col[1] = g;
  16.141 +	col[2] = b;
  16.142 +	vbe_set_palette(idx, col, 1, pal_bits);
  16.143 +}
  16.144 +
  16.145 +void wait_vsync(void)
  16.146 +{
  16.147 +	/* TODO */
  16.148 +}
  16.149 +
  16.150 +static unsigned int make_mask(int sz, int pos)
  16.151 +{
  16.152 +	unsigned int i, mask = 0;
  16.153 +
  16.154 +	for(i=0; i<sz; i++) {
  16.155 +		mask |= 1 << i;
  16.156 +	}
  16.157 +	return mask << pos;
  16.158 +}
  16.159 +
  16.160 +
  16.161 +#endif	/* GFX_H_ */
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/dos/vbegfx.h	Mon Jan 19 15:49:14 2015 +0200
    17.3 @@ -0,0 +1,24 @@
    17.4 +#ifndef VBEGFX_H_
    17.5 +#define VBEGFX_H_
    17.6 +
    17.7 +#ifdef __cplusplus
    17.8 +extern "C" {
    17.9 +#endif
   17.10 +
   17.11 +void *set_video_mode(int xsz, int ysz, int bpp);
   17.12 +int set_text_mode(void);
   17.13 +
   17.14 +int get_color_depth(void);
   17.15 +int get_color_bits(int *rbits, int *gbits, int *bbits);
   17.16 +int get_color_shift(int *rshift, int *gshift, int *bshift);
   17.17 +int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask);
   17.18 +
   17.19 +void set_palette(int idx, int r, int g, int b);
   17.20 +
   17.21 +void wait_vsync(void);
   17.22 +
   17.23 +#ifdef __cplusplus
   17.24 +}
   17.25 +#endif
   17.26 +
   17.27 +#endif	/* VBEGFX_H_ */
    18.1 --- a/src/fblib.c	Mon Jan 19 02:32:01 2015 +0200
    18.2 +++ b/src/fblib.c	Mon Jan 19 15:49:14 2015 +0200
    18.3 @@ -1,6 +1,21 @@
    18.4  #include "fblib.h"
    18.5  #include "fblibimp.h"
    18.6  
    18.7 +int fb_get_width(void)
    18.8 +{
    18.9 +	return fb_width;
   18.10 +}
   18.11 +
   18.12 +int fb_get_height(void)
   18.13 +{
   18.14 +	return fb_height;
   18.15 +}
   18.16 +
   18.17 +int fb_get_bpp(void)
   18.18 +{
   18.19 +	return fb_bpp;
   18.20 +}
   18.21 +
   18.22  void fb_set_palette(int *colors)
   18.23  {
   18.24  	fb_set_palette_range(0, 256, colors);
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/fblibdos.c	Mon Jan 19 15:49:14 2015 +0200
    19.3 @@ -0,0 +1,62 @@
    19.4 +#ifdef FBLIB_DOS
    19.5 +#include "vbegfx.h"
    19.6 +
    19.7 +static unsigned char *framebuf;
    19.8 +
    19.9 +int fb_init(int width, int height, int bpp)
   19.10 +{
   19.11 +	init_timer(128);
   19.12 +	if(kb_init(32) == -1) {
   19.13 +		fprintf(stderr, "failed to initialize keyboard driver\n");
   19.14 +		return false;
   19.15 +	}
   19.16 +
   19.17 +	if(!(framebuf = set_video_mode(width, height, bpp))) {
   19.18 +		return -1;
   19.19 +	}
   19.20 +	fb_width = width;
   19.21 +	fb_height = height;
   19.22 +	fb_bpp = get_color_depth();
   19.23 +
   19.24 +
   19.25 +	return 0;
   19.26 +}
   19.27 +
   19.28 +void fb_shutdown(void)
   19.29 +{
   19.30 +	framebuf = 0;
   19.31 +	set_text_mode();
   19.32 +}
   19.33 +
   19.34 +void *fb_begin_frame(void)
   19.35 +{
   19.36 +	return framebuf;
   19.37 +}
   19.38 +
   19.39 +void fb_end_frame(void)
   19.40 +{
   19.41 +	wait_vsync(void);
   19.42 +}
   19.43 +
   19.44 +void fb_set_palette_range(int start, int count, int *colors)
   19.45 +{
   19.46 +	/* TODO: add a range-palette setter in vbegfx.c */
   19.47 +	int i;
   19.48 +	for(i=0; i<count; i++) {
   19.49 +		set_palette(start + i, colors[0], colors[1], colors[2]);
   19.50 +		colors += 3;
   19.51 +	}
   19.52 +}
   19.53 +
   19.54 +int fb_process_events(void)
   19.55 +{
   19.56 +	if(handle_keyboard() == -1) {
   19.57 +		return -1;
   19.58 +	}
   19.59 +	if(handle_mouse() == -1) {
   19.60 +		return -1;
   19.61 +	}
   19.62 +	return 0;
   19.63 +}
   19.64 +
   19.65 +#endif	/* FBLIB_DOS */
    20.1 --- a/src/fblibsdl.c	Mon Jan 19 02:32:01 2015 +0200
    20.2 +++ b/src/fblibsdl.c	Mon Jan 19 15:49:14 2015 +0200
    20.3 @@ -61,21 +61,6 @@
    20.4  	SDL_Quit();
    20.5  }
    20.6  
    20.7 -int fb_get_width(void)
    20.8 -{
    20.9 -	return fb_width;
   20.10 -}
   20.11 -
   20.12 -int fb_get_height(void)
   20.13 -{
   20.14 -	return fb_height;
   20.15 -}
   20.16 -
   20.17 -int fb_get_bpp(void)
   20.18 -{
   20.19 -	return fb_bpp;
   20.20 -}
   20.21 -
   20.22  void *fb_begin_frame(void)
   20.23  {
   20.24  	if(!surf) return 0;
    21.1 --- a/src/level.c	Mon Jan 19 02:32:01 2015 +0200
    21.2 +++ b/src/level.c	Mon Jan 19 15:49:14 2015 +0200
    21.3 @@ -3,6 +3,11 @@
    21.4  #include <string.h>
    21.5  #include <ctype.h>
    21.6  #include <math.h>
    21.7 +#if defined(_MSC_VER) || defined(__WATCOMC__)
    21.8 +#include <malloc.h>
    21.9 +#else
   21.10 +#include <alloca.h>
   21.11 +#endif
   21.12  #include "level.h"
   21.13  
   21.14  #define C_WALL		'#'
    22.1 --- a/src/tileset.c	Mon Jan 19 02:32:01 2015 +0200
    22.2 +++ b/src/tileset.c	Mon Jan 19 15:49:14 2015 +0200
    22.3 @@ -5,6 +5,11 @@
    22.4  #include <errno.h>
    22.5  #include <ctype.h>
    22.6  #include <assert.h>
    22.7 +#if defined(_MSC_VER) || defined(__WATCOMC__)
    22.8 +#include <malloc.h>
    22.9 +#else
   22.10 +#include <alloca.h>
   22.11 +#endif
   22.12  #include "tileset.h"
   22.13  #include "image.h"
   22.14