From 86ea36402d2ba296db0950d85e18c50f7ee7006b Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 14 Jun 2023 04:46:36 +0300 Subject: [PATCH] dos port underway --- .gitignore | 13 + Makefile | 100 ++++++++ libs/cgmath/cgmmisc.inl | 8 +- libs/drawtext/Makefile | 30 +++ libs/drawtext/draw.c | 4 +- libs/drawtext/drawgl.c | 2 +- libs/drawtext/drawrast.c | 2 +- libs/drawtext/drawtext.dep | 25 -- libs/drawtext/drawtext.dsp | 2 +- libs/drawtext/drawtext_impl.h | 92 ------- libs/drawtext/dtximpl.h | 92 +++++++ libs/drawtext/font.c | 2 +- libs/imago/Makefile | 84 +++++++ libs/treestor/Makefile | 32 +++ libs/treestor/src/treestor.c | 2 +- src/cmesh.c | 5 +- src/dos/cdpmi.h | 105 ++++++++ src/dos/djdpmi.c | 35 +++ src/dos/dosutil.h | 19 ++ src/dos/gfx.c | 544 +++++++++++++++++++++++++++++++++++++++++ src/dos/gfx.h | 81 ++++++ src/dos/keyb.c | 266 ++++++++++++++++++++ src/dos/keyb.h | 55 +++++ src/dos/logger.c | 172 +++++++++++++ src/dos/logger.h | 17 ++ src/dos/main.c | 130 ++++++++++ src/dos/mouse.h | 25 ++ src/dos/pit8254.h | 51 ++++ src/dos/scancode.h | 61 +++++ src/dos/timer.c | 182 ++++++++++++++ src/dos/vbe.c | 525 +++++++++++++++++++++++++++++++++++++++ src/dos/vbe.h | 242 ++++++++++++++++++ src/dos/vga.c | 71 ++++++ src/dos/vga.h | 49 ++++ src/dos/vgaregs.h | 85 +++++++ src/dos/watdpmi.c | 59 +++++ src/gaw/gawswtnl.c | 4 +- src/gaw/gawswtnl.h | 9 + src/meshgen.c | 40 +-- src/rbtree.c | 2 +- src/rtk_impl.h | 2 +- 41 files changed, 3172 insertions(+), 154 deletions(-) create mode 100644 Makefile create mode 100644 libs/drawtext/Makefile delete mode 100644 libs/drawtext/drawtext.dep delete mode 100644 libs/drawtext/drawtext_impl.h create mode 100644 libs/drawtext/dtximpl.h create mode 100644 libs/imago/Makefile create mode 100644 libs/treestor/Makefile create mode 100644 src/dos/cdpmi.h create mode 100644 src/dos/djdpmi.c create mode 100644 src/dos/dosutil.h create mode 100644 src/dos/gfx.c create mode 100644 src/dos/gfx.h create mode 100644 src/dos/keyb.c create mode 100644 src/dos/keyb.h create mode 100644 src/dos/logger.c create mode 100644 src/dos/logger.h create mode 100644 src/dos/main.c create mode 100644 src/dos/mouse.h create mode 100644 src/dos/pit8254.h create mode 100644 src/dos/scancode.h create mode 100644 src/dos/timer.c create mode 100644 src/dos/vbe.c create mode 100644 src/dos/vbe.h create mode 100644 src/dos/vga.c create mode 100644 src/dos/vga.h create mode 100644 src/dos/vgaregs.h create mode 100644 src/dos/watdpmi.c diff --git a/.gitignore b/.gitignore index 01e8736..be7677e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,21 @@ *.swp *.a *.lib +*.LIB retroray *.cfg data/ *.exe config.mk +*.obj +*.OBJ +*.err +*.ERR +*.lbc +*.LBC +*.occ +*.OCC +*.lnk +*.LNK +*.map +*.MAP diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fe31353 --- /dev/null +++ b/Makefile @@ -0,0 +1,100 @@ +!ifdef __UNIX__ +dosobj = src/dos/djdpmi.obj src/dos/gfx.obj src/dos/keyb.obj src/dos/logger.obj & + src/dos/main.obj src/dos/timer.obj src/dos/vbe.obj src/dos/vga.obj src/dos/watdpmi.obj +appobj = src/app.obj src/cmesh.obj src/darray.obj src/font.obj src/logger.obj & + src/meshgen.obj src/meshload.obj src/options.obj src/rbtree.obj src/rt.obj & + src/rtk.obj src/scene.obj src/scr_mod.obj src/scr_rend.obj src/util.obj +gawobj = src/gaw/gaw_sw.obj src/gaw/gawswtnl.obj src/gaw/polyclip.obj src/gaw/polyfill.obj + +incpath = -Isrc -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/treestor/include -Ilibs/drawtext +libpath = libpath libs/dos +!else +dosobj = src\dos\djdpmi.obj src\dos\gfx.obj src\dos\keyb.obj src\dos\logger.obj & + src\dos\main.obj src\dos\timer.obj src\dos\vbe.obj src\dos\vga.obj src\dos\watdpmi.obj +appobj = src\app.obj src\cmesh.obj src\darray.obj src\font.obj src\logger.obj & + src\meshgen.obj src\meshload.obj src\options.obj src\rbtree.obj src\rt.obj & + src\rtk.obj src\scene.obj src\scr_mod.obj src\scr_rend.obj src\util.obj +gawobj = src\gaw\gaw_sw.obj src\gaw\gawswtnl.obj src\gaw\polyclip.obj src\gaw\polyfill.obj + +incpath = -Isrc -Isrc\dos -Ilibs -Ilibs\imago\src -Ilibs\treestor\include -Ilibs\drawtext +libpath = libpath libs\dos +!endif + +obj = $(dosobj) $(appobj) $(gawobj) +bin = retroray.exe + +opt = -otexan +def = -DGFX_SW +libs = imago.lib treestor.lib drawtext.lib + +AS = nasm +CC = wcc386 +LD = wlink +ASFLAGS = -fobj +CFLAGS = -d3 -5 -fp5 $(opt) $(def) -s -zq -bt=dos $(incpath) +LDFLAGS = option map $(libpath) library { $(libs) } + +$(bin): cflags.occ $(obj) $(libs) + %write objects.lnk $(obj) + %write ldflags.lnk $(LDFLAGS) + $(LD) debug all name $@ system dos4g file { @objects } @ldflags + +.c: src;src/dos;src/gaw +.asm: src;src/dos;src/gaw + +cflags.occ: Makefile + %write $@ $(CFLAGS) + +.c.obj: .autodepend + $(CC) -fo=$@ @cflags.occ $[* + +.asm.obj: + nasm $(ASFLAGS) -o $@ $[*.asm + + +!ifdef __UNIX__ +clean: .symbolic + rm -f $(obj) + rm -f $(bin) + rm -f cflags.occ *.lnk + +imago.lib: + cd libs/imago + wmake + cd ../.. + +treestor.lib: + cd libs/treestor + wmake + cd ../.. + +drawtext.lib: + cd libs/drawtext + wmake + cd ../.. + +!else + +imago.lib: + cd libs\imago + wmake + cd ..\.. + +treestor.lib: + cd libs\treestor + wmake + cd ..\.. + +drawtext.lib: + cd libs\drawtext + wmake + cd ..\.. + +clean: .symbolic + del src\*.obj + del src\dos\*.obj + del src\gaw\*.obj + del *.lnk + del cflags.occ + del $(bin) +!endif diff --git a/libs/cgmath/cgmmisc.inl b/libs/cgmath/cgmmisc.inl index a3cdfb5..0def727 100644 --- a/libs/cgmath/cgmmisc.inl +++ b/libs/cgmath/cgmmisc.inl @@ -10,12 +10,12 @@ static CGM_INLINE float cgm_deg_to_rad(float deg) { - return M_PI * deg / 180.0f; + return CGM_PI * deg / 180.0f; } static CGM_INLINE float cgm_rad_to_deg(float rad) { - return 180.0f * rad / M_PI; + return 180.0f * rad / CGM_PI; } static CGM_INLINE float cgm_smoothstep(float a, float b, float x) @@ -87,7 +87,7 @@ static CGM_INLINE float cgm_spline(float a, float b, float c, float d, float t) static CGM_INLINE void cgm_discrand(cgm_vec3 *pt, float rad) { - float theta = 2.0f * M_PI * (float)rand() / RAND_MAX; + float theta = 2.0f * CGM_PI * (float)rand() / RAND_MAX; float r = sqrt((float)rand() / RAND_MAX) * rad; pt->x = cos(theta) * r; pt->y = sin(theta) * r; @@ -101,7 +101,7 @@ static CGM_INLINE void cgm_sphrand(cgm_vec3 *pt, float rad) u = (float)rand() / RAND_MAX; v = (float)rand() / RAND_MAX; - theta = 2.0f * M_PI * u; + theta = 2.0f * CGM_PI * u; phi = acos(2.0f * v - 1.0f); pt->x = cos(theta) * sin(phi) * rad; diff --git a/libs/drawtext/Makefile b/libs/drawtext/Makefile new file mode 100644 index 0000000..d75d408 --- /dev/null +++ b/libs/drawtext/Makefile @@ -0,0 +1,30 @@ +obj = font.obj draw.obj drawgl.obj drawrast.obj utf8.obj + +!ifdef __UNIX__ +alib = ../../drawtext.lib +!else +alib = ..\..\drawtext.lib +!endif + +CC = wcc386 +CFLAGS = -d1 -5 -fp5 -otexan -zq -DNO_FREETYPE -DNO_OPENGL + +$(alib): $(obj) + %write objects.lbc $(obj) + wlib -b -n $@ @objects + +.c.obj: .autodepend + %write cflags.occ $(CFLAGS) + $(CC) -fo=$@ @cflags.occ $[* + +!ifdef __UNIX__ +clean: .symbolic + rm -f $(obj) + rm -f $(alib) +!else +clean: .symbolic + del *.obj + del objects.lbc + del cflags.occ + del $(alib) +!endif diff --git a/libs/drawtext/draw.c b/libs/drawtext/draw.c index 523239f..02b83da 100644 --- a/libs/drawtext/draw.c +++ b/libs/drawtext/draw.c @@ -18,13 +18,13 @@ along with this program. If not, see . #include #include #include -#if defined(WIN32) || defined(__WIN32__) +#if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__) #include #else #include #endif #include "drawtext.h" -#include "drawtext_impl.h" +#include "dtximpl.h" void dtx_position(float x, float y) { diff --git a/libs/drawtext/drawgl.c b/libs/drawtext/drawgl.c index edcd56b..e20c8a8 100644 --- a/libs/drawtext/drawgl.c +++ b/libs/drawtext/drawgl.c @@ -16,7 +16,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "drawtext.h" -#include "drawtext_impl.h" +#include "dtximpl.h" struct quad { struct dtx_vertex v[6]; diff --git a/libs/drawtext/drawrast.c b/libs/drawtext/drawrast.c index 66543a5..99106c8 100644 --- a/libs/drawtext/drawrast.c +++ b/libs/drawtext/drawrast.c @@ -19,7 +19,7 @@ along with this program. If not, see . #include #include #include "drawtext.h" -#include "drawtext_impl.h" +#include "dtximpl.h" static const char *drawchar(const char *str, float *xpos, float *ypos, int *should_flush); static void flush(void); diff --git a/libs/drawtext/drawtext.dep b/libs/drawtext/drawtext.dep deleted file mode 100644 index 1d20c2a..0000000 --- a/libs/drawtext/drawtext.dep +++ /dev/null @@ -1,25 +0,0 @@ -# Microsoft Developer Studio Generated Dependency File, included by drawtext.mak - -.\draw.c : \ - ".\drawtext.h"\ - ".\drawtext_impl.h"\ - - -.\drawgl.c : \ - ".\drawtext.h"\ - ".\drawtext_impl.h"\ - - -.\drawrast.c : \ - ".\drawtext.h"\ - ".\drawtext_impl.h"\ - - -.\font.c : \ - ".\drawtext.h"\ - ".\drawtext_impl.h"\ - - -.\utf8.c : \ - ".\drawtext.h"\ - diff --git a/libs/drawtext/drawtext.dsp b/libs/drawtext/drawtext.dsp index 8af8890..aa33d14 100644 --- a/libs/drawtext/drawtext.dsp +++ b/libs/drawtext/drawtext.dsp @@ -101,7 +101,7 @@ SOURCE=.\drawtext.h # End Source File # Begin Source File -SOURCE=.\drawtext_impl.h +SOURCE=.\dtximpl.h # End Source File # Begin Source File diff --git a/libs/drawtext/drawtext_impl.h b/libs/drawtext/drawtext_impl.h deleted file mode 100644 index a107873..0000000 --- a/libs/drawtext/drawtext_impl.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -libdrawtext - a simple library for fast text rendering in OpenGL -Copyright (C) 2011-2016 John Tsiombikas - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program. If not, see . -*/ -#ifndef DRAWTEXT_IMPL_H_ -#define DRAWTEXT_IMPL_H_ - -#include "drawtext.h" - -struct glyph { - int code; - float x, y, width, height; - /* normalized coords [0, 1] */ - float nx, ny, nwidth, nheight; - float orig_x, orig_y; - float advance; - struct glyph *next; -}; - -struct dtx_glyphmap { - int ptsize; - - int xsz, ysz; - unsigned int xsz_shift; - unsigned char *pixels; - unsigned int tex; - int tex_valid; - void *udata; - - int cstart, cend; /* character range */ - int crange; - - float line_advance; - float baseline; - - struct glyph *glyphs; - struct dtx_glyphmap *next; -}; - -struct dtx_font { - /* freetype FT_Face */ - void *face; - - /* list of glyphmaps */ - struct dtx_glyphmap *gmaps; - - /* last returned glyphmap (cache) */ - struct dtx_glyphmap *last_gmap; -}; - -#ifdef DTX_DEFINE_COMMON -#define DTX_COMMON -#else -#define DTX_COMMON extern -#endif - -DTX_COMMON struct dtx_font *dtx_font; -DTX_COMMON int dtx_font_sz; -DTX_COMMON int dtx_buf_mode; /* DTX_NBF is 0 */ -DTX_COMMON float dtx_cur_color[4]; -DTX_COMMON int dtx_cur_color_int[4]; -DTX_COMMON float dtx_cur_offset[2]; - -#define fperror(str) \ - fprintf(stderr, "%s: %s\n", (str), strerror(errno)) - -/* returns zero if it should NOT be printed and modifies xpos/ypos */ -/* implemented in font.c */ -struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos); - -DTX_COMMON const char *(*dtx_drawchar)(const char*, float*, float*, int*); -DTX_COMMON void (*dtx_drawflush)(void); - -int dtx_gl_setopt(enum dtx_option opt, int val); -int dtx_gl_getopt(enum dtx_option opt, int *ret); -int dtx_rast_setopt(enum dtx_option opt, int val); -int dtx_rast_getopt(enum dtx_option opt, int *ret); - -#endif /* DRAWTEXT_IMPL_H_ */ diff --git a/libs/drawtext/dtximpl.h b/libs/drawtext/dtximpl.h new file mode 100644 index 0000000..a107873 --- /dev/null +++ b/libs/drawtext/dtximpl.h @@ -0,0 +1,92 @@ +/* +libdrawtext - a simple library for fast text rendering in OpenGL +Copyright (C) 2011-2016 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +*/ +#ifndef DRAWTEXT_IMPL_H_ +#define DRAWTEXT_IMPL_H_ + +#include "drawtext.h" + +struct glyph { + int code; + float x, y, width, height; + /* normalized coords [0, 1] */ + float nx, ny, nwidth, nheight; + float orig_x, orig_y; + float advance; + struct glyph *next; +}; + +struct dtx_glyphmap { + int ptsize; + + int xsz, ysz; + unsigned int xsz_shift; + unsigned char *pixels; + unsigned int tex; + int tex_valid; + void *udata; + + int cstart, cend; /* character range */ + int crange; + + float line_advance; + float baseline; + + struct glyph *glyphs; + struct dtx_glyphmap *next; +}; + +struct dtx_font { + /* freetype FT_Face */ + void *face; + + /* list of glyphmaps */ + struct dtx_glyphmap *gmaps; + + /* last returned glyphmap (cache) */ + struct dtx_glyphmap *last_gmap; +}; + +#ifdef DTX_DEFINE_COMMON +#define DTX_COMMON +#else +#define DTX_COMMON extern +#endif + +DTX_COMMON struct dtx_font *dtx_font; +DTX_COMMON int dtx_font_sz; +DTX_COMMON int dtx_buf_mode; /* DTX_NBF is 0 */ +DTX_COMMON float dtx_cur_color[4]; +DTX_COMMON int dtx_cur_color_int[4]; +DTX_COMMON float dtx_cur_offset[2]; + +#define fperror(str) \ + fprintf(stderr, "%s: %s\n", (str), strerror(errno)) + +/* returns zero if it should NOT be printed and modifies xpos/ypos */ +/* implemented in font.c */ +struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos); + +DTX_COMMON const char *(*dtx_drawchar)(const char*, float*, float*, int*); +DTX_COMMON void (*dtx_drawflush)(void); + +int dtx_gl_setopt(enum dtx_option opt, int val); +int dtx_gl_getopt(enum dtx_option opt, int *ret); +int dtx_rast_setopt(enum dtx_option opt, int val); +int dtx_rast_getopt(enum dtx_option opt, int *ret); + +#endif /* DRAWTEXT_IMPL_H_ */ diff --git a/libs/drawtext/font.c b/libs/drawtext/font.c index b66e917..b5ee0e6 100644 --- a/libs/drawtext/font.c +++ b/libs/drawtext/font.c @@ -34,7 +34,7 @@ along with this program. If not, see . #include FT_FREETYPE_H #endif #include "drawtext.h" -#include "drawtext_impl.h" +#include "dtximpl.h" struct io { void *data; diff --git a/libs/imago/Makefile b/libs/imago/Makefile new file mode 100644 index 0000000..4e8f410 --- /dev/null +++ b/libs/imago/Makefile @@ -0,0 +1,84 @@ +!ifdef __UNIX__ +libpng = libpng/png.obj libpng/pngerror.obj libpng/pngget.obj libpng/pngmem.obj & + libpng/pngpread.obj libpng/pngread.obj libpng/pngrio.obj libpng/pngrtran.obj & + libpng/pngrutil.obj libpng/pngset.obj libpng/pngtrans.obj libpng/pngwio.obj & + libpng/pngwrite.obj libpng/pngwtran.obj libpng/pngwutil.obj +zlib = zlib/adler32.obj zlib/compress.obj zlib/crc32.obj zlib/deflate.obj & + zlib/gzio.obj zlib/infback.obj zlib/inffast.obj zlib/inflate.obj & + zlib/inftrees.obj zlib/trees.obj zlib/uncompr.obj zlib/zutil.obj +jpeglib = jpeglib/jcapimin.obj jpeglib/jcapistd.obj jpeglib/jccoefct.obj & + jpeglib/jccolor.obj jpeglib/jcdctmgr.obj jpeglib/jchuff.obj jpeglib/jcinit.obj & + jpeglib/jcmainct.obj jpeglib/jcmarker.obj jpeglib/jcmaster.obj jpeglib/jcomapi.obj & + jpeglib/jcparam.obj jpeglib/jcphuff.obj jpeglib/jcprepct.obj jpeglib/jcsample.obj & + jpeglib/jctrans.obj jpeglib/jdapimin.obj jpeglib/jdapistd.obj jpeglib/jdatadst.obj & + jpeglib/jdatasrc.obj jpeglib/jdcoefct.obj jpeglib/jdcolor.obj jpeglib/jddctmgr.obj & + jpeglib/jdhuff.obj jpeglib/jdinput.obj jpeglib/jdmainct.obj jpeglib/jdmarker.obj & + jpeglib/jdmaster.obj jpeglib/jdmerge.obj jpeglib/jdphuff.obj jpeglib/jdpostct.obj & + jpeglib/jdsample.obj jpeglib/jdtrans.obj jpeglib/jerror.obj jpeglib/jfdctflt.obj & + jpeglib/jfdctfst.obj jpeglib/jfdctint.obj jpeglib/jidctflt.obj jpeglib/jidctfst.obj & + jpeglib/jidctint.obj jpeglib/jidctred.obj jpeglib/jmemmgr.obj jpeglib/jmemnobs.obj & + jpeglib/jquant1.obj jpeglib/jquant2.obj jpeglib/jutils.obj +obj = src/conv.obj src/filejpeg.obj src/filepng.obj src/fileppm.obj src/filergbe.obj & + src/filetga.obj src/ftmodule.obj src/imago2.obj src/modules.obj & + $(libpng) $(zlib) $(jpeglib) + +alib = ../../imago.lib +!else +libpng = libpng\png.obj libpng\pngerror.obj libpng\pngget.obj libpng\pngmem.obj & + libpng\pngpread.obj libpng\pngread.obj libpng\pngrio.obj libpng\pngrtran.obj & + libpng\pngrutil.obj libpng\pngset.obj libpng\pngtrans.obj libpng\pngwio.obj & + libpng\pngwrite.obj libpng\pngwtran.obj libpng\pngwutil.obj +zlib = zlib\adler32.obj zlib\compress.obj zlib\crc32.obj zlib\deflate.obj & + zlib\gzio.obj zlib\infback.obj zlib\inffast.obj zlib\inflate.obj & + zlib\inftrees.obj zlib\trees.obj zlib\uncompr.obj zlib\zutil.obj +jpeglib = jpeglib\jcapimin.obj jpeglib\jcapistd.obj jpeglib\jccoefct.obj & + jpeglib\jccolor.obj jpeglib\jcdctmgr.obj jpeglib\jchuff.obj jpeglib\jcinit.obj & + jpeglib\jcmainct.obj jpeglib\jcmarker.obj jpeglib\jcmaster.obj jpeglib\jcomapi.obj & + jpeglib\jcparam.obj jpeglib\jcphuff.obj jpeglib\jcprepct.obj jpeglib\jcsample.obj & + jpeglib\jctrans.obj jpeglib\jdapimin.obj jpeglib\jdapistd.obj jpeglib\jdatadst.obj & + jpeglib\jdatasrc.obj jpeglib\jdcoefct.obj jpeglib\jdcolor.obj jpeglib\jddctmgr.obj & + jpeglib\jdhuff.obj jpeglib\jdinput.obj jpeglib\jdmainct.obj jpeglib\jdmarker.obj & + jpeglib\jdmaster.obj jpeglib\jdmerge.obj jpeglib\jdphuff.obj jpeglib\jdpostct.obj & + jpeglib\jdsample.obj jpeglib\jdtrans.obj jpeglib\jerror.obj jpeglib\jfdctflt.obj & + jpeglib\jfdctfst.obj jpeglib\jfdctint.obj jpeglib\jidctflt.obj jpeglib\jidctfst.obj & + jpeglib\jidctint.obj jpeglib\jidctred.obj jpeglib\jmemmgr.obj jpeglib\jmemnobs.obj & + jpeglib\jquant1.obj jpeglib\jquant2.obj jpeglib\jutils.obj +obj = src\conv.obj src\filejpeg.obj src\filepng.obj src\fileppm.obj src\filergbe.obj & + src\filetga.obj src\ftmodule.obj src\imago2.obj src\modules.obj & + $(libpng) $(zlib) $(jpeglib) + +alib = ..\..\imago.lib +!endif + +#opt = -5 -fp5 -od +opt = -5 -fp5 -otexan +dbg = -d1 +def = -DPNG_NO_SNPRINTF + +CC = wcc386 +CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -Ilibpng -Izlib -Ijpeglib + +$(alib): $(obj) + %write objects.lbc $(obj) + wlib -b -n $@ @objects + +.c: src;libpng;jpeglib;zlib + +.c.obj: .autodepend + %write cflags.occ $(CFLAGS) + $(CC) -fo=$@ @cflags.occ $[* + +!ifdef __UNIX__ +clean: .symbolic + rm -f $(obj) + rm -f $(alib) +!else +clean: .symbolic + del src\*.obj + del zlib\*.obj + del libpng\*.obj + del jpeglib\*.obj + del objects.lbc + del cflags.occ + del $(alib) +!endif diff --git a/libs/treestor/Makefile b/libs/treestor/Makefile new file mode 100644 index 0000000..0686cd6 --- /dev/null +++ b/libs/treestor/Makefile @@ -0,0 +1,32 @@ +!ifdef __UNIX__ +obj = src/treestor.obj src/text.obj src/dynarr.obj +alib = ../../treestor.lib +!else +obj = src\treestor.obj src\text.obj src\dynarr.obj +alib = ..\..\treestor.lib +!endif + +CC = wcc386 +CFLAGS = -d1 -5 -fp5 -otexan -zq -Iinclude + +$(alib): $(obj) + %write objects.lbc $(obj) + wlib -b -n $@ @objects + +.c: src + +.c.obj: .autodepend + %write cflags.occ $(CFLAGS) + $(CC) -fo=$@ @cflags.occ $[* + +!ifdef __UNIX__ +clean: .symbolic + rm -f $(obj) + rm -f $(alib) +!else +clean: .symbolic + del src\*.obj + del objects.lbc + del cflags.occ + del $(alib) +!endif diff --git a/libs/treestor/src/treestor.c b/libs/treestor/src/treestor.c index 115c2b4..5e00a80 100644 --- a/libs/treestor/src/treestor.c +++ b/libs/treestor/src/treestor.c @@ -5,7 +5,7 @@ #include #include "treestor.h" -#ifdef WIN32 +#if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__) #include #else #include diff --git a/src/cmesh.c b/src/cmesh.c index 9e9833e..d6b7912 100644 --- a/src/cmesh.c +++ b/src/cmesh.c @@ -1,9 +1,9 @@ #include #include -#include #include #include #include +#include "sizeint.h" #include "gaw/gaw.h" #include "cmesh.h" @@ -1118,8 +1118,9 @@ void cmesh_flip_faces(struct cmesh *cm) nelem = cm->vattr[CMESH_ATTR_VERTEX].nelem; for(i=0; i +#include + +#define virt_to_phys(v) ((v) + __djgpp_base_address) +#define phys_to_virt(p) ((p) - __djgpp_base_address) + +#else /* not djgpp (basically watcom) */ + +#define virt_to_phys(v) (v) +#define phys_to_virt(p) (p) + +#endif /* __DJGPP__ */ + +#include "inttypes.h" +#include "util.h" + +#pragma pack (push, 1) +struct dpmi_regs { + uint32_t edi, esi, ebp; + uint32_t reserved; + uint32_t ebx, edx, ecx, eax; + uint16_t flags; + uint16_t es, ds, fs, gs; + uint16_t ip, cs, sp, ss; +} PACKED; +#pragma pack (pop) + +enum { + FLAGS_CF = 0x000001, + FLAGS_PF = 0x000004, + FLAGS_ZF = 0x000040, + FLAGS_SF = 0x000080, + FLAGS_IF = 0x000020, + FLAGS_DF = 0x000040, + FLAGS_VM = 0x020000, + FLAGS_ID = 0x200000, +}; + +uint16_t dpmi_alloc(unsigned int par, uint16_t *sel); +void dpmi_free(uint16_t sel); +void dpmi_int(int inum, struct dpmi_regs *regs); +void *dpmi_mmap(uint32_t phys_addr, unsigned int size); +void dpmi_munmap(void *addr); + +#ifdef __WATCOMC__ +#pragma aux dpmi_alloc = \ + "mov ax, 0x100" \ + "int 0x31" \ + "mov [edi], dx" \ + "jnc alloc_skip_err" \ + "xor ax, ax" \ + "alloc_skip_err:" \ + value[ax] \ + parm[ebx][edi] \ + modify[dx]; + +#pragma aux dpmi_free = \ + "mov ax, 0x101" \ + "int 0x31" \ + parm[dx] \ + modify[ax]; + +#pragma aux dpmi_int = \ + "mov ax, 0x300" \ + "xor ecx, ecx" \ + "int 0x31" \ + parm[ebx][edi] \ + modify[ax ecx]; + +#pragma aux dpmi_mmap = \ + "mov ax, 0x800" \ + "mov cx, bx" \ + "shr ebx, 16" \ + "mov di, si" \ + "shr esi, 16" \ + "int 0x31" \ + "jnc mmap_skip_err" \ + "xor bx, bx" \ + "xor cx, cx" \ + "mmap_skip_err:" \ + "mov ax, bx" \ + "shl eax, 16" \ + "mov ax, cx" \ + value[eax] \ + parm[ebx][esi] \ + modify[bx cx di esi]; + +#pragma aux dpmi_munmap = \ + "mov ax, 0x801" \ + "mov cx, bx" \ + "shr ebx, 16" \ + "int 0x31" \ + parm[ebx] \ + modify[ax cx ebx]; +#endif /* __WATCOMC__ */ + +#ifdef __DJGPP__ +#define dpmi_int(inum, regs) __dpmi_int((inum), (__dpmi_regs*)(regs)) +#endif + +#endif /* DPMI_H_ */ diff --git a/src/dos/djdpmi.c b/src/dos/djdpmi.c new file mode 100644 index 0000000..f3a06b9 --- /dev/null +++ b/src/dos/djdpmi.c @@ -0,0 +1,35 @@ +#ifdef __DJGPP__ +#include +#include +#include "cdpmi.h" +#include "inttypes.h" + +uint16_t dpmi_alloc(unsigned int par, uint16_t *sel) +{ + int tmp; + uint16_t seg = __dpmi_allocate_dos_memory(par, &tmp); + *sel = tmp; + return seg; +} + +void dpmi_free(uint16_t sel) +{ + __dpmi_free_dos_memory(sel); +} + +void *dpmi_mmap(uint32_t phys_addr, unsigned int size) +{ + __dpmi_meminfo mem; + mem.address = phys_addr; + mem.size = size; + __dpmi_physical_address_mapping(&mem); + return (void*)(mem.address - __djgpp_base_address); +} + +void dpmi_munmap(void *addr) +{ + __dpmi_meminfo mem; + mem.address = (uint32_t)addr + __djgpp_base_address; + __dpmi_free_physical_address_mapping(&mem); +} +#endif /* __DJGPP__ */ diff --git a/src/dos/dosutil.h b/src/dos/dosutil.h new file mode 100644 index 0000000..4e4c8c3 --- /dev/null +++ b/src/dos/dosutil.h @@ -0,0 +1,19 @@ +#ifndef DOSUTIL_H_ +#define DOSUTIL_H_ + +#include +#include + +#ifdef __DJGPP__ +#include + +#define outp(p, v) outportb(p, v) +#define outpw(p, v) outportw(p, v) +#define outpd(p, v) outportl(p, v) + +#define inp(p) inportb(p) +#define inpw(p) inportw(p) +#define inpd(p) inportl(p) +#endif + +#endif /* DOSUTIL_H_ */ diff --git a/src/dos/gfx.c b/src/dos/gfx.c new file mode 100644 index 0000000..0a8a00c --- /dev/null +++ b/src/dos/gfx.c @@ -0,0 +1,544 @@ +#include +#include +#include +#include +#include "app.h" +#include "cdpmi.h" +#include "gfx.h" +#include "vbe.h" +#include "vga.h" +#include "util.h" +#include "cpuid.h" + +#ifdef __DJGPP__ +#define VMEM_PTR ((void*)(0xa0000 + __djgpp_conventional_base)) +#else +#define VMEM_PTR ((void*)0xa0000) +#endif + +#define SAME_BPP(a, b) \ + ((a) == (b) || ((a) == 16 && (b) == 15) || ((a) == 15 && (b) == 16) || \ + ((a) == 32 && (b) == 24) || ((a) == 24 && (b) == 32)) + +void (*blit_frame)(void*, int); + +extern int dblsize; + +static void blit_frame_lfb(void *pixels, int vsync); +static void blit_frame_banked(void *pixels, int vsync); +static void blit_frame_lfb_2x(void *pixels, int vsync); +static void blit_frame_banked_2x(void *pixels, int vsync); +static uint32_t calc_mask(int sz, int pos); + +static void enable_wrcomb(uint32_t addr, int len); +static const char *mtrr_type_name(int type); +static void print_mtrr(void); + +static struct video_mode *vmodes; +static int num_vmodes; + +static int vbe_init_ver; +static struct vbe_info vbe; + +/* current mode */ +static struct video_mode *curmode; +static void *vpgaddr[2]; +static int frontidx, backidx; +static int pgcount, pgsize, fbsize; + + +int init_video(void) +{ + int i, num, max_modes; + struct video_mode *vmptr; + + if(vbe_info(&vbe) == -1) { + fprintf(stderr, "failed to retrieve VBE information\n"); + return -1; + } + vbe_print_info(stdout, &vbe); + + num_vmodes = 0; + max_modes = 64; + if(!(vmodes = malloc(max_modes * sizeof *vmodes))) { + fprintf(stderr, "failed to allocate video modes list\n"); + return -1; + } + + num = vbe_num_modes(&vbe); + for(i=0; i= max_modes) { + int newmax = max_modes ? (max_modes << 1) : 16; + if(!(vmptr = realloc(vmodes, newmax * sizeof *vmodes))) { + fprintf(stderr, "failed to grow video mode list (%d)\n", newmax); + free(vmodes); + return -1; + } + vmodes = vmptr; + max_modes = newmax; + } + + vmptr = vmodes + num_vmodes++; + memset(vmptr, 0, sizeof *vmptr); + vmptr->mode = vbe.modes[i]; + vmptr->xsz = minf.xres; + vmptr->ysz = minf.yres; + vmptr->bpp = minf.bpp; + vmptr->pitch = minf.scanline_bytes; + if(minf.mem_model == VBE_TYPE_DIRECT) { + vmptr->rbits = minf.rsize; + vmptr->gbits = minf.gsize; + vmptr->bbits = minf.bsize; + vmptr->rshift = minf.rpos; + vmptr->gshift = minf.gpos; + vmptr->bshift = minf.bpos; + vmptr->rmask = calc_mask(minf.rsize, minf.rpos); + vmptr->gmask = calc_mask(minf.gsize, minf.gpos); + vmptr->bmask = calc_mask(minf.bsize, minf.bpos); + /*vmptr->bpp = vmptr->rbits + vmptr->gbits + vmptr->bbits;*/ + } + if(minf.attr & VBE_ATTR_LFB) { + vmptr->fb_addr = minf.fb_addr; + } + vmptr->max_pages = minf.num_img_pages; + vmptr->win_gran = minf.win_gran; + + printf("%04x: ", vbe.modes[i]); + vbe_print_mode_info(stdout, &minf); + } + fflush(stdout); + + vbe_init_ver = VBE_VER_MAJOR(vbe.ver); + return 0; +} + +void cleanup_video(void) +{ + free(vmodes); +} + +struct video_mode *video_modes(void) +{ + return vmodes; +} + +int num_video_modes(void) +{ + return num_vmodes; +} + +struct video_mode *get_video_mode(int idx) +{ + if(idx == VMODE_CURRENT) { + return curmode; + } + return vmodes + idx; +} + +int match_video_mode(int xsz, int ysz, int bpp) +{ + int i, best = -1; + struct video_mode *vm; + + for(i=0; ixsz != xsz || vm->ysz != ysz) continue; + if(SAME_BPP(vm->bpp, bpp)) { + best = i; + } + if(vm->bpp == bpp) break; + } + + if(best == -1) { + fprintf(stderr, "failed to find video mode %dx%d %d bpp)\n", xsz, ysz, bpp); + return -1; + } + return best; +} + +int find_video_mode(int mode) +{ + int i; + struct video_mode *vm; + + vm = vmodes; + for(i=0; imode == mode) return i; + } + return -1; +} + +void *set_video_mode(int idx, int nbuf) +{ + unsigned int mode; + struct video_mode *vm = vmodes + idx; + + if(curmode == vm) return vpgaddr[0]; + + printf("setting video mode %x (%dx%d %d bpp)\n", (unsigned int)vm->mode, + vm->xsz, vm->ysz, vm->bpp); + fflush(stdout); + + mode = vm->mode | VBE_MODE_LFB; + if(vbe_setmode(mode) == -1) { + mode = vm->mode; + if(vbe_setmode(mode) == -1) { + fprintf(stderr, "failed to set video mode %x\n", (unsigned int)vm->mode); + return 0; + } + printf("Warning: failed to get a linear framebuffer. falling back to banked mode\n"); + } + + /* unmap previous video memory mapping, if there was one (switching modes) */ + if(vpgaddr[0] && vpgaddr[0] != VMEM_PTR) { + dpmi_munmap(vpgaddr[0]); + vpgaddr[0] = vpgaddr[1] = 0; + } + + curmode = vm; + if(nbuf < 1) nbuf = 1; + if(nbuf > 2) nbuf = 2; + pgcount = nbuf > vm->max_pages + 1 ? vm->max_pages + 1 : nbuf; + pgsize = vm->ysz * vm->pitch; + fbsize = pgcount * pgsize; + + if(vm->bpp > 8) { + printf("rgb mask: %x %x %x\n", (unsigned int)vm->rmask, + (unsigned int)vm->gmask, (unsigned int)vm->bmask); + printf("rgb shift: %d %d %d\n", vm->rshift, vm->gshift, vm->bshift); + } + printf("pgcount: %d, pgsize: %d, fbsize: %d\n", pgcount, pgsize, fbsize); + if(vm->fb_addr) { + printf("phys addr: %p\n", (void*)vm->fb_addr); + } + fflush(stdout); + + if(vm->fb_addr) { + vpgaddr[0] = (void*)dpmi_mmap(vm->fb_addr, fbsize); + if(!vpgaddr[0]) { + fprintf(stderr, "failed to map framebuffer (phys: %lx, size: %d)\n", + (unsigned long)vm->fb_addr, fbsize); + set_text_mode(); + return 0; + } + memset(vpgaddr[0], 0xaa, pgsize); + + if(pgcount > 1) { + vpgaddr[1] = (char*)vpgaddr[0] + pgsize; + backidx = 1; + page_flip(FLIP_NOW); /* start with the second page visible */ + } else { + frontidx = backidx = 0; + vpgaddr[1] = 0; + } + + blit_frame = dblsize ? blit_frame_lfb_2x : blit_frame_lfb; + + /* only attempt to set up write combining if the CPU we're running on + * supports memory type range registers, and we're running on ring 0 + */ + if(CPU_HAVE_MTRR) { + int cpl = get_cpl(); + if(cpl > 0) { + fprintf(stderr, "Can't set framebuffer range to write-combining, running in ring %d\n", cpl); + } else { + uint32_t len = (uint32_t)vbe.vmem_blk << 16; + + /* if vmem_blk is 0 or if the reported size is absurd (more than + * 256mb), just use the framebuffer size for this mode to setup the + * mtrr + */ + if(!len || len > 0x10000000) { + printf("reported vmem too large or overflowed, using fbsize for wrcomb setup\n"); + len = fbsize; + } + print_mtrr(); + enable_wrcomb(vm->fb_addr, len); + } + } + + } else { + vpgaddr[0] = VMEM_PTR; + vpgaddr[1] = 0; + + blit_frame = dblsize ? blit_frame_banked_2x : blit_frame_banked; + + /* calculate window granularity shift */ + vm->win_gran_shift = 0; + vm->win_64k_step = 1; + if(vm->win_gran > 0 && vm->win_gran < 64) { + int gran = vm->win_gran; + while(gran < 64) { + vm->win_gran_shift++; + gran <<= 1; + } + vm->win_64k_step = 1 << vm->win_gran_shift; + } + + printf("granularity: %dk (step: %d)\n", vm->win_gran, vm->win_64k_step); + } + + /* allocate main memory framebuffer */ + if(demo_resizefb(vm->xsz, vm->ysz, vm->bpp) == -1) { + fprintf(stderr, "failed to allocate %dx%d (%d bpp) framebuffer\n", vm->xsz, + vm->ysz, vm->bpp); + set_text_mode(); + return 0; + } + + fflush(stdout); + return vpgaddr[0]; +} + +int set_text_mode(void) +{ + /* unmap previous video memory mapping, if there was one (switching modes) */ + if(vpgaddr[0] && vpgaddr[0] != VMEM_PTR) { + dpmi_munmap(vpgaddr[0]); + vpgaddr[0] = vpgaddr[1] = 0; + } + + vga_setmode(3); + curmode = 0; + return 0; +} + +void *page_flip(int vsync) +{ + if(!vpgaddr[1]) { + /* page flipping not supported */ + return vpgaddr[0]; + } + + vbe_swap(backidx ? pgsize : 0, vsync ? VBE_SWAP_VBLANK : VBE_SWAP_NOW); + frontidx = backidx; + backidx = (backidx + 1) & 1; + + return vpgaddr[backidx]; +} + + +static void blit_frame_lfb(void *pixels, int vsync) +{ + demo_post_draw(pixels); + + if(vsync) wait_vsync(); + memcpy64(vpgaddr[frontidx], pixels, pgsize >> 3); +} + +static void blit_frame_banked(void *pixels, int vsync) +{ + int sz, offs, pending; + unsigned char *pptr = pixels; + + demo_post_draw(pixels); + + if(vsync) wait_vsync(); + + /* assume initial window offset at 0 */ + offs = 0; + pending = pgsize; + while(pending > 0) { + sz = pending > 65536 ? 65536 : pending; + /*memcpy64(VMEM_PTR, pptr, sz >> 3);*/ + memcpy(VMEM_PTR, pptr, sz); + pptr += sz; + pending -= sz; + offs += curmode->win_64k_step; + vbe_setwin(0, offs); + } + vbe_setwin(0, 0); +} + +static void blit_frame_lfb_2x(void *pixels, int vsync) +{ + demo_post_draw(pixels); + + if(vsync) wait_vsync(); + memcpy64(vpgaddr[frontidx], pixels, pgsize >> 3); +} + +static void blit_frame_banked_2x(void *pixels, int vsync) +{ + int sz, offs, pending; + unsigned char *pptr = pixels; + + demo_post_draw(pixels); + + if(vsync) wait_vsync(); + + /* assume initial window offset at 0 */ + offs = 0; + pending = pgsize; + while(pending > 0) { + sz = pending > 65536 ? 65536 : pending; + /*memcpy64(VMEM_PTR, pptr, sz >> 3);*/ + memcpy(VMEM_PTR, pptr, sz); + pptr += sz; + pending -= sz; + offs += curmode->win_64k_step; + vbe_setwin(0, offs); + } + vbe_setwin(0, 0); +} + +static uint32_t calc_mask(int sz, int pos) +{ + uint32_t mask = 0; + while(sz-- > 0) { + mask = (mask << 1) | 1; + } + return mask << pos; +} + +#define MSR_MTRRCAP 0xfe +#define MSR_MTRRDEFTYPE 0x2ff +#define MSR_MTRRBASE(x) (0x200 | ((x) << 1)) +#define MSR_MTRRMASK(x) (0x201 | ((x) << 1)) +#define MTRRDEF_EN 0x800 +#define MTRRCAP_HAVE_WC 0x400 +#define MTRRMASK_VALID 0x800 + +#define MTRR_WC 1 + +static int get_page_memtype(uint32_t addr, int num_ranges) +{ + int i; + uint32_t rlow, rhigh; + uint32_t base, mask; + + for(i=0; i 0) { + if(get_page_memtype(addr, num_ranges) != MTRR_WC) { + return 0; + } + addr += 4096; + len -= 4096; + } + return 1; +} + +static int alloc_mtrr(int num_ranges) +{ + int i; + uint32_t rlow, rhigh; + + for(i=0; i> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + mask = ~mask & 0xfffff000; + + printf(" ... mask: %08x\n", (unsigned int)mask); + + _disable(); + get_msr(MSR_MTRRDEFTYPE, &def, &rhigh); + set_msr(MSR_MTRRDEFTYPE, def & ~MTRRDEF_EN, rhigh); + + set_msr(MSR_MTRRBASE(mtrr), addr | MTRR_WC, 0); + set_msr(MSR_MTRRMASK(mtrr), mask | MTRRMASK_VALID, 0); + + set_msr(MSR_MTRRDEFTYPE, def | MTRRDEF_EN, 0); + _enable(); +} + +static const char *mtrr_names[] = { "N/A", "W C", "N/A", "N/A", "W T", "W P", "W B" }; + +static const char *mtrr_type_name(int type) +{ + if(type < 0 || type >= sizeof mtrr_names / sizeof *mtrr_names) { + return mtrr_names[0]; + } + return mtrr_names[type]; +} + +static void print_mtrr(void) +{ + int i, num_ranges; + uint32_t rlow, rhigh, base, mask; + + get_msr(MSR_MTRRCAP, &rlow, &rhigh); + num_ranges = rlow & 0xff; + + for(i=0; i + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the program. If not, see +*/ +#define KEYB_C_ + +#include +#include +#include +#include +#include +#include + +#ifdef __WATCOMC__ +#include +#endif +#ifdef __DJGPP__ +#include +#include +#include +#endif + +#include "keyb.h" +#include "scancode.h" +#include "inttypes.h" +#include "dosutil.h" + +#define KB_INTR 0x9 +#define KB_PORT 0x60 + +#define PIC1_CMD_PORT 0x20 +#define OCW2_EOI (1 << 5) + +#ifdef __WATCOMC__ +#define INTERRUPT __interrupt __far + +#define DONE_INIT (prev_handler) +static void (INTERRUPT *prev_handler)(); +#endif + +#ifdef __DJGPP__ +#define INTERRUPT + +#define DONE_INIT prev_intr.pm_offset +static _go32_dpmi_seginfo intr, prev_intr; +#endif + +static void INTERRUPT kbintr(); + +static int *buffer; +static int buffer_size, buf_ridx, buf_widx; +static int last_key; + +static unsigned int num_pressed; +static unsigned char keystate[256]; + +#define ADVANCE(x) ((x) = ((x) + 1) % buffer_size) + +int kb_init(int bufsz) +{ + if(DONE_INIT) { + fprintf(stderr, "keyboard driver already initialized!\n"); + return 0; + } + + buffer_size = bufsz; + if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) { + fprintf(stderr, "failed to allocate input buffer, continuing without\n"); + buffer_size = 0; + } + buf_ridx = buf_widx = 0; + last_key = -1; + + memset(keystate, 0, sizeof keystate); + num_pressed = 0; + + /* set our interrupt handler */ + _disable(); +#ifdef __WATCOMC__ + prev_handler = _dos_getvect(KB_INTR); + _dos_setvect(KB_INTR, kbintr); +#endif +#ifdef __DJGPP__ + _go32_dpmi_get_protected_mode_interrupt_vector(KB_INTR, &prev_intr); + intr.pm_offset = (intptr_t)kbintr; + intr.pm_selector = _go32_my_cs(); + _go32_dpmi_allocate_iret_wrapper(&intr); + _go32_dpmi_set_protected_mode_interrupt_vector(KB_INTR, &intr); +#endif + _enable(); + + return 0; +} + +void kb_shutdown(void) +{ + if(!DONE_INIT) { + return; + } + + /* restore the original interrupt handler */ + _disable(); +#ifdef __WATCOMC__ + _dos_setvect(KB_INTR, prev_handler); +#endif +#ifdef __DJGPP__ + _go32_dpmi_set_protected_mode_interrupt_vector(KB_INTR, &prev_intr); + _go32_dpmi_free_iret_wrapper(&intr); +#endif + _enable(); + + free(buffer); +} + +int kb_isdown(int key) +{ + switch(key) { + case KB_ANY: + return num_pressed; + + case KB_ALT: + return keystate[KB_LALT] + keystate[KB_RALT]; + + case KB_CTRL: + return keystate[KB_LCTRL] + keystate[KB_RCTRL]; + } + + if(isalpha(key)) { + key = tolower(key); + } + return keystate[key]; +} + +#ifdef __WATCOMC__ +void halt(void); +#pragma aux halt = \ + "sti" \ + "hlt"; +#endif + +#ifdef __DJGPP__ +#define halt() asm volatile("sti\n\thlt\n\t") +#endif + +void kb_wait(void) +{ + int key; + while((key = kb_getkey()) == -1) { +#ifdef USE_HLT + /* put the processor to sleep while waiting for keypresses, but first + * make sure interrupts are enabled, or we'll sleep forever + */ + halt(); +#endif + } + kb_putback(key); +} + +int kb_getkey(void) +{ + int res; + + if(buffer) { + if(buf_ridx == buf_widx) { + return -1; + } + res = buffer[buf_ridx]; + ADVANCE(buf_ridx); + } else { + res = last_key; + last_key = -1; + } + return res; +} + +void kb_putback(int key) +{ + if(buffer) { + /* go back a place */ + if(--buf_ridx < 0) { + buf_ridx += buffer_size; + } + + /* if the write end hasn't caught up with us, go back one place + * and put it there, otherwise just overwrite the oldest key which + * is right where we were. + */ + if(buf_ridx == buf_widx) { + ADVANCE(buf_ridx); + } + + buffer[buf_ridx] = key; + } else { + last_key = key; + } +} + +static void INTERRUPT kbintr() +{ + unsigned char code; + int key, c, press; + static int ext; + + code = inp(KB_PORT); + + if(code == 0xe0) { + ext = 1; + goto eoi; + } + + if(code & 0x80) { + press = 0; + code &= 0x7f; + + if(num_pressed > 0) { + num_pressed--; + } + } else { + press = 1; + + num_pressed++; + } + + if(ext) { + key = scantbl_ext[code]; + c = key; + ext = 0; + } else { + key = scantbl[code]; + c = (keystate[KB_LSHIFT] | keystate[KB_RSHIFT]) ? scantbl_shift[code] : key; + } + + if(press) { + /* append to buffer */ + last_key = c; + if(buffer_size > 0) { + buffer[buf_widx] = c; + ADVANCE(buf_widx); + /* if the write end overtook the read end, advance the read end + * too, to discard the oldest keypress from the buffer + */ + if(buf_widx == buf_ridx) { + ADVANCE(buf_ridx); + } + } + } + + /* and update keystate table */ + keystate[key] = press; + +eoi: + outp(PIC1_CMD_PORT, OCW2_EOI); /* send end-of-interrupt */ +} diff --git a/src/dos/keyb.h b/src/dos/keyb.h new file mode 100644 index 0000000..478d17e --- /dev/null +++ b/src/dos/keyb.h @@ -0,0 +1,55 @@ +/* +DOS interrupt-based keyboard driver. +Copyright (C) 2013 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the program. If not, see +*/ +#ifndef KEYB_H_ +#define KEYB_H_ + +#include "app.h" + +#define KB_ANY (-1) +#define KB_ALT (-2) +#define KB_CTRL (-3) +#define KB_SHIFT (-4) + +#ifdef __cplusplus +extern "C" { +#endif + +int kb_init(int bufsz); /* bufsz can be 0 for no buffered keys */ +void kb_shutdown(void); /* don't forget to call this at the end! */ + +/* Boolean predicate for testing the current state of a particular key. + * You may also pass KB_ANY to test if any key is held down. + */ +int kb_isdown(int key); + +/* waits for any keypress */ +void kb_wait(void); + +/* removes and returns a single key from the input buffer. + * If buffering is disabled (initialized with kb_init(0)), then it always + * returns the last key pressed. + */ +int kb_getkey(void); + +void kb_putback(int key); + +#ifdef __cplusplus +} +#endif + +#endif /* KEYB_H_ */ diff --git a/src/dos/logger.c b/src/dos/logger.c new file mode 100644 index 0000000..fe308e4 --- /dev/null +++ b/src/dos/logger.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include "logger.h" +#include "util.h" + +#ifdef __WATCOMC__ +#include +#endif +#ifdef __DJGPP__ +#include +#endif + +void ser_putchar(int c); +void ser_puts(const char *s); +void ser_printf(const char *fmt, ...); + +static int setup_serial(int sdev); + +static int logfd = -1, orig_fd1 = -1; +static int log_isfile; + +int init_logger(const char *fname) +{ + int sdev; + + if(logfd != -1) return -1; + + log_isfile = 0; + if(strcasecmp(fname, "CON") == 0) { + return 0; + } + + if((logfd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { + fprintf(stderr, "init_logger: failed to open %s: %s\n", fname, strerror(errno)); + return -1; + } + + if(sscanf(fname, "COM%d", &sdev) == 1) { + setup_serial(sdev - 1); + } else { + log_isfile = 1; + } + + orig_fd1 = dup(1); + close(1); + close(2); + dup(logfd); + dup(logfd); + return 0; +} + +void stop_logger(void) +{ + if(logfd >= 0) { + close(logfd); + logfd = -1; + } + if(orig_fd1 >= 0) { + close(1); + close(2); + dup(orig_fd1); + dup(orig_fd1); + orig_fd1 = -1; + + freopen("CON", "w", stdout); + freopen("CON", "w", stderr); + } +} + +int print_tail(const char *fname) +{ + FILE *fp; + char buf[512]; + long lineoffs[16]; + int c, nlines; + + if(!log_isfile) return 0; + + printf("demo_abort called. see demo.log for details. Last lines:\n\n"); + + if(!(fp = fopen(fname, "rb"))) { + return -1; + } + nlines = 0; + lineoffs[nlines++] = 0; + while(fgets(buf, sizeof buf, fp)) { + lineoffs[nlines & 0xf] = ftell(fp); + nlines++; + } + + if(nlines > 16) { + long offs = lineoffs[nlines & 0xf]; + fseek(fp, offs, SEEK_SET); + } + while((c = fgetc(fp)) != -1) { + fputc(c, stdout); + } + fclose(fp); + return 0; +} + +#define UART1_BASE 0x3f8 +#define UART2_BASE 0x2f8 + +#define UART_DATA 0 +#define UART_DIVLO 0 +#define UART_DIVHI 1 +#define UART_FIFO 2 +#define UART_LCTL 3 +#define UART_MCTL 4 +#define UART_LSTAT 5 + +#define DIV_9600 (115200 / 9600) +#define DIV_38400 (115200 / 38400) +#define LCTL_8N1 0x03 +#define LCTL_DLAB 0x80 +#define FIFO_ENABLE_CLEAR 0x07 +#define MCTL_DTR_RTS_OUT2 0x0b +#define LST_TRIG_EMPTY 0x20 + +static unsigned int iobase; + +static int setup_serial(int sdev) +{ + if(sdev < 0 || sdev > 1) { + return -1; + } + iobase = sdev == 0 ? UART1_BASE : UART2_BASE; + + /* set clock divisor */ + outp(iobase | UART_LCTL, LCTL_DLAB); + outp(iobase | UART_DIVLO, DIV_9600 & 0xff); + outp(iobase | UART_DIVHI, DIV_9600 >> 8); + /* set format 8n1 */ + outp(iobase | UART_LCTL, LCTL_8N1); + /* assert RTS and DTR */ + outp(iobase | UART_MCTL, MCTL_DTR_RTS_OUT2); + return 0; +} + +void ser_putchar(int c) +{ + if(c == '\n') { + ser_putchar('\r'); + } + + while((inp(iobase | UART_LSTAT) & LST_TRIG_EMPTY) == 0); + outp(iobase | UART_DATA, c); +} + +void ser_puts(const char *s) +{ + while(*s) { + ser_putchar(*s++); + } +} + +void ser_printf(const char *fmt, ...) +{ + va_list ap; + char buf[512]; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + ser_puts(buf); +} diff --git a/src/dos/logger.h b/src/dos/logger.h new file mode 100644 index 0000000..56f6be7 --- /dev/null +++ b/src/dos/logger.h @@ -0,0 +1,17 @@ +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int init_logger(const char *fname); +void stop_logger(void); + +int print_tail(const char *fname); + +#ifdef __cplusplus +} +#endif + +#endif /* LOGGER_H_ */ diff --git a/src/dos/main.c b/src/dos/main.c new file mode 100644 index 0000000..b353f33 --- /dev/null +++ b/src/dos/main.c @@ -0,0 +1,130 @@ +/* +RetroRay - integrated standalone vintage modeller/renderer +Copyright (C) 2023 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include +#include +#include +#include "app.h" +#include "keyb.h" +#include "gfx.h" +#include "cdpmi.h" +#include "mouse.h" +#include "options.h" + +static uint32_t *vmem; +static int quit, disp_pending; + +int main(int argc, char **argv) +{ + int i; + int vmidx; + int mx, my, bnstate, bndiff; + static int prev_mx, prev_my, prev_bnstate; + +#ifdef __DJGPP__ + __djgpp_nearptr_enable(); +#endif + + kb_init(32); + + if(!have_mouse()) { + fprintf(stderr, "No mouse detected. Make sure the mouse driver is installed\n"); + return 1; + } + set_mouse_limits(0, 0, 639, 479); + set_mouse(320, 240); + + if(init_video() == -1) { + return 1; + } + + if((vmidx = match_video_mode(640, 480, 32)) == -1) { + return 1; + } + if(!(vmem = set_video_mode(vmidx, 1))) { + return 1; + } + + win_width = 640; + win_height = 480; + win_aspect = (float)win_width / (float)win_height; + + if(app_init() == -1) { + goto break_evloop; + } + disp_pending = 1; + + for(;;) { + int key; + while((key = kb_getkey()) != -1) { + app_keyboard(key, 1); + if(quit) goto break_evloop; + } + + bnstate = read_mouse(&mx, &my); + bndiff = bnstate ^ prev_bnstate; + + if(bndiff & 1) app_mouse(0, bnstate & 1, mx, my); + if(bndiff & 2) app_mouse(1, bnstate & 2, mx, my); + if(bndiff & 4) app_mouse(3, bnstate & 4, mx, my); + + if(disp_pending) { + disp_pending = 0; + app_display(); + } + } + +break_evloop: + app_shutdown(); + set_text_mode(); + cleanup_video(); + kb_shutdown(); + return 0; +} + +long app_getmsec(void) +{ + return time(0) * 1000; /* TODO */ +} + +void app_redisplay(void) +{ + disp_pending = 1; +} + +void app_swap_buffers(void) +{ + blit_frame(framebuf, opt.vsync); +} + +void app_quit(void) +{ + quit = 1; +} + +void app_resize(int x, int y) +{ +} + +void app_fullscreen(int fs) +{ +} + +void app_vsync(int vsync) +{ +} diff --git a/src/dos/mouse.h b/src/dos/mouse.h new file mode 100644 index 0000000..b54f6a9 --- /dev/null +++ b/src/dos/mouse.h @@ -0,0 +1,25 @@ +#ifndef MOUSE_H_ +#define MOUSE_H_ + +enum { + MOUSE_LEFT = 1, + MOUSE_RIGHT = 2, + MOUSE_MIDDLE = 4 +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int have_mouse(void); +void show_mouse(int show); +int read_mouse(int *xp, int *yp); +void set_mouse(int x, int y); +void set_mouse_limits(int xmin, int ymin, int xmax, int ymax); +void set_mouse_rate(int xrate, int yrate); + +#ifdef __cplusplus +} +#endif + +#endif /* MOUSE_H_ */ diff --git a/src/dos/pit8254.h b/src/dos/pit8254.h new file mode 100644 index 0000000..4389883 --- /dev/null +++ b/src/dos/pit8254.h @@ -0,0 +1,51 @@ +/* +colcycle - color cycling image viewer +Copyright (C) 2016 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef PIT8254_H_ +#define PIT8254_H_ + +/* frequency of the oscillator driving the 8254 timer */ +#define OSC_FREQ_HZ 1193182 + +/* I/O ports connected to the 8254 */ +#define PORT_DATA0 0x40 +#define PORT_DATA1 0x41 +#define PORT_DATA2 0x42 +#define PORT_CMD 0x43 + +/* command bits */ +#define CMD_CHAN0 0 +#define CMD_CHAN1 (1 << 6) +#define CMD_CHAN2 (2 << 6) +#define CMD_RDBACK (3 << 6) + +#define CMD_LATCH 0 +#define CMD_ACCESS_LOW (1 << 4) +#define CMD_ACCESS_HIGH (2 << 4) +#define CMD_ACCESS_BOTH (3 << 4) + +#define CMD_OP_INT_TERM 0 +#define CMD_OP_ONESHOT (1 << 1) +#define CMD_OP_RATE (2 << 1) +#define CMD_OP_SQWAVE (3 << 1) +#define CMD_OP_SW_STROBE (4 << 1) +#define CMD_OP_HW_STROBE (5 << 1) + +#define CMD_MODE_BIN 0 +#define CMD_MODE_BCD 1 + +#endif /* PIT8254_H_ */ diff --git a/src/dos/scancode.h b/src/dos/scancode.h new file mode 100644 index 0000000..b0e398c --- /dev/null +++ b/src/dos/scancode.h @@ -0,0 +1,61 @@ +/* +colcycle - color cycling image viewer +Copyright (C) 2016 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef KEYB_C_ +#error "do not include scancode.h anywhere..." +#endif + +/* table with rough translations from set 1 scancodes to ASCII-ish */ +static int scantbl[] = { + 0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', /* 0 - e */ + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* f - 1c */ + KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* 1d - 29 */ + KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT, /* 2a - 36 */ + 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 */ + 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 */ + 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 */ + 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */ +}; + +static int scantbl_shift[] = { + 0, KB_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', /* 0 - e */ + '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* f - 1c */ + KB_LCTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', /* 1d - 29 */ + KB_LSHIFT, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', KB_RSHIFT, /* 2a - 36 */ + 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 */ + 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 */ + 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 */ + 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */ +}; + + +/* extended scancodes, after the 0xe0 prefix */ +static int scantbl_ext[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r', KB_RCTRL, 0, 0, /* 10 - 1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2f */ + 0, 0, 0, 0, 0, KB_NUM_MINUS, 0, KB_SYSRQ, KB_RALT, 0, 0, 0, 0, 0, 0, 0, /* 30 - 3f */ + 0, 0, 0, 0, 0, 0, 0, KB_HOME, KB_UP, KB_PGUP, 0, KB_LEFT, 0, KB_RIGHT, 0, KB_END, /* 40 - 4f */ + KB_DOWN, KB_PGDN, KB_INSERT, KB_DEL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7f */ +}; + diff --git a/src/dos/timer.c b/src/dos/timer.c new file mode 100644 index 0000000..5492f0b --- /dev/null +++ b/src/dos/timer.c @@ -0,0 +1,182 @@ +/* for sound we use MIDAS, which takes over the PIT and we can't use it + * therefore only compile this file for NO_SOUND builds. + */ +#ifdef NO_SOUND + +#include +#include +#include +#include +#include + +#ifdef __WATCOMC__ +#include +#endif + +#ifdef __DJGPP__ +#include +#include +#include +#endif + +#include "pit8254.h" +#include "inttypes.h" +#include "util.h" +#include "dosutil.h" + +#define PIT_TIMER_INTR 8 +#define DOS_TIMER_INTR 0x1c + +/* macro to divide and round to the nearest integer */ +#define DIV_ROUND(a, b) \ + ((a) / (b) + ((a) % (b)) / ((b) / 2)) + +static void set_timer_reload(int reload_val); +static void cleanup(void); + +#ifdef __WATCOMC__ +#define INTERRUPT __interrupt __far + +static void INTERRUPT dos_timer_intr(); + +static void (INTERRUPT *prev_timer_intr)(); +#endif + +#ifdef __DJGPP__ +#define INTERRUPT + +static _go32_dpmi_seginfo intr, prev_intr; +#endif + +static void INTERRUPT timer_irq(); + +static volatile unsigned long ticks; +static unsigned long tick_interval, ticks_per_dos_intr; +static int inum; + +void init_timer(int res_hz) +{ + _disable(); + + if(res_hz > 0) { + int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz); + set_timer_reload(reload_val); + + tick_interval = DIV_ROUND(1000, res_hz); + ticks_per_dos_intr = DIV_ROUND(65535L, reload_val); + + inum = PIT_TIMER_INTR; +#ifdef __WATCOMC__ + prev_timer_intr = _dos_getvect(inum); + _dos_setvect(inum, timer_irq); +#endif +#ifdef __DJGPP__ + _go32_dpmi_get_protected_mode_interrupt_vector(inum, &prev_intr); + intr.pm_offset = (intptr_t)timer_irq; + intr.pm_selector = _go32_my_cs(); + _go32_dpmi_allocate_iret_wrapper(&intr); + _go32_dpmi_set_protected_mode_interrupt_vector(inum, &intr); +#endif + } else { + tick_interval = 55; + + inum = DOS_TIMER_INTR; +#ifdef __WATCOMC__ + prev_timer_intr = _dos_getvect(inum); + _dos_setvect(inum, dos_timer_intr); +#endif +#ifdef __DJGPP__ + assert(0); +#endif + } + _enable(); + + atexit(cleanup); +} + +static void cleanup(void) +{ + if(!inum) { + return; /* init hasn't ran, there's nothing to cleanup */ + } + + _disable(); + if(inum == PIT_TIMER_INTR) { + /* restore the original timer frequency */ + set_timer_reload(65535); + } + + /* restore the original interrupt handler */ +#ifdef __WATCOMC__ + _dos_setvect(inum, prev_timer_intr); +#endif +#ifdef __DJGPP__ + _go32_dpmi_set_protected_mode_interrupt_vector(inum, &prev_intr); + _go32_dpmi_free_iret_wrapper(&intr); +#endif + + _enable(); +} + +void reset_timer(void) +{ + ticks = 0; +} + +unsigned long get_msec(void) +{ + return ticks * tick_interval; +} + +void sleep_msec(unsigned long msec) +{ + unsigned long wakeup_time = ticks + msec / tick_interval; + while(ticks < wakeup_time) { +#ifdef USE_HLT + halt(); +#endif + } +} + +static void set_timer_reload(int reload_val) +{ + outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE); + outp(PORT_DATA0, reload_val & 0xff); + outp(PORT_DATA0, (reload_val >> 8) & 0xff); +} + +#ifdef __WATCOMC__ +static void INTERRUPT dos_timer_intr() +{ + ticks++; + _chain_intr(prev_timer_intr); /* DOES NOT RETURN */ +} +#endif + +/* first PIC command port */ +#define PIC1_CMD 0x20 +/* end of interrupt control word */ +#define OCW2_EOI (1 << 5) + +static void INTERRUPT timer_irq() +{ + static unsigned long dos_ticks; + + ticks++; + +#ifdef __WATCOMC__ + if(++dos_ticks >= ticks_per_dos_intr) { + /* I suppose the dos irq handler does the EOI so I shouldn't + * do it if I am to call the previous function + */ + dos_ticks = 0; + _chain_intr(prev_timer_intr); /* XXX DOES NOT RETURN */ + return; /* just for clarity */ + } +#endif + + /* send EOI to the PIC */ + outp(PIC1_CMD, OCW2_EOI); +} + +#endif /* NO_SOUND */ diff --git a/src/dos/vbe.c b/src/dos/vbe.c new file mode 100644 index 0000000..cb37ca1 --- /dev/null +++ b/src/dos/vbe.c @@ -0,0 +1,525 @@ +#include +#include +#include +#include +#include "vbe.h" +#include "cdpmi.h" + + +#define FIXPTR(ptr) \ + do { \ + uint32_t paddr = (uint32_t)(ptr); \ + uint16_t pseg = paddr >> 16; \ + uint16_t poffs = paddr & 0xffff; \ + if(pseg == seg && poffs < 512) { \ + paddr = ((uint32_t)seg << 4) + poffs; \ + } else { \ + paddr = ((uint32_t)pseg << 4) + poffs; \ + } \ + (ptr) = (void*)phys_to_virt(paddr); \ + } while(0) + +/* hijack the "VESA" sig field, to pre-cache number of modes */ +#define NMODES(inf) *(uint16_t*)((inf)->sig) +#define NACCMODES(inf) *(uint16_t*)((inf)->sig + 2) + +static int cur_pitch; +/* TODO update cur_pitch on mode-change and on setscanlen */ + + +int vbe_info(struct vbe_info *info) +{ + void *lowbuf; + uint16_t seg, sel; + uint16_t *modeptr; + uint32_t offs; + struct dpmi_regs regs = {0}; + + assert(sizeof *info == 512); + + if(!(seg = dpmi_alloc(sizeof *info / 16, &sel))) { + return -1; + } + lowbuf = (void*)phys_to_virt((uint32_t)seg << 4); + + memcpy(lowbuf, "VBE2", 4); + + regs.eax = 0x4f00; + regs.es = seg; + regs.edi = 0; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + fprintf(stderr, "vbe_get_info (4f00) failed\n"); + dpmi_free(sel); + return -1; + } + + memcpy(info, lowbuf, sizeof *info); + dpmi_free(sel); + + FIXPTR(info->oem_name); + FIXPTR(info->vendor); + FIXPTR(info->product); + FIXPTR(info->revstr); + FIXPTR(info->modes); + /* implementations without the accel capability, will use the space taken + * by the accel_modes pointer for other data (probably video modes). We + * need to check for the capability before "fixing" this pointer, otherwise + * we'll shuffle random data. + */ + if(info->caps & VBE_ACCEL) { + FIXPTR(info->accel_modes); + } + + /* info->modes should be pointing somewhere at the end of the original + * low memory buffer. make it point at the same offset in the info + * buffer where we copied everything instead. + */ + offs = (char*)info->modes - (char*)lowbuf; + if(offs < sizeof *info) { /* this should always be true */ + info->modes = (uint16_t*)((char*)info + offs); + } + + modeptr = info->modes; + while(*modeptr != 0xffff) { + if(modeptr - info->modes >= 256) { + modeptr = info->modes; + break; + } + modeptr++; + } + NMODES(info) = modeptr - info->modes; + + if(info->caps & VBE_ACCEL) { + modeptr = info->accel_modes; + while(*modeptr != 0xffff) { + if(modeptr - info->accel_modes >= 256) { + modeptr = info->accel_modes; + break; + } + modeptr++; + } + NACCMODES(info) = modeptr - info->accel_modes; + } + return 0; +} + +int vbe_num_modes(struct vbe_info *info) +{ + return NMODES(info); +} + +int vbe_mode_info(int mode, struct vbe_mode_info *minf) +{ + void *lowbuf; + uint16_t seg, sel; + struct dpmi_regs regs = {0}; + + assert(sizeof *minf == 256); + assert(offsetof(struct vbe_mode_info, max_pixel_clock) == 0x3e); + + if(!(seg = dpmi_alloc(sizeof *minf / 16, &sel))) { + return -1; + } + lowbuf = (void*)phys_to_virt((uint32_t)seg << 4); + + regs.eax = 0x4f01; + regs.ecx = mode; + regs.es = seg; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + fprintf(stderr, "vbe_mode_info (4f01) failed\n"); + dpmi_free(sel); + return -1; + } + + memcpy(minf, lowbuf, sizeof *minf); + dpmi_free(sel); + return 0; +} + +void vbe_print_info(FILE *fp, struct vbe_info *vinf) +{ + fprintf(fp, "vbe version: %u.%u\n", VBE_VER_MAJOR(vinf->ver), VBE_VER_MINOR(vinf->ver)); + if(VBE_VER_MAJOR(vinf->ver) >= 2) { + fprintf(fp, "%s - %s (%s)\n", vinf->vendor, vinf->product, vinf->revstr); + if(vinf->caps & VBE_ACCEL) { + fprintf(fp, "vbe/af %d.%d\n", VBE_VER_MAJOR(vinf->accel_ver), VBE_VER_MINOR(vinf->accel_ver)); + } + } else { + fprintf(fp, "oem: %s\n", vinf->oem_name); + } + fprintf(fp, "video memory: %dkb\n", vinf->vmem_blk * 64); + + if(vinf->caps) { + fprintf(fp, "caps:"); + if(vinf->caps & VBE_8BIT_DAC) fprintf(fp, " dac8"); + if(vinf->caps & VBE_NON_VGA) fprintf(fp, " non-vga"); + if(vinf->caps & VBE_DAC_BLANK) fprintf(fp, " dac-blank"); + if(vinf->caps & VBE_ACCEL) fprintf(fp, " af"); + if(vinf->caps & VBE_MUSTLOCK) fprintf(fp, " af-lock"); + if(vinf->caps & VBE_HWCURSOR) fprintf(fp, " af-curs"); + if(vinf->caps & VBE_HWCLIP) fprintf(fp, " af-clip"); + if(vinf->caps & VBE_TRANSP_BLT) fprintf(fp, " af-tblt"); + fprintf(fp, "\n"); + } + + fprintf(fp, "%d video modes available\n", NMODES(vinf)); + if(vinf->caps & VBE_ACCEL) { + fprintf(fp, "%d accelerated (VBE/AF) modes available\n", NACCMODES(vinf)); + } + fflush(fp); +} + +void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf) +{ + fprintf(fp, "%dx%d %dbpp", minf->xres, minf->yres, minf->bpp); + + switch(minf->mem_model) { + case VBE_TYPE_DIRECT: + fprintf(fp, " (rgb"); + if(0) { + case VBE_TYPE_YUV: + fprintf(fp, " (yuv"); + } + fprintf(fp, " %d%d%d)", minf->rsize, minf->gsize, minf->bsize); + break; + case VBE_TYPE_PLANAR: + fprintf(fp, " (%d planes)", minf->num_planes); + break; + case VBE_TYPE_PACKED: + fprintf(fp, " (packed)"); + break; + case VBE_TYPE_TEXT: + fprintf(fp, " (%dx%d cells)", minf->xcharsz, minf->ycharsz); + break; + case VBE_TYPE_CGA: + fprintf(fp, " (CGA)"); + break; + case VBE_TYPE_UNCHAIN: + fprintf(fp, " (unchained-%d)", minf->num_planes); + break; + } + fprintf(fp, " %dpg", minf->num_img_pages); + + if(minf->attr & VBE_ATTR_LFB) { + fprintf(fp, " lfb@%lx", (unsigned long)minf->fb_addr); + } else { + fprintf(fp, " (%dk gran)", (int)minf->win_gran); + } + + fprintf(fp, " ["); + if(minf->attr & VBE_ATTR_AVAIL) fprintf(fp, " avail"); + if(minf->attr & VBE_ATTR_OPTINFO) fprintf(fp, " opt"); + if(minf->attr & VBE_ATTR_TTY) fprintf(fp, " tty"); + if(minf->attr & VBE_ATTR_COLOR) fprintf(fp, " color"); + if(minf->attr & VBE_ATTR_GFX) fprintf(fp, " gfx"); + if(minf->attr & VBE_ATTR_NOTVGA) fprintf(fp, " non-vga"); + if(minf->attr & VBE_ATTR_BANKED) fprintf(fp, " banked"); + if(minf->attr & VBE_ATTR_LFB) fprintf(fp, " lfb"); + if(minf->attr & VBE_ATTR_DBLSCAN) fprintf(fp, " dblscan"); + if(minf->attr & VBE_ATTR_ILACE) fprintf(fp, " ilace"); + if(minf->attr & VBE_ATTR_TRIPLEBUF) fprintf(fp, " trplbuf"); + if(minf->attr & VBE_ATTR_STEREO) fprintf(fp, " stereo"); + if(minf->attr & VBE_ATTR_STEREO_2FB) fprintf(fp, " stdual"); + fprintf(fp, " ]\n"); + fflush(fp); +} + +int vbe_setmode(uint16_t mode) +{ + struct dpmi_regs regs = {0}; + + regs.eax = 0x4f02; + regs.ebx = mode; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + + cur_pitch = vbe_getpitch(); + return 0; +} + +int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc) +{ + void *lowbuf; + uint16_t seg, sel; + struct dpmi_regs regs = {0}; + + assert(sizeof *crtc == 59); + + if(!(seg = dpmi_alloc((sizeof *crtc + 15) / 16, &sel))) { + return -1; + } + lowbuf = (void*)phys_to_virt((uint32_t)seg << 4); + + memcpy(lowbuf, crtc, sizeof *crtc); + + regs.eax = 0x4f02; + regs.ebx = mode; + regs.es = seg; + dpmi_int(0x10, ®s); + + dpmi_free(sel); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + + cur_pitch = vbe_getpitch(); + return 0; +} + +int vbe_getmode(void) +{ + struct dpmi_regs regs = {0}; + + regs.eax = 0x4f03; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return regs.ebx & 0xffff; +} + +int vbe_state_size(unsigned int flags) +{ + struct dpmi_regs regs = {0}; + + regs.eax = 0x4f04; + regs.edx = 0; + regs.ecx = flags; + dpmi_int(0x10, ®s); + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return (regs.ebx & 0xffff) * 64; +} + +int vbe_save(void *stbuf, int sz, unsigned int flags) +{ + void *lowbuf; + uint16_t seg, sel; + struct dpmi_regs regs = {0}; + + if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) { + return -1; + } + lowbuf = (void*)phys_to_virt((uint32_t)seg << 4); + + regs.eax = 0x4f04; + regs.edx = 1; /* save */ + regs.ecx = flags; + regs.es = seg; + dpmi_int(0x10, ®s); + if((regs.eax & 0xffff) != 0x4f) { + dpmi_free(sel); + return -1; + } + + memcpy(stbuf, lowbuf, sz); + dpmi_free(sel); + return 0; +} + +int vbe_restore(void *stbuf, int sz, unsigned int flags) +{ + void *lowbuf; + uint16_t seg, sel; + struct dpmi_regs regs = {0}; + + if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) { + return -1; + } + lowbuf = (void*)phys_to_virt((uint32_t)seg << 4); + + memcpy(lowbuf, stbuf, sz); + + regs.eax = 0x4f04; + regs.edx = 2; /* restore */ + regs.ecx = flags; + regs.es = seg; + dpmi_int(0x10, ®s); + dpmi_free(sel); + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return 0; +} + +int vbe_setwin(int wid, int pos) +{ + struct dpmi_regs regs; + + if(wid & ~1) return -1; + + regs.eax = 0x4f05; + regs.ebx = wid; + regs.edx = pos; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return 0; +} + +int vbe_getwin(int wid) +{ + struct dpmi_regs regs; + + if(wid & ~1) return -1; + + regs.eax = 0x4f05; + regs.ebx = wid; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + + return regs.edx & 0xffff; +} + +int vbe_setscanlen(int len_pix) +{ + struct dpmi_regs regs; + + regs.eax = 0x4f06; + regs.ebx = 0; /* set scanline length in pixels */ + regs.ecx = len_pix; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + + cur_pitch = vbe_getpitch(); + return regs.ecx; +} + +int vbe_getscanlen(void) +{ + struct dpmi_regs regs; + + regs.eax = 0x4f06; + regs.ebx = 1; /* get scanline length */ + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return regs.ecx; +} + +int vbe_getpitch(void) +{ + struct dpmi_regs regs; + + regs.eax = 0x4f06; + regs.ebx = 1; /* get scanline length */ + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return regs.ebx; +} + +int vbe_scanline_info(struct vbe_scanline_info *sinf) +{ + struct dpmi_regs regs; + + regs.eax = 0x4f06; + regs.ebx = 1; /* get scanline length */ + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + + sinf->size = regs.ebx & 0xffff; + sinf->num_pixels = regs.ecx & 0xffff; + sinf->max_scanlines = regs.edx & 0xffff; + return 0; +} + +enum { + SDISP_SET = 0x00, + SDISP_GET = 0x01, + SDISP_ALTSET = 0x02, + SDISP_SET_STEREO = 0x03, + SDISP_GETSCHED = 0x04, + SDISP_STEREO_ON = 0x05, + SDISP_STEREO_OFF = 0x06, + SDISP_SET_VBLANK = 0x80, + SDISP_ALTSET_VBLANK = 0x82, + SDISP_SET_STEREO_VBLANK = 0x83 +}; + +int vbe_setdisp(int x, int y, int when) +{ + struct dpmi_regs regs; + + regs.eax = 0x4f07; + regs.ebx = (when == VBE_SWAP_VBLANK) ? SDISP_SET_VBLANK : SDISP_SET; + regs.ecx = x; + regs.edx = y; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return 0; +} + +int vbe_swap(uint32_t voffs, int when) +{ + struct dpmi_regs regs; + int op; + + switch(when) { + case VBE_SWAP_ASYNC: + op = SDISP_ALTSET; + break; + + case VBE_SWAP_NOW: + /* XXX is this the only way? */ + return vbe_setdisp(voffs % cur_pitch, voffs / cur_pitch, when); + + case VBE_SWAP_VBLANK: + default: + op = SDISP_ALTSET_VBLANK; + break; + } + + + regs.eax = 0x4f07; + regs.ebx = op; + regs.ecx = voffs; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return 0; +} + +int vbe_swap_pending(void) +{ + struct dpmi_regs regs; + + regs.eax = 0x4f07; + regs.ebx = SDISP_GETSCHED; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + return 0; + } + return regs.ecx; +} diff --git a/src/dos/vbe.h b/src/dos/vbe.h new file mode 100644 index 0000000..4193d68 --- /dev/null +++ b/src/dos/vbe.h @@ -0,0 +1,242 @@ +#ifndef VBE_H_ +#define VBE_H_ + +#include +#include "sizeint.h" +#include "util.h" + +#pragma pack (push, 1) +struct vbe_info { + char sig[4]; + uint16_t ver; + char *oem_name; + uint32_t caps; + uint16_t *modes; + uint16_t vmem_blk; /* video memory size in 64k blocks */ + uint16_t oem_ver; + char *vendor; + char *product; + char *revstr; + uint16_t accel_ver; + uint16_t *accel_modes; + char reserved[216]; + char oem_data[256]; +} PACKED; + +struct vbe_mode_info { + uint16_t attr; + uint8_t wina_attr, winb_attr; + uint16_t win_gran, win_size; + uint16_t wina_seg, winb_seg; + uint32_t win_func; + uint16_t scanline_bytes; + + /* VBE 1.2 and above */ + uint16_t xres, yres; + uint8_t xcharsz, ycharsz; + uint8_t num_planes; + uint8_t bpp; + uint8_t num_banks; + uint8_t mem_model; + uint8_t bank_size; /* bank size in KB */ + uint8_t num_img_pages; + uint8_t reserved1; + + /* direct color fields */ + uint8_t rsize, rpos; + uint8_t gsize, gpos; + uint8_t bsize, bpos; + uint8_t xsize, xpos; + uint8_t cmode_info; /* direct color mode attributes */ + + /* VBE 2.0 and above */ + uint32_t fb_addr; /* physical address of the linear framebuffer */ + uint32_t os_addr; /* phys. address of off-screen memory */ + uint16_t os_size; /* size in KB of off-screen memory */ + + /* VBE 3.0 and above */ + uint16_t lfb_scanline_bytes; + uint8_t banked_num_img_pages; + uint8_t lfb_num_img_pages; + uint8_t lfb_rsize, lfb_rpos; + uint8_t lfb_gsize, lfb_gpos; + uint8_t lfb_bsize, lfb_bpos; + uint8_t lfb_xsize, lfb_xpos; + uint32_t max_pixel_clock; + + char reserved2[190]; +} PACKED; + +struct vbe_crtc_info { + uint16_t htotal, hsync_start, hsync_end; + uint16_t vtotal, vsync_start, vsync_end; + uint8_t flags; + uint32_t pixel_clock; + uint16_t rate_centihz; /* refresh rate in 1/100 hz (pck / (htotal * vtotal)) */ + char reserved[40]; +} PACKED; +#pragma pack (pop) + +/* returned by vbe_scanline_info() */ +struct vbe_scanline_info { + int size; + int num_pixels; + int max_scanlines; +}; + +enum { + VBE_8BIT_DAC = 0x01, + VBE_NON_VGA = 0x02, + VBE_DAC_BLANK = 0x04, + VBE_STEREO = 0x08, /* ? */ + VBE_ACCEL = 0x08, + VBE_STEREO_VESA = 0x10, /* ? */ + VBE_MUSTLOCK = 0x10, + VBE_HWCURSOR = 0x20, + VBE_HWCLIP = 0x40, + VBE_TRANSP_BLT = 0x80 +}; + +#define VBE_VER_MAJOR(v) (((v) >> 8) & 0xff) +#define VBE_VER_MINOR(v) ((v) & 0xff) + +/* VBE mode attribute flags (vbe_mode_info.attr) */ +enum { + VBE_ATTR_AVAIL = 0x0001, + VBE_ATTR_OPTINFO = 0x0002, + VBE_ATTR_TTY = 0x0004, + VBE_ATTR_COLOR = 0x0008, + VBE_ATTR_GFX = 0x0010, + /* VBE 2.0 */ + VBE_ATTR_NOTVGA = 0x0020, + VBE_ATTR_BANKED = 0x0040, + VBE_ATTR_LFB = 0x0080, + VBE_ATTR_DBLSCAN = 0x0100, + /* VBE 3.0 */ + VBE_ATTR_ILACE = 0x0200, /* ! */ + VBE_ATTR_TRIPLEBUF = 0x0400, + VBE_ATTR_STEREO = 0x0800, + VBE_ATTR_STEREO_2FB = 0x1000, + /* VBE/AF */ + VBE_ATTR_MUSTLOCK = 0x0200 /* ! */ +}; + +/* VBE memory model type (vbe_mode_info.mem_model) */ +enum { + VBE_TYPE_TEXT, + VBE_TYPE_CGA, + VBE_TYPE_HERCULES, + VBE_TYPE_PLANAR, + VBE_TYPE_PACKED, + VBE_TYPE_UNCHAIN, + VBE_TYPE_DIRECT, + VBE_TYPE_YUV +}; + +/* VBE window attribute (vbe_mode_info.win(a|b)_attr) */ +enum { + VBE_WIN_AVAIL = 0x01, + VBE_WIN_RD = 0x02, + VBE_WIN_WR = 0x04 +}; + +/* mode number flags */ +enum { + VBE_MODE_RATE = 0x0800, /* VBE 3.0+ user-specified refresh rate */ + VBE_MODE_ACCEL = 0x2000, /* VBE/AF */ + VBE_MODE_LFB = 0x4000, /* VBE 2.0+ */ + VBE_MODE_PRESERVE = 0x8000 +}; + +/* standard mode numbers */ +enum { + VBE_640X400_8BPP = 0x100, + VBE_640X480_8BPP = 0x101, + VBE_800X600_4BPP = 0x102, + VBE_800X600_8BPP = 0x103, + VBE_1024X768_4BPP = 0x104, + VBE_1024X768_8BPP = 0x105, + VBE_1280X1024_4BPP = 0x106, + VBE_1280X1024_8BPP = 0x107, + VBE_80X60_TEXT = 0x108, + VBE_132X25_TEXT = 0x109, + VBE_132X43_TEXT = 0x10a, + VBE_132X50_TEXT = 0x10b, + VBE_132X60_TEXT = 0x10c, + /* VBE 1.2 */ + VBE_320X200_15BPP = 0x10d, + VBE_320X200_16BPP = 0x10e, + VBE_320X200_24BPP = 0x10f, + VBE_640X480_15BPP = 0x110, + VBE_640X480_16BPP = 0x111, + VBE_640X480_24BPP = 0x112, + VBE_800X600_15BPP = 0x113, + VBE_800X600_16BPP = 0x114, + VBE_800X600_24BPP = 0x115, + VBE_1024X768_15BPP = 0x116, + VBE_1024X768_16BPP = 0x117, + VBE_1024X768_24BPP = 0x118, + VBE_1280X1024_15BPP = 0x119, + VBE_1280X1024_16BPP = 0x11a, + VBE_1280X1024_24BPP = 0x11b, + /* VBE 2.0 */ + VBE_1600X1200_8BPP = 0x120, + VBE_1600X1200_15BPP = 0x121, + VBE_1600X1200_16BPP = 0x122, + + VBE_VMEM_MODE = 0x81ff +}; + +/* VBE CRTC flags (vbe_crtc_info.flags) */ +enum { + VBE_CRTC_DBLSCAN = 0x01, + VBE_CRTC_ILACE = 0x02, + VBE_CRTC_HSYNC_NEG = 0x04, + VBE_CRTC_VSYNC_NEG = 0x08 +}; + +enum { + VBE_STATE_CTRLHW = 0x01, + VBE_STATE_BIOS = 0x02, + VBE_STATE_DAC = 0x04, + VBE_STATE_REGS = 0x08, + + VBE_STATE_ALL = 0xffff +}; + +enum { + VBE_SWAP_NOW, + VBE_SWAP_VBLANK, + VBE_SWAP_ASYNC /* schedule swap and return (triple-buffering) */ +}; + +int vbe_info(struct vbe_info *info); +int vbe_num_modes(struct vbe_info *info); +int vbe_mode_info(int mode, struct vbe_mode_info *minf); + +void vbe_print_info(FILE *fp, struct vbe_info *info); +void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf); + +int vbe_setmode(uint16_t mode); +int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc); +int vbe_getmode(void); + +int vbe_state_size(unsigned int flags); +int vbe_save(void *stbuf, int sz, unsigned int flags); +int vbe_restore(void *stbuf, int sz, unsigned int flags); + +int vbe_setwin(int wid, int pos); +int vbe_getwin(int wid); + +/* returns the actual length in pixels, which might not be what was requested */ +int vbe_setscanlen(int len_pix); +int vbe_getscanlen(void); +int vbe_getpitch(void); +int vbe_scanline_info(struct vbe_scanline_info *sinf); + +int vbe_setdisp(int x, int y, int when); +int vbe_swap(uint32_t voffs, int when); +int vbe_swap_pending(void); /* 0: not pending (done) or error, 1: pending swap */ +/* TODO add stereo swap */ + +#endif /* VBE_H_ */ diff --git a/src/dos/vga.c b/src/dos/vga.c new file mode 100644 index 0000000..f2f8142 --- /dev/null +++ b/src/dos/vga.c @@ -0,0 +1,71 @@ +#include +#include "vga.h" +#include "vgaregs.h" +#include "cdpmi.h" +#include "dosutil.h" + +static void crtc_write(int reg, unsigned char val); +static unsigned char crtc_read(int reg); + +int vga_setmode(int mode) +{ + struct dpmi_regs regs = {0}; + + regs.eax = mode; /* func 00 | mode */ + dpmi_int(0x10, ®s); + return 0; +} + +static unsigned short crtc_modex_regs[] = { + 0x0d06, /* vertical total */ + 0x3e07, /* vcount overflow bit */ + 0x4109, /* double-scan */ + 0xea10, /* vsync start */ + 0xac11, /* vsync end & protect */ + 0xdf12, /* vertical visible */ + 0x0014, /* no dword mode */ + 0xe715, /* vblank start */ + 0x0616, /* vblank end */ + 0xe317, /* byte mode */ + 0 +}; + +int vga_setmodex(void) +{ + int i; + unsigned char val; + + vga_setmode(0x13); + + /* disable chain-4 (C4=0, O/E=1 (sequential), EM=1 (extmem), A/G=0 (gfx) */ + outpw(VGA_SC_ADDR_PORT, VGA_SC_MEMMODE_REG | 0x0600); + /* pull reset low */ + outpw(VGA_SC_ADDR_PORT, VGA_SC_RESET_REG | 0x0100); + /* 25mhz dot clock, 60hz scan */ + outp(VGA_MISC_PORT, VGA_MISC_480 | VGA_MISC_PG1 | VGA_MISC_CLK25 | + VGA_MISC_CPUEN | VGA_MISC_COLOR); + /* return reset high */ + outpw(VGA_SC_ADDR_PORT, VGA_SC_RESET_REG | 0x0300); + + /* disable CRTC write-protect */ + crtc_write(CRTC_VRETEND_REG, crtc_read(CRTC_VRETEND_REG) & ~CRTC_VRETEND_PR); + /* change CRTC registers */ + for(i=0; crtc_modex_regs[i]; i++) { + outpw(VGA_CRTC_PORT, crtc_modex_regs[i]); + } + + vga_planemask(0xf); + memset(VGA_FBADDR, 3, 320 * 240 / 4); + return 0; +} + +static void crtc_write(int reg, unsigned char val) +{ + outpw(VGA_CRTC_ADDR_PORT, reg | ((unsigned int)val << 8)); +} + +static unsigned char crtc_read(int reg) +{ + outp(VGA_CRTC_ADDR_PORT, reg); + return inp(VGA_CRTC_DATA_PORT); +} diff --git a/src/dos/vga.h b/src/dos/vga.h new file mode 100644 index 0000000..d8a341c --- /dev/null +++ b/src/dos/vga.h @@ -0,0 +1,49 @@ +#ifndef VGA_H_ +#define VGA_H_ + +#include "inttypes.h" +#include "dosutil.h" +#include "cdpmi.h" +#include "vgaregs.h" + +#define VGA_FBADDR ((void*)phys_to_virt(0xa0000)) + +int vga_setmode(int mode); +int vga_setmodex(void); + +#define vga_planemask(mask) vga_sc_write(VGA_SC_MAPMASK_REG, mask) + +#ifdef __WATCOMC__ +void vga_setpal(int16_t idx, uint8_t r, uint8_t g, uint8_t b); +#pragma aux vga_setpal = \ + "test ax, 0x8000" \ + "jnz skip_dacaddr" \ + "mov dx, 0x3c8" \ + "out dx, al" \ + "skip_dacaddr:" \ + "mov dx, 0x3c9" \ + "mov al, bl" \ + "shr al, 2" \ + "out dx, al" \ + "mov al, bh" \ + "shr al, 2" \ + "out dx, al" \ + "mov al, cl" \ + "shr al, 2" \ + "out dx, al" \ + parm[ax][bl][bh][cl] \ + modify[dx]; +#endif /* __WATCOMC__ */ + +#define vga_sc_write(reg, data) \ + outpw(VGA_SC_ADDR_PORT, (uint16_t)(reg) | ((uint16_t)(data) << 8)) +#define vga_sc_read(reg) \ + (outp(VGA_SC_ADDR_PORT, reg), inp(VGA_SC_DATA_PORT)) +#define vga_crtc_write(reg, data) \ + outpw(VGA_CRTC_PORT, (uint16_t)(reg) | ((uint16_t)(data) << 8)) +#define vga_crtc_read(reg) \ + (outp(VGA_CRTC_ADDR_PORT, reg), inp(VGA_CRTC_DATA_PORT)) +#define vga_crtc_wrmask(reg, data, mask) \ + outp(VGA_CRTC_DATA_PORT, (crtc_read(reg) & ~(mask)) | (data)) + +#endif /* VGA_H_ */ diff --git a/src/dos/vgaregs.h b/src/dos/vgaregs.h new file mode 100644 index 0000000..15c4090 --- /dev/null +++ b/src/dos/vgaregs.h @@ -0,0 +1,85 @@ +#ifndef VGAREGS_H_ +#define VGAREGS_H_ + +/* ---- VGA registers ---- */ +#define VGA_AC_PORT 0x3c0 +#define VGA_AC_RD_PORT 0x3c1 +#define VGA_SC_ADDR_PORT 0x3c4 +#define VGA_SC_DATA_PORT 0x3c5 +#define VGA_GC_ADDR_PORT 0x3ce +#define VGA_GC_DATA_PORT 0x3cf +#define VGA_CRTC_PORT 0x3d4 +#define VGA_CRTC_ADDR_PORT 0x3d4 +#define VGA_CRTC_DATA_PORT 0x3d5 +#define VGA_STAT0_PORT 0x3c2 +#define VGA_STAT1_PORT 0x3da +#define VGA_MISC_PORT 0x3c2 +#define VGA_MISC_RD_PORT 0x3cc + +/* attribute controller registers */ +#define VGA_AC_EN 0x20 +#define VGA_AC_MODE_REG 0x10 + +/* sequence controller registers */ +#define VGA_SC_RESET_REG 0x00 +#define VGA_SC_CLOCK_REG 0x01 +#define VGA_SC_MAPMASK_REG 0x02 +#define VGA_SC_MEMMODE_REG 0x04 + +/* graphics controller registers */ +#define VGA_GC_SR_REG 0x00 +#define VGA_GC_SREN_REG 0x01 +#define VGA_GC_ROT_REG 0x03 +#define VGA_GC_MODE_REG 0x05 +#define VGA_GC_MASK_REG 0x08 + +/* attribute controller mode register (10h) bits */ +#define VGA_AC_MODE_GFX 0x01 +#define VGA_AC_MODE_MONO 0x02 +#define VGA_AC_MODE_LGE 0x04 +#define VGA_AC_MODE_BLINK 0x08 +#define VGA_AC_MODE_PIXPAN 0x20 +#define VGA_AC_MODE_8BIT 0x40 + +/* misc register bits */ +#define VGA_MISC_COLOR 0x01 +#define VGA_MISC_CPUEN 0x02 +#define VGA_MISC_CLK25 0 +#define VGA_MISC_CLK28 0x04 +#define VGA_MISC_PG1 0x20 +#define VGA_MISC_400 0 +#define VGA_MISC_350 0x40 +#define VGA_MISC_480 0xc0 + + +/* CRTC registers */ +#define CRTC_HTOTAL_REG 0x00 +#define CRTC_HEND_REG 0x01 +#define CRTC_HBLSTART_REG 0x02 +#define CRTC_HBLEND_REG 0x03 +#define CRTC_HRETSTART_REG 0x04 +#define CRTC_HRETEND_REG 0x05 +#define CRTC_VTOTAL_REG 0x06 +#define CRTC_OVF_REG 0x07 +#define CRTC_PRESET_REG 0x08 +#define CRTC_MAXSCAN_REG 0x09 +#define CRTC_CURSTART_REG 0x0a +#define CRTC_CUREND_REG 0x0b +#define CRTC_STARTH_REG 0x0c +#define CRTC_STARTL_REG 0x0d +#define CRTC_CURH_REG 0x0e +#define CRTC_CURL_REG 0x0f +#define CRTC_VRETSTART_REG 0x10 +#define CRTC_VRETEND_REG 0x11 +#define CRTC_VEND_REG 0x12 +#define CRTC_OFFSET_REG 0x13 +#define CRTC_UL_REG 0x14 +#define CRTC_VBLSTART_REG 0x15 +#define CRTC_VBLEND_REG 0x16 +#define CRTC_MODE_REG 0x17 +#define CRTC_LCMP_REG 0x18 + +/* CRTC register bits */ +#define CRTC_VRETEND_PR 0x80 + +#endif /* VGAREGS_H_ */ diff --git a/src/dos/watdpmi.c b/src/dos/watdpmi.c new file mode 100644 index 0000000..04d7b94 --- /dev/null +++ b/src/dos/watdpmi.c @@ -0,0 +1,59 @@ +#ifdef __WATCOMC__ +#include "cdpmi.h" + +void dpmi_real_int(int inum, struct dpmi_real_regs *regs) +{ + unsigned char int_num = (unsigned char)inum; + __asm { + mov eax, 0x300 + mov edi, regs + mov bl, int_num + mov bh, 0 + xor ecx, ecx + int 0x31 + } +} + +void *dpmi_mmap(uint32_t phys_addr, unsigned int size) +{ + uint16_t mem_high, mem_low; + uint16_t phys_high = phys_addr >> 16; + uint16_t phys_low = phys_addr & 0xffff; + uint16_t size_high = size >> 16; + uint16_t size_low = size & 0xffff; + unsigned int err, res = 0; + + __asm { + mov eax, 0x800 + mov bx, phys_high + mov cx, phys_low + mov si, size_high + mov di, size_low + int 0x31 + add res, 1 + mov err, eax + mov mem_high, bx + mov mem_low, cx + } + + if(res == 2) { + return 0; + } + return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low)); +} + +void dpmi_munmap(void *addr) +{ + uint16_t mem_high = (uint32_t)addr >> 16; + uint16_t mem_low = (uint16_t)addr; + + __asm { + mov eax, 0x801 + mov bx, mem_high + mov cx, mem_low + int 0x31 + } +} +#else +int stop_gcc_crying_about_empty_translation_units = 0; +#endif /* __WATCOM__ */ diff --git a/src/gaw/gawswtnl.c b/src/gaw/gawswtnl.c index a30d56c..c307f8a 100644 --- a/src/gaw/gawswtnl.c +++ b/src/gaw/gawswtnl.c @@ -187,7 +187,7 @@ void gaw_rotate(float deg, float x, float y, float z) { static float m[16]; - float angle = M_PI * deg / 180.0f; + float angle = CGM_PI * deg / 180.0f; float sina = sin(angle); float cosa = cos(angle); float one_minus_cosa = 1.0f - cosa; @@ -266,7 +266,7 @@ void gaw_perspective(float vfov_deg, float aspect, float znear, float zfar) { static float m[16]; - float vfov = M_PI * vfov_deg / 180.0f; + float vfov = CGM_PI * vfov_deg / 180.0f; float s = 1.0f / tan(vfov * 0.5f); float range = znear - zfar; diff --git a/src/gaw/gawswtnl.h b/src/gaw/gawswtnl.h index 11d462b..d016291 100644 --- a/src/gaw/gawswtnl.h +++ b/src/gaw/gawswtnl.h @@ -130,6 +130,15 @@ void gaw_swtnl_drawprim(int prim, struct vertex *v, int vnum); #if defined(__i386__) || defined(__386__) || defined(MSDOS) + +#ifndef INLINE +#if (__STDC_VERSION__ >= 199901) || defined(__GNUC__) +#define INLINE inline +#else +#define INLINE __inline +#endif +#endif + /* fast conversion of double -> 32bit int * for details see: * - http://chrishecker.com/images/f/fb/Gdmfp.pdf diff --git a/src/meshgen.c b/src/meshgen.c index b9e394f..9804913 100644 --- a/src/meshgen.c +++ b/src/meshgen.c @@ -5,8 +5,8 @@ /* -------- sphere -------- */ -#define SURAD(u) ((u) * 2.0 * M_PI) -#define SVRAD(v) ((v) * M_PI) +#define SURAD(u) ((u) * 2.0 * CGM_PI) +#define SVRAD(v) ((v) * CGM_PI) static void sphvec(cgm_vec3 *v, float theta, float phi) { @@ -47,19 +47,19 @@ void gen_sphere(struct cmesh *mesh, float rad, int usub, int vsub, float urange, u = 0.0; for(i=0; ix = 0.5 * theta / M_PI + 0.5; - uvarr->y = phi / M_PI; + uvarr->x = 0.5 * theta / CGM_PI + 0.5; + uvarr->y = phi / CGM_PI; uvarr++; } } @@ -254,11 +254,11 @@ void gen_torus(struct cmesh *mesh, float mainrad, float ringrad, int usub, int v u = 0.0; for(i=0; ix = pos.x * cos(angle); res->y = pos.y; res->z = pos.x * sin(angle); @@ -807,7 +807,7 @@ void gen_revol(struct cmesh *mesh, int usub, int vsub, cgm_vec2 (*rfunc)(float, } } -static inline void sweep_vert(cgm_vec3 *res, float u, float v, float height, +static CGM_INLINE void sweep_vert(cgm_vec3 *res, float u, float v, float height, cgm_vec2 (*sf)(float, float, void*), void *cls) { cgm_vec2 pos = sf(u, v, cls); diff --git a/src/rbtree.c b/src/rbtree.c index 765e542..7bc97b3 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -7,8 +7,8 @@ the terms of the 3-clause BSD license. See COPYING for details. */ #include #include -#include #include +#include "sizeint.h" #include "rbtree.h" #define INT2PTR(x) ((void*)(intptr_t)(x)) diff --git a/src/rtk_impl.h b/src/rtk_impl.h index 1b53c5e..34afd0f 100644 --- a/src/rtk_impl.h +++ b/src/rtk_impl.h @@ -2,7 +2,7 @@ #define RTK_IMPL_H_ #include -#include "inttypes.h" +#include "sizeint.h" #include "rtk.h" enum { -- 1.7.10.4