;MACROS --------------------------------------------------------------------------

; CycleFor <count>
;  if the count is less than the interrupt period, compiles a delay loop of the
;  required cycles. For large delays, compiles code to set up to a 3 byte timer
;  to an interrupt count equal to the delay and then waits for the counter to 
;  zero.

; Delay value, [usec,msec,sec,cycles]
;  Calculates cycles from delay value and units (milli seconds, micro seconds, 
;  or seconds). Calls cyclefor to delay that number of cycles

IFNDEF CPUMHZ
	error 'Please define the speed the processor will run at. E.g. CPUMHz = 50 '
	ENDIF

IFNDEF IntPeriod
	IntPeriod = 256	;set to the max value of delay possible without a real ISR.
	ENDIF


IFNDEF Timers
; Timer ISR registers (sample: See sasmtemp.src for complete setup
flags			=	7	;general flag register
TimerFlag		=	flags.2	;timer rollover flag
Timers			=	$	;timer
TimerAccL		=	8	;timer accumulator low
TimerAccH		=	9	;timer accumulator high
TimerAccT		=	10	;timer accumulator top
			watch TimerFlag, 1, ubin
			watch TimerAccL, 24, uhex
		ENDIF

mynop	MACRO
	expand
 mov !7,w ;can't single step nop
	noexpand
	ENDM

nsec	EQU	-9
usec	EQU	-6
msec	EQU	-3
sec 	EQU	1
cycles	EQU	0


cyclefor MACRO 1
	local _cycles,_temp,_ints3,_ints2,_ints1
	noexpand
_cycles = \1
_temp = 0
IF _cycles - 10 > IntPeriod OR _cycles < 0
  IF (IntPeriod =256)
	error 'This delay requires an actual ISR'
	ENDIF
 _cycles = _cycles - 10
 _ints3 = $FF - (_cycles/(IntPeriod*$10000))
 _ints2 = $FF - (_cycles/(IntPeriod*$100)//$100)
 _ints1 = $FF - (_cycles/IntPeriod//$100)

	IF Timers > $0F
;	ERROR 'Timers must be in bank 0'
 expand
 bank Timers
 noexpand
			ENDIF
	expand
 clr 	TimerAccL
 mov 	TimerAccT, #_ints3
 mov 	TimerAccH, #_ints2
 mov 	TimerAccL, #_ints1
 clrb	TimerFlag
 sb  	TimerFlag
 jmp 	$-2
	noexpand
 _cycles = _cycles // IntPeriod
ELSE
 expand
 ;cycles to delay:
 _temp = _cycles
 noexpand
 _temp = $ // 4
 IF _temp == 2
  IF _cycles < 5 
   REPT	_cycles
    mynop
    ENDR
   _cycles = 0
  ELSE
   mynop
   _cycles = _cycles -1
   ENDIF
  ENDIF
 IF _temp == 1
  IF _cycles < 7 
   REPT	_cycles
    mynop
    ENDR
   _cycles = 0
  ELSE
   _cycles = _cycles - 2
   _loops = _cycles / 5
   expand
 mov w, #_loops
 page $+1
 decsz 1
 jmp $-1
   noexpand
   _cycles = _cycles // 5 ;cycles left over
   ENDIF
  ENDIF
 IF _cycles > 5
  _cycles = _cycles - 1
  _loops = _cycles / 5
  expand
 mov w, #_loops
 decsz 1
 clrb 2.1
  noexpand
  _cycles = _cycles // 5 ;cycles left over
  ENDIF
 IF _cycles > 0
  REPT	_cycles
   mynop
   ENDR
  ENDIF
 ENDIF
	ENDM

delayhelp MACRO
	ERROR 'USAGE: delay value, [usec,msec,sec,cycles]'
	ENDM

delay	MACRO	value, units
;	local _cycles ;if this is local, the call to cyclefor don't work.
 noexpand
;Calculates cycles from delay value and units (milli seconds, micro seconds, or seconds)
;calls cyclefor to delay that number of cycles. 
;Expects CpuMhz set to CPU MHz.
 _cycles = 0
 IF  value < 1000 && value > 0 
  IF ?units=='sec'
   _cycles = (value * 100000000 / (100/CpuMhz))
   ENDIF
  IF ?units=='msec'
   _cycles = (value * 1000000 / (1000/CpuMhz))
   ENDIF
  IF ?units=='usec'
   _cycles = (value * 1000 / (1000/CpuMhz))
   ENDIF
  IF ?units=='nsec'
   _cycles = (value * 10 + 5 / (10000/CpuMhz))
   ENDIF
  IF ?units=='cycles'
   _cycles = value
   ENDIF
  IF _cycles < 1
   expand
 ;delay less than one cycle at this processor speed'
   noexpand
  ELSE
   cyclefor _cycles
   ENDIF

 ELSE
	delayhelp
  ENDIF
	ENDM



