J151 SC88PIO
TITLE 'SC88PIO EXAMPLE PROGRAM' ; ; This is an example program for the SC88PIO board. ; ; A real time clock is set up and the time ; is sent to a terminal continuously. ; Users are free to copy and adapt this code for programs ; that run on the SC88PIO. Most applications will not need all the code here. ; ; The code performs the following operations: ; ; Initialises the SCC and includes input and output routines ; ; Initialises timer 2 of the 80188 as a interrupt source and ; sets up its interrupt vector. ; ; The interrupt handler increments a real time clock. ; ; Sets up the chip select for this EPROM for an 8K, 16K or 32K EPROM ; ; This program was assembled using Digital Research's ; ASM86 as supplied with Concurrent DOS. ; ; This assembler is an 8086 assembler and so does not include the ; extra instructions available on the 80188 so the following ; library (also supplied with Concurrent) must be included: INCLUDE 186.LIB ; *********************************************** ; * Definitions ; *********************************************** ; Set baud rate. The allowed values are ; 1 = 50 baud ; 2 = 75 baud ; 3 = 110 baud ; 4 = 134.5 baud ; 5 = 150 baud ; 6 = 300 baud ; 7 = 600 baud ; 8 = 1200 baud ; 9 = 1800 baud ; 10 = 2400 baud ; 11 = 3600 baud ; 12 = 4800 baud ; 13 = 7200 baud ; 14 = 9600 baud ; BDEF EQU 14 ; Console baud rate BDEF EQU 8 ; Printer baud rate ; Set to real-time clock ticks in ms TICK EQU 20 ; 50 Hz WAITI EQU 2 ; 8 MHz 2 wait states for peripherals WAITE EQU 2 ; 8 MHz 2 wait states for EPROM WAITR EQU 0 ; 8 MHz 0 wait states for RAM ; INTREG EQU 0FF00H ; internal register address (I/O) EOIREG EQU INTREG+022H ; end-of-interrupt register timer TINTCR EQU INTREG+032H ; interrupt control register TCNT2 EQU INTREG+060H ; timer 2 count register TMAXA2 EQU INTREG+062H ; maximum count A register TMCW2 EQU INTREG+066H ; mode-control word UMCS EQU INTREG+0A0H ; upper memory chip select register LMCS EQU INTREG+0A2H ; lower memory chip select register MPCS EQU INTREG+0A8H ; peripheral chip select register RELREG EQU INTREG+0A4H ; relocation register ; PBA EQU 0F800H ; peripheral base address (I/O) SCC EQU PBA+0H ; SCC SCCBD EQU SCC ; SCC channel B control register SCCAC EQU SCC+1 ; SCC channel A control register SCCBD EQU SCC+2 ; SCC channel B data register SCCAC EQU SCC+3 ; SCC channel A data register LF EQU 10 CR EQU 13 ; *********************************************** ; Storage declarations ; *********************************************** ; Define stack segment and stack usage SSEG 0030H ; initialisation stack top is 03FFH ORG 0100H STACK EQU $ ; Define data segment and usage DSEG 0040H ; data area is 400H upwards DATA EQU $ ; A real-time clock is set up on initialisation TIMEF RB 1 ; time fraction in 20ms (binary) TIMES RB 1 ; time seconds (BCD) TIMEM RB 1 ; time minutes (BCD) TIMEH RB 1 ; time hours (BCD) ; ; *********************************************** ; Start of Code ; ; Serial port drivers ; ; *********************************************** ; Users code will probably fit into the top 2K of the EPROM. ; In this case use CSEG OFF80H and change the ORG statement ; for the top 16 bytes of the EPROM ; CSEG 0FE00H ; 8K PROGRAM ORG 0 ; SCC initialisation data table ; ; All data consists of two bytes - the SCC register number ; followed by the value to be written ; SCCTA DB 009H, 080H ; reset channel A DB 004H, 04CH ; clock x16, 2 stop bits DB 001H, 000H ; disable external status interrupts DB 003H, 0C0H ; Rx 8 bits DB 005H, 062H ; Tx 8 bits, RTS DB 009H, 000H ; clear reset DB 00АH, 000H DB 00BH, 056H ; clocks use baud rate generator SCCLA1 EQU OFFSET - OFFSET SCCTA DB 00EH, 002H ; BRG source DB 00EH, 003H ; BRG enable DB 003H, 0C1H ; Rx enable DB 005H, 0EAH ; Tx enable, DTR, RTS DB 00FH, 000H ; disable external status interrupts DB 000H, 010H ; Reset external status interrupts DB 000H, 010H ; twice! SCCLA2 EQU OFFSET - OFFSET SCCTA - OFFSET SCCLA1 SCCTB DB 009H, 040H ; reset channel B DB 004H, 04CH ; clock x16, 2 stop bits DB 003H, ; Rx 8 bits, auto enables DB 005H, 062H ; Tx 8 bits, RTS DB 009H, 000H ; clear reset DB 00AH, 000H DB 00BH, 056H ; clocks use baud rate generator SCCLB1 EQU OFFSET - OFFSET SCCTB DB 00ЕH, 002H ; BRG source DB 00EH, 003H ; BRG enable DB 003H, 0C14 ; Rx enable DB 005H, 0EAH ; Tx enable, DTR, RTS DB 00FH, 000H ; Disable external status interrupts DB 000H, 010H ; Reset external status interrupts DB 000H, 010H ; Twice! SCCLB2 EQU OFFSET $ - OFFSET SCCTB - OFFSET SCCLB1 ; SCC baud rate divisors for x16 clock, PCLK = 4 MHz DIVIS DW 12500, 2500, 1665, 1134, 924, 831, 415, 206 DW 102, 67, 50, 33, 24, 15, 11, 5 ; ; I/O routines ; ; Initialise channel A ; CONINT: PUSHA ; save registers MOV DX, SCCAC MOV BX, BDEF*2 MOV SI, OFFSET SCCTA PUSH DS PUSHW SCCLA2 ; Length of second part of table MOV CX, SCCLA1 ; Length of first part of table JMPS CHINT ; ; Initialise channel B ; LISINT: PUSHA MOV DX, SCCBC MOV BX, PDEF*2 MOV SI, OFFSET SCCTB PUSH DS PUSHW SCCLB2 ; Length of second part of table MOV CX, SCCLB1 ; Length of first part of table CHINT: PUSH CS ; set DS register DS CHIN1: OUTSB ; access recovery time of SCC prevents LOOP CHIN1 ; use of REP OUTS instruction MOV AL, 12 OUT DX, AL MOV AX, OFFSET DIVIS[BX] OUT DX, AL MOV AL, 13 OUT DX, AL MOV AL, AH OUT DX, AL POP CX ; Length of second part of table CHIN2: OUTSB LOOP CHIN2 POP DS ; restore registers ΡΟΡΑ RET ; ; Input status of channel A ; Returns AL = 0FFH if char available else 0 ; CONIST: PUSH DX MOV DX, SCCAC JUMPS CHIST ; ; Input status of channel B ; LISIST: PUSH DX MOV DX, SCCBC CHIST: IN AL, DX AND AL, 01 JZ CHIS1 OR AL, 0FFH CHIS1: POP DX RET ; ; Input a character from channel A ; Returns AL = char ; CONIN: CALL CONIST JZ CONIN ; Wait until char available PUSH DX MOV DX, SCCAD JUMPS CHIN ; ; Input a character from channel B ; LISIN: CALL LISIST JZ LISIN PUSH DX MOV DX,SCCBD CHIN: IN AL,DX AND AL,07FH POP DX RET ; ; Output status of channel A ; Returns AL = 0FFH if char can be sent ; CONOST: PUSH DX MOV DX, SCCAC IN AL,DX AND AL, 04 JZ CONOS1 OR AL, 0FFH CONOS1: POP DX RET ; ; Output status of channel B ; Returns AL = 0FFH if SCC ready to send char and CTS line asserted ; LISOST: PUSH DX MOV DX, SCCBC IN AL, DX AND AL, 024H CMP AL, 024H JNZ LISOS1 ; If NOT (EMPTY AND CTS) OR AL, 0FFH POP DX RET LISOS1: XOR AL, AL POP DX RET ; ; Output a character to channel A ; Call with AL = char ; CONOUT: PUSH AX CONOTW: CALL CONOST JZ CONOTW ; Wait until ready POP AX PUSH DX MOV DX, SCCAD OUT DX, AL POP DX RET ; ; Output a character to channel B ; Call with AL = char ; LISOUT: PUSH AX LISOTW: CALL LISOST JZ LISOTW POP AX PUSH DX MOV DX, SCCBD OUT DX, AL POP DX RET ; ********************************************* ; ; Interrupt Handler ; ; ********************************************* ; Timer 2 is set up as a real time clock ; On each interrupt ( every 20ms ) the following locations are incremented ; ; TIMEF fractions of a second (in 20ms) in binary ; TIMES seconds in BCD ; TIMEM minutes in BCD ; TIMEH hours in BCD ; TIMINT: PUSH AX ; save registers] PUSH DX PUSH BX PUSH DS MOV AX, SEG DATA MOV DS, AX XOR AX, AX MOV BX, OFFSET TIMEF INC BYTE PTR [BX] ; increment fraction CMP BYTE PTR [BX], 50 ; 1 second? JB TIMIN1 MOV [BX], AH INC BX MOV AL, [BX] ; increment seconds INC AL DAA MOV [BX], AL CMP AL, 60H ; 1 minute ? JB TIMIN1 MOV [BX], AH INC BX MOV AL, [BX] ; increment minutes INC AL DAA MOV [BX], AL CMP AL, 60H ; 1 hour? JB TIMIN1 MOV [BX], AH INC BX MOV AL, [BX] ; increment hours INC AL DAA MOV [BX], AL TIMIN1: POP DS POP BX MOV DX, EOIREG ; issue a non-specific MOV AX, 08000H ; end-of-interrupt command OUT DX, AX POP DX ; restore registers POP AX IRET ;********************************************** ; ; Messages and utilities ; ;********************************************** SIGNON: DB CR,LF,LF DB ' _____****<<<< The SC88PIO >>>>****_____' DB CR,LF,LF,LF,0 TIMEIS: DB CR, 'The time is ', 0 MINS: DB ' minutes and ' , 0 SECS DB ' seconds' , 0 ; ; Utility routines ; print a string terminated by a zero byte ; WRITES: MOV AL, CS:[BX] TEST AL,AL JZ WRITER CALL CONOUT INC BX JMPS WRITES WRITER: RET ; print CX hex digits from AX WRITEH: DEC CX ; if CX > 1 WRITE1 PUSH AX ; then WRITEH (AX-, -1) DB ; SHR AX, 4 CALL WRITEH POP AX WRITE1: AND AL, 00FH DAA ; if AF then add 6 ADD AL, 0F0H ; and set carry else subtract 10 ADC AL, 040H ; convert to ASCII CALL CONOUT RET ; print CX decimal digits from AX by recursion PDEC: MOV BL, 10 DIV BL DEC CX ; if CX > 1. PDEC1: PUSH AX ; then PDEC (AX/10, CX-1) XOR AH, AH CALL PDEC POP AX PDEC1: MOV AL, AH AND AL, 00FH ADD AL, '0' CALL CONOUT RET ; ; print AX in hex ; PWORDH: PUSH CX MOV CX, 4 CALL WRITEH POP CX RET ; ; print AL in hex ; PBYTEH: PUSH CX ΜΟV CX, 2 CALL WRITEH POP CX RET ; ********************************************* ; * ; * Initialisation code ; * ; ********************************************* START: CLI ; ensure interrupts are disabled MOV DX, LMCS ; LMCS MOV AX, 03FF8H + WAITR ; 256K RAM OUT DX, AX MOV DX, MPCS MOV AX, 080B8H ; PCS are in I/O space OUT DX, AX MOV DX, PACS MOV AX, 00FBCH + WAITI ; PBAFF80 OUT DX, AX OUT DX, AL MOV AX, SEG STACK ; set up stack pointer MOV SS, AX MOV SP, OFFSET STACK MOV AX, SEG DATA MOV DS, AX CLD ; clear direction STI CALL CONINT ; Initialise serial ports CALL LISTNT MOV BX, OFFSET SIGNON ; Print greetings CALL WRITES ; ; Set up interrupt handler for Timer 2 ; XOR AX, AX ; Write address of interrupt MOV ES, AX ; handler into interrupt table MOV AX, OFFSET TIMINT MOV BX, 76 MOV ES:[BX], AX ; Offset into address 0004CH MOV BX, 78 ; Segment into address 0004EH MOV AX, SEG TIMINT MOV ES:[BX], AX MOV AX, SEG DATA ; Zero time and date MOV ES, AX XOR AX, AX MOV CX, 3 MOV DI, OFFSET TIMEF REP STOS AX ΜΟV DX, TCNT2 ; Set up timer 2 XOR AX, AX ; clear count OUT DX, AX MOV AX, 2000*TICK ; real-time clock constant OUT DX, AX MOV AX, 0E001H ; EN, INT, CONT OUT DX, AX MOV DX, TINTCR ; enable timer interrupts XOR AX, AX ; priority = 0 OUT DX, AX ; ; Example Program ; PUSHW SEG DATA ; Set up DS register POP DS PROG: MOV BX, OFFSET TIMEIS ; 'The time is ' CALL WRITES CLI MOV AL, TIMEF ; Read time while ints are disabled PUSH AX MOV AL, TIMES PUSH AX MOV AL, TIMEM STI CALL PBYTEH ; Print number of minutes MOV BX, OFFSET MINS ; ' minutes and ' CALL WRITES POP AX ; Print number of seconds CALL PBYTEH MOV AL,'.' ; '.' CALL CONOUT POP AX ; Fraction in 20ms XOR AH,AH SHL AL,1 ; * 2 MOV CX,2 CALL PDEC ; Print hundredths of a second MOV BX,OFFSET SECS ; ' seconds' CALL WRITES JMP PROG ;************************************************ ; Reset entry point ;************************************************ ; The 80188 processor jumps to segment 0FFFFH offset 00000H on reset ; This corresponds to the top 16 bytes of the EPROM in IC18 ; Thus these bytes must set up the UMCS register so that the whole ; EPROM is enabled and then jump to the rest of the initialisation ; code CSEG 0FFFFH ORG 1FF0H ; This positions this code in the ; top 16 bytes of a 8K EPROM MOV DX,UMCS ; Chip select register for EPROM ; MOV AX,0FE3CH + WAITE ; 8K Enable ONE of these statements ; MOV AX,0FC3CH + WAITE ; 16K depending on your size of MOV AX,0F83CH + WAITE ; 32K EPPROM OUT DX,AX ; Set up UMCS JMPF START ; Jump to code in rest of EPROM END