/************************************************************************\
 * File Version Information
 * $Header: /Altair32v2/ct_rtc.c 2     11/08/06 9:21p Racini $
 ************************************************************************/
/************************************************************************\
  MITS Altair Emulator
  Compu/Time RTC driver

  Copyright (c) 2006 Richard A. Cini

  This module emulates the Compu/Time real-time-clock peripheral board.
  The device is fairly simple: it consists of some address selection
  logic, a time base (MM5369), the RTC chip (MM5375AC) and a 7-segment
  to BCD encoder (the clock chip was designed to directly drive an
  LED display, so a BCD encoder is needed).

  I/O port assignment is on any 4-byte boundry although the board only
  uses port BASE+0. You can read and set the time and date through
  a BASIC or machine language program (year is not tracked). Setting
  the clock and alarm is not supported because we don't want the
  emulator messing with the host machine's clock. Reading the time
  or date is accomplished by writing a command to the port indicating
  which register to read, followed immediately by a read from the same
  port. Data is returned as binary coded decimal, so some conversion
  is necessary on the host side to change it to ASCII for printing
  (add 30h).


Change Log: 
  2006/06/08  RAC -- Began coding.
  2006/11/15  RAC -- RELEASE MARKER -- v3.20.0400
  
\************************************************************************/
#include <windows.h>
#include <stdio.h>		// C-lib
#include "altair32.h"	// includes "resource.h"

	
/**************************************************************\
*   I/O Instruction Handlers  *********************************|
***************************************************************|
*
*	I/O instruction handlers are called from the CPU module
*  	when an IN or OUT instruction is issued.
*
*  	Each function is passed an 'io' flag, where 0 means a read
*  	from the port, and 1 means a write to the port.  On input,
*	the actual input is passed as the return value. On output,
*	'data' is written to the device.
\**************************************************************/

/*--  RTC80h  -------------------------------------------------
	Data register for the Compu/Time RTC device. The sequence
	to access the RTC is to first write a command to the board
	indicating which RTC register you want to read, folloed by
	a read from the same I/O port to retrieve the desired
	data.

	Therefore, for any "transaction" we will pass through this
	routine twice.

-------------------------------------------------------------*/
int rtc80h(int io, int data)
{
	static BOOL bCmdMode;		// have we requested read from RTC?
	static byte ucDigit;		// digit data register
	SYSTEMTIME systime;			// systemtime structure


	if (io == 0) {				// READ
		if (!bCmdMode){			// not in command mode so just exit
			return 0xff;
		}

		bCmdMode = FALSE;			// reset command mode and return data
		return ucDigit;				// to calling program
	}
	else {							// WRITE
		bCmdMode = TRUE;			// set command mode on write
		GetLocalTime(&systime);		// get local time; GetSystemTime uses UTC
		switch (data){				// let's find out what command
			case 0:					// read hour tens .wHour
				// Convert to BCD. Hour (0-23), minute (0-59), seconds (0-59)
				// month (1-12) day (1-31). SYSTIME results need to be converted to
				// decimal before being returned to the program so lets do some
				// simple math.
				ucDigit = systime.wHour / 10;
				break;
			case 1:						// read hour units
				ucDigit = systime.wHour % 10;
				break;
			case 2:						// read minute tens .wMinute
				ucDigit = systime.wMinute / 10;
				break;
			case 3:						// read minute units
				ucDigit = systime.wMinute % 10;
				break;
			case 4:						// read second tens .wSeconds
				ucDigit = systime.wSecond / 10;
				break;
			case 5:						// read second units
				ucDigit = systime.wSecond % 10;
				break;
			case 8:						// read month tens .wMonth
				ucDigit = systime.wMonth / 10;
				break;
			case 9:						// read month units
				ucDigit = systime.wMonth % 10;
				break;
			case 0x0a:					// read day tens .wDay
				ucDigit = systime.wDay / 10;
				break;
			case 0x0b:					// read day units
				ucDigit = systime.wDay % 10;
				break;
			default:
				// bad command, return 0xff
				ucDigit = 0xff;
		} //switch

		return 0xff;
	} //else
}


/*  end of file: ct_rtc.c  */
