include "m8c.inc"
include "memory.inc"

export _qpdata0
export _qpdata1
export _qperrs0
export _qperrs1
export _QuadPhase_ISR
export _qpoffset

;-----------------------------------------------
; Variable Allocation
;-----------------------------------------------
AREA InterruptRAM (RAM, REL, CON)

// the state is just the last sampled value, shifted so that
// the two bits are in bits 2 and 3 (e.g., mask 0x0c)
qpstate0: blk 1 
qpstate1: blk 1

qptemp:   blk 1

_qpdata0: blk 2
_qperrs0: blk 1
_qpdata1: blk 2
_qperrs1: blk 1

_qpoffset: blk 1

AREA UserModules (ROM, REL, CON)

// We construct a jump table just from the qp0 functions,
// but use it for both qp0 and qp1. Thus, the tables must be identical.

FORW: equ qp0base_plus1  - qp0base
BACK: equ qp0base_minus1 - qp0base
ERR:  equ qp0base_err    - qp0base
IDLE: equ qp0done        - qp0base

// we look up what to do on each cycle in this table.

qpstatetable:

// QUADRATURE PHASE DECODER
// this table is selected by setting qpoffset=0x00
//     newstate:
//      00    01    10    1     oldstate
	DB IDLE, BACK, FORW, ERR   // 00
	DB FORW, IDLE, ERR,  BACK  // 01
	DB BACK, ERR,  IDLE, FORW  // 10
	DB ERR,  FORW, BACK, IDLE  // 11

// SINGLE PHASE DECODER-- only go forward, and ignore high bits
// this table is selected by setting qpoffset=0x10
//     newstate:
//      00    01    10    11    oldstate
	DB IDLE, FORW, IDLE, FORW  // 00
	DB FORW, IDLE, FORW, IDLE  // 01
	DB IDLE, FORW, IDLE, FORW  // 10
	DB FORW, IDLE, FORW, IDLE  // 11

_QuadPhase_ISR:
	push a
	// NOTE: We DON'T CURRENTLY USE X, so save time by not saving it!
	
	
	// read the port exactly once. the port cannot be read
	// ANYWHERE else, including user code, without potentially
	// causing us to miss an interrupt. (int=change since last read)
	mov A, reg[PRT2DR]

	// get the upper nibble (pins 4-7) into the low bits (0-3)	
	// on this hardware revision, they're hooked up to low order pins

	// we'll need this data three times... so save it a couple times.	
	mov  [qptemp], A
	
qp0: // do channel 0
	 // construct oldstate.input
	and A, 0x3
	or A, [qpstate0]
	
	// compute the new state
	add   A, [_qpoffset]
	index qpstatetable
	jacc  qp0base

qp0base:
qp0base_minus1:
	add   [_qpdata0+1], 0xff // note: The C compiler uses big endian
	adc   [_qpdata0+0], 0xff
	jmp   qp0done

qp0base_plus1:
	add   [_qpdata0+1], 0x01
	adc   [_qpdata0+0], 0x00
	jmp   qp0done

qp0base_err:
	inc   [_qperrs0]
	
qp0done:

qp1: // do channel 1
	 // construct oldstate.input
	mov A, [qptemp]
	asr A
	asr A
	and A, 0x3
	or A, [qpstate1]
	
	add   A, [_qpoffset]
	index qpstatetable
	jacc  qp1base
	
qp1base:
qp1base_minus1:
	add   [_qpdata1+1], 0xff
	adc   [_qpdata1+0], 0xff
	jmp   qp1done

qp1base_plus1:
	add   [_qpdata1+1], 0x01
	adc   [_qpdata1+0], 0x00
	jmp   qp1done

qp1base_err:
	inc   [_qperrs1]
	
qp1done:

qpcleanup:	
	// save our state and move the state bits to bits 2 and 3
	mov A, [qptemp]

	mov [qpstate1], A	
	and [qpstate1], 0xc

	// A still contains [qptemp]
	asl A
	asl A
	and A, 0xc
	mov [qpstate0], A
		
	pop a
	
	reti
