Thursday, December 17, 2009

COMTASK.C

/*****************************************************************************
            COMMUNICATION TASK FOR 68HC16-BASED TERMO-LOGGER
                                  WITH
                    SLIP PROTOCOL AS DATA-LINK LAYER

                             (c) June 1995
                              by M. Lutfi
                        Engineering Physics Dept
                    Faculty of Industrial Technology
                       Institut Teknologi Bandung

        =======================================================

      Each received character is copied into  a queue by the interrupt
      routine and each character will be send by SCI_trm_task
      periodically then gives a semaphore to other tasks via SCI_SEMA.
      Before data copied to other segment/buffer, data must be
      depacketized. ComTask always calls Depacketizer routine when
      he receives data. MCX16 manages timing each period.

      We don't need interrupt handler, because we don't use it.
      To transmitting a character, just put it into SCI_TRM_QUEUE


      If needed, QSPI routines can be added as request.

                           (c) M. Lutfi, 1995
             Last updated: 5-June-1995 at MKN, Suropati 231
******************************************************************************/
#define _WSC_

#include "mcx16.h"
#include "sysdef.h"


#define SCI_IV       0x3A           /* interrupt vector number */
#define IL_QSPI         1           /* QSPI has lowest priority */
#define IL_SCI          7           /* SCI has highest priority */
#define SIZE          512           /* buffer size */
#define TDRE        0x100           /* transmit ready bit */
#define SYS_CLOCK   16780000L       /* HC16EVB's system clock */
#define BAUD_RATE(bps)     (SYS_CLOCK/(bps*32))

/*
  SLIP special character codes
*/
#define FR_END              0xC0 /* indicates end of packet */
#define FR_ESC              0xDB /* indicates byte stuffing */
#define T_FR_END            0xDC /* FR_ESC T_FR_END means END data byte */
#define T_FR_ESC            0xDD /* FR_ESC T_FR_ESC means ESC data byte */

#ifdef _WSC_    /* if WSC compiler */
    #include <wslxa.h>
    #include "_qsm.h"
    #include "sysdef.h"

#else       /* this not for WSC compiler */
    #include <dos.h>
    #include <stdio.h>
    #define FOREVER    for(;;)
    int scsr;
    int scdr;
    int qmcr;
    int qilr;
    int qilr_ilqspi;
    int qilr_ilsci;
    int qivr;
    int sccr0;
    int sccr1, sccr1_pe, sccr1_m, sccr1_te, sccr1_re;
#endif

   /* below are values for SCBR baud rates */
#define BPS_110          1748
#define BPS_600           874
#define BPS_1200          437
#define BPS_2400          218
#define BPS_4800          109
#define BPS_9600           55
#define BPS_19200           27
#define BPS_32768           16
#define    BPS_38400           14
#define BPS_500000          1


/**************************** GLOBAL VARIABLES *******************************
char in_char;
char out_char;
******************************************************************************/


/******************************************************************************
                              SEND_PACKET:
        sends a packet of length "len", starting at location "p"
******************************************************************************/
void send_packet(void *data, int len)
{
   /* send an initial END character to flush out any data (garbage) that
    * have accumulated in the receiver due to line noise
    */
   char *p;

   p = (char *)data;
   send_char(FR_END);

   /* for each byte in the packet, send the appropriate character
    * sequence
    */
   while (len--) {
      if (*p==FR_END) {
          send_char(FR_ESC);
          send_char(T_FR_END);
      }
      else
      if (*p==FR_ESC) {
         send_char(FR_ESC);
         send_char(T_FR_ESC);
      }
      else   /* otherwise, we just send the character */
         send_char(*p);
      p++;
   }
   /* tell the receiver that we're done sending the packet */
   send_char(FR_END);
}


/***************************** RECV_PACKET ***********************************
            receive a packet into the queue located at "p".
 *      If more than len bytes are received, the packet will be
 *      truncated.
 *      Returns the number of bytes stored in the buffer.
 *****************************************************************************/
int recv_packet(void *p, int len)
{
   char c;
   int received = 0;

   /* sit in a loop reading bytes until we put together a whole packet.
    * Make sure not to copy them into the packet if we run out of room.
    */
   while (1) {
      /* get a character to process */
      c = get_char();

      /* handle bytestuffing if necessary */
      if (c==FR_END) {
         /* a minor optimization: if there is no data in the packet,
          * ignore it. This is meant to avoid bothering IP with all
          * the empty packets generated by the duplicate FR_END char-
          * racters which are in turn sent to try to detect line noise.
          */
          if (received)
            return (received);
      }
      else
      if (c==FR_ESC) {
         c = get_char();

         /* if "c" is not and FR_ESC character, wait and get another
          * character and then figure out what to store in the packet
          * based on that.
          */
          if (c==T_FR_END)
            c = FR_END;
          else
          if (c==T_FR_ESC)
            c = FR_ESC;
          goto STORE;
      }
      else {
      STORE:
         /* here we fall into the default handler and let it store
          * the charater for us
          */
          if (received < len)
            p[received++] = c;
      }
   }
   _mcx_signal(SCI_RCV_SEMA);
}


/****************************************************************************
                       SCI driver Initialization
 > Sets up the ACIA and starts an infinite loop of receive transmit
 > QSM configuration summary:
   * After reset, the QSM remains in an idle state, requiring initialization
     of several registers before any serial operations may begin execution.
   * The type of serial frame (8 or 9 bit) and the use of partiy must be
     determined by M. PE and PT.
   * For receive operation, WAKE, RWU, ILT, ILIE must be considered.
     The receiver must be enabled (RE) and, usually, RIE should be set.
   * For transmit operation, the transmitter must be enabled (TE) and,
     usually, TIE should be set. The use of wired-OR mode (WOMS) must also
     be decided. Once the transmitter is configured, data is not sent
     until TDRE and TC are cleared. To clear TDRE and TC, the SCSR read
     must be followed by a write to SCDR (either the lower byte or the
     entire word).
   * QIVR should be programmed to one of the user-defined vectors ($40-$FF)
     during initialization of the QSM.
     After reset, QIVR determines which two vectors in the exception vector
     table are to be used for QSM interrupts. The QSPI and SCI submodules
     have separate interrupt vectors adjacent to each other.
     Both submodules use the same interrupt vector which LSB:
        1: interrupt generated by QSPI
        0: interrupt generated by QSCI
 > Detail Configurations in QSM:
   * QMCR:
        STOP = 0 (Normal QSM clock operation)
        FRZ1 = 0 (Ignore the FREEZE signal on the IMB)
        SUPV = 1 (supervisor access)
        IARB = $A (priority = 10; $F = highest priority, used by timer)
   * QILR:
        ILQSPI = 1 (lowest priority)
        ILSCI  = 7 (highest priority)
        QIVR   = set to SCI interrupt handler's address

****************************************************************************/

TCTASK.C

/*
���������������������������������������������������������������������������͸
�                                                                           �
�                          THERMOCOUPLE TASK                                �
�                                                                           �
�                          Copyright (c) 1994                               �
�                           by Lutfi Shahab                                 �
�               Instrumentation and Controls Laboratory                     �
�                     Dept. of Engineering Physics                          �
�                      Institut Teknologi Bandung                           �
�                                                                           �
�  Date:      20/11/94                                                      �
�                                                                           �
�  Platform : Motorola 68HC16 Microcontroller                               �
�               running mcx16 multitasking kernel                           �
�  Compiler : Whitesmith HC16 Compiler                                      �
�  Target   : EPROM-targeted binary code                                    �
�                                                                           �
�  Description:                                                             �
�      This module contains routines for Thermocouple Linearization using   �
�  polynomial curvefitting. Only thermocouple type K can be calculated.     �
�  Temperature adjusted to Celcius.                                         �
�                                                                           �
���������������������������������������������������������������������������;
*/

#define _WSC_
#define _FAR_

#ifdef _WSC_
#include <wslxa.h>
#else
enum {ADC_1, ADC_2, ADC_3, ADC_4, ADC_5,ADC_6, ADC_7, ADC_8, N_ADC_CHANNELS};
#endif
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#ifdef _WSC_
#include "mcxapi.h"
#include "sysdef.h"
#endif

#define VREF_PLUS         +2500.0       /* mV */
#define VREF_MIN          -2500.0       /* mV */
#define RESOLUTION          10          /* bits */
#define KELVIN_TO_C        273.20       /* based on IPTS-68 */
#define LM335_VT            10.00       /* mV per Kelvin degree */
#define TC_GAIN_AMP            (10000/40)     /* gain of TC op-amp; uV/uV */
#define DIGIT_TO_MILLIVOLT(d)    (((d)*scale)+VREF_MIN) /* mV */


/* seebeck coefficients for all TC types */
#define SEEBECK_COEF_K       40.01 /* uV/K */
#define SEEBECK_COEF_TC       5.20
#define SEEBECK_COEF_BN        18.05
#define SEEBECK_COEF_E         59.80
#define SEEBECK_COEF_JT        51.08
#define SEEBECK_COEF_JP        17.94
#define SEEBECK_COEF_JN        33.10
#define SEEBECK_COEF_K         40.01
#define SEEBECK_COEF_KP      26.47
#define SEEBECK_COEF_KN      13.54
#define SEEBECK_COEF_R        5.62
#define SEEBECK_COEF_S        5.70
#define SEEBECK_COEF_T       39.67
#define SEEBECK_COEF_TP       6.33
#define SEEBECK_COEF_TN      33.32

#define SEEBECK_COEF         SEEBECK_COEF_K

/* number of linearization polynomial equations as T(V) */
#define NUMEQN_V            5

/* number of linearization polynomial equations as V(T) */
#define NUMEQN_T            2

#define ORDE_T              10
#define ORDE_V              4
#define TC_VOLT_MIN         tc_table.v_range[0].min
#define TC_VOLT_MAX         tc_table.v_range[NUMEQN_V-1].max


typedef struct {
    double min, max;
}RANGE;


typedef struct {
    RANGE t_range[NUMEQN_T];       /* temperature range */
    RANGE v_range[NUMEQN_V];       /* voltage range */
    double coef_t[NUMEQN_T][ORDE_T+1];   /* polynomial coefficients for every equation of V(T) */
    double coef_v[NUMEQN_V][ORDE_V+1];   /* polynomial coefficients for every equation of T(V) */
} TCRECTYPE;


TCRECTYPE tc_table = {
  /* Temperature ranges (in C) for each polynomial equation of type K */
  {
    {-270.00,    0.00},
    {   0.00, 1372.00},
  },
  /* Voltage ranges in microvolts */
  {
     {-6.457816e+03, -6.441148e+03},
     {-6.441148e+03, -5.891361e+03},
     {-5.891361e+03,  1.853306e+01},
     { 1.853306e+01,  8.136555e+03},
     { 8.136555e+03,  5.487490e+04}
  },
  {
  /* Coefficients for each polynomial equation V(T) */
    {
      0.0000000000E+00, 3.9475433139E+01, 2.7465251138E-02,
     -1.6565406716E-04,-1.5190912392E-06,-2.4581670924E-08,
     -2.4757917816E-10,-1.5585276173E-12,-5.9729921255E-0015,
     -1.2688801216E-17,-1.1382797374E-20
    },
    {
     -1.8533063273E+01, 3.8918344612E+01, 1.6645154356E-02,
     -7.8702374448E-05, 2.2835785557E-07,-3.5700231258E-10,
      2.9932909136E-13,-1.2849848798E-16, 2.2239974336E-20,
      0.00, 0.00
    }
  },

  /* Coefficients for each polynomial equation T(V) in C */
  {
    {-8.887677e+05,-2.054743e+02, 1.307316e-02, 5.611858e-06, 3.034392e-10},
    {-1.215521e+06,-7.993152e+02,-1.971155e-01,-2.160351e-05,-8.879453e-10},
    {0.0000000e+00, 2.382475e-02,-2.372981e-06,-6.567714e-10,-9.208444e-14},
    {0.0000000e+00, 2.548081e-02,-5.270562e-07, 7.989244e-11,-3.520933e-15},
    {-1.035821e+01, 2.712314e-02,-1.781781e-07, 3.243000e-12,-1.166816e-17}
  }
};


double scale;   /* transformation scale */


/* calculate seebeck voltage value for a given temperature and TC */
/*
double calc_seebeck(double tempin)
{
   return (SEEBECK_COEF * tempin);
}
*/


/* calculate TC temperature given volts using polynomial equations */
double volt2temp_poly(double voltin)   /* input voltage */
{
  int pi; /* index to appropriate polynom */
  int i;
  double yout;

  if (voltin < TC_VOLT_MIN)  /* check to see if voltage in valid range */
  {
      voltin = TC_VOLT_MIN;
  }
  else if (voltin > TC_VOLT_MAX)
  {
      voltin = TC_VOLT_MAX;
  }
  pi = 0;
  /* search through breakpoint list looking for proper interval */
  while ( (pi < NUMEQN_V) &&
              !((voltin >= tc_table.v_range[pi].min) &&
               (voltin <= tc_table.v_range[pi].max)))
  {
    pi++;
  }

  /* calculate TC temperature as a function of volts */
  yout = tc_table.coef_v[pi][ORDE_V];

  for (i=ORDE_V-1; i<=0; i--)
  {
       /* efficient, nested polynomial calculation */
    yout = yout*voltin+tc_table.coef_v[pi][i];
  }

  return (yout);
}


/******************************************************************************
                    CONVERTS TC VOLTS TO TEMPERATURE
                    --------------------------------
       Reference temperature sensored by IC LM335Z, which has output
   characteristic: 10 mV/K. Scale has been stated 5/1023 = 4.9 mV/LSB,
   so if we have vi (in integer), it must be multiplied by scale to convert
   to voltage temperature, and divided it by resolution of sensor to get
   real temperature. ref_scale = scale/LM335_VT = (4.9 mV/LSB)/(10 mV/K) =
   0.49 K/LSB. Increasing vi in its LSB will increase temperature by 0.49 K.
       When calibrate (T=25 C), LM335 generate 2.982 volts (273.2+25) according
   to his current temperature. In Differential op-amp, this temperature-based
   voltage used to compute temperature reference. We don't need to compute it
   in MCU.
   All of 'kerumitan' has been handled by op-amps.
*******************************************************************************/
void tc_converter(unsigned int *vi,    /* measured TC volts  */
                   double *temp)          /* linearized temperature */
             /* return: error code, 0 = no error */
{
   int i;
   double v;

   for (i=ADC_1; i<=ADC_8; i++)
   {
      v = DIGIT_TO_MILLIVOLT(vi[i])/TC_GAIN_AMP*1000; /* unit in microvolts !*/
      temp[i] = volt2temp_poly(&v);
   }
}


double lin_t[N_ADC_CHANNELS];       /* linearized temperature */

void TC_Task(void)
{
    unsigned int *mbx;

    /* ADC resolution */
    scale = (double)(VREF_PLUS-VREF_MIN)/(double)((1<<RESOLUTION)-1); /* mV/bit */
    #ifdef _WSC_
    FOREVER
    {
        mbx = _mcx_receive_w(CNV_SEMA);
        tc_converter((mbx, (double *)lin_t);
        _mcx_send_mbx_w(TC_MBX, lin_t, CNV_FINISH_SEMA);
        _mcx_msg_done(mbx);
    }
    #endif
}

SLIISR.S

;����������������������������������������������������������������������������Ŀ
;�                            SLIP PROTOCOL                                   �
;�                          INTERRUPT HANDLER                                 �
;�             for 68HC16Z1 Microcontroller running MCX-16                    �
;�                                                                            �
;�                 compiled with Whitesmiths C compiler                       �
;�                                                                            �
;�                            (c) June 1995                                   �
;�                               M. Lutfi                                     �
;�                      Engineering Physics Dept.                             �
;�                     Faculty of Industrial Tech.                            �
;�                     Institut Technologi Bandung                            �
;�                                                                            �
;������������������������������������������������������������������������������

.PROCESSOR M68HC16
.TITLE "Thesis Project : SLIP - communication handler"
.INCLUDE "hc16regs.mac"
.INCLUDE "mcx16.mac"
.INCLUDE "lgrset.mac"

;*******************************************************************************
;*  SCI DRIVER DATA VARIABLES                                                  *
;*******************************************************************************
.PUBLIC _in_char, _out_char
    .psect  _data

_in_char:    .BYTE (1)
_out_char:   .BYTE (1)
_dest_temp:  .BYTE (1)
_src_temp:   .BYTE (1)


    .psect    _text
    .even

.LIST + .MACRO

;*******************************************************************************
;*                                                                             *
;*                       S C I   I N P U T   D R I V E R                       *
;*                                                                             *
;*******************************************************************************
.PUBLIC _sciidrv
_sciidrv:

rdclr:    ldd    SCSR        ; Get current status of SCI
          bitb   #RDRF       ; See if receive data ready
          beq    scirdy      ; if not SCI is a
          ldab   SCDR        ; Read input data
          bra    rdclr       ; Loop until clear
scirdy:   andp   #0FF1Fh     ; Turn interrupts on again

inloop:   ldab   #1          ; bank 1
          tbek               ; EK = 1
          tbxk               ; XK = 1 (K=$11xx)
          ldab   #SCI_RCV_SEMA
          ldaa   #MCX_WAIT_  ; Wait for input character
          swi

          ldaa   _in_char         ; Get input character captured by isr
          ldx    #_src_temp       ; Move it to safe place
          staa   0,x
          ldab   #SCI_RCV_Q       ; Then move the character into SCIIQ
          ldaa   #MCX_ENQUEUE_W_
          swi

          bra    inloop      ; Loop forever

;*******************************************************************************
;*                                                                             *
;*                     S C I   O U T P U T   D R I V E R                       *
;*                                                                             *
;*******************************************************************************

sciodrv:  ldab   #0Fh
          tbek               ; EK=F  (K=$Fxxx)
          ldab   #1
          tbxk               ; XK=1  (K=$F1xx)

scioloop:
          ldx    #_dest_temp
          ldab   #SCI_TRM_Q      ; Get next character from SCI_TRM_Q and put it into
          ldaa   #MCX_DEQUEUE_W_ ; _dest_temp as temporary location
          swi

          ldab   0,x         ; Get the character
          cmpb   #0Ah        ; New Line?
          bne    notnl       ; Branch if not "\n"
          ldd    SCSR        ; Get SCI status
          ldaa   #0Dh
          staa   SCDR+1      ; Output a "\r"
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCI_TRM_SEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT_
          swi

notnl:    ldd    SCSR        ; Read status
          ldaa   0,x         ; Get character to output
          staa   SCDR+1      ; Output it
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCI_TRM_SEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT_
          swi

          bra    scioloop    ; Loop forever

;*******************************************************************************
;*                                                                             *
;*           S C I   I N T E R R U P T   S E R V I C E   R O U T I N E         *
;*                                                                             *
;*******************************************************************************


sciisr:   orp    #INTS_OFF   ; Save the interrupt context
          pshm   d,e,x,y,z,k
          ldab   #1
          tbek               ; EK=1  (K=$1xxx)
          tbyk               ; YK=1  (K=$1x1x)
          tbzk               ; ZK=1  (K=$1x11)
          clrb
          tbxk               ; XK=0  (K=$1011)
          ldx    0000h       ; x = [$10000]
          tst    000Ah
          bne    notlvl0
          ldy    0004h       ; y = [$10004]
          sts    8,y         ; [y+8] = SP
          lds    14h,x       ; SP = [X+20]
notlvl0:  inc    000Ah       ; [$1000A] = [$1000A]+1
          andp   #SCIINTON   ; Interrupts back on
          ldz    12h,x

          ldab   #0Fh        ; EK = F  (K=$Fx11)
          tbek
          ldab   #1
          tbxk               ; XK = 1  (K=$F111)
          ldx    #0000      ;h
          ldy    #_in_char   ; y = &inchar

          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    notout      ; If not, this is not an output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    chkrd       ; TDRE not set
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1. That takes care of the output side

          ldd    SCSR        ; Now treat a possible input interrupt that is
                             ;  simultaneous with the output. Reread the status
          bitb   #RDRF       ; Check for RDRF set
          beq    noin        ; Branch if no input occurred
          ldd    SCDR        ; Yes it did. Read the input character
          andb   #7Fh        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
          PSHSEMA SCI_TRM_SEMA   ; Put SCI_TRM_SEMA into Signal List
noin:     ldaa   #SCI_TRM_SEMA   ; Now signal the SCI output semaphore
          jmp    isrrtn

notout:
          ldd    SCSR        ; Read status again
chkrd:
          bitb   #RDRF       ; See if this is an input interrupt. Check RDRF
          beq    notin       ; It is not an input interrupt. So what was it?
          ldd    SCDR        ; If it was an input interrupt, get the character
          stab   0,y         ; Store in temporary location (inchar)
                             ; That takes care of the input. Now see if there
                             ;  was a simultaneous output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    noout       ; TDRE not set
          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    noout       ; If not, this cannot be an output interrupt
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1
          PSHSEMA SCI_TRM_SEMA   ; Signal SCI Output Semaphore

noout:    ldaa   #SCI_RCV_SEMA   ; Now signal the input semaphore
          jmp    isrrtn

notin:    clra               ; This wasn't a recognizable SCI interrupt
          jmp    isrrtn

;*******************************************************************************
;*  SCI VECTOR                                                                 *
;*******************************************************************************


.END

SCIDRV.S

;*****************************************************************************
;*                                                                           *
;*                 S C I   D R I V E R   M O D U L E                         *
;*             UNDER HC16 MULTITASKING EXECUTIVE (MCX16)                     *
;*                         WITH SLIP PROTOCOL                                *
;*                                                                           *
;            Compiled with Whitesmith Cross Assember ver 1.9                 *
;*                        (c) 11 December 1994                               *
;*                            by M. Lutfi                                    *
;*                          Thesis Project                                   *
;*                 Instrumentation and Controls lab.                         *
;*                 Department of Engineering Physics                         *
;*                  FACULTY OF INDUSTRIAL TECHNOLOGY                         *
;*                  BANDUNG INSTITUTE OF TECHNOLOGY                          *
;*****************************************************************************
.PROCESSOR M68HC16
.TITLE "SCI DRIVER MODULE"

.INCLUDE "lgrset.s"

          .PAGE "SCIDRV"
;*******************************************************************************
;*                                                                             *
;*                       S C I   I N P U T   D R I V E R                       *
;*                      with SLIP data-link layer protocol                     *
;*******************************************************************************


sciidrv:
      orp    #INTS_OFF   ; Turn off interrupts while enabling SCI
      ldab   #0Fh
      tbek               ; EK = F (K=Fxxxh)

      ldd    #008Ah
      std    QMCR        ; Set IARB=10 for intermodule bus arbitration

      ldd    QILR        ; Get content of QSM Interrupt Levels Register
      anda   #0E8h       ; Clear out ILSCI field
      oraa   #SCIINTLV   ; Set SCI interrupt level in ILSCI field
      ldab   #SCIINTV    ; Load SCI Interrupt Vector #
      std    QILR        ; Update QILR

      ldd    #RIE+RE+TE  ; Receiver enabled with interrupts active,
                         ; Transmitter enabled without interrupts,
                         ; 1 Start Bit, 1 Stop Bit, 8 Data Bits
      std    SCCR1       ; Set up SCI operating conditions
      ldd    #BR9600     ; Set up 9600 baud rate
      std    SCCR0

rdclr:
      ldd    SCSR        ; Get current status of SCI
      bitb   #RDRF       ; See if receive data ready
      beq    scirdy      ; if not SCI is a
      ldab   SCDR        ; Read input data
      bra    rdclr       ; Loop until clear

scirdy:
      andp   #0FF1Fh      ; Turn interrupts on again

inloop:
      ldab   #1
      tbek               ; EK = 1
      tbxk               ; XK = 1 (K=11xxh)
      ldab   #SCIISEMA
      ldaa   #MCX_WAIT   ; Wait for input character
      swi

      ldaa   inchar      ; Get input character captured by isr
      ldx    #EQ3src     ; Move it to safe place
      staa   0,x
      ldab   #SCIIQ      ; Then move the character into SCIIQ
      ldaa   #MCX_ENQUEUE_W
      swi

      bra    inloop      ; Loop forever

          .PAGE "SCIDRV"
;*******************************************************************************
;*                                                                             *
;*                     S C I   O U T P U T   D R I V E R                       *
;*                                                                             *
;*******************************************************************************

sciodrv:  ldab   #0Fh
          tbek               ; EK=F  (K=Fxxxh)
          ldab   #1
          tbxk               ; XK=1  (K=F1xxh)

scioloop: ldx    #DQ4dest
          ldab   #SCIOQ      ; Get next character from SCIOQ and put it into
          ldaa   #MCX_QUEUE_W  ; DQ4dest as temporary location
          swi

          ldab   0,x         ; Get the character
          cmpb   #0Ah        ; New Line?
          bne    notnl       ; Branch if not "\n"
          ldd    SCSR        ; Get SCI status
          ldaa   #0Dh
          staa   SCDR+1      ; Output a "\r"
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

notnl:    ldd    SCSR        ; Read status
          ldaa   0,x         ; Get character to output
          staa   SCDR+1      ; Output it
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

          bra    scioloop    ; Loop forever

          .PAGE "SCIDRV"
;�����������������������������������������������������������������������������Ŀ
;�                                                                             �
;�           S C I   I N T E R R U P T   S E R V I C E   R O U T I N E         �
;�                                                                             �
 �������������������������������������������������������������������������������

.MACRO pshsema
          ldab   ?1
          orp    #INTS_OFF
          lde    06h,x
          stab   e,z
          incw   06h,x
          andp   #SCIINTON
 .EXITM

sciisr:
          orp    #INTS_OFF   ; Save the interrupt context
          pshm   d,e,x,y,z,k
          ldab   #1
          tbek               ; EK=1  (K=1xxxh)
          tbyk               ; YK=1  (K=1x1xh)
          tbzk               ; ZK=1  (K=1x11h)
          clrb
          tbxk               ; XK=0  (K=1011h)
          ldx    0000h
          tst    000Ah
          bne    notlvl0
          ldy    0004
          sts    8,y
          lds    14h,x
notlvl0:  inc    000Ah
          andp   #SCIINTON   ; Interrupts back on
          ldz    12h,x

          ldab   #0Fh         ; EK = F  (K=$Fx11)
          tbek
          ldab   #1
          tbxk               ; XK = 1  (K=$F111)
          ldx    #0000
          ldy    #inchar

          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    notout      ; If not, this is not an output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    chkrd       ; TDRE not set
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1. That takes care of the output side

          ldd    SCSR        ; Now treat a possible input interrupt that is
                             ;  simultaneous with the output. Reread the status
          bitb   #RDRF       ; Check for RDRF set
          beq    noin        ; Branch if no input occurred
          ldd    SCDR        ; Yes it did. Read the input character
          andb   #7Fh        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
          pshsema SCIISEMA   ; Put SCIISEMA into Signal List
noin:     ldaa   #SCIOSEMA   ; Now signal the SCI output semaphore
          jmp    isrrtn

notout:   ldd    SCSR        ; Read status again
chkrd:    bitb   #RDRF       ; See if this is an input interrupt. Check RDRF
          beq    notin       ; It is not an input interrupt. So what was it?
          ldd    SCDR        ; If it was an input interrupt, get the character
          andb   #7Fh        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
                             ; That takes care of the input. Now see if there
                             ;  was a simultaneous output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    noout       ; TDRE not set
          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    noout       ; If not, this cannot be an output interrupt
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1
          pshsema SCIOSEMA   ; Signal SCI Output Semaphore

noout:    ldaa   #SCIISEMA   ; Now signal the input semaphore
          jmp    isrrtn

notin:    clra               ; This wasn't a recognizable SCI interrupt
          jmp    isrrtn

          .PAGE "SCIDRV"
;���������������������������������������������������������������������������Ŀ
;� SCI VECTOR                                                                �
;�����������������������������������������������������������������������������

          .PSECT   _text
          .ADDR    sciisr

;���������������������������������������������������������������������������Ŀ
;� SCI DRIVER DATA VARIABLES                                                 �
;�����������������������������������������������������������������������������

          .PSECT _data ; 003FDh

inchar:   .BYTE     1
DQ4dest:  .BYTE     1
EQ3src:   .BYTE     1

.END

SCIDRV.ASM

******************************************************************************
*                       S C I   D R I V E R   M O D U L E                     *
*                                                                             *
*******************************************************************************

isrrtn    equ    $360        ; Address of Common Interrupt Exit routine

SCIINTLV  equ    5           ; SCI Interrupt Level
SCIINTV   equ    $3A         ; SCI Interrupt Vector

QMCR      equ    $FC00
QILR      equ    $FC04       ; QSM Interrupt Levels Register
QIVR      equ    $FC05       ; QSM Interrupt Vector Register

SCCR0     equ    $FC08       ; SCI Control Register 0
SCCR1     equ    $FC0A       ; SCI Control Register 1
SCSR      equ    $FC0C       ; SCI Status Register
SCDR      equ    $FC0E       ; SCI Data Register

*******************************************************************************
*  SCCR1 REGISTER FIELDS                                                      *
*******************************************************************************

SRK       equ    $01         ; Send Break
RWU       equ    $02         ; Receiver Wakeup
RE        equ    $04         ; Receiver Enable
TE        equ    $08         ; Transmitter Enable
RIE       equ    $20         ; Receiver Interrupt Enable
TIE       equ    $80         ; Transmitter Interrupt Enable

*******************************************************************************
*  SCI STATUS REGISTER FIELDS                                                 *
*******************************************************************************

RDRF      equ    $40         ; Receive Data Register Full
TDRE      equ    $01         ; Transmit Data Register Empty (high byte of $0100)

*******************************************************************************
*  SCI DRIVER EQUATES                                                         *
*******************************************************************************

INTS_OFF  equ    $00E0       ; Disable interrupts
SCIINTON  equ    (SCIINTLV<<5+$FF1F) ; Enable interrupts at SCIINTLV (2)
BR9600    equ    $37         ; SCCR0(0-12) setting for 9600 Baud

          PAGE
*******************************************************************************
*                                                                             *
*                       S C I   I N P U T   D R I V E R                       *
*                                                                             *
*******************************************************************************

sciidrv:  orp    #INTS_OFF   ; Turn off interrupts while enabling SCI
          ldab   #$F
          tbek               ; EK = F (K=$Fxxx)

          ldd    #$008A
          std    QMCR        ; Set IARB=10 for intermodule bus arbitration

          ldd    QILR        ; Get content of QSM Interrupt Levels Register
          anda   #$E8        ; Clear out ILSCI field
          oraa   #SCIINTLV   ; Set SCI interrupt level in ILSCI field
          ldab   #SCIINTV     ; Load SCI Interrupt Vector #
          std    QILR        ; Update QILR

          ldd    #RIE+RE+TE  ; Receiver enabled with interrupts active,
                             ; Transmitter enabled without interrupts,
                             ; 1 Start Bit, 1 Stop Bit, 8 Data Bits
          std    SCCR1       ; Set up SCI operating conditions
          ldd    #BR9600     ; Set up 9600 baud rate
          std    SCCR0

rdclr:    ldd    SCSR        ; Get current status of SCI
          bitb   #RDRF       ; See if receive data ready
          beq    scirdy      ; if not SCI is a
          ldab   SCDR        ; Read input data
          bra    rdclr       ; Loop until clear
scirdy:   andp   #$FF1F      ; Turn interrupts on again

inloop:   ldab   #1          ; bank 1
          tbek               ; EK = 1
          tbxk               ; XK = 1 (K=$11xx)
          ldab   #SCIISEMA
          ldaa   #MCX_WAIT   ; Wait for input character
          swi

          ldaa   inchar      ; Get input character captured by isr
          ldx    #EQ3src     ; Move it to safe place
          staa   0,x
          ldab   #SCIIQ      ; Then move the character into SCIIQ
          ldaa   #MCX_ENQUEUE_W
          swi

          bra    inloop      ; Loop forever

          PAGE
*******************************************************************************
*                                                                             *
*                     S C I   O U T P U T   D R I V E R                       *
*                                                                             *
*******************************************************************************

sciodrv:  ldab   #$F
          tbek               ; EK=F  (K=$Fxxx)
          ldab   #1
          tbxk               ; XK=1  (K=$F1xx)

scioloop: ldx    #DQ4dest
          ldab   #SCIOQ      ; Get next character from SCIOQ and put it into
          ldaa   #MCX_DEQUEUE_W  ; DQ4dest as temporary location
          swi

          ldab   0,x         ; Get the character
          cmpb   #$0A        ; New Line?
          bne    notnl       ; Branch if not "\n"
          ldd    SCSR        ; Get SCI status
          ldaa   #$0D
          staa   SCDR+1      ; Output a "\r"
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

notnl:    ldd    SCSR        ; Read status
          ldaa   0,x         ; Get character to output
          staa   SCDR+1      ; Output it
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

          bra    scioloop    ; Loop forever

          PAGE
*******************************************************************************
*                                                                             *
*           S C I   I N T E R R U P T   S E R V I C E   R O U T I N E         *
*                                                                             *
*******************************************************************************

pshsema   macro
          ldab   #\1
          orp    #INTS_OFF
          lde    $06,x
          stab   e,z
          incw   $06,x
          andp   #SCIINTON
          endm

sciisr:   orp    #INTS_OFF   ; Save the interrupt context
          pshm   d,e,x,y,z,k
          ldab   #1
          tbek               ; EK=1  (K=$1xxx)
          tbyk               ; YK=1  (K=$1x1x)
          tbzk               ; ZK=1  (K=$1x11)
          clrb
          tbxk               ; XK=0  (K=$1011)
          ldx    $0000       ; x = [$10000]
          tst    $000A
          bne    notlvl0
          ldy    $0004       ; y = [$10004]
          sts    8,y         ; [y+8] = SP
          lds    $14,x       ; SP = [X+20]
notlvl0:  inc    $000A       ; [$1000A] = [$1000A]+1
          andp   #SCIINTON   ; Interrupts back on
          ldz    $12,x

          ldab   #$F         ; EK = F  (K=$Fx11)
          tbek
          ldab   #1
          tbxk               ; XK = 1  (K=$F111)
          ldx    #$0000      ;
          ldy    #inchar     ; y = &inchar

          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    notout      ; If not, this is not an output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    chkrd       ; TDRE not set
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1. That takes care of the output side

          ldd    SCSR        ; Now treat a possible input interrupt that is
                             ;  simultaneous with the output. Reread the status
          bitb   #RDRF       ; Check for RDRF set
          beq    noin        ; Branch if no input occurred
          ldd    SCDR        ; Yes it did. Read the input character
          andb   #$7F        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
          pshsema SCIISEMA   ; Put SCIISEMA into Signal List
noin:     ldaa   #SCIOSEMA   ; Now signal the SCI output semaphore
          jmp    isrrtn

notout:   ldd    SCSR        ; Read status again
chkrd:    bitb   #RDRF       ; See if this is an input interrupt. Check RDRF
          beq    notin       ; It is not an input interrupt. So what was it?
          ldd    SCDR        ; If it was an input interrupt, get the character
          andb   #$7F        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
                             ; That takes care of the input. Now see if there
                             ;  was a simultaneous output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    noout       ; TDRE not set
          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    noout       ; If not, this cannot be an output interrupt
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1
          pshsema SCIOSEMA   ; Signal SCI Output Semaphore

noout:    ldaa   #SCIISEMA   ; Now signal the input semaphore
          jmp    isrrtn

notin:    clra               ; This wasn't a recognizable SCI interrupt
          jmp    isrrtn

          PAGE
*******************************************************************************
*  SCI VECTOR                                                                 *
*******************************************************************************

          ORG    SCIINTV*2

          dc.w   sciisr

*******************************************************************************
*  SCI DRIVER DATA VARIABLES                                                  *
*******************************************************************************

          ORG    $003FD

inchar:   ds     1
DQ4dest:  ds     1
EQ3src:   ds     1

*******************************************************************************
*                                                                             *
*                       S C I   D R I V E R   M O D U L E                     *
*