delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1994/03/29/10:30:59

Date: Tue, 29 Mar 94 07:54:48 -0700
From: jan kok <kok AT CS DOT ColoState DOT EDU>
To: djgpp AT sun DOT soe DOT clarkson DOT edu
Subject: problem using X00 utility with djgcc

x00 is a utility (get from ftp.clarkson.edu /pub/msdos/fossil) that replaces
the int14 BIOS code (serial port, etc. drivers) with interrupt-mode
drivers. I'm having trouble making it work reliably.  The main problem is that
it stops receiving characters from the serial port after receiving a random,
variable number (a couple dozen) of characters.  After stopping receiving
characters, the keyboard input still works ok.  Reinitializing the serial port
makes it receive some more, but it will stop receiving again.

I think the problem might be due to using djgcc (version 109) and the 32-bit
address environment.  Although I don't need to pass any 32-bit addresses to
x00 to make it fail, I am still pretty suspicious, because some of the x00
commands (such as 0x18 (read block) or 0x1B (get driver info)) require passing
a pointer to a buffer, by putting the pointer into es:di.  I don't see how
this can work, if the address is > 1MB, because es is a 16-bit register.  Is
there a way in the djgcc environment to allocate some memory in the bottom
1MB, in case I want to use one of the commands which needs a pointer?

Could the problem be an incompatibility of x00 with a 32-bit environment, or
am I doing something else wrong?  The odd thing is, that the x00 package
provides an interface to Microsoft C, including the huge model.  I don't know
if that works, though.

The serial card that I'm using has a UM82C862F which is a combination IDE,
floppy, printer, dual serial, and Hollerith card reader interface.  x00
thinks it's a couple of 16450s at the usual COM1 and COM2 addresses and IRQs.
QuickLinkII (communication program) and MS-Kermit have no problem
communicating with it.

What is exception 13 (are where are the exception numbers documented?)

Thanks,
- Jan

--------------------- reg.h -------------------
typedef struct {
  	unsigned ax;
	unsigned bx;
	unsigned cx;
	unsigned dx;
	unsigned si;
	unsigned di;
	unsigned bp;
  	unsigned es;
	} REGISTERS;
----------------------------------------------
/* int14.s */
/* This file creates a function "int14" which can be called from C.  It
   provides an interface to the int 14 BIOS call. */

	.globl _int14
_int14:
	/* Create new stack frame, save caller's registers. */
	pushl %ebp
	movl %esp, %ebp
	pushl %ebx
	pushl %ecx
	pushl %edx
	pushl %esi
	pushl %edi
	pushl %es

	/* Get the arg to int14, which is a ptr to a "REGISTERS" structure. */
	movl 8(%ebp), %eax
	pushl %eax		/* Save it for later... */

	/* Move data from structure into registers. */
	/* ebp and esi are never used as args to int14. */
	/* pushl 28(%eax) */
	push $0
	pop %es		/* gets exception 13 if use pushl 28(%eax) above. */
	movl 20(%eax), %edi
	movl 12(%eax), %edx
	movl 8(%eax), %ecx
	movl 4(%eax), %ebx
	movl (%eax), %eax

	/* Call serial port routine. */
	int $0x14

	/* Move regs to REGISTERS structure. */
	/* Nothing is ever returned in edi, esi or ebp. */
	xchg %eax, (%esp)
	popl (%eax)		/* eax from int14 goes to structure. */
	movl %ebx, 4(%eax)
	movl %ecx, 8(%eax)
	movl %edx, 12(%eax)

	/* Restore caller's registers. */
	/* This function has no return value, so no need to set eax. */
	popl %es
	popl %edi
	popl %esi
	popl %edx
	popl %ecx
	popl %ebx
	leave	
	ret	
----------------- test program -----------------
#include "reg.h"
#include <stdio.h>
#include <std.h>

#define X00OK	0x1954

#define Initialize 0x1c			/* x00 driver takes both 0x4 and 0x1c*/
#define Deinitialize (Initialize+1)

#define FP_OFF(x) (((int)x) & 15)
#define FP_SEG(x) (((int)x) >> 4)

REGISTERS regs;

int port = 1;

#define INFOLEN 20

/* Call the x00 driver with given function code.
/* See the files x00ref.doc and fossil.cht for more info on x00.
/* Note, I wasn't able to get Block Read command to work (bug in int14.s ?),
/* so I used Peek Ahead instead. */
void x00port(code)
{
    regs.ax = code << 8;
    regs.dx = port;
    int14(&regs);
}

/* Initialize serial port. */
void initport()
{
    regs.bx = 0;			/* No ^C processing. */
    x00port(Initialize);
    if (regs.ax != X00OK) {
	printf("Serial port initialization failed.  Please make sure x00 driver is installed.\n");
	exit(1);
    }

    regs.ax = (0 << 8)			/* Set Baud Rate. */
	+ (0 << 5)			/* 19200 baud. */
	+ (8-5);			/* 8 bits. */
    regs.dx = port;
    int14(&regs);

    x00port(0xf);			/* Disable flow control. */

    x00port(0xa);			/* Purge Input Buffer. */
}

main()
{
    int i;
    int key;
    char infobuf[INFOLEN];

    initport();

    regs.bx = 0;			/* No ^C processing. */
    regs.dx = 0xff;			/* Initialize keyboard. */
    regs.ax = Initialize << 8;
    int14(&regs);
    if (regs.ax != X00OK) {
	printf("Keyboard initialization failed.\n");
	exit(1);
    }

    printf("go!\n");

#if 1
    /* This loop implements a terminal emulator (for debugging). */
    while (1) {

	x00port(0x20);		/* Read With No Wait serial port. */
	if (regs.ax != 0xffff) {
	    /* If a char has arrived from serial port, print it. */
	    printf("%c", regs.ax); fflush(stdout);
	}

	x00port(0xd);			/* Peek Ahead keyboard. */
	if (regs.ax != 0xffff) {
	    /* If a key was typed, get it, echo it, and send it to serial port.
	       ^C exits this program. */
	    x00port(0xe);		/* Read Keyboard. */
	    key = regs.ax & 0xff;	/* x00 leaves garbage in upper byte. */
	    if (key == 3)
		/* ^C - exit */
		break;

	    if (key != 13 && (key < 32 || key > 126))
		/* Not a printable character, echo its hex code. */
		printf("<0x%x>", key);
	    else
		printf("%c", key);
	    fflush(stdout); /* Make char echo immediately. */

	    switch (key) {

	      case 'i':
		/* Display x00 info. */
		regs.cx = INFOLEN;
/* ??????????? es is a 16-bit register.  How could this work??????????? */
		regs.es = FP_SEG(infobuf);
		regs.di = FP_OFF(infobuf);
		printf("infobuf=0x%x regs.es=0x%x regs.di=0x%x\n",
		       infobuf, regs.es, regs.di);
		sleep(1);
		x00port(0x1b);			/* Get x00 info. */
		for (i = 0; i < INFOLEN; i++)
		    printf("%x ", 0xff & infobuf[i]);
		printf("\n");
		break;

	      case 'r':
		/* Reinit serial port. */
		initport();
		break;

	      case 's':
		/* Print status. */
		x00port(0x3);
		printf("status = 0x%x\n", regs.ax);
		break;

	      case 't':
		/* Transmit a string. */
		for (i='a'; i <= 'a'; i++) {
		    regs.ax = 0xb << 8	/* Transmit Char, No Wait. */
			+ i;		/* The char to transmit. */
		    regs.dx = port;
		    int14(&regs);
		    if (regs.ax == 0)
			printf("\7Xmit buf full\n");
		}
		break;

	      case 'u':
		system("xu s");
		break;

	      default:
		regs.ax = 0xb << 8	/* Transmit Char, No Wait. */
		    + key;		/* The char to transmit. */
		regs.dx = port;
		int14(&regs);
		if (regs.ax == 0)
		    printf("\7Xmit buf full\n");

	    } /* Switch. */
	} /* If keyboard char. */
    } /* Main while loop. */
#endif

    regs.ax = Deinitialize << 8;
    regs.dx = 0xff;			/* Deactivate keyboard. */
    int14(&regs);

    x00port(Deinitialize);		/* Deactivate Port. */
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019