2026-03-30 18:12:24 -04:00
|
|
|
/*
|
|
|
|
|
* DOS HAL backend for GW-BASIC 2026.
|
|
|
|
|
*
|
|
|
|
|
* Uses BIOS/DOS interrupts for terminal I/O, keyboard input,
|
2026-03-30 19:42:45 -04:00
|
|
|
* and screen control. Selected at compile time via __MSDOS__.
|
|
|
|
|
* Linux HAL (hal_posix.c) is unchanged -- full backward compatibility.
|
2026-03-30 18:12:24 -04:00
|
|
|
*
|
2026-04-10 06:32:47 -04:00
|
|
|
* Build: wcc386 -bt=dos -mf -ox -za99 -D__MSDOS__ -Iinclude (32-bit)
|
|
|
|
|
* wcc -bt=dos -mm -ox -za99 -D__MSDOS__ -Iinclude (16-bit)
|
2026-03-30 18:12:24 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef __MSDOS__
|
|
|
|
|
|
|
|
|
|
#include "hal.h"
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <conio.h>
|
2026-03-30 19:42:45 -04:00
|
|
|
#include <i86.h>
|
2026-03-30 18:12:24 -04:00
|
|
|
#include <dos.h>
|
|
|
|
|
|
2026-04-10 06:32:47 -04:00
|
|
|
/* int86 (16-bit real mode) vs int386 (32-bit protected mode) */
|
|
|
|
|
#ifdef _M_I86
|
|
|
|
|
#define INTX(n, r_in, r_out) int86(n, r_in, r_out)
|
|
|
|
|
#else
|
|
|
|
|
#define INTX(n, r_in, r_out) int386(n, r_in, r_out)
|
|
|
|
|
#endif
|
|
|
|
|
|
2026-03-30 18:12:24 -04:00
|
|
|
static int cursor_row = 0;
|
|
|
|
|
static int cursor_col = 0;
|
|
|
|
|
static int screen_cols = 80;
|
|
|
|
|
static int screen_rows = 25;
|
|
|
|
|
|
|
|
|
|
/* --- BIOS video services (INT 10h) --- */
|
|
|
|
|
|
|
|
|
|
static void bios_set_cursor(int row, int col)
|
|
|
|
|
{
|
|
|
|
|
union REGS r;
|
2026-03-30 19:42:45 -04:00
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
|
r.h.ah = 0x02;
|
|
|
|
|
r.h.bh = 0;
|
|
|
|
|
r.h.dh = (unsigned char)row;
|
|
|
|
|
r.h.dl = (unsigned char)col;
|
2026-04-10 06:32:47 -04:00
|
|
|
INTX(0x10, &r, &r);
|
2026-03-30 18:12:24 -04:00
|
|
|
cursor_row = row;
|
|
|
|
|
cursor_col = col;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bios_get_cursor(int *row, int *col)
|
|
|
|
|
{
|
|
|
|
|
union REGS r;
|
2026-03-30 19:42:45 -04:00
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
|
r.h.ah = 0x03;
|
2026-03-30 18:12:24 -04:00
|
|
|
r.h.bh = 0;
|
2026-04-10 06:32:47 -04:00
|
|
|
INTX(0x10, &r, &r);
|
2026-03-30 18:12:24 -04:00
|
|
|
*row = r.h.dh;
|
|
|
|
|
*col = r.h.dl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bios_scroll_up(int lines, int attr, int r1, int c1, int r2, int c2)
|
|
|
|
|
{
|
|
|
|
|
union REGS r;
|
2026-03-30 19:42:45 -04:00
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
|
r.h.ah = 0x06;
|
|
|
|
|
r.h.al = (unsigned char)lines;
|
|
|
|
|
r.h.bh = (unsigned char)attr;
|
|
|
|
|
r.h.ch = (unsigned char)r1;
|
|
|
|
|
r.h.cl = (unsigned char)c1;
|
|
|
|
|
r.h.dh = (unsigned char)r2;
|
|
|
|
|
r.h.dl = (unsigned char)c2;
|
2026-04-10 06:32:47 -04:00
|
|
|
INTX(0x10, &r, &r);
|
2026-03-30 18:12:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bios_write_char(int ch, int attr)
|
|
|
|
|
{
|
|
|
|
|
union REGS r;
|
2026-03-30 19:42:45 -04:00
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
|
r.h.ah = 0x09;
|
|
|
|
|
r.h.al = (unsigned char)ch;
|
2026-03-30 18:12:24 -04:00
|
|
|
r.h.bh = 0;
|
2026-03-30 19:42:45 -04:00
|
|
|
r.h.bl = (unsigned char)attr;
|
|
|
|
|
r.w.cx = 1;
|
2026-04-10 06:32:47 -04:00
|
|
|
INTX(0x10, &r, &r);
|
2026-03-30 18:12:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --- Terminal I/O --- */
|
|
|
|
|
|
|
|
|
|
static void dos_putch(int ch)
|
|
|
|
|
{
|
|
|
|
|
if (ch == '\n') {
|
|
|
|
|
cursor_col = 0;
|
|
|
|
|
cursor_row++;
|
|
|
|
|
if (cursor_row >= screen_rows) {
|
|
|
|
|
bios_scroll_up(1, 0x07, 0, 0, screen_rows - 1, screen_cols - 1);
|
|
|
|
|
cursor_row = screen_rows - 1;
|
|
|
|
|
}
|
|
|
|
|
bios_set_cursor(cursor_row, cursor_col);
|
|
|
|
|
} else if (ch == '\r') {
|
|
|
|
|
cursor_col = 0;
|
|
|
|
|
bios_set_cursor(cursor_row, cursor_col);
|
|
|
|
|
} else if (ch == '\b') {
|
|
|
|
|
if (cursor_col > 0) cursor_col--;
|
|
|
|
|
bios_set_cursor(cursor_row, cursor_col);
|
|
|
|
|
} else {
|
|
|
|
|
bios_write_char(ch, 0x07);
|
|
|
|
|
cursor_col++;
|
|
|
|
|
if (cursor_col >= screen_cols) {
|
|
|
|
|
cursor_col = 0;
|
|
|
|
|
cursor_row++;
|
|
|
|
|
if (cursor_row >= screen_rows) {
|
|
|
|
|
bios_scroll_up(1, 0x07, 0, 0, screen_rows - 1, screen_cols - 1);
|
|
|
|
|
cursor_row = screen_rows - 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bios_set_cursor(cursor_row, cursor_col);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dos_puts(const char *s)
|
|
|
|
|
{
|
2026-03-30 19:42:45 -04:00
|
|
|
while (*s) dos_putch(*s++);
|
2026-03-30 18:12:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dos_getch(void)
|
|
|
|
|
{
|
|
|
|
|
union REGS r;
|
2026-03-30 19:42:45 -04:00
|
|
|
memset(&r, 0, sizeof(r));
|
2026-03-30 18:12:24 -04:00
|
|
|
r.h.ah = 0x00;
|
2026-04-10 06:32:47 -04:00
|
|
|
INTX(0x16, &r, &r);
|
2026-03-30 19:42:45 -04:00
|
|
|
return r.h.al ? r.h.al : (0x100 | r.h.ah);
|
2026-03-30 18:12:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool dos_kbhit(void)
|
|
|
|
|
{
|
|
|
|
|
return kbhit() != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dos_locate(int row, int col)
|
|
|
|
|
{
|
|
|
|
|
bios_set_cursor(row, col);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dos_get_cursor_row(void) { return cursor_row; }
|
|
|
|
|
static int dos_get_cursor_col(void) { return cursor_col; }
|
|
|
|
|
|
|
|
|
|
static void dos_cls(void)
|
|
|
|
|
{
|
|
|
|
|
bios_scroll_up(0, 0x07, 0, 0, screen_rows - 1, screen_cols - 1);
|
|
|
|
|
bios_set_cursor(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 19:42:45 -04:00
|
|
|
static void dos_set_width(int cols) { (void)cols; }
|
2026-03-30 18:12:24 -04:00
|
|
|
static void dos_enable_raw(void) { }
|
|
|
|
|
static void dos_disable_raw(void) { }
|
|
|
|
|
|
|
|
|
|
static void dos_write_raw(const char *data, int len)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
dos_putch(data[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dos_init(void)
|
|
|
|
|
{
|
|
|
|
|
union REGS r;
|
2026-03-30 19:42:45 -04:00
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
|
r.h.ah = 0x0F;
|
2026-04-10 06:32:47 -04:00
|
|
|
INTX(0x10, &r, &r);
|
2026-03-30 18:12:24 -04:00
|
|
|
screen_cols = r.h.ah;
|
2026-03-30 19:42:45 -04:00
|
|
|
screen_rows = 25; /* safe default; BIOS data area read needs far ptr */
|
2026-03-30 18:12:24 -04:00
|
|
|
bios_get_cursor(&cursor_row, &cursor_col);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 19:42:45 -04:00
|
|
|
static void dos_shutdown(void) { }
|
2026-03-30 18:12:24 -04:00
|
|
|
|
|
|
|
|
static hal_ops_t dos_hal = {
|
2026-03-30 19:42:45 -04:00
|
|
|
dos_putch, dos_puts, dos_getch, dos_kbhit,
|
|
|
|
|
dos_locate, dos_get_cursor_row, dos_get_cursor_col,
|
|
|
|
|
dos_cls, dos_set_width, dos_enable_raw, dos_disable_raw,
|
|
|
|
|
dos_write_raw, 80, 25, 1 /* is_tty */,
|
|
|
|
|
dos_init, dos_shutdown
|
2026-03-30 18:12:24 -04:00
|
|
|
};
|
|
|
|
|
|
2026-03-30 19:42:45 -04:00
|
|
|
hal_ops_t *hal_dos_create(void) { return &dos_hal; }
|
2026-03-30 18:12:24 -04:00
|
|
|
|
|
|
|
|
#endif /* __MSDOS__ */
|