Use far heap for TUI screen buffer on 16-bit DOS

The 4KB screen buffer (80x25x2 bytes) was allocated from near heap via
calloc(), which exhausted the 64KB data segment on 16-bit DOS. Now uses
_fcalloc()/_ffree() from OpenWatcom's far heap on 16-bit, keeping the
buffer outside DGROUP.

The TUI now works fully on 16-bit FreeDOS: full-screen editor, F-key
bar, cursor positioning, and scroll -- all via BIOS INT 10h through the
DOS HAL, with the screen buffer in far memory.

Changes:
- tui.h: GW_FAR macro (expands to __far on 16-bit, nothing elsewhere),
  tui.screen declared as tui_cell_t GW_FAR *
- tui.c: _fcalloc/_ffree for 16-bit, _fmemmove for scroll_up()
- TUI_CELL() macro works unchanged (far pointer dereference is
  transparent)
This commit is contained in:
Eremey Valetov
2026-04-10 14:37:10 -04:00
parent 817c26f55f
commit 54e5ecd6ec
2 changed files with 26 additions and 3 deletions
+9 -1
View File
@@ -4,6 +4,14 @@
#include <stdint.h>
#include <stdbool.h>
/* On 16-bit DOS, the screen buffer lives in far heap to save near heap.
* GW_FAR expands to __far on 16-bit OpenWatcom, nothing elsewhere. */
#if defined(_M_I86)
#define GW_FAR __far
#else
#define GW_FAR
#endif
#define TUI_DEFAULT_ROWS 25
#define TUI_DEFAULT_COLS 80
#define TUI_MAX_ROWS 200
@@ -50,7 +58,7 @@ typedef struct {
/* TUI state */
typedef struct {
tui_cell_t *screen; /* dynamically allocated [rows * cols] */
tui_cell_t GW_FAR *screen; /* dynamically allocated [rows * cols] */
int rows; /* screen height (default 25) */
int cols; /* screen width (default 80) */
int cursor_row;
+17 -2
View File
@@ -9,6 +9,9 @@
#include <unistd.h>
#include <sys/ioctl.h>
#endif
#ifdef _M_I86
#include <malloc.h> /* _fcalloc, _ffree */
#endif
tui_state_t tui;
@@ -37,8 +40,13 @@ static const char *default_fkeys[10] = {
static void scroll_up(void)
{
int bottom = tui.view_bottom;
#ifdef _M_I86
_fmemmove(&TUI_CELL(0, 0), &TUI_CELL(1, 0),
bottom * tui.cols * sizeof(tui_cell_t));
#else
memmove(&TUI_CELL(0, 0), &TUI_CELL(1, 0),
bottom * tui.cols * sizeof(tui_cell_t));
#endif
for (int c = 0; c < tui.cols; c++) {
TUI_CELL(bottom, c).ch = ' ';
TUI_CELL(bottom, c).attr = tui.current_attr;
@@ -666,10 +674,13 @@ void tui_init(bool fullscreen)
tui.view_bottom = tui.rows - 1;
/* Allocate screen buffer */
/* On 16-bit DOS, use far heap to avoid exhausting the 64KB data segment */
#ifdef _M_I86
tui.screen = _fcalloc(tui.rows * tui.cols, sizeof(tui_cell_t));
#else
tui.screen = calloc(tui.rows * tui.cols, sizeof(tui_cell_t));
#endif
if (!tui.screen) {
/* Not enough near heap (common on 16-bit DOS).
* Disable TUI — batch mode still works via HAL. */
tui.active = false;
return;
}
@@ -732,7 +743,11 @@ void tui_shutdown(void)
printf("\033[0 q");
fflush(stdout);
#ifdef _M_I86
_ffree(tui.screen);
#else
free(tui.screen);
#endif
tui.screen = NULL;
signal(SIGINT, SIG_DFL);