{******************************************************************************
 ******************************************************************************
 *
 *
 *  EZ-KIT Lite resident monitor
 *
 *  This file is part of the ADSP 2181 EZ-KIT Lite resident monitor.
 *
 *  The monitor is loaded from the on-board EPROM through the BDMA
 *  interface during power up.
 *
 *  The complete source codes include the following files:
 *
 *  INTVEC  .DSP : interrupt vector table
 *  UART    .DSP : UART simulation routine
 *  MAIN    .DSP : main module
 *  SELFTEST.DSP : power up self test routine
 *  UTILITY .DSP : send a line of ASCII text through serial line
 *  COMMAND .DSP : command loop and command interpreter
 *  CODEC   .DSP : 1847 codec initialization and interrupt handling
 *
 *  TONE    .DAT : 32 samples of one complete cycle sine wave
 *  CONSTANT.K   : constants
 *
 *
 ******************************************************************************
 ******************************************************************************}





.module/ram     COMMAND;

.include        <constant.k>;

.entry          lastCmdOK;
.entry          irq1isr;
.entry          cmdProc;

.global         usrRan;
.global         intsVec;

.var/dm/ram     usrRan, temp;
.var/dm/ram     ok [9], bad [11], aliveCnt;
.var/pm/ram/abs=0x3fc0     intsVec [0x30];      { do not change this address }


.init ok: 'o', 'k', 0, 0, 0, 0, 0, 0, 0;
.init bad: 'y','o','u',' ','t','y','p','e',':', 0, 0;
.init aliveCnt: 0x2f;
.init usrRan: 0;        { 1 if user program is running. }






{******************************************************************************
 *
 *  This command parser accepts these commands:
 *
 *  1.  Beep
 *      received:$$$
 *      send    :ok[led count][alive called count][selftest hi][selftest lo]
 *
 *
 *      [led count] is the lower 8 bits of a counter incremented at 28800 rate.
 *      [alive called count] is incremented by one each time alive is called.
 *      [selftest hi][selftest lo] is the selftest result
 *      beep
 *
 *  2.  Alive inquiry
 *      received:$OK
 *      send    :ok[led count][alive called count][selftest hi][selftest lo]
 *
 *      [led count] is the lower 8 bits of a counter incremented at 28800 rate.
 *      [alive called count] is incremented by one each time alive is called.
 *      [selftest hi][selftest lo] is the selftest result
 *
 *  3.  upload DM
 *      received:$UD[hi start][lo start][hi len][lo len]
 *      send    :[hi][lo]...[hi sum][lo sum]$!
 *
 *  4.  upload PM
 *      received:$UP[hi start][lo start][hi len][lo len]
 *      send    :[hi][mi][lo]...[hi sum][mi sum][lo sum]$!
 *
 *  5.  download DM
 *      received:$DD[hi start][lo start][hi len][lo len][hi][lo]...
 *      send    :![hi sum][lo sum]
 *
 *  6.  download PM
 *      received:$DP[hi start][lo start][hi len][lo len][hi][mi][lo]...
 *      send    :![hi sum][mi sum][lo sum]
 *
 *  7.  Call subroutine
 *      received:$GO[hi address][loaddress]
 *      send    :![hi address][loaddress]
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  :
 *  update :
 *  output :
 *  destroy:
 *  keep   :
 *  memory :
 *  calls  :
 *
 ******************************************************************************}
{-- wait for first $ --}

cmdProc:
        idle;
        call get_char_ax1;

        ay1 = 0x24;
        none = ax1 - ay1;
        if eq jump cmdPrmpt;        { receive command prompt $ }

        none = pass ax1;
        if eq jump cmdProc;         { skip 0x00 }


{-- command not regconized --}
        dm (bad + 9) = ax1;         { for others, send back string: you type:? }
        i7 = ^bad;
        call sendLine;
        jump cmdProc;


cmdPrmpt:
{-- now get the next two characters (will time out.) --}
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }

        none = pass ar;
        if eq jump cmdProc;     { if both zero, discard; host clearing }
{-- now the first character is in upper 8 bits of ar and second in lower. --}



{******************************************************************************
 *
 *  this is the command dispatcher.
 *
 ******************************************************************************}

        m7 = 1;
        l7 = 0;

        ay0 = 0x4f4b;           { ASCII for 'OK' }
        none = ar - ay0;
        if eq jump alive;


        ay0 = 0x2424;           { ASCII for '$$' }
        none = ar - ay0;
        if eq jump beep;


        ay0 = 0x5544;           { ASCII for 'UD' }
        none = ar - ay0;
        if eq jump updm;



        ay0 = 0x5550;           { ASCII for 'UP' }
        none = ar - ay0;
        if eq jump uppm;


        ay0 = 0x4444;           { ASCII for 'DD' }
        none = ar - ay0;
        if eq jump dndm;


        ay0 = 0x4450;           { ASCII for 'DP' }
        none = ar - ay0;
        if eq jump dnpm;


        ay0 = 0x474f;           { ASCII for 'GO' }
        none = ar - ay0;
        if eq jump go;





{-- command not regconized --}
        dm (bad + 9) = ar;
        i7 = ^bad;


lastCmdBad:
        ar = BEEP_1000_mS;          { beep }
        dm (codecBeep) = ar;
        ar = LEDRateBad;            { get fast LED blink rate value. }
        dm (led_cntr_top) = ar;     { set led counter reset value. }
        jump cmdProc;


lastCmdOK:
        ar = LEDRateGood;           { get slow LED blink rate value. }
        dm (led_cntr_top) = ar;     { set led counter reset value. }
        jump cmdProc;





{******************************************************************************
 *
 *  received:$$$
 *
 *  send    :ok[led count][alive called count][selftest hi][selftest lo]
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy: none
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
beep:
        ar = BEEP_0100_mS;              { enable codec to beep }
        dm (codecBeep) = ar;


{******************************************************************************
 *
 *  received:$OK
 *
 *  send    :ok[led count][alive called count][selftest hi][selftest lo]
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy:
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
alive:
{-- byte 2 is led counter; byte 3 is alive called count --}
        ar = 0x6f6b;                { send ok }
        call out_int_ar;

        ax1 = dm (led_cntr);        { get led counter }
        call out_char_ax1;          { send lower 8 bits }

        ar = dm (aliveCnt);         { get and increment aliveCnt }
        ar = ar + 1;
        dm (aliveCnt) = ar;
        ax1 = ar;
        call out_char_ax1;          { send lower 8 bits }

        ar = dm (selfTstRst);       { get selftest result }
        call out_int_ar;
        ar = 0x0a0d;                { send line feed/carriage return }
        call out_int_ar;
        jump lastCmdOK;



{******************************************************************************
 *
 *  received:$UD[hi start][lo start][hi len][lo len]
 *
 *  send    :[hi][lo]...[hi sum][lo sum]$!
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy: none
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
updm:
{   get start }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }
        i7 = ar;

{   get len }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }

{   the loop }
        af = pass 0;                { zero checksum }
        cntr = ar;
        do updm0 until ce;
        ar = dm (i7, m7);
        af = ar + af;               { compute checksum }
        call out_int_ar;            { send to host }
updm0:  nop;

        ar = pass af;               { send checksum }
        call out_int_ar;

        jump lastCmdOK;




{******************************************************************************
 *
 *  received:$UP[hi start][lo start][hi len][lo len]
 *
 *  send    :[hi][mi][lo]...[hi sum][mi sum][lo sum]$!
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy: none
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
uppm:
{   get start }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }
        i7 = ar;

{   get len }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }

{   the loop }
        mr = 0;                     { zero checksum }
        cntr = ar;
        do uppm0 until ce;

        ay1 = pm (i7, m7);

        { compute checksum }
        sr1 = 0;                    { px in lower 8 sr0 }
        sr0 = px;
        si = ay1;
        sr = sr or lshift si by 8 (lo);    { or in upper 16 bits }
        ay0 = mr0;
        ar = sr0 + ay0;             { do a 24 bits add; hi:lo in mr1:mr0 }
        mr0 = ar;                   { number is in lower 24 bits of 32 bits }
        ay0 = mr1;
        ar = sr1 + ay0 + c;         { add with carry }
        mr1 = ar;

        ar = ay1;
        call out_int_ar;            { send upper 16 bits. }
        ax1 = px;
        call out_char_ax1;          { send lower 8 bits. }
uppm0:  nop;

{   compute and send 24 bits checksum }
{   these codes are also used by download pm }
        sr = lshift mr0 by 8 (lo);  { shirt upper 16 bits into sr1 }
        sr = sr or lshift mr1 by 8 (hi);  { shirt upper 16 bits into sr1 }
        ar = sr1;
        call out_int_ar;            { send upper 16 bits. }
        ax1 = mr0;                  { lower 8 bits still in mr0 }
        call out_char_ax1;          { and lower 8 bits. }

        jump lastCmdOK;


{******************************************************************************
 *
 *  received:$DD[hi start][lo start][hi len][lo len][hi][lo]...
 *
 *  send    :![hi sum][lo sum]
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy: none
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
dndm:
{   get start }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }
        i7 = ar;

{   get len }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }

{   the loop }
        af = pass 0;
        cntr = ar;
        do dndm0 until ce;
        call get_int_ar_to;
        if lt jump dndmBad;         { check time out: jump if timeout }
        dm (i7, m7) = ar;
dndm0:  af = ar + af;               { compute checksum }

{   send checksum }
        ar = pass af;               { send checksum }
        call out_int_ar;

        jump lastCmdOK;


dndmBad:
{   time out, clean up counter, loop, and PC stacks. }
{   These codes are also used by download pm }
      { pop cntr; }         { no need to pop counter because it's empty. }
        pop pc;                     { popping relavent stacks since we }
        pop loop;                   { are jumping out of do loop. }
        jump lastCmdBad;



{******************************************************************************
 *
 *  received:$DP[hi start][lo start][hi len][lo len][hi][mi][lo]...
 *
 *  send    :![hi sum][mi sum][lo sum]
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy: none
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
dnpm:
{   get start }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }
        i7 = ar;

{   get len }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }

{   the loop }
        mr = 0;
        cntr = ar;
        do dnpm0 until ce;

        call get_int_ar_to;
        if lt jump dndmBad;         { check time out: share download dm codes }
        ay1 = ar;                   { save upper 16 bits in ay1 }
        call get_char_ax1_to;       { get lowest 8 bits. }
        if lt jump dndmBad;         { check time out: share download dm codes }
        px = ax1;                   { load px }

        { compute checksum }
        sr1 = 0;                    { px in lower 8 sr0 }
        sr0 = px;
        si = ay1;
        sr = sr or lshift si by 8 (lo);    { or in upper 16 bits }
        ay0 = mr0;
        ar = sr0 + ay0;             { do a 24 bits add; hi:lo in mr1:mr0 }
        mr0 = ar;                   { number is in lower 24 bits of 32 bits }
        ay0 = mr1;
        ar = sr1 + ay0 + c;         { add with carry }
        mr1 = ar;

dnpm0:  pm (i7, m7) = ay1;          { save to pm }

{   compute and send 24 bits checksum }
        jump uppm0;                 { share upload pm code }





{******************************************************************************
 *
 *  received:$GO[hi address][loaddress]
 *
 *  send    :![hi address][loaddress]
 *
 *  user program to jump to 0x3fff to continue monitor program.
 *
 *
 *  before running user program:
 *  1.  dis timer
 *  2.  enable IRQ1
 *  3.  mask all ints
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy: none
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
go:
{   get address }
        call get_int_ar_to;
        if lt jump lastCmdBad;      { check time out }
        i7 = ar;
        call out_int_ar;            { echo address back to host }
go1:    ar = dm (flag_tx_ready);    { wait until last transmit is done. }
        none = pass ar;
        if eq jump go1;

        ar = 1;                     { set user program running flag }
        dm (usrRan) = ar;

        dis timer;                  {   disable timer (will be enable by IRQ1 }
        imask = 0;


        ax0 = 0;
        dm (System_Control_Reg) = ax0;  {   shut down sport 0 }
        dm (SPORT0_Autobuf) = ax0;      {   turn off auto-buffering }

        ay1 = i7;                   { copy 0x3fc0..ef 0x00..2f }
        i4 = 0;                     { PC will download 0..2f to 3fc0..ef }
        l4 = 0;
        m4 = 0;
        i7 = ^intsVec;
        m7 = 1;
        cntr = %intsVec;
        do usrVec until ce;
        ax0 = pm (i4, m4);          { current int vec to be saved }
        ax1 = px;
        ay0 = pm (i7, m4);          { downloaded int vec to move to low mem }
        {   px implicit }
        pm (i4, m7) = ay0;
        px = ax1;
usrVec: pm (i7, m7) = ax0;


        i7 = ay1;
{   call USER codes }
        call (i7);
{   returned from USER codes }

        dis ints;
        dis timer;
        ifc = b#00000011111111;         { clear pending interrupt }
        nop;

{   pop stacks; in case user program did not empty stacks }
        pop sts;       pop sts;       pop sts;       pop sts;
        pop cntr;      pop cntr;      pop cntr;      pop cntr;
        pop pc;        pop pc;        pop pc;        pop pc;
        pop loop;      pop loop;      pop loop;      pop loop;


        ar = 0;                     { clear user program running flag }
        dm (usrRan) = ar;

{   restore just in case }
        l7 = 0;
        m7 = 1;                 { restore for memory transfer }


        i4 = 0;                     { restore saved int vec. }
        l4 = 0;
        i7 = ^intsVec;
        cntr = %intsVec;
        do usrVec1 until ce;
        ar = pm (i7, m7);          { downloaded int vec to move to low mem }
usrVec1:pm (i4, m7) = ar;          {   px implicit }

        icntl = b#00010;
        mstat = b#1000000;
        imask = b#0000000001;

        ar = 1;
        dm (codecBeep) = ar;

        ena ints;

        call codecInit;

        call init_uart;             { intialize uart routine }
        call turn_rx_on;            { turn on uart }

        ar = BEEP_0100_mS;          { enable codec to beep }
        dm (codecBeep) = ar;

        jump lastCmdOK;





{******************************************************************************
 *  A high to low transition on flag_in signifies the start bit; it also
 *  triggers IRQ1 ISR which then turn on timer if the timer is off.  This is
 *  at to most 1/3 bit period too late but we shoudl still catch the byte.
 *
 *
 *  REGISTER USAGE SUMMARY:
 *
 *  input  : none
 *  update : none
 *  output : none
 *  destroy: none
 *  keep   : none
 *  memory : none
 *  calls  : none
 *
 ******************************************************************************}
irq1isr:
        pop sts;
        ena timer;              { start timer now }
        rts;                    { note rts }



.endmod;
