Compare commits

...
2 Commits
Author SHA1 Message Date
veclavtlica fd54d48aca push WDosX 2026-10-08 13:46:34 +03:00
veclavtlica b92458862e new approach for dos port 2026-10-08 13:46:16 +03:00
15 changed files with 190 additions and 119 deletions
+2
View File
@@ -3,6 +3,8 @@
**/*.EXE
**/*.exe
**/*.out
**/*.BAK
**/*.wdl
*.sublime-*
Player/player
+1 -1
View File
@@ -2,6 +2,6 @@
#define PLR_DISPLAY_H
__attribute__((used)) extern int plr_display_x11_main(int argc, char *argv[]);
extern int plr_display_dos_main(int argc, char *argv[]);
__attribute__((used)) extern int plr_display_dos_main(void);
#endif
+126 -108
View File
@@ -7,146 +7,164 @@
#define MODE_VGA_320_200_8 0x13
#define MODE_VESA_640_480_8 0x101
/*
TODO: https://github.com/depp/elf2dos/blob/master/elf/elf.go
https://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description
Do not use anything but Clang in the end.
*/
// 8-color VGA palette gradient, lighter shades of lavender to pink
#define COLOR_OFFSET 0x50
#define COLOR_NUM 8
#define COLOR_STEP (HEIGHT / COLOR_NUM)
/* https://wiki.osdev.org/VESA_Video_Modes */
_Packed struct VbeInfoBlock {
char VbeSignature[4]; // == "VESA"
uint16_t VbeVersion; // == 0x0300 for VBE 3.0
uint16_t OemStringPtr[2]; // isa vbeFarPtr
uint8_t Capabilities[4];
uint16_t VideoModePtr[2]; // isa vbeFarPtr
uint16_t TotalMemory; // as # of 64KB blocks
uint8_t Reserved[492];
};
// /* https://wiki.osdev.org/VESA_Video_Modes */
// _Packed struct VbeInfoBlock {
// char VbeSignature[4]; // == "VESA"
// uint16_t VbeVersion; // == 0x0300 for VBE 3.0
// uint16_t OemStringPtr[2]; // isa vbeFarPtr
// uint8_t Capabilities[4];
// uint16_t VideoModePtr[2]; // isa vbeFarPtr
// uint16_t TotalMemory; // as # of 64KB blocks
// uint8_t Reserved[492];
// };
_Packed struct ModeInfoBlock {
uint16_t
attributes; // deprecated, only bit 7 should be of interest to you, and it
// indicates the mode supports a linear frame buffer.
uint8_t window_a; // deprecated
uint8_t window_b; // deprecated
uint16_t granularity; // deprecated; used while calculating bank numbers
uint16_t window_size;
uint16_t segment_a;
uint16_t segment_b;
uint32_t win_func_ptr; // deprecated; used to switch banks from protected mode
// without returning to real mode
uint16_t pitch; // number of bytes per horizontal line
uint16_t width; // width in pixels
uint16_t height; // height in pixels
uint8_t w_char; // unused...
uint8_t y_char; // ...
uint8_t planes;
uint8_t bpp; // bits per pixel in this mode
uint8_t banks; // deprecated; total number of banks in this mode
uint8_t memory_model;
uint8_t bank_size; // deprecated; size of a bank, almost always 64 KB but may
// be 16 KB...
uint8_t image_pages;
uint8_t reserved0;
// _Packed struct ModeInfoBlock {
// uint16_t
// attributes; // deprecated, only bit 7 should be of interest to you, and
// it
// // indicates the mode supports a linear frame buffer.
// uint8_t window_a; // deprecated
// uint8_t window_b; // deprecated
// uint16_t granularity; // deprecated; used while calculating bank numbers
// uint16_t window_size;
// uint16_t segment_a;
// uint16_t segment_b;
// uint32_t win_func_ptr; // deprecated; used to switch banks from protected
// mode
// // without returning to real mode
// uint16_t pitch; // number of bytes per horizontal line
// uint16_t width; // width in pixels
// uint16_t height; // height in pixels
// uint8_t w_char; // unused...
// uint8_t y_char; // ...
// uint8_t planes;
// uint8_t bpp; // bits per pixel in this mode
// uint8_t banks; // deprecated; total number of banks in this mode
// uint8_t memory_model;
// uint8_t bank_size; // deprecated; size of a bank, almost always 64 KB but
// may
// // be 16 KB...
// uint8_t image_pages;
// uint8_t reserved0;
uint8_t red_mask;
uint8_t red_position;
uint8_t green_mask;
uint8_t green_position;
uint8_t blue_mask;
uint8_t blue_position;
uint8_t reserved_mask;
uint8_t reserved_position;
uint8_t direct_color_attributes;
// uint8_t red_mask;
// uint8_t red_position;
// uint8_t green_mask;
// uint8_t green_position;
// uint8_t blue_mask;
// uint8_t blue_position;
// uint8_t reserved_mask;
// uint8_t reserved_position;
// uint8_t direct_color_attributes;
uint32_t framebuffer; // physical address of the linear frame buffer; write
// here to draw to the screen
uint32_t off_screen_mem_off;
uint16_t off_screen_mem_size; // size of memory in the framebuffer but not
// being displayed on the screen
uint8_t reserved1[206];
};
// uint32_t framebuffer; // physical address of the linear frame buffer; write
// // here to draw to the screen
// uint32_t off_screen_mem_off;
// uint16_t off_screen_mem_size; // size of memory in the framebuffer but not
// // being displayed on the screen
// uint8_t reserved1[206];
// };
static char get_video_mode();
#pragma aux get_video_mode = "mov ah, 0x0f" \
"int 0x10" value[al] modify[ah];
// static char get_video_mode();
// #pragma aux get_video_mode = "mov ah, 0x0f" \
// "int 0x10" value[al] modify[ah];
static void set_video_mode(unsigned char);
#pragma aux set_video_mode = "mov ah, 0x00" \
"int 0x10" parm[al] modify[ah];
// static void set_video_mode(unsigned char);
// #pragma aux set_video_mode = "mov ah, 0x00" \
// "int 0x10" parm[al] modify[ah];
static void set_vesa_video_mode(unsigned short);
#pragma aux set_vesa_video_mode = "mov ax, 0x4f02" \
"int 0x10" parm[bx] modify[ah];
// static void set_vesa_video_mode(unsigned short);
// #pragma aux set_vesa_video_mode = "mov ax, 0x4f02" \
// "int 0x10" parm[bx] modify[ah];
static void wait_for_key();
#pragma aux wait_for_key = "mov ah, 0x00" \
"int 0x16" modify[ah];
// static void wait_for_key();
// #pragma aux wait_for_key = "mov ah, 0x00" \
// "int 0x16" modify[ah];
static short get_vesa_controller_info(struct VbeInfoBlock *);
#pragma aux get_vesa_controller_info = "mov ax, 0x4f00" \
"int 0x10" parm[es di] value[ax];
// static short get_vesa_controller_info(struct VbeInfoBlock *);
// #pragma aux get_vesa_controller_info = "mov ax, 0x4f00" \
// "int 0x10" parm[es di] value[ax];
static short get_vesa_mode_info(uint16_t mode, struct ModeInfoBlock *);
#pragma aux get_vesa_mode_info = "mov ax, 0x4F01" \
"int 0x10" parm[cx][es di] value[ax];
// static short get_vesa_mode_info(uint16_t mode, struct ModeInfoBlock *);
// #pragma aux get_vesa_mode_info = "mov ax, 0x4F01" \
// "int 0x10" parm[cx][es di] value[ax];
/* https://wiki.osdev.org/User:Omarrx024/VESA_Tutorial*/
static char *find_display_memory(void) {
struct VbeInfoBlock *ctrl = (struct VbeInfoBlock *)0x2000;
struct ModeInfoBlock *inf = (struct ModeInfoBlock *)0x3000;
uint16_t *modes;
int i;
// /* https://wiki.osdev.org/User:Omarrx024/VESA_Tutorial*/
// static char *find_display_memory(void) {
// struct VbeInfoBlock *ctrl = (struct VbeInfoBlock *)0x2000;
// struct ModeInfoBlock *inf = (struct ModeInfoBlock *)0x3000;
// uint16_t *modes;
// int i;
strncpy(ctrl->VbeSignature, "VBE2", 4);
if (get_vesa_controller_info(ctrl) != 0x004F)
return NULL;
// strncpy(ctrl->VbeSignature, "VBE2", 4);
// if (get_vesa_controller_info(ctrl) != 0x004F)
// return NULL;
modes = (uint16_t *)(ctrl->VideoModePtr);
for (i = 0; modes[i] != 0xFFFF; ++i) {
if (get_vesa_mode_info(modes[i], inf) != 0x004F)
continue;
// modes = (uint16_t *)(ctrl->VideoModePtr);
// for (i = 0; modes[i] != 0xFFFF; ++i) {
// if (get_vesa_mode_info(modes[i], inf) != 0x004F)
// continue;
// Check if this is a graphics mode with linear frame buffer support
if ((inf->attributes & 0x80) != 0x80)
continue;
// // Check if this is a graphics mode with linear frame buffer support
// if ((inf->attributes & 0x80) != 0x80)
// continue;
// Check if this is a packed pixel or direct color mode
if (inf->memory_model != 4 && inf->memory_model != 6)
continue;
// // Check if this is a packed pixel or direct color mode
// if (inf->memory_model != 4 && inf->memory_model != 6)
// continue;
// Check if this is exactly the mode we're looking for
if (WIDTH == inf->width && HEIGHT == inf->height && 256 == inf->pitch)
return (char *)inf->framebuffer;
}
// // Check if this is exactly the mode we're looking for
// if (WIDTH == inf->width && HEIGHT == inf->height && 256 == inf->pitch)
// return (char *)inf->framebuffer;
// }
return NULL;
}
// return NULL;
// }
extern int plr_display_dos_main(int argc, char *argv[]) {
char far *buf = (char far *)0xA0000; // VGA memory address
// extern int plr_display_dos_main(int argc, char *argv[]) {
extern int plr_display_dos_main(void) {
char *buf = (char *)0xA0000; // VGA memory address
int x, y;
unsigned char saved_mode = get_video_mode(); // Save original mode
set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode
// unsigned char saved_mode = get_video_mode(); // Save original mode
// set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode
buf = find_display_memory();
// buf = find_display_memory();
/* TODO: Fetch info about the mode, to know the availability */
/* as well as base address in memory */
/* https://wiki.osdev.org/VESA_Video_Modes */
// Now draw. We draw pixel-by-pixel by directly setting the video memory like
// it was an array. We step the color every 25 pixels so that we have 8 bands
// of even height.
for (y = 0; y < HEIGHT; y++) {
for (x = 0; x < WIDTH; x++) {
buf[y * WIDTH + x] = COLOR_OFFSET + y / COLOR_STEP;
// Now draw. We draw pixel-by-pixel by directly setting the video memory
// like it was an array. We step the color every 25 pixels so that we have 8
// bands of even height.
// for (y = 0; y < HEIGHT; y++) {
// for (x = 0; x < WIDTH; x++) {
// buf[y * WIDTH + x] = COLOR_OFFSET + y / COLOR_STEP;
// }
// }
// wait_for_key();
// set_video_mode(saved_mode); // Restore original mode
while (1) {
for (y = 0; y < HEIGHT; y++) {
for (x = 0; x < WIDTH; x++) {
buf[y * WIDTH + x] = COLOR_OFFSET + y / COLOR_STEP;
}
}
}
wait_for_key();
set_video_mode(saved_mode); // Restore original mode
return 0;
}
+47
View File
@@ -0,0 +1,47 @@
.section .data
.align 4
# The DPMI Register Structure (50 bytes total)
# This holds the register states injected into Real Mode.
dpmi_regs:
.long 0 # edi (offset 0)
.long 0 # esi (offset 4)
.long 0 # ebp (offset 8)
.long 0 # esp / reserved (offset 12)
.long 0 # ebx (offset 16)
.long 0 # edx (offset 20)
.long 0 # ecx (offset 24)
dpmi_eax:
.long 0 # eax (offset 28)
.short 0 # flags(offset 32)
.short 0 # es (offset 34)
.short 0 # ds (offset 36)
.short 0 # fs (offset 38)
.short 0 # gs (offset 40)
.short 0 # ip (offset 42)
.short 0 # cs (offset 44)
.short 0 # sp (offset 46)
.short 0 # ss (offset 48)
.section .text
.global _start
_start:
call plr_display_dos_main
# 1. Set up the Real-Mode registers inside the DPMI structure
# AH = 4Ch (DOS Exit Function), AL = 00h (Return Code 0)
movl $0x00004C00, dpmi_eax
# 2. Call DPMI Simulate Real Mode Interrupt
movw $0x0300, %ax # DPMI Function: Simulate Real Mode Interrupt
movb $0x21, %bl # Interrupt number to trigger (INT 21h)
movb $0x00, %bh # Flags (Must be 0)
movw $0x0000, %cx # Number of words to copy to RM stack (0)
# ES:EDI points to our DPMI register block.
# In WDOSX flat model, %es already targets the flat data descriptor.
movl $dpmi_regs, %edi
int $0x31 # Trigger DPMI host to execute the RM interrupt
# --- Execution halts here as DOS terminates the program ---
+14 -5
View File
@@ -3,8 +3,9 @@ RELEASE ?= 0 # Optimize.
DEBUG ?= 1 # Emit debug info.
SQUEEZE ?= 0 # Nuclear option to save space.
BITS ?= 64
CFLAGS = -Wall -std=gnu99 -flto=thin -ffast-math -fno-ident -fvisibility=hidden
CFLAGS = -Wall -std=gnu99 -flto=thin -ffast-math -fno-ident -fvisibility=hidden -fuse-ld=lld
ifeq ($(MAKECMDGOALS),linux)
CFLAGS += -fno-pic -fno-pie
ifeq ($(RELEASE), 1)
CFLAGS += -Wl,--ignore-data-address-equality -Wl,--ignore-function-address-equality \
-Wl,--optimize-bb-jumps
@@ -30,7 +31,7 @@ else
CFLAGS += -DNDEBUG -Wl,--strip-all
endif
ifeq ($(RELEASE), 1)
CFLAGS += -O1 -fuse-ld=lld -fmerge-all-constants -Wl,-O3 \
CFLAGS += -O3 -fmerge-all-constants -Wl,-O3 \
-ffunction-sections -fdata-sections -Wl,--gc-sections \
-Wl,-mllvm,--vectorize-slp=true \
-Wl,-mllvm,--enable-gvn-hoist=true
@@ -49,6 +50,9 @@ DOS = maindos.c Display/dos.c
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
%.o: %.s $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
# TODO: Make it work with no stdlib.
linux: CFLAGS += -static -mbmi2 -nostdlib
linux: $(LINUX) | $(SRC)
@@ -59,9 +63,14 @@ wasm: CFLAGS += --target=wasm32 -nostdlib -Wl,--no-entry -msimd128 -mbulk-memory
wasm:
$(CC) -o player.wasm $(WASM) $(CFLAGS)
# TODO: Use https://github.com/amindlost/pmodew
dos: $(DOS) $(DEPS)
wcl386 -bt=dos4g -ox -l=dos4g $(DOS)
# https://tippach.hier-im-netz.de/wdosx
dos: CFLAGS += -ffreestanding -m32 -fno-PIC -fno-PIE -no-pie -nostdlib -nodefaultlibs
dos:
$(CC) -c ./Main/dos.s -o ./Main/dos.o $(CFLAGS)
$(CC) -c ./Display/dos.c -o ./Display/dos.o $(CFLAGS)
ld.lld -m elf_i386 --oformat binary -Ttext 0x0 --image-base=0x0 ./Main/dos.o ./Display/dos.o -o dos.bin
dosbox -noconsole -c "mount c $(PWD)" -c "c:" -c "WDOSX\STUBIT.EXE DOS.BIN" -exit
mv ./DOS.BIN ./DOS.EXE
clean:
rm -r *.o ../*.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-5
View File
@@ -1,5 +0,0 @@
#include "Display/display.h"
extern int main(int argc, char *argv[]) {
return plr_display_dos_main(argc, argv);
}