    $serial_port_incoming = "";
    $serial_port_next_xmit = 0;
    $serial_port_next_recv = 0;
    $serial_port_xmit_overrun = 0;
    $serial_port_recv_overrun = 0;
    $serial_port_data_taken = 0;
    $serial_port_speed = 1000;	# 1000 clock ticks per byte.  This is a rate of
				# 16k per second, or 64 kilobaud, for a 16 Mhz
				# processor.

    def $serial_port_simulator ()
    {
				# Loop forever, waiting for events
	while (1) {
				# Wait for write or read to relevant registers,
				# or until transmit/receive time is over
	    blockuntil portwrite(0x3f8, 0x3f9), portread(0x3f8, 0x3f9),	
		       breaktime($serial_port_next_xmit),
	               breaktime($serial_port_next_recv);
				# Handle event
	    if (portwrite($port, $value, $size)) {
				# Handle write to transmit port
		if ($size == 2 || $port == 0x3f9) {
		    print "Illegal write to serial port!  ", %w $port;
		    breaknow;
		} else {
		    if ($serial_port_next_xmit) { # Are we transmitting?
			print "Serial port transmit overrun transmitting ", %b $value;
			$serial_port_xmit_overrun = 1;
		    } else {
			print "Serial port writes ", %b $value;
		    }
		    $serial_port_next_xmit = clock + $serial_port_speed;
		}
	    } elsif (portread($port, $size)) {
		if ($size == 2) {
		    print "Illegal to read words from serial port!";
		    breaknow;
		} elsif ($port == 0x3f8) {
				# Handle read from receive port
		    if ($serial_port_data_taken) {
			print "Serial port data read multiple times";
		    }
		    $serial_port_data_taken = 1;
				# Make receieved character available
		    outbyte 0x3f8, $serial_port_incoming[0];
		    print "Serial port data read: ", %b $serial_port_incoming[0];
		} elsif ($port == 0x3f9) {
				# Handle read from status port
		    $status = 0;
		    if (length($serial_port_incoming) > 0 &&
			!$serial_port_data_taken)  { $status = $status | 1; }
		    if ($serial_port_recv_overrun) { $status = $status | 2; }
		    if (!$serial_port_next_xmit)   { $status = $status | 4; }
		    if ($serial_port_xmit_overrun) { $status = $status | 8; }
				# Reading the port clears these bits
		    $serial_port_recv_overrun = 0;
		    $serial_port_xmit_overrun = 0;
		    outbyte 0x3f9, $status;
		}
	    } elsif (breaktime($when)) {
				# Handle timed event
		if ($when >= $serial_port_next_xmit) {
				# Finished sending character
		    $serial_port_next_xmit = 0;
				# Send interrupt to processor
		    interrupt 12;
		}
		if ($when >= $serial_port_next_recv) {
				# Finished receiving a character
		    $serial_port_incoming = substr($serial_port_incoming, 1);
		    if (length($serial_port_incoming) == 0) {
			$serial_port_next_recv = 0;
		    } else {
				# Send interrupt to processor
			$serial_port_kick_recv(0);
		    }
		}
	    }
	}
    }

    def $serial_port_kick_recv($str)
    {
     	if ($str) { $serial_port_incoming = $str; }
	interrupt 12;
	if (!$serial_port_data_taken { $serial_port_recv_overrun = 1; }
	$serial_port_next_recv = clock + $serial_port_speed;
	$serial_port_data_taken = 0;
    }

