*BSD News Article 20997


Return to BSD News archive

Newsgroups: comp.os.386bsd.development
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!elroy.jpl.nasa.gov!decwrl!netcomsv!netcom.com!jmonroy
From: jmonroy@netcom.com (Jesus Monroy Jr)
Subject: Code for: Test of the Intel 8254 shut-down/parity-check command
Message-ID: <jmonroyCDDv6z.ErA@netcom.com>
Organization: NETCOM On-line Communication Services (408 241-9760 guest)
Date: Wed, 15 Sep 1993 06:54:35 GMT
Lines: 613

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	i8254/i82.c
#	i8254/i82.doc
#	i8254/isa.h
#	i8254/isa_bus.s
#	i8254/notes
#	i8254/osdepend.h
#	i8254/timer.h
#
echo x - i8254/i82.c
sed 's/^X//' >i8254/i82.c << 'END-of-i8254/i82.c'
X/*
X        Test of the Intel 8254 shut-down/parity-check command
X
X*/
X
X/* Internal Documentation */
X#define TEST_TYPE       "shut-down/parity-check"
X#define PROGRAM_VERSION "version 1.0.0"
X
X/* identify OS and compiler maker */
X#define     COMPILER        __ZTC__
X
X/* standard headers               */
X#include <stdio.h>              /* Standard Input/Ouput */
X#include <stdlib.h>             /* Standard Library */
X#include <stddef.h>             /* Standard Definitions for ANSI C */
X
X/* alias for readablity            */
X#define  u_char             unsigned char   /* alias */
X#define  u_short            u_char          /* another alias */
X
X/* stuff to fiddle with            */
X#define  SHORT_COUNT        10  /* count-down time for timer */
X#define  DEBUG              0   /* Debugging aids ON=1/OFF=0 */
X#define  SHOW_IT(x)         printf(#x" %02x\n",x)
X
X/* local headers (same directory) */
X#include    "osdepend.h"        /* OS Dependent routines and variables */
X#include    "timer.h"           /* Constants for Intel 8254 timer */
X
X/* //////////////////////////////////////////////////
X
X        Program constants
X
X*/
X#define START_INTERNAL  "INTERNAL NOTES: "
X#define END_INTERNAL    "END INTERNAL NOTES!!!"
X#define AUTHOR          "jmonroy@netcom.com"
X#define MAINTAINER      AUTHOR
X#define FILENAME        "Filename:"
X#define CHIP_IN_TEST    "Intel 8254"
X#define COMPILE_TimeDate "compile time & date:"
X
X/* Internal documentation to executable */
Xstatic u_char  *compile_info[8] = { (u_char *) START_INTERNAL,
X                            (u_char *) AUTHOR"; ",
X                            (u_char *) FILENAME" "__FILE__,
X                            (u_char *) CHIP_IN_TEST"; ",
X                            (u_char *) TEST_TYPE" "PROGRAM_VERSION"; ",
X                            (u_char *) COMPILE_TimeDate" " __TIME__" ",
X                            (u_char *) __DATE__ ,   /* stamps todays date */
X                            (u_char *) END_INTERNAL
X                           };
X
X/* //////////////////////////////////////////////////
X
X        M  A  I  N
X
X*/
Xmain (int argc,char **argv)
X{
X    u_char  scratch,temp;
X    int     offset;
X
X
X    printf(" Test of the "CHIP_IN_TEST" "TEST_TYPE" for the "OS_STRG"\n");
X    printf("    Report errors to "MAINTAINER"\n");
X
X    /* Don't shut down the time of day so parity will error */
X    for (offset = TIMER1_COUNTER1; offset < TIMER1_COUNTER2 + 1; offset++) {
X
X                    /* Set control mode to software retriggerable */
X                    /* Set read/write to LSB then MSB */
X                    /* and Identify counter */
X        scratch =   CNTLR_MODE4 |  CNTRL_RW_LSB_MSB | (CNTRL_WRD_COUNTER0 << offset);
X
X        #if DEBUG
X            SHOW_IT(scratch);
X        #endif
X
X        /* issue command */
X        outb(TIMER1_BASE_ADDR + TIMER1_CNTRL_WORD, scratch);
X
X        /* write LSB */
X        outb(TIMER1_BASE_ADDR + offset, SHORT_COUNT);
X
X        /* write MSB */
X        outb(TIMER1_BASE_ADDR + offset, SHORT_COUNT);
X
X    }
X
X    printf(" ************ ENDS RESET ************\n");
X    printf(" READ-BACK COMMAND REPORTS\n");
X
X    for (offset = TIMER1_COUNTER0; offset < TIMER1_COUNTER2 + 1; offset++) {
X
X        /* identify readback command parameters */
X        scratch = CMD_READBACK | (CMD_COUNTER0 << offset);
X
X        #if DEBUG
X            SHOW_IT(scratch);
X        #endif
X
X        /* issue command */
X        outb(TIMER1_BASE_ADDR + TIMER1_CNTRL_WORD, scratch);
X
X        /* get back status */
X        scratch = inb(TIMER1_BASE_ADDR + offset);
X
X        /* report results */
X        printf("\n    Timer channel %i reports %2x\n", offset, scratch);
X
X
X        /* report OUT pin and Null count */
X        if (scratch & STAT_OUTPUT_HI)
X            printf("        The OUT pin is high.\n");
X        if (scratch & STAT_NULL_COUNT)
X            printf("        Null count is returned.\n");
X
X
X		/* should return a value 1..6 */
X        temp = ((scratch & CNTRL_MODE_MASK) >> 1);
X        printf("        Control mode is %4x; ", temp);
X
X
X		/* report if counting in BSD or binary mode */
X		temp = (scratch & CNTRL_NUM_MASK);
X        printf("counting in %s.\n", (temp) ? "bcd":"binary");
X
X        /* read/write is lsb, msb or "lsb then msb" */
X        printf("        Read/Write format is ");
X        switch (scratch & CNTRL_RW_MASK) {
X            case CNTRL_RW_LSB_MSB:
X                    printf("LSB_MSB");
X                    scratch = inb(TIMER1_BASE_ADDR + offset);
X                    temp    = inb(TIMER1_BASE_ADDR + offset);
X                    printf(" %#02x%02x", scratch, temp);
X                    break;
X            case CNTRL_RW_MSB:
X                    printf("MSB");
X                    scratch = inb(TIMER1_BASE_ADDR + offset);
X                    printf(" %#02x", scratch);
X                    break;
X            case CNTRL_RW_LSB:
X                    printf("LSB") ;
X                    scratch = inb(TIMER1_BASE_ADDR + offset);
X                    printf(" %#02x", scratch);
X                    break;
X        }
X        printf("\n");
X
X    }
X    printf(" ************ ENDS REPORTS ************\n");
X
X}
X
X
END-of-i8254/i82.c
echo x - i8254/i82.doc
sed 's/^X//' >i8254/i82.doc << 'END-of-i8254/i82.doc'
X
X
X        Test of the Intel 8254 shut-down/parity-check command
X        -----------------------------------------------------
X
Xversion: 1.0.0
Xdate: 09-14-1993
Xauthor: jmonroy@netcom.com
X
X        Purpose:  Test the for parity errors by shutting down
X                  the RAM refresh timer.
X
X                  While looking for the reason for DMA overruns
X                  in the development of an FDC driver for
X                  386bsd, suggestions were made that shutting
X                  down the timer has no effect on the system;
X                  reasons for this varied.
X
X        Compiling: I have made the code transportable.
X                   It has been tested with:
X
X                   MSDOS
X                   -----
X                   Zortech Personal C   v. 1.07
X                   Turbo C              v. 2.01
X                   Microsoft Quick C    v. 2.50
X
X                   386BSD
X                   ------
X                   GNU C++              v. 1.39
X
X
X
X        How this works.
X        ---------------
X                Simply the program issue a command to change
X        to mode 4 (described in the notes) with a "count-down"
X        value of 0x0a0a (2,570).  This is done to timers 1 and 2,
X        the RAM refresh timer and the speaker timer, respectively.
X        Timer 0 is left running because most OSes cannot operate
X        without a timer for the "deadloop".
X
X
X        What should happen.
X        -------------------
X                On most 286 systems nothing will happen till a
X        interrupt is generated (I.E., keyboard pressed) or a RAM
X        chip finally loses it's charge.  At this point, some system
X        will hang for a long while, some will immediately parity
X        error.
X                On 386bsd expect a "csh" coredump followed by a
X        system panic.  The system will then reboot.  On some systems
X        a parity error will never register.
X
X
X        What does this prove?
X        ---------------------
X                Namely that the RAM refresh is controllable via
X        the i8254 timer on the IBM/ISA architecture.
X
X
X        WARNING        WARNING        WARNING        WARNING
X        WARNING        WARNING        WARNING        WARNING
X        WARNING        WARNING        WARNING        WARNING
X        -------        -------        -------        -------
X
X                To get your system back in working order you will
X        have to do a "cold boot".  This means the RAM has to be
X        recounted.   The equivalent is hit the red button on the
X        front of the computer _or_ if you don't have one -- turn
X        your machine off, then on (don't forget to count to 10).
X
X                Also if you have a slightly flakey RAM chip this
X        may be just the thing to make it fail completely.  You
X        have been warned.
X
X
X        About 386BSD
X        ------------
X                For the 386bsd version it was necessary to add the
X        inb() and outb() code.  Even though this is in the "locore"
X        section of the kernel, I do not know the exact method of adding
X        it to this code.
X
X                Compile as:
X
X                cc -c isa_bus.s
X                cc i82.c isa_bus.o
X
X
X        Files included
X        --------------
X        i82.c           Source code for the main program.
X        i82.doc         This file.
X        isa.h           Included for convience.
X        timer.h         Code related directly to the Intel 8254 timer.
X        osdepend.h      Operating System Dependent stuff.
X        isa_bus.s       GAS (Gnu ASsemble) code for inb() and outb().
X                        This file is only for 386bsd.
X        notes           My notes for the Intel 8254 from various
X                        sources.
X
X
X        ERRORS, PROBLEMS or QUESTIONS
X        -----------------------------
X
X                To reach me send e-mail to jmonroy@netcom.com
X
END-of-i8254/i82.doc
echo x - i8254/isa.h
sed 's/^X//' >i8254/isa.h << 'END-of-i8254/isa.h'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * William Jolitz.
X *
X *	@(#)isa.h	5.7 (Berkeley) 5/9/91
X */
X
X/*
X * ISA Bus conventions
X */
X
X#ifndef LOCORE
Xunsigned char inb(), rtcin();
Xvoid outb();
Xextern unsigned int atdevbase;	/* offset in virtual memory of ISA io mem */
Xvoid sysbeep(int,int);
Xunsigned kbd_8042cmd(int);
X#endif
X
X
X/*
X * Input / Output Port Assignments
X */
X
X#ifndef IO_BEGIN
X#define	IO_ISABEGIN	0x000		/* 0x000 - Beginning of I/O Registers */
X
X		/* CPU Board */
X#define IO_DMA1		0x000		/* 8237A DMA Controller #1 */
X#define IO_ICU1		0x020		/* 8259A Interrupt Controller #1 */
X#define IO_TIMER1	0x040		/* 8252 Timer #1 */
X#define IO_TIMER2	0x048		/* 8252 Timer #2 */
X#define IO_KBD		0x060		/* 8042 Keyboard */
X#define IO_RTC		0x070		/* RTC */
X#define IO_NMI		IO_RTC		/* NMI Control */
X#define IO_DMAPG	0x080		/* DMA Page Registers */
X#define IO_ICU2		0x0A0		/* 8259A Interrupt Controller #2 */
X#define IO_DMA2		0x0C0		/* 8237A DMA Controller #2 */
X#define IO_NPX		0x0F0		/* Numeric Coprocessor */
X
X		/* Cards */
X					/* 0x100 - 0x16F Open */
X
X#define IO_WD2		0x170		/* Secondary Fixed Disk Controller */
X
X					/* 0x178 - 0x1EF Open */
X
X#define IO_WD1		0x1f0		/* Primary Fixed Disk Controller */
X#define IO_GAME		0x200		/* Game Controller */
X
X					/* 0x208 - 0x277 Open */
X
X#define IO_LPT2		0x278		/* Parallel Port #2 */
X
X					/* 0x280 - 0x2F7 Open */
X
X#define IO_COM2		0x2f8		/* COM2 i/o address */
X
X					/* 0x300 - 0x36F Open */
X
X#define IO_FD2		0x370		/* secondary base i/o address */
X#define IO_LPT1		0x378		/* Parallel Port #1 */
X
X					/* 0x380 - 0x3AF Open */
X
X#define IO_MDA		0x3B0		/* Monochome Adapter */
X#define IO_LPT3		0x3BC		/* Monochome Adapter Printer Port */
X#define IO_VGA		0x3C0		/* E/VGA Ports */
X#define IO_CGA		0x3D0		/* CGA Ports */
X
X					/* 0x3E0 - 0x3EF Open */
X
X#define IO_FD1		0x3f0		/* primary base i/o address */
X#define IO_COM1		0x3f8		/* COM1 i/o address */
X
X#define	IO_ISAEND	0x3FF		/* - 0x3FF End of I/O Registers */
X#endif	IO_ISABEGIN
X
X/*
X * Input / Output Memory Physical Addresses
X */
X
X#ifndef	IOM_BEGIN
X#define	IOM_BEGIN	0x0a0000		/* Start of I/O Memory "hole" */
X#define	IOM_END		0x100000		/* End of I/O Memory "hole" */
X#define	IOM_SIZE	(IOM_END - IOM_BEGIN)
X#endif	IOM_BEGIN
X
X/*
X * RAM Physical Address Space (ignoring the above mentioned "hole")
X */
X
X#ifndef	RAM_BEGIN
X#define	RAM_BEGIN	0x0000000	/* Start of RAM Memory */
X#define	RAM_END		0x1000000	/* End of RAM Memory */
X#define	RAM_SIZE	(RAM_END - RAM_BEGIN)
X#endif	RAM_BEGIN
X
X/*
X * Oddball Physical Memory Addresses
X */
X#ifndef	COMPAQ_RAMRELOC
X#define	COMPAQ_RAMRELOC	0x80c00000	/* Compaq RAM relocation/diag */
X#define	COMPAQ_RAMSETUP	0x80c00002	/* Compaq RAM setup */
X#define	WEITEK_FPU	0xC0000000	/* WTL 2167 */
X#define	CYRIX_EMC	0xC0000000	/* Cyrix EMC */
X#endif	COMPAQ_RAMRELOC
END-of-i8254/isa.h
echo x - i8254/isa_bus.s
sed 's/^X//' >i8254/isa_bus.s << 'END-of-i8254/isa_bus.s'
X    /*
X	 * I/O bus instructions via C
X	 */
X	.globl	_inb
X_inb:	movl	4(%esp),%edx
X	subl	%eax,%eax	# clr eax
X	NOP
X	inb	%dx,%al
X	ret
X
X
X	.globl	_inw
X_inw:	movl	4(%esp),%edx
X	subl	%eax,%eax	# clr eax
X	NOP
X	inw	%dx,%ax
X	ret
X
X
X	.globl	_rtcin
X_rtcin:	movl	4(%esp),%eax
X	outb	%al,$0x70
X	subl	%eax,%eax	# clr eax
X	inb	$0x71,%al	# Compaq SystemPro 
X	ret
X
X	.globl	_outb
X_outb:	movl	4(%esp),%edx
X	NOP
X	movl	8(%esp),%eax
X	outb	%al,%dx
X	NOP
X	ret
X
X	.globl	_outw
X_outw:	movl	4(%esp),%edx
X	NOP
X	movl	8(%esp),%eax
X	outw	%ax,%dx
X	NOP
X	ret
X
END-of-i8254/isa_bus.s
echo x - i8254/notes
sed 's/^X//' >i8254/notes << 'END-of-i8254/notes'
X
XNotes to the i8254 timer chip.
X
X	From: IBM Personal Computer Troubleshooting & Repair
X              for the IBM PC, PC/XT, and PC AT; by Robert C. Brenner
X              Pub. Howard W. Sams & Company
X
X              pg. 106
X                timer 0 (zero) produces the time-of-day irq at 18.2 times/sec.
X                timer 1 produces the RAM refresh at 66,287 times/sec.
X                timer 2 is varied for the speaker driver.
X
X              pg. 122
X                Out1 occurs every 15usec (microseconds).
X                Note: Out1 is directly tied to timer 1.
X
X    From: 1988 Intel Microprocessor and Peripherial Handbook, vol.2
X
X              pg. 2-34
X                Mode 2: Rate Generator (condensed)
X                The mode functions like a divide-by-N counter.
X                OUT will initially be high.  When the initial count
X                has decremented to 1, OUT goes low for one CLK pulse.
X                OUT goes high again, the Counter reloads the initial
X                count and the process is repeated.  Mode 2 is
X                periodic; the same sequence is repeated indefinitely.
X
X                (Read book/section for programming specifics.)
X                Note: A count (N) of 1 is illegal.
X
X              pg. 2-39
X                Mode 4:  Software Triggered Strobe (condensed)
X                OUT will be initially high.  When the initial count
X                expires, OUT will go low for one CLK pulse and then go
X                high again.  The counting sequence is "triggered" by
X                writting the initial count.
X
X                OUT will not go low again until a new count is loaded;
X                this then is the software "trigger", allowing OUT to
X                go low when the count terminates again.
X
X                (Read book/section for programming specifics.)
X                Note: OUT does not strobe low until N+1 CLK pulses
X                      after the initial count is written.
X
X
END-of-i8254/notes
echo x - i8254/osdepend.h
sed 's/^X//' >i8254/osdepend.h << 'END-of-i8254/osdepend.h'
X/*
X
X        functions as dependent on OS and Compiler
X*/
X#if (MSDOS)
X
X    #define  OS_STRG            "MSDOS"
X    #define TIMER1_BASE_ADDR    0x40    /* IO_TIMER1 for 386bsd*/
X
X    #if (COMPILER == __ZTC__)  /* Zortech Personal C */
X
X        #include <dos.h>
X        #define  outb(addr,var)     outp(addr,var)
X        #define  inb(addr)          inp(addr)
X
X    #elif (COMPILER == __TC__)  /* Borland Turbo C */
X
X        #include <dos.h>
X        #define  outb(addr,var)     outportb(addr,var)
X        #define  inb(addr)          inportb(addr)
X
X    #elif (COMPILER == __MSC__)  /* Microsoft Quick C */
X
X        #include <conio.h>
X        #define  outb(addr,var)     outp(addr,var)
X        #define  inb(addr)          inp(addr)
X    #endif
X
X#else /* assume 386BSD and GNU C++ */
X    #include "isa.h"
X    #define  OS_STRG            "386BSD"
X    #define  TIMER1_BASE_ADDR   IO_TIMER1
X#endif
X
X
END-of-i8254/osdepend.h
echo x - i8254/timer.h
sed 's/^X//' >i8254/timer.h << 'END-of-i8254/timer.h'
X/* /////////////////////////////////////////////
X
X        Some defines for the Intel 8254 PIT (Programable Interrupt Timer)
X
X*/
X/* /////////////////////////////////////////////
X
X        I/O Address and offsets to registers.
X
X*/
X#define TIMER1_COUNTER0         0       /* Offset to counter 0 */
X#define TIMER1_COUNTER1         1       /* Offset to counter 1 */
X#define TIMER1_COUNTER2         2       /* Offset to counter 2 */
X#define TIMER1_CNTRL_WORD       3       /* Offset to Control Register */
X
X/* /////////////////////////////////////////////
X
X	Control Word Format
X
X    See data guides for how the modes work.
X    Note: Except for the READBACK command,
X          only one counter can be programed
X          at a time.
X*/
X
X#define CNTRL_WRD_READBACK      0xC0    /* 1100 0000 */
X#define CNTRL_WRD_COUNTER2      0x80    /* control applies to this register, if high */
X#define CNTRL_WRD_COUNTER1      0x40    /* control applies to this register, if high */
X#define CNTRL_WRD_COUNTER0      0x20    /* control applies to this register, if high */
X#define CNTRL_COUNTER_LATCH     0X00    /* bits 5 & 4 must be zero */
X#define CNTRL_RW_LSB_MSB        0x30    /* read/write to counter register is LSB then MSB */
X#define CNTRL_RW_MSB            0x20    /* read/write to counter register is MSB */
X#define CNTRL_RW_LSB            0x10    /* read/write to counter register is LSB */
X#define CNTLR_MODE5             0x0A    /* 1 << 5 */
X#define CNTLR_MODE4             0x08    /* 1 << 4 */
X#define CNTLR_MODE3             0x06    /* 1 << 3 */
X#define CNTLR_MODE2             0x04    /* 1 << 2 */
X#define CNTLR_MODE1             0x02    /* 1 << 1 */
X#define CNTLR_MODE0             0x00    /* 1 << 0; bit 1 must be low */
X#define CNTRL_DO_BCD            0x01    /* count as Binary Coded Decimal */
X#define CNTRL_DO_BIN            0x00    /* bit 0 must be low for Binary counting */
X
X/* Alias Logic Masks for readablity */
X#define CNTRL_RW_MASK           CNTRL_RW_LSB_MSB
X#define CNTRL_MODE_MASK         0x0E    /* Look at high 3 bits in nibble */
X#define CNTRL_NUM_MASK          CNTRL_DO_BCD
X
X
X/*  /////////////////////////////////////////////
X
X        Command Format
X
X   Issuing the correct bits will return the program
X   mode and "latched" count of the counter, in the
X   respective counter register.
X
X*/
X#define CMD_READBACK            CNTRL_WRD_READBACK /* without this - the command does not happen */
X#define CMD_NO_LATCH_COUNT      0x20    /* don't latch the current timer value */
X#define CMD_NO_LATCH_STAT       0x10    /* don't latch the current status value */
X#define CMD_COUNTER2            0x08    /* this command applies to this register, if bit high */
X#define CMD_COUNTER1            0x04    /* same as above */
X#define CMD_COUNTER0            0x02    /* same as above */
X#define CMD_RESERVE             0x01    /* don't use this bit */
X
X/*
X
X        Status  Register Format
X
X   After issuing a ""readback"" command the status
X   information comes back in the format below.
X   The lower 6 bits follow the Control Word Format.
X
X*/
X#define STAT_OUTPUT_HI          0x80    /* The OUT pin is High */
X#define STAT_NULL_COUNT         0x40    /* currently a null count hit on the counter */
X
END-of-i8254/timer.h
exit