RaceGauge

RaceGauge Source Code

****************************************************************************
*  CELEBSS.ASM
*       Program for controlling and displaying dash information on LCDs
*
*  Copyright (c) 1999, 2003 Richard Goedeken.
*
*    CELEBSS.ASM is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    CELEBSS.ASM is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
*

***************
*   EQUATES   *
***************
REGBS   EQU  $1000      start of registers
RAMBS   EQU  $2000      start of data
STACKBS EQU  $3fff      top of stack
ROMBS   EQU  $e000      start of program

PORTD   EQU  REGBS+$08  Port D I/O Register
DDRD    EQU  REGBS+$09  Data direction for port D
PORTE   EQU  REGBS+$0A  port e
CFORC   EQU  REGBS+$0B  force output compare
TCNT    EQU  REGBS+$0E  timer count
TOC5    EQU  REGBS+$1E  oc5 reg
TCTL1   EQU  REGBS+$20  timer control 1
TMSK1   EQU  REGBS+$22  timer mask 1
TFLG1   EQU  REGBS+$23  timer flag 1
TMSK2   EQU  REGBS+$24  timer mask 2
TFLG2   EQU  REGBS+$25  timer flag 2
PACTL   EQU  REGBS+$26  Pulse Accumulator Control
PACNT   EQU  REGBS+$27  Pulse Accumulator Counter
SPCR    EQU  REGBS+$28  SPI Control
BAUD    EQU  REGBS+$2B  sci baud reg
SCCR1   EQU  REGBS+$2C  sci control1 reg
SCCR2   EQU  REGBS+$2D  sci control2 reg
SCSR    EQU  REGBS+$2E  sci status reg
SCDAT   EQU  REGBS+$2F  sci data reg

ADCTL   EQU  REGBS+$30  A/D Control Register
ADR1    EQU  REGBS+$31  A/D conversion result registers
ADR2    EQU  REGBS+$32
ADR3    EQU  REGBS+$33
ADR4    EQU  REGBS+$34

BPROT   EQU  REGBS+$35  block protect reg
OPTION  EQU  REGBS+$39  option reg
COPRST  EQU  REGBS+$3A  cop reset reg
PPROG   EQU  REGBS+$3B  ee prog reg
HPRIO   EQU  REGBS+$3C  hprio reg
CONFIG  EQU  REGBS+$3F  config register

LCDData EQU  $b5f0
LCDCtrl EQU  $b5f1

* Interrupt Vector Location
RTIVec          EQU     $fff0
IRQVec          EQU     $fff2
ResetVec        EQU     $fffe

ACIA	EQU	$B5F8	axiom 65c51 address
*			+0 = RX/TX register
*			+1 = status
*			+2 = command
*			+3 = control

IMGSIZE EQU  3840       image size

***************
* Direct Page *
***************
  org $0000

***************
*     RAM     *
***************
        ORG  RAMBS

VARSTART        EQU     *

TimerFired      fcb     0

Odometer        fcb     0, 0, 0         * BCD
MileCount       fdb     0               * overflow at 4000 pulses (1 mile)
TripMeter       fcb     0, 0            * BCD
TripCount       fdb     0               * overflow at 400 pulses (1/10th mile)

BCDSpeed        fcb     0, 0            * BCD
BCDRPM          fcb     0, 0            * BCD
BCDVoltage      fcb     0, 0            * BCD

BCD060Time      fcb     0, 0            * BCD
BCDQMTime       fcb     0, 0            * BCD
BCDQMSpeed      fcb     0, 0            * BCD

sSpeed          fcb     0               ; sampled binary values of sensors
sVoltage        fcb     0
sTemp           fcb     0
sFuel           fcb     0
sRPM            fcb     0

s060Time        fcb     0
sQMTime         fcb     0
sQMSpeed        fcb     0

cSpeed          fcb     0               ; changed flags
cVoltage        fcb     0
cTemp           fcb     0
cFuel           fcb     0
cRPM            fcb     0
cTripMeter      fcb     0
cOdometer       fcb     0

c060            fcb     0
cQM             fcb     0

*************** All BCD variables are right-justified
****************************** General **************************************
LCDAddress      fdb     0
LCDBkColor      fcb     0
**************************** Decompress *************************************
DecompState     fcb     0
DecompCount     fcb     0

tRuns           fdb     0
ImgByte         fcb     0
ImgBit          fcb     0
Color           fcb     0
**************************** ReadHuffCode ***********************************
CPointer        fdb     0
HuffBit         fcb     0
HCode           fdb     0
HCodeBits       fcb     0
****************************** DrawLine *************************************
LineX1          fcb     0
LineY1          fcb     0
LineX2          fcb     0
LineY2          fcb     0
LineColor       fcb     0

LHeight         fcb     0
LWidth          fcb     0
LCounter        fcb     0
LineLCDBit      fcb     0
LineLCDAddr     fdb     0
LineYAdd        fdb     0
**************************** DrawLCDDigit ***********************************
SLDDigit        fcb     0
SLDOffset       fdb     0
SLDDigitBuf     rmb     96
***************************** DisplaySpeed **********************************
oldSpeed        fcb     0
newSpeed        fcb     0
************************ DrawFuel and DrawTemp ******************************
BarGraph        rmb     6
BGByte          fcb     0
DPMLCDInvert    fcb     0               * for DisplayPMRace
****************************** Int30MS **************************************
PulseCount      fdb     0
QMCount         fdb     0               ;stop at 1000 pulses (1/4 mile!)

SpeedBuf        rmb     31      ;for instantaneous speed calculations
SBufIdx         fcb     0
tSpeed0         fcb     0       ;temp variables
tSpeed1         fcb     0

PMState         fcb     0       ; Performance mode state
*                               ; 0 =off, 1 =testing speed, 2=race!
PMOldSpeed      fcb     0
PMRaceTime      fdb     0
PMTrip060       fcb     0

SFBuf           rmb     16      ;for filtering calculated speed
SFBufIdx        fcb     0
SFSample        fcb     0
SFAvgTimer      fcb     0

SlowCount       fcb     0       ;for updating fuel & temp at 30.5/4 Hz

FuelBuf         rmb     32      ;for filtering measured fuel level
FBufIdx         fcb     0
FuelSample      fcb     0       ;filtered (average) fuel level

TempBuf         rmb     32      ;for filtering measured temperature
TBufIdx         fcb     0
TempSample      fcb     0       ;filtered (average) temperature

VoltageBuf      rmb     16      ;for filtering measured voltage value
VBufIdx         fcb     0
VoltSample      fcb     0
VoltAvgTimer    fcb     0

TripTimer       fcb     0

ImgBuf1         rmb     IMGSIZE
ImgBuf2         rmb     IMGSIZE

VAREND          EQU     *

***********************
* Program starts here *
***********************
        ORG  ROMBS
START
         LDS #STACKBS   set stack pointer, DO NOT set when running under monitor

         sei
         jsr InitSystem
         jsr InitVariables
         jsr InitDisplay
         cli

         clr TimerFired
MLoop1:
         ldaa TimerFired        ;wait until 30 MS timer fires
         beq MLoop1

         jsr UpdateDisplay

         clr TimerFired

         bra MLoop1
         rts

*____________________________________________________________________________
InitLCD:
  clr LCDCtrl           ;reset LCD module(s)
  jsr ILDelay           ;wait a while
  ldaa #$80
  staa LCDCtrl          ;bring it out of reset
  jsr ILDelay           ;wait a while

  clra                  ;graphics mode, display active
  ldab #$32
  jsr OutLCD1
  clra                  ;graphics mode, display active
  ldab #$32
  jsr OutLCD2

  jsr ILDelay           ;wait a while
  ldaa #$01             ;8 pixels per byte
  ldab #7
  jsr OutLCD1
  ldaa #$01             ;8 pixels per byte
  ldab #7
  jsr OutLCD2

  jsr ILDelay           ;wait a while
  ldaa #$02             ;# of columns = 30 bytes * 8 = 240
  ldab #29
  jsr OutLCD1
  ldaa #$02             ;# of columns = 30 bytes * 8 = 240
  ldab #29
  jsr OutLCD2

  jsr ILDelay           ;wait a while
  ldaa #$03             ;duty cycle = 1/128
  ldab #127
  jsr OutLCD1
  ldaa #$03             ;duty cycle = 1/128
  ldab #127
  jsr OutLCD2

  jsr ILDelay
  ldaa #$08             ;Display Start Address = 0
  clrb
  jsr OutLCD1
  ldaa #$08             ;Display Start Address = 0
  clrb
  jsr OutLCD2
  jsr ILDelay
  ldaa #$09
  clrb
  jsr OutLCD1
  ldaa #$09
  clrb
  jsr OutLCD2

  rts


ILDelay:
  pshx
  ldx #$e000
ILDLoop1:
  dex
  bne ILDLoop1
  pulx
  rts

*____________________________________________________________________________
* A = byte to send to instruction register
* B = byte to send to data register
OutLCD1:
  psha
  staa LCDData
  ldaa #$a0
  staa LCDCtrl
  ldaa #$b0
  staa LCDCtrl
  ldaa #$a0
  staa LCDCtrl

  clra
  stab LCDData
  ldaa #$80
  staa LCDCtrl
  ldaa #$90
  staa LCDCtrl
  ldaa #$80
  staa LCDCtrl
  pula
  rts

OutLCD2:
  psha
  staa LCDData
  ldaa #$e0
  staa LCDCtrl
  ldaa #$f0
  staa LCDCtrl
  ldaa #$e0
  staa LCDCtrl

  clra
  stab LCDData
  ldaa #$c0
  staa LCDCtrl
  ldaa #$d0
  staa LCDCtrl
  ldaa #$c0
  staa LCDCtrl
  pula
  rts

*____________________________________________________________________________
UpdateDisplay:
  ldaa PORTD
  bita #$08                     ;test for hi beam
  bne UDNoHiBeam
UDHiBeam:
  jsr SetHiBeam
  bra UDHiBeamEnd

UDNoHiBeam:
  jsr ClearHiBeam

UDHiBeamEnd:
  tst cSpeed                    ;see if speedo needs to be updated
  beq UDSkipSpeedo
  clr cSpeed
  ldab sSpeed
  clra
  ldx #10
  idiv                          ;get ones digit
  stab BCDSpeed+1
  xgdx
  ldx #10
  idiv                          ;get tens digit
  lslb
  lslb
  lslb
  lslb                          ;shift left 4 times for BCD
  orab BCDSpeed+1
  stab BCDSpeed+1
  xgdx                          ;get hundreds digit into D
  stab BCDSpeed
  jsr DisplaySpeed

UDSkipSpeedo:
  tst cVoltage                  ;see if voltage needs to be updated
  beq UDSkipVoltage
  clr cVoltage
  ldab sVoltage
  clra
  ldx #10
  idiv                          ;get tenths digit
  stab BCDVoltage+1
  xgdx
  ldx #10
  idiv                          ;get ones digit
  lslb
  lslb
  lslb
  lslb                          ;shift left 4 times for BCD
  orab BCDVoltage+1
  stab BCDVoltage+1
  xgdx                          ;get tens digit into D
  stab BCDVoltage
  jsr DisplayVoltage

UDSkipVoltage:
  tst cFuel                     ;see if fuel level needs to be updated
  beq UDSkipFuel
  clr cFuel
  ldaa sFuel
  cmpa #48
  blo UDFuelN1
  ldaa #48
UDFuelN1:
  jsr DrawFuel

UDSkipFuel:
  tst cTemp                     ;see if temperature needs to be updated
  beq UDSkipTemp
  clr cTemp
  ldaa sTemp
  jsr DrawTemp

UDSkipTemp:
  tst cTripMeter                ;see if trip meter needs to be displayed
  beq UDSkipTrip
  clr cTripMeter
  jsr DisplayTripMeter

UDSkipTrip:
  tst cOdometer                 ;see if trip meter needs to be displayed
  beq UDSkipOdo
  clr cOdometer
  jsr DisplayOdometer

UDSkipOdo:
  tst c060                      ;see if 0-60 perf. value needs to be displayed
  beq UDSkip060
  clr c060
  ldab s060Time
  clra
  ldx #10
  idiv                          ;get tenths digit
  stab BCD060Time+1
  xgdx
  ldx #10
  idiv                          ;get ones digit
  lslb
  lslb
  lslb
  lslb                          ;shift left 4 times for BCD
  orab BCD060Time+1
  stab BCD060Time+1
  xgdx                          ;get tens digit into D
  stab BCD060Time
  jsr Display060

UDSkip060:
  tst cQM                       ;see if QMile perf shite needs to be displayed
  beq UDSkipQM
  clr cQM
  ldab sQMTime
  clra
  ldx #10
  idiv                          ;get tenths digit
  stab BCDQMTime+1
  xgdx
  ldx #10
  idiv                          ;get ones digit
  lslb
  lslb
  lslb
  lslb                          ;shift left 4 times for BCD
  orab BCDQMTime+1
  stab BCDQMTime+1
  xgdx                          ;get tens digit into D
  stab BCDQMTime

  ldab sQMSpeed
  clra
  ldx #10
  idiv                          ;get ones digit
  stab BCDQMSpeed+1
  xgdx
  ldx #10
  idiv                          ;get tens digit
  lslb
  lslb
  lslb
  lslb                          ;shift left 4 times for BCD
  orab BCDQMSpeed+1
  stab BCDQMSpeed+1
  xgdx                          ;get hundreds digit into D
  stab BCDQMSpeed

  jsr DisplayQMile

UDSkipQM:

  rts
*____________________________________________________________________________
InitVariables:

* reset all variable memory to 0
  ldx #VARSTART
IVLoop1:
  clr ,x
  inx
  cmpx #VAREND
  blo IVLoop1

* read odometer, TripMeter from EEPROM
  ldx #$b600                            ;address of on-MCU EEPROM
  ldy #Odometer
  ldab #9                               ;grab 9 bytes
IVLoop2:
  ldaa ,x
  staa ,y
  inx
  iny
  decb
  bne IVLoop2

* setup LCD for white background
  ldaa #$ff
  staa LCDBkColor

  rts

*____________________________________________________________________________
InitDisplay:

  jsr InitLCD

  jsr ClearLCDAddrs

  ldx #IMGSIZE          ;clear both LCD displays
IDLoop0:
  ldaa #$0c
  ldab #$ff             ;reset display byte
  jsr OutLCD1           ;send it to LCD
  ldaa #$0c
  ldab #$ff             ;reset display byte
  jsr OutLCD2           ;send it to LCD

  dex
  bne IDLoop0

* Decompress the images, display them on the LCDs

  ldx #ImgBuf1          clear out logo buffer
  ldy #54*60
  ldaa #$ff
IDLoop1:
  staa ,x
  inx
  dey
  bne IDLoop1

  ldd #0                setup the decompression pointer
  std LCDAddress
  staa DecompState      setup decompression state (logo)
  ldaa #30
  staa DecompCount      setup logo counter
  jsr Decompress

  jsr DisplayImages

  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ClearLCDAddrs:
  ldaa #$0a             ;Clear Cursor Addresses for both LCDs
  clrb
  jsr OutLCD1
  ldaa #$0b
  clrb
  jsr OutLCD1
  ldaa #$0a
  clrb
  jsr OutLCD2
  ldaa #$0b
  clrb
  jsr OutLCD2
  rts
*____________________________________________________________________________
InitSystem:

*********************** Init Options Register
  ldaa #$93             ;A/D activated, IRQ level-sensitive, COP deactivated
  staa OPTION           init option register

*********************** Interrupt vectors stored in EEPROM

*********************** Setup Pulse Accumulator
  ldaa #$53
  staa PACTL
  ldaa #$40
  staa TFLG2            ;clear real-time interrupt flag
  staa TMSK2

*********************** Deactivate SCI & SPI, set data direction for port D
  ldaa #$20
  staa DDRD
  clr SPCR
  clr SCCR2

  rts

*____________________________________________________________________________
ClearPMDisplay:

* initialize performance counters to blank
  ldaa #$0a
  staa BCD060Time
  staa BCDQMTime
  staa BCDQMSpeed
  ldaa #$aa
  staa BCD060Time+1
  staa BCDQMTime+1
  staa BCDQMSpeed+1

* Display it
  jsr DisplayPMOff

  jsr Display060
  jsr DisplayQMile

  sei
  ldd #1841
  std LCDAddress
  ldab #56              ;56 lines
CPMDLoop1:
  pshb

  ldaa #$0a             ;Set Cursor Address low order
  ldab LCDAddress+1
  jsr OutLCD2
  ldaa #$0b             ;Set cursor address high order
  ldab LCDAddress
  jsr OutLCD2

  ldaa #19              ;19 bytes wide
CPMDLoop2:
  psha

  ldaa #$0c
  ldab LCDBkColor       ;reset display byte
  jsr OutLCD2           ;send it to LCD

  pula
  deca
  bne CPMDLoop2

  ldd LCDAddress
  addd #30              ;go to next line
  std LCDAddress

  pulb
  decb
  bne CPMDLoop1

  cli
  rts
*____________________________________________________________________________
DisplaySpeed:
  ldaa sSpeed
  cmpa #150                     ;max analog speedo at 150mph
  blo DSN1
  ldaa #150
DSN1:
  staa newSpeed

  clra
  ldab oldSpeed
  lsld
  lsld
  addd #SinCos
  xgdx
  ldab oldSpeed
  lsrb
  lsrb
  lsrb
  andb #$fe
  abx

  ldaa ,x                get cos (x) value
  ldab #181
  mul
  adda #90
  staa LineX2

  ldaa 1,x               get sin (x) value
  ldab #181
  mul
  adda #38
  staa LineY2

  ldaa #148
  staa LineX1
  ldaa #96
  staa LineY1

  jsr ClrLine           ;erase old line

  clra
  ldab newSpeed
  lsld
  lsld
  addd #SinCos
  xgdx
  ldab newSpeed
  stab oldSpeed         ;save this so we can erase this line next time
  lsrb
  lsrb
  lsrb
  andb #$fe
  abx

  ldaa ,x                get cos (x) value
  ldab #181
  mul
  adda #90
  staa LineX2

  ldaa 1,x               get sin (x) value
  ldab #181
  mul
  adda #38
  staa LineY2

  ldaa #148
  staa LineX1
  ldaa #96
  staa LineY1

  jsr SetLine           ;draw new line

  ldx #124              ;one's digit
  ldaa BCDSpeed+1
  anda #$0f             ;isolate low-order nybble
  jsr DrawLCDDigit

  ldx #121              ;ten's digit
  ldaa BCDSpeed+1
  lsra
  lsra
  lsra
  lsra                  ;shift right by four to get binary value from BCD
  jsr DrawLCDDigit

  tst BCDSpeed          ;set the leading one if speed >= 100mph
  bne DSHundred
  jsr ClearLCDLeading1
  jmp DSDone
DSHundred:
  jsr SetLCDLeading1
DSDone:
  rts
*____________________________________________________________________________
* A = Temperature (0 = 25C, 48 = 145C)
DrawTemp:
  ldx #BarGraph

  clr ,x
  clr 1,x
  clr 2,x
  clr 3,x
  clr 4,x
  clr 5,x
  ldab #$ff
DTLoop1:
  bita #$f8
  beq DTL1End
  stab ,x
  inx
  suba #8
  bra DTLoop1

DTL1End:
  tsta
  beq DTL2End
  clrb
DTLoop2:
  sec
  rolb
  deca
  bne DTLoop2
  stab ,x               ;now [BarGraph] is a binary bit mask

DTL2End:
  ldaa #$88
  staa BGByte

  sei                   ;dont allow interrupts
  ldx #181              ;starting address on LCD panel
  stx LCDAddress
  ldy #22               ;22 lines
DTLoop3:
  ldx #BarGraph
  ldaa ,x
  anda BGByte
  eora LCDBkColor
  jsr OutLCD2Byte       ;this sets the LCD Address

  ldaa #5               ;5 more bytes
DTLoop3_1:
  psha

  ldaa #$0c
  inx
  ldab ,x
  andb BGByte
  eorb LCDBkColor
  jsr OutLCD2

  pula
  deca
  bne DTLoop3_1

  ldd LCDAddress                ;go to next line
  addd #30
  std LCDAddress

  ror BGByte
  ldaa BGByte
  bita #$f0
  bne DTL3N1
  ldaa #$88
  staa BGByte

DTL3N1:
  dey
  bne DTLoop3
  cli                           ;reenable interrupts
  rts

*____________________________________________________________________________
* A = fuel level (0 = empty, 48 = full)
DrawFuel:
  ldx #BarGraph

  ldab LCDBkColor
  stab ,x
  stab 1,x
  stab 2,x
  stab 3,x
  stab 4,x
  stab 5,x
  comb
DFLoop1:
  bita #$f8
  beq DFL1End
  stab ,x
  inx
  suba #8
  bra DFLoop1

DFL1End:
  tsta
  beq DFL2End
  clrb
DFLoop2:
  sec
  rolb
  deca
  bne DFLoop2
  eorb LCDBkColor
  stab ,x

DFL2End:
  sei
  ldx #1471             ;starting address on LCD panel
  stx LCDAddress
  ldy #22               ;22 lines
DFLoop3:
  ldx #BarGraph
  ldaa ,x
  jsr OutLCD2Byte
  ldaa #$0c
  ldab 1,x
  jsr OutLCD2
  ldaa #$0c
  ldab 2,x
  jsr OutLCD2
  ldaa #$0c
  ldab 3,x
  jsr OutLCD2
  ldaa #$0c
  ldab 4,x
  jsr OutLCD2
  ldaa #$0c
  ldab 5,x
  jsr OutLCD2
  ldd LCDAddress
  addd #30
  std LCDAddress
  dey
  bne DFLoop3
  cli
  rts

*____________________________________________________________________________
SetHiBeam:
  sei
  ldx #HiBeamImg
  ldd #137
  std LCDAddress

  ldab #7               ;7 lines
SHBLoop1:
  pshb                  ;save loop counter

  ldaa ,x               ;first byte
  eora LCDBkColor
  jsr OutLCD1Byte
  inx

  ldab ,x               ;second byte
  eorb LCDBkColor
  ldaa #$0c
  jsr OutLCD1
  inx

  ldab ,x               ;third byte
  eorb LCDBkColor
  ldaa #$0c
  jsr OutLCD1
  inx

  ldd LCDAddress
  addd #30
  std LCDAddress

  pulb
  decb
  bne SHBLoop1
  cli
  rts

ClearHiBeam:
  sei
  ldd #137
  std LCDAddress

  ldab #7               ;7 lines
CHBLoop1:
  pshb                  ;save loop counter

  ldaa LCDBkColor       ;first byte
  jsr OutLCD1Byte

  ldaa #$0c
  ldab LCDBkColor       ;second byte
  jsr OutLCD1

  ldaa #$0c
  ldab LCDBkColor       ;third byte
  jsr OutLCD1

  ldd LCDAddress
  addd #30
  std LCDAddress

  pulb
  decb
  bne CHBLoop1
  cli
  rts

*____________________________________________________________________________
DisplayPMOff:
  ldx #PMOffImg
  lda #0
  bra DisplayPMode

DisplayPMRace:
  ldx #PMRaceImg
  lda #$ff
  bra DisplayPMode

DisplayPMode:
  eora LCDBkColor
  staa DPMLCDInvert
  sei
  ldy #85
  sty LCDAddress

  ldab #10              ;10 lines
DPMLoop1:
  pshb                  ;save loop counter

  ldaa ,x               ;first byte
  eora DPMLCDInvert
  jsr OutLCD2Byte
  inx

  ldaa #$0c
  ldab ,x               ;second byte
  eorb DPMLCDInvert
  jsr OutLCD2
  inx

  ldaa #$0c
  ldab ,x               ;third byte
  eorb DPMLCDInvert
  jsr OutLCD2
  inx

  ldaa #$0c
  ldab ,x
  eorb DPMLCDInvert
  jsr OutLCD2
  inx

  ldd LCDAddress
  addd #30
  std LCDAddress

  pulb
  decb
  bne DPMLoop1
  cli
  rts

*____________________________________________________________________________
DisplayOdometer:

  ldx #3525
  ldaa Odometer
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #3526
  ldaa Odometer
  anda #$0f
  jsr DrawSmallDigit

  ldx #3527
  ldaa Odometer+1
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #3528
  ldaa Odometer+1
  anda #$0f
  jsr DrawSmallDigit

  ldx #3529
  ldaa Odometer+2
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #3530
  ldaa Odometer+2
  anda #$0f
  jsr DrawSmallDigit
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayTripMeter:
  ldx #2821
  ldaa TripMeter
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #2822
  ldaa TripMeter
  anda #$0f
  jsr DrawSmallDigit

  ldx #2823
  ldaa TripMeter+1
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #2824
  ldaa TripMeter+1
  anda #$0f
  jsr DrawSmallDigit
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayVoltage:
  ldx #6692
  ldaa BCDVoltage
  anda #$0f
  jsr DrawBigDigit

  ldx #6693
  ldaa BCDVoltage+1
  lsra
  lsra
  lsra
  lsra
  jsr DrawBigDigit
  ldx #6695
  ldaa BCDVoltage+1
  anda #$0f
  jsr DrawBigDigit
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayDigRPM:
  ldx #1471
  ldaa BCDRPM
  lsra
  lsra
  lsra
  lsra
  jsr DrawBigDigit
  ldx #1472
  ldaa BCDRPM
  anda #$0f
  jsr DrawBigDigit

  ldx #1473
  ldaa BCDRPM+1
  lsra
  lsra
  lsra
  lsra
  jsr DrawBigDigit
  ldx #1474
  ldaa BCDRPM+1
  anda #$0f
  jsr DrawBigDigit
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Display060:
  ldx #4606
  ldaa BCD060Time
  anda #$0f
  jsr DrawSmallDigit

  ldx #4607
  ldaa BCD060Time+1
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #4608
  ldaa BCD060Time+1
  anda #$0f
  jsr DrawSmallDigit
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayQMile:
  ldx #5116
  ldaa BCDQMTime
  anda #$0f
  jsr DrawSmallDigit

  ldx #5117
  ldaa BCDQMTime+1
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #5118
  ldaa BCDQMTime+1
  anda #$0f
  jsr DrawSmallDigit

  ldx #5416
  ldaa BCDQMSpeed
  anda #$0f
  jsr DrawSmallDigit

  ldx #5417
  ldaa BCDQMSpeed+1
  lsra
  lsra
  lsra
  lsra
  jsr DrawSmallDigit
  ldx #5418
  ldaa BCDQMSpeed+1
  anda #$0f
  jsr DrawSmallDigit

  rts

*____________________________________________________________________________
* This works for either LCD module
* X = LCD offset of digit (>= $f00 for LCD #2)
* A = binary digit (0-9)
DrawBigDigit:
  tab
  lslb
  lslb
  lslb
  lslb
  ldy #BigDigitBits
  aby

  sei
  cpx #$f00
  bhs DBDLcd2
DBDLcd1:
  ldab #15                      ;fifteen lines high
DBDL1Loop1:
  stx LCDAddress
  ldaa ,y
  eora LCDBkColor
  jsr OutLCD1Byte
  iny
  xgdx
  addd #30                      ;go to next line
  xgdx
  decb
  bne DBDL1Loop1
  cli
  rts

DBDLcd2:
  xgdx
  subd #$f00
  xgdx
  ldab #15                      ;fifteen lines high
DBDL2Loop1:
  stx LCDAddress
  ldaa ,y
  eora LCDBkColor
  jsr OutLCD2Byte
  iny
  xgdx
  addd #30                      ;go to next line
  xgdx
  decb
  bne DBDL2Loop1
  cli
  rts

*____________________________________________________________________________
* This works for either LCD module
* X = LCD offset of digit (>= $f00 for LCD #2)
* A = binary digit (0-9)
DrawSmallDigit:
  tab
  lslb
  lslb
  lslb
  ldy #DigitBits
  aby

  sei
  cpx #$f00
  bhs DSDLcd2
DSDLcd1:
  ldab #7                       ;seven lines high
DSDL1Loop1:
  stx LCDAddress
  ldaa ,y
  eora LCDBkColor
  jsr OutLCD1Byte
  iny
  xgdx
  addd #30                      ;go to next line
  xgdx
  decb
  bne DSDL1Loop1
  cli
  rts

DSDLcd2:
  xgdx
  subd #$f00
  xgdx
  ldab #7                       ;seven lines high
DSDL2Loop1:
  stx LCDAddress
  ldaa ,y
  eora LCDBkColor
  jsr OutLCD2Byte
  iny
  xgdx
  addd #30                      ;go to next line
  xgdx
  decb
  bne DSDL2Loop1
  cli
  rts

*____________________________________________________________________________
* Note this is only for LCD #1
* X = LCD offset of digit
* A = binary digit (0-9)
DrawLCDDigit:
  stx SLDOffset
  tab                           ;b = LCD digit
  ldx #LCDDigitSegs
  abx                           ;x = pointer to digit information
  ldaa ,x
  staa SLDDigit

  ldab #96                      ;clear out the digit buffer
  ldx #SLDDigitBuf
SLDLoop0:
  clr ,x
  inx
  decb
  bne SLDLoop0

  ldaa #1
  bita SLDDigit
  beq SLDSkipA

  ldx #SLDDigitBuf
  ldy #LCDSegA
  ldab #9
SLDLoopA:
  ldaa ,y
  staa ,x
  inx
  iny
  decb
  bne SLDLoopA

SLDSkipA:
  lsr SLDDigit
  ldaa #1
  bita SLDDigit
  beq SLDSkipB

  ldx #SLDDigitBuf+5
  ldy #LCDSegBC
  ldab #14
SLDLoopB:
  ldaa ,y
  oraa ,x
  staa ,x
  inx
  inx
  inx
  iny
  decb
  bne SLDLoopB

SLDSkipB:
  lsr SLDDigit
  ldaa #1
  bita SLDDigit
  beq SLDSkipC

  ldx #SLDDigitBuf+50
  ldy #LCDSegBC
  ldab #14
SLDLoopC:
  ldaa ,y
  oraa ,x
  staa ,x
  inx
  inx
  inx
  iny
  decb
  bne SLDLoopC

SLDSkipC:
  lsr SLDDigit
  ldaa #1
  bita SLDDigit
  beq SLDSkipD

  ldx #SLDDigitBuf+84
  ldy #LCDSegD
  ldab #9
SLDLoopD:
  ldaa ,y
  oraa ,x
  staa ,x
  inx
  iny
  decb
  bne SLDLoopD

SLDSkipD:
  lsr SLDDigit
  ldaa #1
  bita SLDDigit
  beq SLDSkipE

  ldx #SLDDigitBuf+48
  ldy #LCDSegEF
  ldab #14
SLDLoopE:
  ldaa ,y
  oraa ,x
  staa ,x
  inx
  inx
  inx
  iny
  decb
  bne SLDLoopE

SLDSkipE:
  lsr SLDDigit
  ldaa #1
  bita SLDDigit
  beq SLDSkipF

  ldx #SLDDigitBuf+3
  ldy #LCDSegEF
  ldab #14
SLDLoopF:
  ldaa ,y
  oraa ,x
  staa ,x
  inx
  inx
  inx
  iny
  decb
  bne SLDLoopF

SLDSkipF:
  lsr SLDDigit
  ldaa #1
  bita SLDDigit
  beq SLDSkipG

  ldx #SLDDigitBuf+42
  ldy #LCDSegG
  ldab #9
SLDLoopG:
  ldaa ,y
  oraa ,x
  staa ,x
  inx
  iny
  decb
  bne SLDLoopG

SLDSkipG:
  sei
  ldd SLDOffset         ;now dump the LCD Digit buffer out to the LCD
  std LCDAddress

  ldab #32              ;32 lines
  ldx #SLDDigitBuf
SLDLoop1:
  pshb                  ;save loop counter

  ldaa ,x               ;first byte
  eora LCDBkColor
  jsr OutLCD1Byte
  inx

  ldaa #$0c
  ldab ,x               ;second byte
  eorb LCDBkColor
  jsr OutLCD1
  inx

  ldaa #$0c
  ldab ,x               ;third byte
  eorb LCDBkColor
  jsr OutLCD1
  inx

  ldd LCDAddress
  addd #30
  std LCDAddress

  pulb
  decb
  bne SLDLoop1
  cli
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SetLCDLeading1:
  sei
  ldx #150
  stx LCDAddress

  ldab #29              ;29 iterations
  ldx #LCDLeading1
SLL1Loop1:
  pshb                  ;save loop counter

  ldaa ,x
  eora LCDBkColor
  jsr OutLCD1Byte
  inx

  ldd LCDAddress
  addd #30
  std LCDAddress

  pulb
  decb
  bne SLL1Loop1
  cli
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ClearLCDLeading1:
  sei
  ldx #150
  stx LCDAddress

  ldab #29              ;29 iterations
CLL1Loop1:
  ldaa LCDBkColor
  jsr OutLCD1Byte

  xgdx
  addd #30
  std LCDAddress
  xgdx

  decb
  bne CLL1Loop1
  cli
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OutLCD1Byte:
  pshb
  psha
  ldaa #$0a             ;Set Cursor Address low order
  ldab LCDAddress+1
  jsr OutLCD1
  ldaa #$0b             ;Set cursor address high order
  ldab LCDAddress
  jsr OutLCD1
  pulb
  ldaa #$0c
  jsr OutLCD1
  pulb
  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OutLCD2Byte:
  pshb
  psha
  ldaa #$0a             ;Set Cursor Address low order
  ldab LCDAddress+1
  jsr OutLCD2
  ldaa #$0b             ;Set cursor address high order
  ldab LCDAddress
  jsr OutLCD2
  pulb
  ldaa #$0c
  jsr OutLCD2
  pulb
  rts

*____________________________________________________________________________
SetLine:

  ldaa LCDBkColor
  bita #$ff
  beq SLN1
  ldaa #$0e
  staa LineColor
  bra DrawLine
SLN1:
  ldaa #$0f
  staa LineColor
  bra DrawLine

ClrLine:
  ldaa LCDBkColor
  bita #$ff
  beq CLN1
  ldaa #$0f
  staa LineColor
  bra DrawLine
CLN1:
  ldaa #$0e
  staa LineColor

DrawLine:
  ldaa LineX2                   ;make sure we go left to right
  cmpa LineX1
  bhs DLN1
  ldd LineX1                    ;swap start and end coords
  ldx LineX2
  std LineX2
  stx LineX1
DLN1:
  ldaa LineY1                   ;calculate LCD Address for starting coord
  ldab #30
  mul
  xgdx                          ;x = LCD Address for start of line
  ldab LineX1                   ;get X coord
  lsrb                          ;shift right 3 times to divide by 8
  lsrb
  lsrb
  abx                           ;now x = LCD Address for starting pixel
  stx LineLCDAddr
  ldaa LineX1                   ;get X coord
  anda #7                       ;get bit #
  staa LineLCDBit

  ldaa LineX2
  suba LineX1                   ;a = width of line
  inca
  staa LWidth

  ldaa LineY2
  suba LineY1
  bge DLN2
  nega
DLN2:
  inca
  staa LHeight                  ;a = height of line
  cmpa LWidth
  bhs LineVertical

LineHorizontal:
  ldx  #30                      ;assume top to bottom (y increment = 30 bytes)
  ldab LineY2
  cmpb LineY1                   ;make sure this is the case
  bhs LHN1
  ldx #-30                      ;nope, y increment = -30 bytes
LHN1:
  stx LineYAdd                  ;store y increment

*  ldaa LWidth                   ;initialize Y increment counter
*  lsra
*  staa LCounter
  clr LCounter

  sei
  clra
  ldab LWidth                   ;interate X times
  xgdy
LHLoop1:
  ldaa #$0a             ;Set Cursor Address low order
  ldab LineLCDAddr+1
  jsr OutLCD1
  ldaa #$0b             ;Set cursor address high order
  ldab LineLCDAddr
  jsr OutLCD1
  ldaa LineColor
  ldab LineLCDBit
  jsr OutLCD1           ;clear a point
  inc LineLCDBit        ;increment x by 1
  ldaa LineLCDBit
  bita #$08
  beq LHL1N1
  ldx LineLCDAddr       ;increment LCD address by 1
  inx
  stx LineLCDAddr
  clr LineLCDBit        ;bit = 0
LHL1N1:
  ldaa LCounter         ;get Y increment counter
  adda LHeight
  bvs LHL1N2
  staa LCounter
  cmpa LWidth
  blo LHL1N3
LHL1N2:
  suba LWidth
  staa LCounter
  ldd LineLCDAddr       ;increment Y
  addd LineYAdd
  std LineLCDAddr
LHL1N3:
  dey
  bne LHLoop1
  cli
  rts

LineVertical:
  ldx #30                       ;assume top to bottom (y increment = 30 bytes)
  ldab LineY2
  cmpb LineY1                   ;make sure this is the case
  bhs LVN1
  ldx #-30                      ;nope, y increment = -30 bytes
LVN1:
  stx LineYAdd                  ;store y increment

*  ldaa LHeight                  ;initialize Y increment counter
*  lsra
*  staa LCounter
  clr LCounter

  sei
  clra
  ldab LHeight                  ;interate Y times
  xgdy
LVLoop1:
  ldaa #$0a             ;Set Cursor Address low order
  ldab LineLCDAddr+1
  jsr OutLCD1
  ldaa #$0b             ;Set cursor address high order
  ldab LineLCDAddr
  jsr OutLCD1
  ldaa LineColor
  ldab LineLCDBit
  jsr OutLCD1           ;clear a point

  ldd LineLCDAddr       ;increment Y
  addd LineYAdd
  std LineLCDAddr

  ldaa LCounter         ;get X increment counter
  adda LWidth
  bvs LVL1N1
  staa LCounter
  cmpa LHeight
  blo LVL1N2
LVL1N1:
  suba LHeight
  staa LCounter
  inc LineLCDBit        ;increment x by 1
  ldaa LineLCDBit
  bita #$08
  beq LVL1N2
  ldx LineLCDAddr       ;increment LCD address by 1
  inx
  stx LineLCDAddr
  clr LineLCDBit        ;bit = 0
LVL1N2:
  dey
  bne LVLoop1
  cli
  rts


*____________________________________________________________________________
Decompress:
  ldx #Huff_data        Setup huffman code extracting variables
  stx CPointer
  ldaa #8
  staa HuffBit

  ldx TotalRuns         Setup initial loop variables
  stx tRuns
  clr Color
  ldaa #8
  staa ImgBit

DLoop1:
  jsr ReadHuffCode      returns Run Length in X
  ldab Color            get color in accum. b
  cpx #$100             skip color inversion
  beq DL1N1             if run length = 256
  com Color             invert color for next time
DL1N1:
  ldaa ImgByte
DLoop1_1:
  asrb                  get color into carry bit
  rora                  put into image byte
  dec ImgBit            -> Check to see if the image byte is full
  bne DL11N1

  jsr DecompOutByte

  ldaa #8               reset ImgBit = 8
  staa ImgBit
DL11N1:
  dex
  bne DLoop1_1
DL11End:
  staa ImgByte          save these for next time

  ldx tRuns
  dex
  stx tRuns
  cmpx #0
  bne DLoop1

  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DecompOutByte:
  tst DecompState       ;see if we are decompressing the logo or the images
  beq LCDSBState0

  pshx                  ;we are decompressing the images
  ldx LCDAddress
  inx
  stx LCDAddress        ;store incremented address
  xgdx
  addd #ImgBuf1-1
  xgdx
  staa ,x               ;put in memory buffer
  pulx
  rts

LCDSBState0:
  pshx                  ;we are decompressing the logo
  ldx LCDAddress
  inx
  stx LCDAddress        ;store incremented addreses
  xgdx
  addd #ImgBuf1+29
  xgdx
  coma
  staa ,x               ;put in memory buffer
  dec DecompCount
  bne LCDSBS0N1
  xgdx
  ldd LCDAddress        ;end of line
  addd #30              ;go to next 60-byte wide line
  std LCDAddress
  xgdx
  ldaa #30              ;reset DecompCount
  staa DecompCount
  cpx #54*60            ;are we at the end of the logo display?
  blo LCDSBS0N1
  psha
  pshb
  jsr DisplayLogo       ;display the logo animation
  clr LCDAddress        ;clear the LCDAddress pointer
  clr LCDAddress+1
  inc DecompState       ;go to state 1 (decompressing images)
  pulb
  pula
LCDSBS0N1:
  pulx
  rts

*___________________________________________________________________________
DisplayImages:
  jsr ClearLCDAddrs     ;Set both LCD cusor addresses to 0

  ldx #ImgBuf1
  ldy #ImgBuf2
DILoop1:
  ldaa #$0c
  ldab ,x
  eorb LCDBkColor
  jsr OutLCD1

  ldaa #$0c
  ldab ,y
  eorb LCDBkColor
  jsr OutLCD2

  inx
  iny
  cpx #ImgBuf1+3840
  bne DILoop1

* erase the tachometer band

  ldx #SinCos+618
DILoop2:
  ldaa ,x                get cos (x) value
  adda #66
  staa LineX2
  ldaa ,x                get cos (x) value
  ldab #228
  mul
  addb #128
  adca #75
  staa LineX1

  ldaa 1,x               get sin (y) value
  adda #14
  staa LineY2
  ldaa 1,x               get sin (y) value
  ldab #228
  mul
  addb #128
  adca #23
  staa LineY1
  pshx
  jsr ClrLine
  dec LineY1
  dec LineY2
  jsr ClrLine
  pulx
  dex
  dex
  cpx #SinCos
  bhs DILoop2

  ldaa #1                       ;set all changed flags so we update everything
  staa cSpeed
  staa cVoltage
  staa cTemp
  staa cFuel
  staa cRPM
  staa cTripMeter
  staa cOdometer

  jsr ClearPMDisplay            ;reset Performance mode display

  rts

*___________________________________________________________________________
DisplayLogo:
  ldaa #31
  staa DecompCount      ;big loop counter

DLogoLoop1:
* Set cursor address for logo

  ldaa #$0a             ;Set Cursor Address low order
  ldab #$56
  jsr OutLCD1
  ldaa #$0b             ;Set cursor address high order
  ldab #$4
  jsr OutLCD1

* display logo image
  ldx #ImgBuf1          ;x = pointer to logo image in memory
  ldaa #54              ;54 rows
DLogoLoop1_1:
  ldab #30              ;30 bytes per row
DLogoLoop1_1_1:
  pshb
  psha
  ldaa #$0c
  ldab ,x
  jsr OutLCD1
  pula
  pulb
  inx
  decb
  bne DLogoLoop1_1_1    ;end of row?
  xgdx
  addd #30
  xgdx
  deca
  bne DLogoLoop1_1      ;end of image?

* move logo to the left by 8 pixels
  clrb
  ldx #ImgBuf1+3239     ;54*60-1
  ldy #54*60
DLogoLoop1_2:
  ldab ,x
  staa ,x
  tba
  dex
  dey
  bne DLogoLoop1_2

  dec DecompCount
  bne DLogoLoop1
  rts

*____________________________________________________________________________
* Returns next run length in X
ReadHuffCode:
  clr HCodeBits         ;0 initial bits for huffman code
  clr HCode
  clr HCode+1

  ldx CPointer
  ldaa ,x               ;a = current byte in huffman data stream
  ldab #8
  subb HuffBit
  bitb #$ff
  beq RHCL0End
RHCLoop0:
  lsla                  ;shift A left once
  decb
  bne RHCLoop0
RHCL0End:

RHCLoop1:
  rola                  ;shift 1 bit from huffman stream into huffman code
  rol HCode+1
  rol HCode

  inc HCodeBits         ;1 more bit in the huffman code
  dec HuffBit
  bne RHCL1N1
  ldaa #8
  staa HuffBit
  ldx CPointer
  inx
  stx CPointer
  ldaa ,x               ;get next byte in huffman stream
RHCL1N1:

  psha                  ;save huffman byte
  ldab HCodeBits        ;get # of bits in code
  lslb
  lslb
  clra
  addd #HCBitPtrs
  xgdx
  ldaa 2,x              ;load # of huffman codes with this many bits
  tsta                  ;skip search if there are 0 codes with
  beq RHCL11End         ;this number of bits
  ldx ,x                ;get pointer to first huffman code

  xgdx
  addd #HCTable
  xgdx

  ldy HCode             ;code to match is in Y
RHCLoop1_1:
  cpy ,x
  beq RHCFound

  inx
  inx
  inx
  deca
  bne RHCLoop1_1
RHCL11End:
  pula
  jmp RHCLoop1

RHCFound:
  pula                  ;pull A off of stack
  ldab 2,x              ;get Run Length value
  clra
  xgdx
  inx                   ;run length = X

  rts

*____________________________________________________________________________
* 32.768 ms timer interrupt
Int30MS:

  ldaa sSpeed
  staa PMOldSpeed               ;save currently displayed speed

* get Pulse Accumulator Count and store in circular SpeedBuf buffer
  clra
  ldab PACNT                    ;get pulse accum. count in reg. B
  staa PACNT
  std PulseCount                ;store here for now

  tba
  ldab SBufIdx
  ldx #SpeedBuf
  abx
  staa ,x                       ;store most recent pulse count in buffer

  ldab #14                      ;number of pulse samples to accumulate
I30SpeedLoop1:
  inx
  cmpx #SpeedBuf+31
  blo I30SL1N1
  ldx #SpeedBuf                 ;reset to beginning of circular buffer
I30SL1N1:
  adda ,x                       ;accumulate pulse count sample into A
  decb
  bne I30SpeedLoop1

  staa tSpeed0                  ;save speed for most recent 1/2 second

  clra                          ;accumulate -1s <= t <= -.5s
  ldab #15                      ;number of pulse samples to accumulate
I30SpeedLoop2:
  inx
  cmpx #SpeedBuf+31
  blo I30SL2N1
  ldx #SpeedBuf                 ;reset to beginning of circular buffer
I30SL2N1:
  adda ,x                       ;accumulate pulse count sample into A
  decb
  bne I30SpeedLoop2

  inx
  cmpx #SpeedBuf+31
  blo I30SpeedN1
  ldx #SpeedBuf
I30SpeedN1:
  ldab ,x                       ;get oldest speed sample
  incb                          ;round up
  lsrb                          ;divide by 2
  aba                           ;accumulate

  staa tSpeed1                  ;save speed for 2nd most recent 1/2 second
  nega
  adda tSpeed0                  ;get tSpeed0-tSpeed1
  asra
  adda tSpeed0
  adda tSpeed1                  ;now A = predicted instantaneous speed

  dec SBufIdx                   ;decrement index variable
  bpl I30SpeedN2
  ldab #30
  stab SBufIdx
I30SpeedN2:

  ldab #230                     ;multiplication factor
  mul                           ;get speed in MPH
  cmpa #200                     ;check for > 200 mph
  blo I30SpeedN3
  ldaa #199                     ;max out at 199
I30SpeedN3:
* now a = calculated instantaneous speed value (in MPH)

  ldx #SFBuf
  ldab SFBufIdx
  abx
  staa ,x                       ;store speed sample in ring buffer
  staa SFSample

  incb                          ;advance ring buffer pointer
  andb #$0f                     ;bit mask
  stab SFBufIdx
  ldx #SFBuf
  abx

  suba ,x                       ;get differential
  anda #$fc                     ;test high bits
  beq I30SpeedN4
  coma
  anda #$fc
  beq I30SpeedN4
  ldaa SFSample
  staa sSpeed
  inc cSpeed                    ;set voltage display update flag
  clr SFAvgTimer
  bra I30SpeedEnd

I30SpeedN4:
  ldx #SFBuf
  ldaa #16                      ;16-entry ring buffer
  ldy #0
I30SpeedLoop3:
  ldab ,x                       ;get sum of buffer entry values
  inx
  aby
  deca
  bne I30SpeedLoop3

  xgdy                          ;get sum into D accumulator
  lsrd
  lsrd
  lsrd
  lsrd                          ;now D is average
  cmpb sSpeed                   ;check to see if average = displayed value
  beq I30SpeedN5
  inc SFAvgTimer
  ldaa SFAvgTimer
  cmpa #12
  bne I30SpeedEnd

  stab sSpeed
  inc cSpeed                    ;update display

I30SpeedN5:
  clr SFAvgTimer

I30SpeedEnd:
  ldaa PMState                  ;get state of performance mode
  tsta
  bne I30PModeN1
*                       PMode state = 0, off
  ldaa PMOldSpeed               ;get currently displayed speed
  beq I30PMode0N1               ;if not = 0
  jmp I30PModeEnd               ;then get outa here
I30PMode0N1:
  ldaa PulseCount+1             ;else get last pulse count
  bne I30PMode0N2               ;if = 0
  jmp I30PModeEnd               ;then get outa here
I30PMode0N2:
  ldx #0
  stx QMCount                   ;clear quarter-mile counter
  stx PMRaceTime                ;clear race timer
  clr PMTrip060
  inc PMState                   ;go to state 1 (test speed)
  jmp I30PModeEnd               ;get outa here

I30PModeN1:
  psha
  ldd PulseCount
  addd QMCount
  std QMCount                   ;accumulate distance for quarter mile
  ldd PMRaceTime
  addd #1                       ;add 1 tick to the clock
  std PMRaceTime
  pula
  cmpa #1
  bne I30PMode2                 * mode 1 = wait for 2 secs & check speed
  ldd PMRaceTime
  cmpd #61
  blo I30PModeEnd
  ldaa SFSample                 ; get instantaneous speed (MPH)
  cmpa #15                      ; see if we are going 15
  bhs I30PMN1_1                 ; if we are, go to race mode!
  clr PMState                   ; otherwise  go to mode 0
  bra I30PModeEnd

I30PMN1_1:
  ldaa #2                       ;go to mode 2 (race!)
  staa PMState
  jsr ClearPMDisplay            ;clear graph, meters
  jsr DisplayPMRace             ;show race mode!

I30PMode2:
*                                we are in race mode!
  ldd PMRaceTime                ;time since starting
  cpd #450
  bhi I30PM2N1                  ;if > 450 then dont plot point
  ldx #3
  idiv
  tstb                          ;if remainder != 0
  bne I30PM2N1                  ;the dont plot point
  xgdx                          ;get time (tenths of a sec.) in B
  ldaa SFSample                 ;A = instantaneous speed
  jsr I30PlotPoint              ;plot point on the graph

I30PM2N1:
  tst PMTrip060                 ;have we hit 60 before?
  bne I30PM2N2                  ;if not
  ldaa SFSample                 ;get current speed
  cmpa #60                      ;are we going 60 now?
  blo I30PM2N2                  ;if so
  ldd PMRaceTime                ;get current time
  ldx #3
  idiv                          ;div by 3 to get tenths of a sec
  xgdx                          ;get time in B
  stab s060Time                 ;store
  inc c060                      ;update display
  inc PMTrip060                 ;now we have hit 60
I30PM2N2:
  ldd QMCount                   ;get # of pulses since we started
  cpd #1000                     ;have we hit the QM yet?
  blo I30PM2N3                  ;if so
  ldaa SFSample                 ;get current speed
  staa sQMSpeed                 ;store
  ldd PMRaceTime                ;get current time
  ldx #3
  idiv                          ;div by 3 to get tenths of a sec
  xgdx                          ;get time in B
  stab sQMTime
  inc cQM                       ;update quarter-mile display
  clr PMState                   ;go to state 0
  jsr DisplayPMOff              ;display race mode: off
I30PM2N3:
  ldd PMRaceTime                ;get race time
  cmpd #765                     ;have we been in race for > 25.5 seconds?
  blo I30PModeEnd               ;if so
  clr PMState                   ;go to state 0
  jsr DisplayPMOff

I30PModeEnd:

  ldd MileCount                 ;get odometer pulse count
  addd PulseCount
  cmpd #4000
  blo I30N1
  subd #4000
  psha                          ;save reg A
  ldaa Odometer+2               ;increment the odometer reading
  adda #1
  daa
  staa Odometer+2
  ldaa Odometer+1
  adca #0
  daa
  staa Odometer+1
  ldaa Odometer
  adca #0
  daa
  staa Odometer
  inc cOdometer                 ;set display flag
  pula
I30N1:
  std MileCount

  ldd TripCount                 ;get trip meter pulse count
  addd PulseCount
  cmpd #400
  blo I30N2
  subd #400
  psha
  ldaa TripMeter+1              ;increment trip meter
  adda #1
  daa
  staa TripMeter+1
  ldaa TripMeter
  adca #0
  daa
  staa TripMeter
  inc cTripMeter                ;set display flag
  pula
I30N2:
  std TripCount

  ldaa PORTD
  bita #$04                     ;test for trip reset switch
  bne I30TripUp
  inc TripTimer
  bne I30TripN1
  ldaa #$ff
  staa TripTimer
  jmp I30SkipTrip
I30TripN1:
  ldaa TripTimer
  cmpa #90                      ;4 seconds
  bne I30SkipTrip
  ldaa #$ff
  staa TripTimer
  com LCDBkColor                ;invert background/foreground color
  jsr InitLCD                   ;re-initialize display
  jsr DisplayImages
  clr PACNT                     ;clear pulse count so speedo isn't fucked
  bra I30SkipTrip

I30TripUp:
  ldaa TripTimer
  clr TripTimer
  cmpa #$ff
  beq I30SkipTrip
  cmpa #4
  blo I30SkipTrip
  clr TripMeter
  clr TripMeter+1               ;clear trip meter
  ldaa #$01
  staa cTripMeter               ;update trip meter display

I30SkipTrip:
  ldaa #$10
  staa ADCTL                    ;start A/D conversion
  nop
  nop                           ;blow away some time
I30Loop1:
  ldaa ADCTL
  bita #$80
  beq I30Loop1                  ;wait until conversion complete

* The Fuel and Temp guages will be updated at 1/4 the frequency of the
* other displays.
  inc SlowCount                 ;see if we should update fuel&temp
  ldaa #$03
  anda SlowCount
  bne I30SkipSlow

* calculate fuel level reading
  ldx #FuelBuf
  ldab FBufIdx
  abx                           ;x = pointer to fuel buffer to store sample
  ldaa ADR3
  staa ,x
  incb                          ;move to next sample in buffer
  andb #$1f                     ;32-entry buffer
  stab FBufIdx

  ldx #FuelBuf
  jsr I30Avg32                  ;get average value of samples in buffer
  staa FuelSample

  tab
  ldaa #1
  negb
  sbca #0                       ;D = 256-F
  xgdx
  ldaa #116                     ;scale factor
  ldab FuelSample
  mul                           ;X = 256-F, D = 116*F
  idiv
  xgdx                          ;b = displayed fuel value
  cmpb sFuel
  beq I30FuelEnd
  stab sFuel
  inc cFuel
I30FuelEnd:

* calculate temperature reading
  ldx #TempTable
  ldab ADR2
  ldaa #0
I30TempLoop1:
  cmpb ,x
  bhs I30TL1End
  inca
  inx
  bra I30TempLoop1

I30TL1End:
  ldx #TempBuf                  ;now 0 <= A <= 48  == linear temp [25C,145C]
  ldab TBufIdx
  abx                           ;x = pointer to temp. buffer to store sample
  staa ,x
  incb                          ;move to next sample in buffer
  andb #$1f                     ;32-entry buffer
  stab TBufIdx

  ldx #TempBuf
  jsr I30Avg32                  ;get average value of samples in buffer in A

  cmpa sTemp
  beq I30TempEnd
  staa sTemp
  inc cTemp
I30TempEnd:

I30SkipSlow:

*** Note:
* This code below updates a 16-entry ring buffer
* with transformed Voltage samples.... Update display under these conditions:
*   if (abs(sum(d_dt(VoltSamples)) / numSamples) > 0.5)
*     sVoltage = VoltSamples[current]; updateVoltage
*   else if (avg(VoltSamples) != sVoltage)
*     timer++; if (timer > 20)
*       sVoltage = avg(VoltSamples); updateVoltage
*   else timer=0;
  ldaa ADR1                     ;get voltage sample
  ldab #223
  mul                           ;now a = 10ths of a volt
  ldx #VoltageBuf
  ldab VBufIdx
  abx
  staa ,x                       ;store voltage sample in ring buffer
  staa VoltSample

  incb                          ;advance ring buffer pointer
  andb #$0f                     ;bit mask
  stab VBufIdx
  ldx #VoltageBuf
  abx

  suba ,x                       ;get differential
  anda #$fc                     ;test high bits
  beq I30VoltageN1
  coma
  anda #$fc
  beq I30VoltageN1
  ldaa VoltSample
  staa sVoltage
  inc cVoltage                  ;set voltage display update flag
  clr VoltAvgTimer
  bra I30VoltageEnd

I30VoltageN1:
  ldx #VoltageBuf
  ldaa #16                      ;16-entry ring buffer
  ldy #0
I30VoltLoop1:
  ldab ,x                       ;get sum of buffer entry values
  inx
  aby
  deca
  bne I30VoltLoop1

  xgdy                          ;get sum into D accumulator
  lsrd
  lsrd
  lsrd
  lsrd                          ;now D is average
  cmpb sVoltage                 ;check to see if average = displayed value
  beq I30VoltageN2
  inc VoltAvgTimer
  ldaa VoltAvgTimer
  cmpa #20
  bne I30VoltageEnd

  stab sVoltage
  inc cVoltage                  ;update display

I30VoltageN2:
  clr VoltAvgTimer

I30VoltageEnd:

  ldaa #$ff                     set byte telling main loop that timer fired
  staa TimerFired

  ldaa #$40                     reset timer interrupt flag
  staa TFLG2

  rti                           exit

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* IN::  A = speed (MPH)
*       B = time (tenths of a second)
I30PlotPoint:
  pshb                  ;save B for now
  cmpa #100             ;if speed > 100
  blo I30PPN1
  ldaa #100             ;speed = 100
I30PPN1:
  ldab #141
  mul                   ;now a = y displacement on graph
  nega
  adda #116             ;now A = Y coordinate for graph
  ldab #30              ;30 bytes per line
  mul                   ;now D = offset to start of display line for point
  xgdx                  ;put into X for now

  pulb                  ;retrieve the time
  addb #80              ;graph is 80 columns over
  tba                   ;copy into A
  lsrb
  lsrb
  lsrb                  ;now b = offset to byte int display line
  abx                   ;add into display line offset for total offset
  stx LCDAddress        ;store here

  anda #7               ;get bit # to set
  psha                  ;save for a moment

  ldaa #$0a             ;Set Cursor Address low order
  ldab LCDAddress+1
  jsr OutLCD2
  ldaa #$0b             ;Set cursor address high order
  ldab LCDAddress
  jsr OutLCD2
  ldaa #$0f
  adda LCDBkColor       ;don't worry about it, I got it covered
  pulb                  ;get bit # to set
  jsr OutLCD2           ;set a point

  rts

*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* IN-   X = pointer to buffer to average
* OUT-  A = average value

I30Avg32:
  ldy #0
  ldaa #32                      ;calculate average of all 32 samples
I30A32Loop1:
  ldab ,x
  inx
  aby
  deca
  bne I30A32Loop1

  xgdy                          ;D = sum of 32 samples
  lsld
  lsld
  lsld                          ;now a = average value
  rts

*____________________________________________________________________________
IntPowerDown:

* Save Odometer, TripMeter in on-chip EEPROM

  sei                           Make sure interrupts are turned off

  ldab #$0e                     Erase first row of EEPROM ($b600-$b60f)
  stab PPROG                    Set to Row Erase Mode
  stab $b600                    Write any Data to any Address in Row
  ldab #$0F
  stab PPROG                    Turn on High Voltage
  jsr Dly10                     Delay 10 ms
  clr PPROG                     Turn Off High Voltage and Set to Read

  ldx #$b600                    Address to begin storing data
  ldy #Odometer
  ldab #9                       save 9 bytes
IPDLoop1:
  pshb                          save loop counter

  ldaa ,y
  jsr IPDProgram
  inx
  iny

  pulb
  decb
  bne IPDLoop1

IPDEndLoop:
  bra IPDEndLoop                wait for power to die

IPDProgram:
  ldab #$02
  stab PPROG                    Set EELAT Bit (EEPGM = 0)
  staa 0,x                      Store Data to EEPROM Address
  ldab #$03
  stab PPROG                    Set EEPGM Bit (EELAT = 1)
  jsr Dly10                     Delay 10 ms
  clr PPROG                     Turn Off High Voltage and Set to READ Mode
  rts

Dly10:
  pshx                          This waits 10ms before returning

  ldx #3333
D10Loop:
  dex
  bne D10Loop

  pulx
  rts

*____________________________________________________________________________
* Permanent Data Area

HiBeamImg       fcb     $00, $ee, $03, $00, $0f, $00, $80, $0f, $00
                fcb     $80, $cf, $03, $80, $0f, $00, $00, $0f, $00
                fcb     $00, $ee, $03
PMOffImg        fcb     $f0, $80, $19, $00, $0c, $43, $04, $00, $04, $42
                fcb     $04, $00, $02, $44, $04, $00, $02, $e4, $1f, $00
                fcb     $02, $44, $04, $00, $02, $44, $04, $00, $04, $42
                fcb     $04, $00, $0c, $41, $04, $00, $f8, $e0, $0e, $00
PMRaceImg       fcb     $7e, $00, $00, $80, $c4, $00, $00, $80, $84, $00
                fcb     $00, $80, $84, $00, $00, $80, $44, $70, $38, $8e
                fcb     $34, $88, $26, $91, $24, $e0, $02, $9f, $44, $98
                fcb     $02, $81, $84, $88, $06, $03, $0e, $f9, $3d, $9e

DigitBits       fcb     $1e, $21, $21, $21, $21, $21, $1e, 0    * 0
                fcb     $08, $0c, $08, $08, $08, $08, $1c, 0    * 1
                fcb     $1f, $20, $20, $1e, $01, $01, $3e, 0    * 2
                fcb     $1f, $20, $20, $1e, $20, $20, $1f, 0    * 3
                fcb     $21, $21, $21, $3e, $20, $20, $20, 0    * 4
                fcb     $1f, $01, $01, $1f, $20, $20, $1f, 0    * 5
                fcb     $1e, $01, $01, $1f, $21, $21, $1e, 0    * 6
                fcb     $3f, $20, $10, $08, $04, $02, $01, 0    * 7
                fcb     $1e, $21, $21, $1e, $21, $21, $1e, 0    * 8
                fcb     $1e, $21, $21, $3e, $20, $20, $1f, 0    * 9
                fcb     $00, $00, $00, $3f, $00, $00, $00, 0    * A (-)

BigDigitBits    fcb     $3e, $7f, $63, $63, $63, $63, $63, $63, $63  * 0
                fcb     $63, $63, $63, $63, $7f, $3e, 0
                fcb     $60, $70, $78, $78, $60, $60, $60, $60, $60  * 1
                fcb     $60, $60, $60, $60, $60, $60, 0
                fcb     $3e, $7f, $63, $63, $63, $60, $30, $38, $18  * 2
                fcb     $1c, $0c, $06, $07, $7f, $7f, 0
                fcb     $3e, $7f, $63, $63, $63, $60, $7c, $3c, $60  * 3
                fcb     $63, $63, $63, $63, $7f, $3e, 0
                fcb     $70, $78, $78, $6c, $6c, $6c, $64, $66, $66  * 4
                fcb     $66, $63, $ff, $ff, $60, $60, 0
                fcb     $7f, $7f, $03, $03, $03, $3f, $7f, $63, $60  * 5
                fcb     $63, $63, $63, $63, $7f, $3e, 0
                fcb     $3e, $7f, $63, $63, $03, $3f, $7f, $63, $63  * 6
                fcb     $63, $63, $63, $63, $7f, $3e, 0
                fcb     $7f, $7f, $60, $30, $30, $30, $18, $18, $1c  * 7
                fcb     $0c, $0c, $06, $06, $06, $03, 0
                fcb     $3e, $7f, $63, $63, $63, $63, $3e, $3e, $63  * 8
                fcb     $63, $63, $63, $63, $7f, $3e, 0
                fcb     $3e, $7f, $63, $63, $63, $63, $7f, $7e, $60  * 9
                fcb     $63, $63, $63, $63, $7f, $3e, 0



LCDDigitSegs    fcb     $3f, 6, $5b, $4f, $66, $6d, $7d, 7, $7f, $6f

LCDSegA         fcb     $80, $ff, $1f, 0, $ff, $0f, 0, $fe, 7
LCDSegBC        fcb     $40, $60, $70, $70, $70, $70, $70, $70, $70, $70
                fcb     $70, $70, $60, $40
LCDSegD         fcb     0, $fe, 7, 0, $ff, $0f, $80, $ff, $1f
LCDSegEF        fcb     $20, $60, $e0, $e0, $e0, $e0, $e0, $e0, $e0, $e0
                fcb     $e0, $e0, $60, $20
LCDSegG         fcb     0, $ff, $0f, $80, $ff, $1f, 0, $ff, $0f
LCDLeading1     fcb     $40, $60, $70, $70, $70, $70, $70, $70, $70, $70
                fcb     $70, $70, $60, $40, $00, $40, $60, $70, $70, $70
                fcb     $70, $70, $70, $70, $70, $70, $70, $60, $40

TotalRuns       FDB     5009

HCTable:
  FCB $00,$00,$00, $00,$06,$01, $00,$04,$02, $00,$0a,$03
  FCB $00,$3d,$04, $00,$2c,$05, $00,$72,$06, $00,$79,$08
  FCB $00,$74,$0b, $00,$7e,$0c, $00,$5d,$2f, $00,$fb,$07
  FCB $00,$ff,$0a, $00,$b9,$0d, $00,$e1,$0e, $00,$e3,$0f
  FCB $00,$ed,$10, $00,$eb,$11, $00,$b7,$18, $00,$b8,$3a
  FCB $00,$fa,$e0, $01,$cc,$09, $01,$f3,$12, $01,$d8,$15
  FCB $01,$cd,$19, $01,$78,$1c, $01,$7a,$3b, $01,$68,$87
  FCB $01,$7b,$ee, $01,$c5,$ff, $03,$9c,$13, $03,$9d,$14
  FCB $03,$9e,$16, $03,$fa,$17, $03,$fb,$1a, $02,$d2,$1d
  FCB $03,$b2,$1e, $03,$b3,$20, $02,$d3,$28, $03,$9f,$29
  FCB $03,$a8,$2c, $02,$f3,$2d, $02,$f8,$31, $03,$b8,$34
  FCB $02,$d4,$37, $02,$d5,$38, $02,$d6,$40, $02,$d7,$44
  FCB $02,$d8,$45, $03,$f8,$4a, $03,$a9,$59, $02,$d9,$81
  FCB $03,$b9,$83, $02,$f9,$85, $02,$fa,$88, $03,$aa,$89
  FCB $02,$da,$8b, $03,$ba,$93, $03,$f9,$a5, $02,$fb,$ae
  FCB $03,$ab,$b3, $02,$db,$b6, $07,$76,$1b, $07,$77,$1f
  FCB $07,$78,$21, $05,$e5,$22, $07,$79,$23, $07,$7a,$24
  FCB $05,$f8,$25, $07,$7b,$26, $05,$f9,$27, $07,$7c,$2a
  FCB $07,$7d,$2b, $07,$7e,$33, $05,$fa,$39, $07,$7f,$3c
  FCB $05,$fb,$3e, $07,$80,$3f, $07,$81,$41, $07,$82,$42
  FCB $07,$83,$43, $07,$84,$48, $05,$fc,$4d, $05,$fd,$50
  FCB $05,$fe,$53, $05,$ff,$65, $07,$85,$66, $07,$86,$67
  FCB $07,$87,$69, $07,$00,$72, $07,$01,$73, $07,$02,$7c
  FCB $07,$03,$7f, $07,$04,$84, $07,$88,$91, $07,$05,$99
  FCB $07,$06,$af, $07,$07,$b5, $07,$10,$bd, $07,$11,$be
  FCB $07,$12,$c1, $07,$13,$c2, $0f,$12,$2e, $0f,$13,$30
  FCB $0f,$14,$32, $0f,$15,$3d, $0f,$16,$46, $0f,$17,$4c
  FCB $0f,$18,$4e, $0f,$19,$5d, $0f,$1a,$68, $0f,$1b,$6d
  FCB $0f,$1c,$6e, $0f,$1d,$75, $0f,$1e,$7a, $0f,$1f,$92
  FCB $0f,$80,$a3, $0f,$81,$d4, $0f,$82,$dc, $0f,$83,$df
  FCB $0f,$84,$e5, $0b,$c8,$e7, $0b,$c9,$ed, $1f,$0a,$35
  FCB $1f,$0b,$47, $1f,$0c,$49, $1f,$0d,$4b, $1f,$0e,$4f
  FCB $1f,$0f,$54, $1f,$10,$57, $1f,$11,$5a, $1f,$12,$5b
  FCB $1f,$13,$5c, $1f,$14,$60, $1f,$15,$62, $1f,$16,$63
  FCB $1f,$17,$6b, $1f,$18,$6f, $1f,$19,$70, $1f,$1a,$71
  FCB $1f,$1b,$76, $1f,$1c,$77, $1f,$1d,$79, $1f,$1e,$7d
  FCB $1f,$1f,$80, $1f,$20,$82, $1f,$21,$86, $1f,$22,$8d
  FCB $1f,$23,$90, $1f,$24,$94, $1f,$25,$95, $1f,$26,$96
  FCB $1f,$27,$98, $1f,$28,$9b, $1f,$29,$9e, $1f,$2a,$a1
  FCB $1f,$2b,$a8, $1f,$2c,$aa, $1f,$2d,$ad, $1f,$2e,$b2
  FCB $1f,$2f,$c5

HCBitPtrs:
  FCB $00,$00,$00,0,  $00,$00,$01,0,  $00,$03,$00,0,  $00,$03,$02,0
  FCB $00,$09,$01,0,  $00,$0c,$00,0,  $00,$0c,$02,0,  $00,$12,$05,0
  FCB $00,$21,$0a,0,  $00,$3f,$09,0,  $00,$5a,$20,0,  $00,$ba,$28,0
  FCB $01,$32,$15,0,  $01,$71,$26,0,  $01,$e3,$00,0,  $01,$e3,$00,0

* Huffman encoded run-lengths for image data
Huff_data:
  FCB $e2, $f1, $79, $ff, $3d, $eb, $de, $23, $a4, $ef, $1a, $4e
  FCB $21, $ab, $76, $6b, $37, $10, $d5, $bb, $be, $e4, $e2, $1a, $96, $7b
  FCB $ed, $59, $26, $fd, $ab, $57, $be, $d7, $29, $f2, $5d, $16, $6d, $a9
  FCB $34, $db, $6d, $ff, $5a, $a6, $da, $92, $b6, $db, $e4, $9e, $f2, $4d
  FCB $1e, $a2, $b3, $7e, $d5, $a2, $69, $a6, $a5, $6e, $eb, $37, $32, $6d
  FCB $eb, $7d, $b7, $b6, $6d, $5a, $c9, $34, $d3, $ef, $ba, $db, $72, $cd
  FCB $b7, $de, $e5, $b9, $6a, $d5, $ab, $34, $d1, $5b, $82, $ed, $ac, $db
  FCB $6d, $f7, $b9, $4b, $35, $6a, $d3, $6d, $55, $ee, $e0, $ba, $6a, $d3
  FCB $6d, $f7, $39, $6b, $35, $69, $36, $9a, $c5, $93, $e4, $fa, $b4, $da
  FCB $0d, $34, $d3, $4d, $52, $b6, $2c, $d0, $92, $cd, $37, $88, $b3, $56
  FCB $89, $2a, $ca, $b3, $dc, $aa, $da, $44, $a2, $aa, $be, $0f, $7b, $be
  FCB $13, $59, $be, $12, $56, $bc, $8b, $38, $bc, $5e, $2f, $84, $73, $1c
  FCB $6e, $63, $c0, $b9, $d7, $7b, $dd, $eb, $db, $f1, $b8, $5e, $fb, $9c
  FCB $cd, $2a, $aa, $ab, $db, $3c, $1d, $7d, $8e, $f2, $a7, $7b, $7a, $f2
  FCB $a5, $33, $ee, $45, $32, $99, $4f, $51, $de, $56, $92, $3e, $d1, $d9
  FCB $ba, $87, $af, $b5, $3c, $bc, $a2, $99, $4c, $a7, $ab, $f2, $b4, $9d
  FCB $11, $d9, $be, $eb, $13, $6d, $06, $24, $a2, $25, $8a, $79, $79, $45
  FCB $32, $99, $4f, $56, $69, $35, $46, $25, $69, $33, $54, $24, $96, $3d
  FCB $a5, $23, $6c, $a6, $a3, $25, $39, $28, $d1, $90, $89, $93, $6d, $87
  FCB $da, $9e, $5e, $55, $ec, $f6, $7b, $ec, $8c, $30, $8d, $93, $23, $32
  FCB $62, $89, $99, $9c, $b6, $50, $8a, $46, $66, $68, $d1, $1c, $94, $29
  FCB $19, $94, $c8, $88, $3e, $d4, $f2, $f2, $fb, $72, $72, $7a, $b2, $64
  FCB $72, $64, $54, $ca, $14, $c8, $8f, $f1, $42, $3d, $01, $24, $4f, $63
  FCB $92, $85, $20, $8a, $49, $48, $3e, $d4, $f2, $f2, $fb, $72, $72, $7a
  FCB $f5, $91, $9c, $99, $11, $99, $42, $99, $14, $e6, $0a, $11, $e8, $0c
  FCB $c8, $8f, $b5, $0a, $34, $56, $8a, $53, $d4, $05, $8f, $54, $8f, $28
  FCB $88, $88, $8b, $14, $d8, $c2, $23, $23, $36, $c3, $0a, $64, $66, $7a
  FCB $82, $84, $13, $6d, $9b, $44, $47, $b5, $2b, $13, $d4, $9a, $6a, $d3
  FCB $63, $ed, $ed, $47, $99, $aa, $aa, $aa, $c9, $59, $ec, $92, $cd, $b6
  FCB $6c, $d1, $5a, $6c, $96, $54, $a4, $8f, $51, $33, $24, $9f, $37, $97
  FCB $45, $3a, $dd, $1f, $2e, $7d, $bb, $77, $cd, $cc, $75, $7b, $d9, $fa
  FCB $b8, $bc, $5e, $2f, $17, $e0, $dd, $e1, $e5, $d8, $77, $77, $da, $fd
  FCB $7b, $6b, $6f, $7d, $e3, $b3, $ff, $73, $bb, $ef, $de, $bd, $cb, $5c
  FCB $22, $d6, $58, $8e, $34, $74, $76, $1c, $94, $f9, $be, $d7, $08, $b5
  FCB $96, $23, $8d, $1d, $1d, $85, $8b, $77, $da, $e3, $60, $ca, $92, $8d
  FCB $34, $22, $62, $24, $92, $16, $21, $b5, $72, $64, $6a, $84, $9a, $8c
  FCB $85, $8f, $ba, $92, $43, $48, $52, $42, $73, $e6, $46, $a1, $32, $19
  FCB $89, $b6, $26, $d9, $90, $4d, $65, $44, $79, $93, $11, $36, $66, $68
  FCB $d3, $58, $e4, $a1, $04, $c4, $61, $10, $99, $cf, $bd, $45, $08, $8b
  FCB $26, $44, $64, $46, $f4, $a5, $88, $8c, $f2, $28, $72, $44, $91, $14
  FCB $b1, $55, $47, $a5, $1e, $ed, $5e, $e4, $73, $ef, $51, $4d, $29, $eb
  FCB $32, $23, $22, $33, $d5, $2c, $44, $1c, $c6, $41, $c9, $19, $91, $14
  FCB $b1, $e8, $a1, $ea, $85, $82, $2c, $47, $3e, $f5, $14, $8f, $54, $db
  FCB $22, $32, $23, $20, $93, $d4, $56, $e6, $32, $08, $88, $36, $88, $92
  FCB $c4, $c5, $08, $25, $46, $66, $46, $45, $a7, $24, $95, $2b, $4a, $cf
  FCB $76, $de, $ed, $b6, $92, $1e, $fb, $ea, $2c, $98, $89, $26, $cc, $c9
  FCB $21, $f7, $0d, $52, $48, $69, $a2, $26, $9b, $5f, $a5, $2f, $db, $e5
  FCB $bb, $c5, $5f, $2c, $af, $15, $9c, $5e, $2f, $56, $bd, $af, $6b, $da
  FCB $f6, $bd, $af, $6b, $da, $f6, $bd, $ba, $97, $74, $ef, $8e, $a3, $77
  FCB $4e, $7c, $77, $c1, $dd, $3b, $eb, $be, $57, $8f, $bb, $e2, $f3, $77
  FCB $4e, $fa, $ef, $b3, $c7, $dc, $fe, $b9, $f9, $fc, $a9, $df, $bb, $2f
  FCB $94, $3c, $4a, $d3, $f9, $33, $be, $f8, $97, $74, $b4, $fb, $8f, $91
  FCB $af, $c5, $c7, $c8, $9d, $e6, $fd, $db, $4e, $ce, $d7, $be, $9d, $97
  FCB $84, $f9, $0a, $f1, $e2, $fc, $11, $fd, $df, $df, $90, $39, $bd, $9f
  FCB $1f, $78, $b6, $5f, $d5, $e2, $b7, $1e, $ab, $4b, $81, $b9, $eb, $7f
  FCB $3b, $8f, $79, $e6, $fc, $5d, $09, $99, $4e, $77, $fa, $e9, $93, $3c
  FCB $ee, $96, $fe, $1f, $31, $86, $53, $9c, $ec, $70, $e8, $0f, $bd, $c3
  FCB $cf, $78, $d0, $0c, $32, $9d, $7f, $d7, $1e, $30, $fb, $dc, $36, $ff
  FCB $73, $e2, $48, $4d, $54, $ed, $e7, $66, $e1, $c6, $1f, $7b, $87, $6e
  FCB $c7, $27, $8c, $a0, $a6, $53, $8f, $e7, $66, $e1, $c6, $16, $fb, $de
  FCB $72, $cd, $f1, $34, $14, $ca, $53, $99, $f3, $e5, $b8, $71, $1c, $dd
  FCB $67, $39, $c9, $e3, $88, $39, $7c, $f9, $9a, $e7, $76, $5b, $23, $73
  FCB $90, $78, $e2, $9c, $ba, $fa, $6b, $9d, $d9, $60, $09, $f3, $8f, $8c
  FCB $29, $67, $5f, $7f, $d8, $05, $7c, $f8, $02, $2c, $ed, $ad, $9f, $0a
  FCB $d3, $05, $9d, $7f, $1a, $49, $3a, $e2, $0e, $e3, $50, $39, $75, $f6
  FCB $77, $f7, $ef, $8d, $a6, $c3, $b8, $db, $47, $2e, $72, $fe, $af, $c7
  FCB $1c, $d4, $0b, $5e, $6e, $df, $87, $3b, $d7, $1d, $40, $0f, $07, $2b
  FCB $b7, $c6, $1d, $eb, $86, $cc, $d1, $6b, $eb, $38, $fc, $61, $de, $78
  FCB $7e, $f5, $fe, $e3, $bf, $8b, $cb, $c3, $cc, $d7, $fb, $8f, $c5, $dd
  FCB $e3, $87, $fe, $5f, $ee, $3f, $86, $bb, $3e, $1f, $db, $e1, $fc, $7f
  FCB $c3, $b3, $b9, $bf, $fc, $3f, $c3, $bb, $dc, $f8, $6e, $1f, $86, $3b
  FCB $2b, $9f, $0f, $c3, $e1, $1d, $95, $cf, $87, $e1, $f0, $8b, $4b, $8f
  FCB $c3, $76, $fc, $2d, $78, $fd, $a5, $ff, $9a, $e7, $c5, $97, $8f, $d2
  FCB $7c, $5a, $4b, $9f, $16, $77, $6f, $de, $ef, $8a, $cf, $6e, $6d, $87
  FCB $f7, $fb, $c6, $a7, $dd, $cd, $ae, $fe, $ff, $78, $68, $66, $2e, $6d
  FCB $77, $37, $f7, $87, $33, $02, $e7, $c1, $b9, $bd, $3c, $6d, $81, $bf
  FCB $78, $35, $bf, $ef, $1b, $60, $6b, $9f, $04, $b7, $e9, $91, $e1, $98
  FCB $13, $f7, $82, $7f, $5f, $80, $3c, $2b, $32, $ae, $7c, $0b, $fa, $e9
  FCB $18, $70, $0f, $de, $05, $fd, $7f, $fa, $0e, $03, $d3, $c0, $b9, $ee
  FCB $90, $07, $01, $fd, $6b, $39, $ef, $d1, $1c, $06, $e6, $d6, $76, $3b
  FCB $7e, $37, $db, $e0, $1d, $8e, $9b, $de, $01, $5b, $f5, $e2, $49, $11
  FCB $d6, $ec, $7f, $fb, $ef, $c6, $77, $bd, $2f, $0c, $cc, $d9, $ba, $dc
  FCB $ef, $4e, $53, $e3, $9f, $bb, $b3, $33, $30, $3a, $dc, $ef, $ff, $73
  FCB $d3, $bb, $49, $22, $3a, $dc, $ef, $ff, $73, $d2, $b7, $63, $53, $d4
  FCB $75, $ae, $75, $74, $ee, $7f, $67, $f4, $23, $d4, $75, $b8, $55, $ff
  FCB $7c, $f4, $db, $9e, $66, $7a, $8e, $b7, $0a, $bf, $ef, $9e, $98, $5a
  FCB $ae, $14, $e9, $7c, $fe, $0b, $55, $c2, $9f, $f6, $8e, $8d, $7e, $9f
  FCB $bd, $7f, $da, $3a, $77, $f7, $cf, $fe, $d1, $d3, $a5, $f1, $f3, $ff
  FCB $b4, $74, $ef, $ee, $be, $96, $8f, $d7, $a7, $5d, $cd, $f3, $fa, $f4
  FCB $eb, $ed, $f8, $f7, $5d, $e9, $d7, $ff, $27, $c7, $7b, $17, $a7, $5f
  FCB $ff, $03, $ab, $3a, $5e, $9d, $7f, $fd, $57, $4b, $d3, $b7, $a7, $c7
  FCB $d9, $0f, $d7, $0e, $de, $9c, $0f, $00, $3a, $5c, $3b, $7f, $ed, $96
  FCB $60, $e9, $70, $ed, $ff, $b6, $50, $0e, $97, $0e, $df, $fb, $64, $00
  FCB $e9, $70, $ed, $ff, $b6, $59, $1b, $a5, $c3, $b7, $ff, $23, $82, $74
  FCB $b8, $76, $ff, $b6, $1d, $cf, $4b, $87, $6f, $fe, $61, $dc, $f4, $b8
  FCB $76, $ff, $e6, $1d, $cf, $4b, $87, $6f, $fe, $61, $dc, $f4, $b8, $76
  FCB $ff, $e4, $70, $4e, $97, $0e, $df, $fb, $6b, $a5, $c3, $b7, $9c, $e0
  FCB $5d, $77, $e7, $76, $bb, $79, $ce, $05, $d7, $7e, $77, $6b, $b7, $fe
  FCB $da, $e9, $70, $ed, $ff, $b6, $ba, $5c, $3b, $7a, $75, $5f, $ae, $1d
  FCB $bd, $3a, $af, $d7, $0e, $bf, $fe, $ab, $a5, $e9, $d7, $ff, $d5, $74
  FCB $bd, $3a, $ff, $fa, $ae, $97, $a7, $5f, $ff, $55, $d3, $fa, $f7, $48
  FCB $d3, $b5, $d7, $d2, $d1, $fb, $9a, $a6, $66, $67, $1b, $af, $a5, $a3
  FCB $f7, $35, $4c, $cc, $ce, $37, $cf, $fe, $d1, $d3, $fb, $54, $8d, $3b
  FCB $5f, $3f, $fb, $47, $4f, $ed, $5a, $99, $f3, $7c, $ff, $ed, $1d, $3f
  FCB $b5, $08, $cf, $9a, $e5, $5d, $2f, $9f, $da, $76, $14, $cc, $cf, $9b
  FCB $f0, $9e, $6d, $ae, $66, $16, $a3, $f0, $aa, $f1, $94, $5d, $b3, $d5
  FCB $a8, $fc, $29, $f1, $4c, $de, $29, $29, $6a, $bf, $0b, $fe, $00, $91
  FCB $3b, $da, $9f, $77, $c5, $cb, $c2, $a0, $22, $2f, $37, $06, $40, $4d
  FCB $a7, $c1, $20, $23, $d7, $c1, $20, $44, $4e, $26, $bc, $97, $17, $8b
  FCB $dc, $af, $6b, $db, $db, $3a, $f5, $ab, $39, $6e, $17, $8f, $2c, $4d
  FCB $c6, $bd, $6b, $37, $0e, $f1, $e5, $8a, $71, $af, $43, $dd, $c6, $f0
  FCB $17, $c7, $95, $8a, $71, $af, $42, $87, $1b, $c0, $2e, $bc, $ac, $45
  FCB $4a, $32, $b4, $a3, $63, $69, $25, $12, $a4, $96, $0a, $1e, $cf, $6a
  FCB $49, $bb, $85, $d7, $95, $84, $88, $d0, $c8, $db, $41, $36, $cc, $8d
  FCB $33, $6c, $c8, $f5, $99, $94, $db, $68, $c8, $db, $b8, $5d, $79, $58
  FCB $e5, $ec, $7a, $88, $8f, $51, $15, $22, $32, $cf, $7d, $66, $65, $23
  FCB $29, $bd, $b5, $57, $5e, $56, $39, $39, $3d, $44, $47, $a8, $8d, $b2
  FCB $23, $2c, $79, $66, $65, $23, $29, $9d, $fd, $75, $e5, $63, $96, $b1
  FCB $ea, $6c, $8f, $51, $19, $11, $1b, $7b, $be, $d3, $45, $6c, $da, $36
  FCB $f7, $77, $0b, $af, $2f, $67, $2a, $d2, $49, $24, $91, $36, $58, $9b
  FCB $6a, $95, $53, $6d, $2a, $55, $9a, $b6, $ee, $17, $5e, $5d, $5a, $eb
  FCB $cb, $83, $42, $ea, $33, $2f, $b5, $2e, $a3, $32, $fb, $52, $ea, $56
  FCB $5f, $6a, $5d, $46, $65, $f6, $a5, $d4, $66, $70, $68, $5d, $46, $67
  FCB $56, $ba, $f2, $ea, $d7, $5e, $5d, $5a, $eb, $ca, $b7, $cd, $5b, $ba
  FCB $5d, $79, $46, $dc, $3a, $9b, $78, $85, $d7, $96, $52, $e5, $ea, $9e
  FCB $21, $75, $e5, $94, $fc, $b1, $4f, $10, $ba, $f2, $ca, $7e, $26, $53
  FCB $6e, $e2, $95, $a7, $f0, $ba, $f2, $ca, $7e, $db, $14, $db, $bf, $3d
  FCB $52, $fe, $5f, $1e, $59, $4a, $af, $54, $29, $6a, $3d, $52, $fa, $65
  FCB $3f, $28, $52, $d4, $f5, $32, $fa, $46, $5c, $ec, $8c, $9a, $d4, $14
  FCB $f8, $8f, $b6, $9a, $b7, $1d, $56, $ad, $df, $bd, $56, $9f, $10, $05
  FCB $a6, $fe, $37, $8e, $ab, $33, $33, $1c, $f3, $f8, $de, $3a, $8c, $66
  FCB $36, $3b, $0e, $26, $94, $66, $66, $76, $1c, $4d, $14, $cc, $cc, $ec
  FCB $38, $94, $96, $33, $27, $3c, $f8, $15, $bb, $e0, $56, $ef, $5e, $5e
  FCB $ac, $9c, $b7, $27, $c0, $4f, $e9, $ab, $ca, $b7, $2d, $66, $e5, $b8
  FCB $8b, $d7, $da, $87, $21, $ee, $a4, $70, $2f, $05, $eb, $ed, $43, $90
  FCB $a1, $f6, $e2, $2f, $5c, $94, $ce, $42, $85, $22, $49, $bb, $bd, $2b
  FCB $4b, $e5, $eb, $92, $99, $c9, $99, $93, $46, $46, $dd, $93, $d5, $2f
  FCB $a7, $ab, $15, $65, $8c, $cc, $a4, $6f, $6f, $2b, $d5, $2f, $a7, $ab
  FCB $1f, $6e, $4c, $cc, $a4, $67, $7b, $f5, $32, $fa, $7a, $b1, $f6, $e4
  FCB $9a, $29, $1b, $7b, $af, $28, $a5, $fc, $be, $3c, $a7, $b1, $cb, $da
  FCB $9b, $69, $a2, $6a, $db, $b2, $f5, $5a, $7f, $0b, $af, $2f, $f5, $fb
  FCB $de, $15, $75, $e5, $cc, $78, $0d, $e1, $57, $5e, $5c, $c7, $ca, $d7
  FCB $5e, $5d, $5a, $eb, $cb, $a9, $42, $66, $7f, $0b, $af, $2e, $a7, $31
  FCB $86, $7f, $0b, $af, $2e, $a4, $06, $19, $fc, $2e, $bc, $ba, $94, $26
  FCB $ab, $62, $8b, $a9, $59, $d4, $a0, $a6, $5b, $0a, $5d, $47, $ae, $a5
  FCB $05, $32, $d8, $99, $75, $24, $5f, $6a, $5d, $47, $ab, $ed, $4b, $a8
  FCB $f5, $88, $9f, $01, $45, $d4, $7a, $c0, $06, $fe, $57, $5e, $58, $01
  FCB $9f, $ca, $eb, $cb, $00, $33, $f9, $5d, $79, $62, $26, $7f, $2b, $af
  FCB $2f, $cf, $e5, $75, $e5, $f9, $fc, $ae, $bc, $bf, $3f, $95, $d7, $97
  FCB $e7, $f2, $ba, $f2, $fc, $fe, $6f, $8f, $2f, $cf, $a7, $e7, $d3, $f3
  FCB $e9, $f9, $c1, $fd, $ff, $d6, $ef, $cb, $6d, $9d, $16, $ef, $cb, $6c
  FCB $33, $6d, $16, $ef, $cb, $6e, $66, $19, $96, $ef, $cb, $6c, $66, $2b
  FCB $2d, $df, $96, $da, $98, $7a, $b7, $7e, $70, $79, $3d, $44, $fe, $9f
  FCB $9f, $4a, $89, $9f, $4a, $41, $9f, $29, $f0, $55, $01, $be, $94, $03
  FCB $3e, $95, $13, $3e, $9f, $9f, $4f, $cf, $a7, $e7, $d3, $f3, $e9, $f9
  FCB $f4, $fc, $fa, $7e, $7d, $3f, $3e, $9f, $9f, $4f, $cf, $a0, $36, $07
  FCB $d1, $00, $0f, $a2, $00, $1f, $40, $6d, $0f, $a0, $10, $1f, $40, $20
  FCB $3e, $9f, $9f, $4f, $cf, $a7, $e7, $d3, $f3, $e9, $f9, $c4, $b5, $e1
  FCB $f9, $c4, $b5, $e1, $f9, $f4, $fc, $fa, $7e, $7d, $3f, $3e, $9f, $9f
  FCB $4f, $cf, $a7, $e7, $d3, $cc, $3e, $9e, $43, $82, $f3, $62, $7b, $b2
  FCB $f0, $f2, $3b, $f3, $c5, $1e, $26, $fe, $d1, $c9, $97, $87, $91, $c1
  FCB $d1, $b4, $23, $5b, $bc, $ce, $1a, $56, $9d, $8a, $bc, $c9, $d4, $15
  FCB $cd, $19, $99, $87, $f6, $e6, $bd, $52, $dd, $e2, $60, $ea, $05, $e0
  FCB $66, $66, $6d, $6e, $e6, $bd, $52, $de, $af, $30, $75, $05, $7f, $68
  FCB $cc, $c8, $b7, $73, $7d, $4c, $ee, $cb, $cc, $1d, $42, $9f, $da, $b6
  FCB $8a, $e6, $ad, $21, $4b, $7a, $bc, $c9, $d4, $15, $6c, $39, $be, $ab
  FCB $4f, $97, $af, $6a, $00, $60, $00, $30, $ff, $c0

* SinCos table for analog tach & speedo

SinCos:
  FCB $04, $6c, $03, $6b, $03, $6a, $03, $69, $03, $68, $02, $67, $02, $66
  FCB $02, $65, $02, $64, $01, $63, $01, $62, $01, $61, $01, $60, $01, $5f
  FCB $00, $5e, $00, $5d, $00, $5c, $00, $5b, $00, $5a, $00, $59, $00, $58
  FCB $00, $57, $00, $56, $00, $55, $00, $54, $00, $53, $00, $52, $00, $51
  FCB $00, $50, $00, $4f, $00, $4e, $00, $4d, $00, $4c, $00, $4b, $00, $4a
  FCB $00, $49, $00, $48, $00, $47, $00, $46, $00, $45, $01, $44, $01, $43
  FCB $01, $42, $01, $41, $01, $40, $02, $3f, $02, $3e, $02, $3d, $02, $3c
  FCB $03, $3b, $03, $3a, $03, $39, $03, $38, $04, $37, $04, $36, $04, $35
  FCB $05, $35, $05, $34, $06, $33, $06, $32, $06, $31, $07, $30, $07, $2f
  FCB $08, $2e, $08, $2d, $08, $2c, $09, $2b, $09, $2a, $0a, $2a, $0a, $29
  FCB $0b, $28, $0b, $27, $0c, $26, $0c, $25, $0d, $24, $0e, $24, $0e, $23
  FCB $0f, $22, $0f, $21, $10, $20, $10, $20, $11, $1f, $12, $1e, $12, $1d
  FCB $13, $1c, $14, $1c, $14, $1b, $15, $1a, $16, $19, $16, $19, $17, $18
  FCB $18, $17, $18, $17, $19, $16, $1a, $15, $1b, $15, $1b, $14, $1c, $13
  FCB $1d, $13, $1e, $12, $1e, $11, $1f, $11, $20, $10, $21, $0f, $22, $0f
  FCB $22, $0e, $23, $0e, $24, $0d, $25, $0d, $26, $0c, $27, $0c, $28, $0b
  FCB $28, $0b, $29, $0a, $2a, $0a, $2b, $09, $2c, $09, $2d, $08, $2e, $08
  FCB $2f, $07, $2f, $07, $30, $06, $31, $06, $32, $06, $33, $05, $34, $05
  FCB $35, $05, $36, $04, $37, $04, $38, $04, $39, $03, $3a, $03, $3b, $03
  FCB $3c, $02, $3d, $02, $3e, $02, $3f, $02, $40, $01, $41, $01, $42, $01
  FCB $43, $01, $44, $01, $45, $01, $46, $00, $47, $00, $48, $00, $49, $00
  FCB $49, $00, $4a, $00, $4b, $00, $4c, $00, $4d, $00, $4e, $00, $4f, $00
  FCB $50, $00, $51, $00, $52, $00, $53, $00, $54, $00, $55, $00, $56, $00
  FCB $57, $00, $58, $00, $59, $00, $5a, $00, $5b, $00, $5c, $00, $5d, $00
  FCB $5e, $01, $5f, $01, $60, $01, $61, $01, $62, $01, $63, $01, $64, $02
  FCB $65, $02, $66, $02, $67, $02, $68, $03, $69, $03, $6a, $03, $6b, $04
  FCB $6c, $04, $6d, $04, $6e, $05, $6f, $05, $70, $05, $71, $06, $72, $06
  FCB $73, $06, $74, $07, $74, $07, $75, $08, $76, $08, $77, $09, $78, $09
  FCB $79, $0a, $7a, $0a, $7b, $0b, $7b, $0b, $7c, $0c, $7d, $0c, $7e, $0d
  FCB $7f, $0d, $80, $0e, $81, $0e, $81, $0f, $82, $0f, $83, $10, $84, $11
  FCB $85, $11, $85, $12, $86, $13, $87, $13, $88, $14, $88, $15, $89, $15
  FCB $8a, $16, $8b, $17, $8b, $17, $8c, $18, $8d, $19, $8d, $19, $8e, $1a
  FCB $8f, $1b, $8f, $1c, $90, $1c, $91, $1d, $91, $1e, $92, $1f, $93, $20
  FCB $93, $20, $94, $21, $94, $22, $95, $23, $95, $24, $96, $24, $97, $25
  FCB $97, $26, $98, $27, $98, $28, $99, $29, $99, $2a, $9a, $2a, $9a, $2b
  FCB $9b, $2c, $9b, $2d, $9b, $2e, $9c, $2f, $9c, $30, $9d, $31, $9d, $32
  FCB $9d, $33, $9e, $34, $9e, $35, $9f, $35, $9f, $36, $9f, $37, $a0, $38
  FCB $a0, $39, $a0, $3a, $a0, $3b, $a1, $3c, $a1, $3d, $a1, $3e, $a1, $3f
  FCB $a2, $40, $a2, $41, $a2, $42, $a2, $43, $a2, $44, $a3, $45, $a3, $46
  FCB $a3, $47, $a3, $48, $a3, $49, $a3, $4a, $a3, $4b, $a3, $4c, $a3, $4d
  FCB $a3, $4e, $a3, $4f, $a3, $50, $a3, $51, $a3, $52, $a3, $53, $a3, $54
  FCB $a3, $55, $a3, $56, $a3, $57, $a3, $58, $a3, $59, $a3, $5a, $a3, $5b
  FCB $a3, $5c, $a3, $5d, $a3, $5e, $a2, $5f, $a2, $60, $a2, $61, $a2, $62
  FCB $a2, $63, $a1, $64, $a1, $65, $a1, $66, $a1, $67, $a0, $68, $a0, $69
  FCB $a0, $6a, $a0, $6b

* table for calculating temperature bargraph length from input A/D sample

TempTable:
  fcb 208, 197, 186, 175, 163, 152, 141, 131, 121, 112, 103, 95, 88, 81, 75
  fcb 69, 64, 59, 55, 51, 47, 44, 41, 38, 35, 33, 31, 29, 27, 25, 24, 22, 21
  fcb 20, 19, 18, 17, 16, 15, 14, 13, 13, 12, 12, 11, 10, 10, 9, 0

**********************Interrupt Vectors
  ORG RTIVec
  fdb #Int30MS

  ORG IRQVec
  fdb #IntPowerDown

  ORG ResetVec
  fdb #START

  END

Back

Hardware
FS Home Page