http://www.edtn.com/embapps/emba035.htm

http://www.geocities.com/robert_lacoste

Steve Thackery says:

[Microchip Application Note AN542 doesn't work]

*No* disrespect to the guys who wrote it, but it doesn't work.

Over the last several months I've been developing a product for my employer which uses a fast fourier transform as part of its functionality. The product is based upon a 17C44, by the way.

I was foolish enough to plan my timescales assuming that the Microchip FFT would be pretty well "plug and play". After all, I do tend to trust the stuff they publish. How wrong I was!

I won't bore you with the details, but Microchip's FFT is seriously defective. I can only guess that it didn't receive much testing. In fact, reading between the lines in AN542 it becomes clear that it was primarily written as a *benchmarking* exercise rather than a reliable FFT module for use in our projects.

Basically, if you test it with the waveform shown in the AN, it works perfectly. I should have been suspicous, even so. The waveform shown is of very low frequency, and has a whole number of cycles in the sampling window. Alter that frequency by even a small amount, so that there isn't a whole number of cycles in the window and the whole thing goes haywire! It generates artefacts in the FFT output all over the place, both above and below the "real" frequency. Similarly, test it at higher frequencies with sine or square waves, and you get a complete spectrum of rubbish at the output.

Incidentally, it wasn't made clear in the AN that permissible input range of values is between 0 and 3FFF. In other words, you need to DC-shift your sound sample so its centred around 1FFF, and adjust its gain. That caught us out for a couple of days!

We assumed it must be something we were doing wrong and spent ages poring over the AN to see if we were doing something stupid. We also tried working through the code itself, but it is almost inpenetrable. We tried everything, including using very small amplitude signals, but to no avail. The output is rubbish *except* with very low frequency square waves with a whole number of cycles in the window.

I can only imagine that there is a scaling problem somewhere in the maths. It looks like there is some sort of overflow or fold-back going on.

This cost me two months of development time and made me very unpopular with my employer and customer!

In the end we gave up and looked elsewhere. This is where Robert Lacoste comes into the picture. He developed his own FFT module from scratch and incorporated it into his PIC'Spectrum product. I contacted him and asked if he would be willing to let us use his FFT module - for prototyping and test purposes only - in our own product. He was willing and incredibly helpful, answering all our questions with clarity.

It took us two days to unplug the Microchip FFT module and plug in the Lacoste module. Here's what happened. It worked PERFECTLY! The output is classic, text-book perfect under all circumstances. Furthermore, it runs at least ten times as fast as the Microchip module.

Let me state publicly my most grateful thanks to Robert. If you need to include an FFT in any of your products, contact him on robert_lacoste@yahoo.fr He allowed us free use in our prototypes, and suggested a very reasonable royalty on our production models. I expect he might extend a similar deal to others.

In summary, then: BEWARE the Microchip FFT, and THANK YOU Robert Lacoste!

;============================================================================
; PROJECT     : PIC'SPECTRUM
;
; FILE        : PICSPECT.ASM
;
; VERSION     : 1.0
;
; DESCRIPTION :
;
; PIC'SCOPE digital audio spectrum analyser - Main source file
;
; This project is a complete audio spectrum analyser with output on a
; standard VGA display, done entirely with a PIC17C756 microcontroler.
;
; The controler is in charge of :
; - ADC acquisition of the incoming signal
; - Fast Fourier Transform of the signal
; - Power calculation and if required logarithmic scaling
; - Video generation entirely in software
; of course in real time.
;
; Developped on MICROCHIP's MPLAB 3.31.0
; To be embedded in a PIC17C756 (32MHz crystal)
;
;============================================================================
;                Developped & Copyrighted by Robert LACOSTE
;============================================================================


;----------------------------------------------------------------------------
; System definitions
;----------------------------------------------------------------------------

		PROCESSOR  17C756	; Assembler directives
		RADIX 	   HEX
		ERRORLEVEL 0
		ERRORLEVEL -302		; no bank control warnings

		TITLE 	   "PIC'SPECTRUM"
		SUBTITLE   "(C) Robert Lacoste"

#include	"P17C756.INC"		; Processor dependant declarations

		; config register :
		; XT osc, no watchdog, brown-out reset active, microcontroler
		__CONFIG (_XT_OSC & _WDT_OFF & _BODEN_ON & _MC_MODE)


;----------------------------------------------------------------------------
; Application constants
;----------------------------------------------------------------------------

MAXPIXVAL	equ	127	; maximum scaled pixel value

INITTIM	equ	$FFFF-254+13+5	; timer load value,
					; 254 because 31.77µS=254*4/32MHz
					; minus 13 for irq to reload delay
					; minus 5 for timer to irq delay

BKG_COLOR	equ	%00000100	; background=Blue
SLINE_COLOR	equ	%00000011	; separation lines=Yellow
SHORTS_COLOR	equ	%00000011	; small scale indicator=Yellow
LONGS_COLOR	equ	%00000011	; long scale indicator=Yellow
FREQ_COLOR	equ	%00000001	; Frequency bars=Red
BKGTITLE_COLOR	equ	%00000010	; Background title=Green
TITLE_COLOR	equ	%00000000	; Title=Black
HOLD_COLOR	equ	%00000001	; Hold=Red


;----------------------------------------------------------------------------
; Vectors
;----------------------------------------------------------------------------

reset_vector	org	$0000
	jmp	start	; Initialisation

intpin_vector	org	$0008
	jmp	start	; should not occur

timer0_vector	org	$0010
	jmp	it_timer	; horizontal sync interrupt

t0cki_vector	org	$0018
	jmp	start	; should not occur

periph_vector	org	$0020
	jmp	start	; should not occur

start_appl	org	$0050	; start of application area


;----------------------------------------------------------------------------
; Inclusion of extern application files
;----------------------------------------------------------------------------

#include 	"vars.inc"		; Variables declarations
#include	"fixed.inc"		; Fixed point arithmetic
#include	"testsig.inc"		; Test signals generation
#include	"fft.inc"		; FFT calculation routines
#include	"powers.inc"		; power calculation & display access
#include	"irq.inc"		; interrupt routine & video generation


;----------------------------------------------------------------------------
; Main starting point
;----------------------------------------------------------------------------

start	nop
		BANKSEL zone_main

;--> Initialisation

	call	initialize	; initialization of ports & variables
	call	realfft	; do the first FFT (on the test signal)
	call	init_timer	; launch timer0 interrupts

mainloop	nop

;--> Power spectrum calculation & scaling

		movlb 0			; if RB7=0 (mode log),
	snb	RB.7
	jmp	spectlin
spectlog	call	powerlog	; calculate spectrum in log scale
	jmp	main1
spectlin	call	powerlin	; else calculate spectrum in lin scale

main1	nop

;--> Analog acquisition

		movlb 0			; if RB6=1 (non hold mode),
	sb	RB.6	; do analog sample acquisition :
	jmp	main2
		movlb 1			; RD1=1 (debug line : ADC going on)
	setb	RD.1
		BANKSEL num_sample	; sample number=0
	clr	num_sample
	call	init_adc	; initialize analog acquisition
		BANKSEL acq_request
	mov	W, #1	; put acqrequest flag to 1
	mov	acq_request, W

	clr	WREG	; and wait for it to be 0
acqwait		cpfseq acq_request
	jmp	acqwait

		movlb 1			; RD1=0 (debug line : ADC going on)
	clrb	RD.1

;--> Do the FFT

		movlb 1			; RD0=1 (debug line : FFT going on)
	setb	RD.0

		BANKSEL zone_main
	call	realfft	; do the FFT

		movlb 1			; RD0=0 (debug line : FFT going on)
	clrb	RD.0

;--> And loop !

main2	jmp	mainloop


;----------------------------------------------------------------------------
; Ports & variables initialization
;----------------------------------------------------------------------------

initialize	nop

;--> Variables initialization

		BANKSEL acq_request	; reset adc control registers
	clr	acq_request
	clr	num_sample

		BANKSEL scan_line	; reset scan line number
	clr	scan_line	; (will be incremented to 1 at the
	clr	scan_line+1	; first interrupt)

		BANKSEL displ0		; reset displ0 buffer
	mov	W, #low displ0
	mov	FSR0, W
	clrb	ALUSTA.FS1	; auto increment mode
	setb	ALUSTA.FS0
	clrb	ALUSTA.C
	mov	W, #low displ0+64
rstdispl0	clr	INDF0
		cpfseq FSR0
	jmp	rstdispl0

		BANKSEL displ1		; reset displ1 buffer
	mov	W, #low displ1
	mov	FSR0, W
	clrb	ALUSTA.FS1	; auto increment mode
	setb	ALUSTA.FS0
	clrb	ALUSTA.C
	mov	W, #low displ0+64
rstdispl1	clr	INDF0
		cpfseq FSR0
	jmp	rstdispl1

	setb	ALUSTA.FS1	; return to non-increment mode

		BANKSEL zone_main
		m_ldaconst H'2000'	; generate test square signal
	mov	W, #16
	call	test_square

;--> Ports initialization

	mov	W, #%11111000	; RB0 to RB2 are outputs
		movlb 0
	mov	DDRB, W
	clr	RB	; initialized to 0

	mov	W, #%10101111	; RC4 and RC6 are outputs
		movlb 1
	mov	DDRC, W
	clrb	RC.4	; RC4=0 (Hsync)
	setb	RC.6	; RC6=1 (Vsync)

	mov	W, #%11111000	; RD0 to RD2 are outputs
		movlb 1
	mov	DDRD, W
	clr	RD	; initialized to 0

	mov	W, #%01111111	; RG7 is output
		movlb 5
	mov	DDRG, W
	clr	RG	; initialized to 0

	ret


;----------------------------------------------------------------------------
; Initialization of timer0
;
; Generate an interrupt every 31.77 micro-second (horizontal refresh
; rate for VGA display in 640x350 mode = 31.476KHz)
;
; Warning : interrupts will start immediatly after calling this routine
;----------------------------------------------------------------------------

init_timer	nop

	setb	CPUSTA.GLINTD	; disable global interrupts

	setb	T0STA.T0CS	; select internal clock
	clrb	T0STA.T0PS3	; and prescale factor 1:1
	clrb	T0STA.T0PS2
	clrb	T0STA.T0PS1
	clrb	T0STA.T0PS0

		BANKSEL tmpcpt
	mov	W, #high INITTIM	; load timer
	mov	tmpcpt, W
	mov	W, #low INITTIM
	mov	TMR0L, W
		movfp tmpcpt,TMR0H

	clrb	INTSTA.PEIE	; disable PEI interrupts
	clrb	INTSTA.T0CKIE	; disable external interrupts on RA1
	clrb	INTSTA.INTE	; disable external interrupts on RA0

	setb	INTSTA.T0IE	; enable timer0 interrupts

	clrb	CPUSTA.GLINTD	; enable global interrupts

	ret


;----------------------------------------------------------------------------
; Configuration of analog acquisition port
;
; Connect the analog source and configure the A/D sub-system. Acquisition
; will be done by the interrupt routine synchronously with video generation.
;----------------------------------------------------------------------------

init_adc	movlb 5
	mov	W, #%10000000	; clock=F/64 (2µS conversion),
	mov	ADCON1, W	; left justified, ref 0/5V

	mov	W, #%10000000	; select chanel AD8
	mov	ADCON0, W

	setb	ADCON0.ADON	; switch on ADC sub-system

	ret



		END

;============================================================================
;                             - END OF FILE -
;============================================================================
;============================================================================
; PROJECT     : UPS'SPECTRUM
;
; FILE        : VARS.INC
;
; VERSION     : 1.0
;
; DESCRIPTION :
;
; Definition of all RAM variables, bank per bank.
; Usage of each variable (used by main program, by interrupt routine or
; both) is defined
;
;============================================================================
;                Developped & Copyrighted by Robert LACOSTE
;============================================================================


;----------------------------------------------------------------------------
; Unbanked RAM
;----------------------------------------------------------------------------

; unbanked RAM $1A to $1A : private unbanked save location for interrupt
; routine. Other locations are in bank 0.

		cblock H'001A'
			sv_bsr		; BSR save location
		endc

; unbanked ram $1B to $1F : arithmetic working registers, to be used only
; by the main program

		cblock H'001B'		; arithmetic working registers
			ra:2		; (format s-2-13)
			rb:2		; (format s-2-13)
			rdiv:1		; (8 bit unsigned int)
		endc


;----------------------------------------------------------------------------
; Bank 0
;----------------------------------------------------------------------------

; $20 to $7F : private registers for the interrupt routine
;	       and exchange registers & flags between main pgr and interrupt

		cblock H'0020'
			zone_irq:0
		endc

		cblock
			scan_line:2	; scan line number, from 1 to 449, H-L
			frame_num:1	; frame number (for blinkings)
			tmpcolor:1	; temporary storage of color
			tmpi:2		; temporary variable
			tmpi2:2		; temporary variable
		endc

		cblock
			sv_alusta	; save location for registers
			sv_wreg		; during interrupt
			sv_fsr0
		endc

		; WARNING : only these 4 registers (with bsr, saved in
		; non-banked ram) are automaticaly saved. Be carefull when
		; using FSR1 or table read registers !

		; Exchange registers et flags between main pgr and interrupt

		cblock
			acq_request:1	; Analog acquisition flag
					; (0:finished, 1:sampling, 2:convert)
			num_sample:1	; Analog sample number
		endc

; $80 to $FF : FFT data buffer 0...63 (2 bytes/value, big endian : H-L)

		cblock H'0080'
			data0:128	; (format s-2-13)
		endc

;----------------------------------------------------------------------------
; Bank 1
;----------------------------------------------------------------------------

; $20 to $7F : private registers for the main program

		cblock H'0120'
			zone_main:0
		endc

		cblock			; temporary variables for FFT and
					; powers
			wr:2		; (format s-2-13)
			wpr:2		; (format s-2-13)
			wi:2		; (format s-2-13)
			wpi:2		; (format s-2-13)
			theta:2		; (format s-2-13)
			mmax:1		; counter
			m:1		; counter
			j:1		; counter
			istep:1		; counter
			i:1		; counter
			i1:1		; counter
			i2:1		; counter
			i3:1		; counter
			i4:1		; counter
		endc

		cblock			; temporary arithm. variables
			h1r:2		; (format s-2-13)
			h1i:2		; (format s-2-13)
			h2r:2		; (format s-2-13)
			h2i:2		; (format s-2-13)
			wtemp:2		; (format s-2-13)
		endc

		cblock			; generic counters
			cptm:2		; (16 bit unsigned int)
			cpti:2		; (16 bit unsigned int)
			cptj:2		; (16 bit unsigned int)
		endc

		cblock			; temporary registers for math.inc
			mres3:1		; for m_mult and m_divi
			mres2:1
			mres1:1
			mres0:1
			msign:1
			x0:2		; for m_sin
			x1:2
			x2:2
			sin_saveb:2
			scaletmp:2	; for m_scalelin and m_scalelog
			logresult:2	; for m_scalelog
		endc

		cblock			; temporary registers for testsig.inc
			test_halfp:1
			test_step:2
			test_cval:2
		endc

		cblock
			tmpcpt:1	; temporary register for inittimer
		endc

; $80 to $FF : FFT data buffer 64...127 (2 bytes/value, big endian : H-L)

		cblock H'0180'
			data1:128	; (format s-2-13)
		endc

;----------------------------------------------------------------------------
; Bank 2
;----------------------------------------------------------------------------

; $20 to $5F : Display buffer 0...63

		cblock H'0220'
			displ0:64	; (value 0..MAXPIXVAL)
		endc

; $60 to $7F : unused

; $80 to $FF : FFT data buffer 128...191 (2 bytes/value, big endian : H-L)

		cblock H'0280'
			data2:128	; (format s-2-13)
		endc

;----------------------------------------------------------------------------
; Bank 3
;----------------------------------------------------------------------------

; $20 to $5F : Display buffer 64...127

		cblock H'0320'
			displ1:64	; (value 0..MAXPIXVAL)
		endc

; $60 to $7F : unused

; $80 to $FF : FFT data buffer 192...255 (2 bytes/value, big endian : H-L)

		cblock H'0380'
			data3:128	; (format s-2-13)
		endc


;============================================================================
;                             - END OF FILE -
;============================================================================
;============================================================================
; PROJECT     : PIC'SPECTRUM
;
; FILE        : FIXED.INC
;
; VERSION     : 1.0
;
; DESCRIPTION :
;
; Fixed point math routines, using a s-2-13 format (sign bit in 2-complement,
; 2 bits for the integer part, 13 bits for the decimal part).
;
; So values ranging +/-3.99999, resolution 1/2 exp 13 = 0.000122
;
; All functions and macros operate on registers ra,rb and rdiv.
; Storage could be in a generic "arithmetic" register (2 bytes) or in the
; FFT data storage table ("data")
;
; The FFT data table ("data") is a 4x64 word (2 bytes) array, each of the
; four blocks being at at fixed adress ($80 to $ff) in the 4 banks.
;
; WARNING : ra/rb/rdiv are supposed to be in unbanked memory. Bank selector
; must be zone_main on input (access to arithmetic tempory registers) and is
; garanteed to be zone_main on exit
;
; In general, WREG is scrambled
;
;============================================================================
;                Developped & Copyrighted by Robert LACOSTE
;============================================================================


;----------------------------------------------------------------------------
; m_lda : 	copy a given general register (2 bytes) in register A
;----------------------------------------------------------------------------

m_lda		macro inreg
		movfp inreg,WREG
	mov	ra, W
		movfp inreg+1,WREG
	mov	ra+1, W
		endm

;----------------------------------------------------------------------------
; m_ldai :	get the data value pointed by reg and store it in A
;----------------------------------------------------------------------------

m_ldai		macro indexreg
		movfp indexreg, WREG
		movlr 0			; start with bank 0
	snb	WREG.7	; select the good bank
	setb	BSR.5
	snb	WREG.6	; based on 2 first bits of WREG
	setb	BSR.4
	clrb	ALUSTA.C	; multiply by 2
		rlcf WREG,1
	setb	WREG.7	; and set high bit (data start at $80)
	mov	FSR0, W	; and use it as an index
		movpf INDF0,ra		; to get msb value
	inc	FSR0
		movpf INDF0,ra+1	; and lsb value
		BANKSEL zone_main	; reset bank register
		endm

;----------------------------------------------------------------------------
; m_ldb : 	copy a given general register (2 bytes) in register B
;----------------------------------------------------------------------------

m_ldb		macro inreg
		movfp inreg,WREG
	mov	rb, W
		movfp inreg+1,WREG
	mov	rb+1, W
		endm

;----------------------------------------------------------------------------
; m_ldbi :	get the data value pointed by reg and store it in B
;----------------------------------------------------------------------------

m_ldbi		macro indexreg
		movfp indexreg,WREG
		movlr 0			; start with bank 0
	snb	WREG.7	; select the good bank
	setb	BSR.5
	snb	WREG.6	; based on 2 first bits of WREG
	setb	BSR.4
	clrb	ALUSTA.C	; multiply by 2
		rlcf WREG,1
	setb	WREG.7	; and set high bit (data start at $80)
	mov	FSR0, W	; and use it as an index
		movpf INDF0,rb		; to get msb value
	inc	FSR0
		movpf INDF0,rb+1	; and lsb value
		BANKSEL zone_main	; reset bank register
		endm

;----------------------------------------------------------------------------
; m_lddiv :	copy a given register (int, 1 byte) in register DIV
;----------------------------------------------------------------------------

m_lddiv		macro inreg
		movfp inreg,WREG
	mov	rdiv, W
		endm

;----------------------------------------------------------------------------
; m_sta :	store the value of A in a given general register (2 bytes)
;----------------------------------------------------------------------------

m_sta		macro outreg
		movfp ra,WREG
	mov	outreg, W
		movfp ra+1,WREG
	mov	outreg+1, W
		endm

;----------------------------------------------------------------------------
; m_stai :	store the value of A in the data value pointed by reg
;----------------------------------------------------------------------------

m_stai		macro indexreg
		movfp indexreg, WREG
		movlr 0			; start with bank 0
	snb	WREG.7	; select the good bank
	setb	BSR.5
	snb	WREG.6	; based on 2 first bits of WREG
	setb	BSR.4
	clrb	ALUSTA.C	; multiply by 2
		rlcf WREG,1
	setb	WREG.7	; and set high bit (data start at $80)
	mov	FSR0, W	; and use it as an index
		movfp ra,INDF0		; to store msb value
	inc	FSR0
		movfp ra+1,INDF0	; and lsb value
		BANKSEL zone_main	; reset bank register
		endm

;----------------------------------------------------------------------------
; m_ldaconst :	load an immediate value in A
;----------------------------------------------------------------------------

m_ldaconst	macro immvalue
	mov	W, #high immvalue
	mov	ra, W
	mov	W, #low  immvalue
	mov	ra+1, W
		endm

;----------------------------------------------------------------------------
; m_mvba :	copy B to A
;----------------------------------------------------------------------------

m_mvba		macro
		movfp rb,WREG
	mov	ra, W
		movfp rb+1,WREG
	mov	ra+1, W
		endm

;----------------------------------------------------------------------------
; m_mvab :	copy A to B
;----------------------------------------------------------------------------

m_mvab		macro
		movfp ra,WREG
	mov	rb, W
		movfp ra+1,WREG
	mov	rb+1, W
		endm

;----------------------------------------------------------------------------
; m_add :	add B to A (A=A+B)
;----------------------------------------------------------------------------

m_add		macro
		movfp rb+1,WREG		; low byte first
	add	ra+1, W
		movfp rb,WREG		; and high byte with carry
		addwfc ra,1
		endm

;----------------------------------------------------------------------------
; m_sub :	substract B to A (A=A-B)
;----------------------------------------------------------------------------

m_sub		macro
		movfp rb+1,WREG		; low byte first
	sub	ra+1, W
		movfp rb,WREG		; and high byte with borrow
		subwfb ra,1
		endm

;----------------------------------------------------------------------------
; m_mult :	multiply A to B (A=A*B)
;		Warning : overflow not detected if result>4
;----------------------------------------------------------------------------

m_mult		movfp ra+1,WREG		; low byte x low byte
		mulwf rb+1
		movpf PRODH,mres1
		movpf PRODL,mres0
		movfp ra,WREG		; high byte x high byte
		mulwf rb
		movpf PRODH,mres3
		movpf PRODL,mres2
		movfp ra+1,WREG		; low byte x high byte
		mulwf rb
		movfp PRODL,WREG
	add	mres1, W
		movfp PRODH,WREG
		addwfc mres2,F
	clr	WREG
		addwfc mres3,F
		movfp ra,WREG		; high byte x low byte
		mulwf rb+1
		movfp PRODL,WREG
	add	mres1, W
		movfp PRODH,WREG
		addwfc mres2,F
	clr	WREG
		addwfc mres3,F
	sb	rb.7	; test if B<0
	jmp	sign_ra
		movfp ra+1,WREG		; if so, adjust value
	sub	mres2, W
		movfp ra,WREG
		subwfb mres3,F
sign_ra	sb	ra.7	; test if A<0
	jmp	sign_end
		movfp rb+1,WREG		; if so, adjust value
	sub	mres2, W
		movfp rb,WREG
		subwfb mres3,F
sign_end	rlcf mres1,F		; shift left one time
		rlcf mres2,F
		rlcf mres3,F
		rlcf mres1,F		; shift left one time
		rlcf mres2,F
		rlcf mres3,F
		rlcf mres1,F		; shift left one time
		rlcf mres2,F
		rlcf mres3,F
		movfp mres3, ra		; forget mres1 and store result
		movfp mres2, ra+1	; in register A
end_mult	ret

;----------------------------------------------------------------------------
; m_divi :	divide A with rdiv (A=A/DIV), rdiv being a non signed integer
;		value and not a fixed decimal value
;
;	call	routines provided in Microchip's application notes (see div.inc)
;----------------------------------------------------------------------------

; Correspondances between AN617 variables and pic'spectrum's...
#define		AARGB0 (ra)
#define		AARGB1 (ra+1)
#define		ACCB0  (ra)
#define		ACCB1  (ra+1)
#define 	BARGB0 (rdiv)
#define		REMB0  (mres0)
#define		TEMP   (mres1)

#include	"div.inc"		; include 16/8 unsigned routine
					; from microchip's application
					; note AN617

m_divi	clrb	msign.0
	sb	ra.7	; save sign of A
	jmp	m_divdiv
	setb	msign.0

	not	ra	; if A<0, A=-A
	not	ra+1
	mov	W, #1
	add	ra+1, W
	mov	W, #0
		addwfc ra,F

m_divdiv	call	FXD1608U	; do the division

	sb	msign.0	; if A was <0
	jmp	end_mdivi
	not	ra	; A=-A
	not	ra+1
	mov	W, #1
	add	ra+1, W
	mov	W, #0
		addwfc ra,F

end_mdivi	ret


;----------------------------------------------------------------------------
; m_div2 :	divide A with 2 (A=A/2)
;----------------------------------------------------------------------------

m_div2		macro
	clrb	ALUSTA.C
		rrcf ra,1		; divide high byte
		rrcf ra+1,1		; and low byte
	snb	ra.6	; test old sign bit
	setb	ra.7	; if set, report it to msb
		endm

;----------------------------------------------------------------------------
; m_sin :	replace A with sin(A)
;
; Sinus calculated by interpolation of tables values got with the MSB of A
; (v_msb and v_msb+1 are the table values corresponding for msb A and the next
; one in the table, with rollover on 0)
;
; ra=(((v_msb+1)*lsb ra+(v_msb)*(1-lsb ra));
;
;----------------------------------------------------------------------------

		radix dec
sintable	dw 0
		dw   255,   511,   766,  1021,  1274,  1527,  1777,  2026
		dw  2273,  2518,  2760,  3000,  3237,  3470,  3700,  3927
		dw  4150,  4368,  4583,  4793,  4998,  5198,  5393,  5583
		dw  5768,  5947,  6120,  6287,  6448,  6603,  6751,  6893
		dw  7028,  7156,  7277,  7391,  7498,  7597,  7689,  7774
		dw  7850,  7920,  7981,  8035,  8081,  8119,  8149,  8171
		dw  8185,  8191,  8189,  8179,  8162,  8136,  8102,  8060
		dw  8011,  7953,  7888,  7815,  7735,  7647,  7551,  7448
		dw  7338,  7221,  7097,  6965,  6827,  6682,  6531,  6373
		dw  6210,  6040,  5864,  5682,  5495,  5303,  5105,  4902
		dw  4695,  4483,  4266,  4046,  3821,  3593,  3361,  3126
		dw  2888,  2647,  2404,  2158,  1910,  1660,  1408,  1156
		dw   902,   647,   391,   135,  -120,  -375,  -631,  -886
		dw -1140, -1393, -1644, -1894, -2142, -2388, -2632, -2873
		dw -3111, -3347, -3579, -3807, -4032, -4253, -4469, -4682
		dw -4889, -5092, -5290, -5483, -5671, -5853, -6029,  6199
		dw  6029,  5853,  5671,  5483,  5290,  5092,  4889,  4682
		dw  4469,  4253,  4032,  3807,  3579,  3347,  3111,  2873
		dw  2632,  2388,  2142,  1894,  1644,  1393,  1140,   886
		dw   631,   375,   120,  -135,  -391,  -647,  -902, -1156
		dw -1408, -1660, -1910, -2158, -2404, -2647, -2888, -3126
		dw -3361, -3593, -3821, -4046, -4266, -4483, -4695, -4902
		dw -5105, -5303, -5495, -5682, -5864, -6040, -6210, -6373
		dw -6531, -6682, -6827, -6965, -7097, -7221, -7338, -7448
		dw -7551, -7647, -7735, -7815, -7888, -7953, -8011, -8060
		dw -8102, -8136, -8162, -8179, -8189, -8191, -8185, -8171
		dw -8149, -8119, -8081, -8035, -7981, -7920, -7850, -7774
		dw -7689, -7597, -7498, -7391, -7277, -7156, -7028, -6893
		dw -6751, -6603, -6448, -6287, -6120, -5947, -5768, -5583
		dw -5393, -5198, -4998, -4793, -4583, -4368, -4150, -3927
		dw -3700, -3470, -3237, -3000, -2760, -2518, -2273, -2026
		dw -1777, -1527, -1274, -1021,  -766,  -511,  -255
		radix hex


m_sin		movpf rb,sin_saveb	; save B register
		movpf rb+1,sin_saveb+1
	clr	x0+1
	mov	W, #low (sintable)	; get table value corresponding
	add	W, ra	; to the MSB of A -> x0
	mov	TBLPTRL, W
	mov	W, #high (sintable)
		addwfc x0+1,W
	mov	TBLPTRH, W
		tablrd 0,0,x0+1		; dummy read, update TABLATH
		tlrd 1,x0		; read high byte
		tablrd 0,1,x0+1		; and low byte.

	clr	x1+1
		movfp ra,WREG		; get table value corresponding
	mov	W, ++WREG	; to the MSB of A+1, with rollover at 0
;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. 
;		addlw low (sintable)	; -> x1
	mov	Hack, W
	mov	W, #low (sintable)	; -> x1
	add	W, Hack
	mov	TBLPTRL, W
	mov	W, #high (sintable)
		addwfc x1+1,W
	mov	TBLPTRH, W
		tablrd 0,0,x1+1		; dummy read, update TABLATH
		tlrd 1,x1		; read high byte
		tablrd 0,1,x1+1		; and low byte.

		movfp ra+1,WREG		; get LSB of A in B
	mov	rb, W	; and convert it to a weight factor
	clr	rb+1
	clrb	ALUSTA.C
		rrcf rb,F
		rrcf rb+1,F
	clrb	ALUSTA.C
		rrcf rb,F
		rrcf rb+1,F
	clrb	ALUSTA.C
		rrcf rb,F
		rrcf rb+1,F

		m_lda x1		; multiply "next" table value by B
	call	m_mult
		m_sta x2		; and save it

		m_ldaconst H'2000'	; calculate 1-weight factor
		m_sub
		m_ldb x0		; and multiply it by "previous" value
	call	m_mult

		m_ldb x2		; add the 2 values
		m_add

end_sin		m_ldb sin_saveb		; restore B
	ret


;----------------------------------------------------------------------------
; m_scalelin :	linear scaling of A, result in WREG (0 to MAXPIXVAL)
;		and in rdiv
;----------------------------------------------------------------------------

m_scalelin	movpf ra,scaletmp	; copy A to scaletmp reg
		movpf ra+1,scaletmp+1
	clrb	ALUSTA.C	; divide by 16
		rrcf scaletmp,F		; 2
		rrcf scaletmp+1,F
	clrb	ALUSTA.C
		rrcf scaletmp,F		; 4
		rrcf scaletmp+1,F
	clrb	ALUSTA.C
		rrcf scaletmp,F		; 8
		rrcf scaletmp+1,F
	clrb	ALUSTA.C
		rrcf scaletmp,F		; 16
		rrcf scaletmp+1,F
		tstfsz scaletmp		; if tmp>255, return MAXPIVXVAL
	jmp	m_scaleover
	mov	W, #MAXPIXVAL	; if tmp>MAXPIXVAL, return MAXPIXVAL
		cpfslt scaletmp+1
	jmp	m_scaleover
		movfp scaletmp+1,WREG
	jmp	end_scalelin

m_scaleover	mov	W, #MAXPIXVAL	; return MAXPIXVAL
end_scalelin	mov	rdiv, W
	ret

;----------------------------------------------------------------------------
; m_scalelog : 	logarithmic scaling of A, result in WREG (0 to 127)
;		and in rdiv
;----------------------------------------------------------------------------

		radix dec
logtable	dw -4652, -4599, -4548, -4496, -4445, -4394, -4344, -4294
		dw -4245, -4196, -4147, -4098, -4050, -4002, -3955, -3908
		dw -3861, -3815, -3769, -3723, -3677, -3632, -3587, -3543
		dw -3498, -3454, -3410, -3367, -3324, -3281, -3238, -3196
		dw -3154, -3112, -3071, -3029, -2988, -2947, -2907, -2867
		dw -2826, -2787, -2747, -2708, -2669, -2630, -2591, -2553
		dw -2514, -2476, -2438, -2401, -2363, -2326, -2289, -2253
		dw -2216, -2180, -2143, -2107, -2072, -2036, -2001, -1965
		dw -1930, -1895, -1861, -1826, -1792, -1758, -1724, -1690
		dw -1656, -1623, -1590, -1556, -1523, -1491, -1458, -1425
		dw -1393, -1361, -1329, -1297, -1265, -1234, -1202, -1171
		dw -1140, -1109, -1078, -1047, -1017,  -986,  -956,  -926
		dw  -896,  -866,  -836,  -806,  -777,  -748,  -718,  -689
		dw  -660,  -631,  -603,  -574,  -545,  -517,  -489,  -461
		dw  -433,  -405,  -377,  -349,  -322,  -294,  -267,  -240
		dw  -213,  -186,  -159,  -132,  -105,   -79,   -52,   -26
		radix hex


m_scalelog	tstfsz ra		; if A<32, return 0
	jmp	log_testover
	mov	W, #32
		cpfslt ra+1
	jmp	log_testover
	mov	W, #0
	jmp	end_scalelog

log_testover	mov	W, #high (032*MAXPIXVAL)	; if A>32xMAXPIXVAL,
		cpfsgt ra			; return MAXPIXVAL
	jmp	log_1
	jmp	log_scaleover
log_1		cpfseq ra
	jmp	log_ok
	mov	W, #low (032*MAXPIXVAL)
		cpfslt ra+1
	jmp	log_scaleover

log_ok	clr	logresult	; clear result register
	clr	logresult+1

		movpf ra,scaletmp	; copy A to scaletmp reg
		movpf ra+1,scaletmp+1	; (A is between 32 and 32xMAXPIXVAL)
	clrb	ALUSTA.C	; multiply tmp by 8
		rlcf scaletmp+1,F	; 2
		rlcf scaletmp,F
	clrb	ALUSTA.C
		rlcf scaletmp+1,F	; 4
		rlcf scaletmp,F
	clrb	ALUSTA.C
		rlcf scaletmp+1,F	; 8
		rlcf scaletmp,F		; (tmp is between 256 and 256xMAXPIXVAL)

		; normalization phase, until tmp < 256
log_normalize	tstfsz scaletmp
	jmp	log_2
	jmp	log_endnorm
log_2	mov	W, #low 4652	; add 256*ln(2)*MAXPIXVAL/ln(MAXPIXVAL)
	add	logresult+1, W	; (=4652) to current evaluation
	mov	W, #high 4652
		addwfc logresult,F
	clrb	ALUSTA.C
		rrcf scaletmp,F		; divide tmp by 2
		rrcf scaletmp+1,F
	jmp	log_normalize	; and loop

log_endnorm	mov	W, #$7F	; tmp is now between 128 and 255
	and	W, scaletmp+1	; substract 128
;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. 
;		addlw low (logtable)	; and use it as index in logtable
	mov	Hack, W
	mov	W, #low (logtable)	; and use it as index in logtable
	add	W, Hack
	mov	TBLPTRL, W
	mov	W, #high (logtable)
		addwfc scaletmp,W
	mov	TBLPTRH, W
		tablrd 0,0,scaletmp+1	; dummy read, update TABLATH
		tlrd 1,scaletmp		; read high byte
		tablrd 0,1,scaletmp+1	; and low byte.
		movfp scaletmp+1,WREG
	add	logresult+1, W	; add this value to result
		movfp scaletmp,WREG
	add	logresult, W

		movfp logresult,WREG	; returned value is high byte
	jmp	end_scalelog

log_scaleover	mov	W, #MAXPIXVAL
end_scalelog	mov	rdiv, W
	ret

;----------------------------------------------------------------------------
; m_mathtest : Test utility for mathlib functions
;
; to be used for debug only
;----------------------------------------------------------------------------


m_mathtest	m_ldaconst H'23EF'	; (1.123)
		m_mvab
		m_ldaconst H'B561'	; (-2.332)
		m_lddiv 0
	nop	; expected :
; RA = -19103 $B561 -2.331909  RB =   9199 $23EF  1.122925  RDIV =    0 $00

	call	m_sin
	nop	; expected :
; RA =  -5931 $E8D5 -0.723999  RB =   9199 $23EF  1.122925  RDIV =    0 $00

	call	m_mult
	nop	; expected :
; RA =  -6660 $E5FC -0.812988  RB =   9199 $23EF  1.122925  RDIV =    0 $00

		m_mvab
		m_ldaconst H'F88B'	; (-0.233)
		m_add
	nop	; expected :
; RA =  -8568 $DE88 -1.045898  RB =  -6660 $E5FC -0.812988  RDIV =    0 $00

	mov	W, #44
	mov	h1i, W
		m_stai h1i
		m_ldaconst 0
	mov	W, #44
	mov	h1i, W
		m_ldbi h1i
		m_mvba
	nop	; expected :
; RA =  -8568 $DE88 -1.045898  RB =  -8568 $DE88 -1.045898  RDIV =    0 $00

		m_ldaconst H'F8DB'	; (-0.2233);
		m_sub
	nop	; expected :
; RA =   6739 $1A53  0.822632  RB =  -8568 $DE88 -1.045898  RDIV =    0 $00

		m_mvab
		m_ldaconst H'470A'	; (2.22)
		m_add
	nop	; expected :
; RA =  24925 $615D  3.042603  RB =   6739 $1A53  0.822632  RDIV =    0 $00

	call	m_sin
		m_mvab
		m_ldaconst H'F560'	; (-0.332)
	call	m_mult
	nop	; expected :
; RA =   -268 $FEF4 -0.032715  RB =    809 $0329  0.098755  RDIV =    0 $00

		m_sta h1r
	mov	W, #31
	mov	h2r, W
		m_lddiv h2r
	call	m_divi
	nop	; expected :
; RA =     -8 $FFF8 -0.000977  RB =    809 $0329  0.098755  RDIV =   31 $1F

		m_ldb h1r
		m_sub
	call	m_mult
	nop	; expected :
; RA =     -8 $FFF8 -0.000977  RB =   -268 $FEF4 -0.032715  RDIV =   31 $1F

		m_mvab
		m_lda h1r
	call	m_sin
	call	m_mult
	nop	; expected :
; RA =      0 $0000  0.000000  RB =     -8 $FFF8 -0.000977  RDIV =   31 $1F

		m_ldaconst H'18E2'	; (0.7776)
	call	m_scalelin
	nop	; expected :
; RA =   6370 $18E2  0.777588  RB =     -8 $FFF8 -0.000977  RDIV =  127 $7F

		m_ldaconst H'C15'	; (0.3776);
	call	m_scalelin
	nop	; expected :
; RA =   3093 $0C15  0.377563  RB =     -8 $FFF8 -0.000977  RDIV =   96 $60

  		m_ldaconst H'C15'	; (0.3776)
		m_div2
	call	m_scalelin
	nop	; expected :
; RA =   1546 $060A  0.188721  RB =     -8 $FFF8 -0.000977  RDIV =   48 $30

		m_ldaconst H'18E2'	; (0.7776);
	call	m_scalelog
	nop	; expected :
; RA =   6370 $18E2  0.777588  RB =     -8 $FFF8 -0.000977  RDIV =  127 $7F

		m_ldaconst H'C15'	; (0.3776)
	call	m_scalelog
	nop	; expected :
; RA =   3093 $0C15  0.377563  RB =     -8 $FFF8 -0.000977  RDIV =  119 $77

		m_ldaconst H'C15'	; (0.3776)
		m_div2
	call	m_scalelog
	nop	; expected :
; RA =   1546 $060A  0.188721  RB =     -8 $FFF8 -0.000977  RDIV =  101 $65

		m_lda h1r
		m_div2
	call	m_sin
		m_mvab
		m_ldaconst H'438D'	; (2.111)
	call	m_mult
	nop	; expected :
; RA =   -280 $FEE8 -0.034180  RB =   -133 $FF7B -0.016235  RDIV =  101 $65

	call	m_scalelog
	nop	; expected :
; RA =   -280 $FEE8 -0.034180  RB =   -133 $FF7B -0.016235  RDIV =    0 $00

	ret

;============================================================================
;                             - END OF FILE -
;============================================================================
;============================================================================
; PROJECT     : PIC'SPECTRUM
;
; FILE        : TESTSIG.INC
;
; VERSION     : 1.0
;
; DESCRIPTION :
;
; Test signals generation (for validation of the FFT routines)
;
; A square test signal is generated during ram initialization, and is
; displayed if the Pic'Spectrum is switched on in hold mode.
;
;============================================================================
;                Developped & Copyrighted by Robert LACOSTE
;============================================================================


;----------------------------------------------------------------------------
; test_square : Generate a square signal
;
; On input, amplitude is in math register A, half-period in WREG
;----------------------------------------------------------------------------

test_square	clr	cpti	; cpti=index to data
	clr	cptj	; cptj=phase
	mov	test_halfp, W	; test_halfp=halfperiod

testsquare_b	inc	cptj	; increment phase
		movfp cptj,WREG
		cpfseq test_halfp	; equal to half-period ?
	jmp	testsquare_norm
	clr	cptj	; if yes, reset phase
		m_mvab
		m_ldaconst H'E000'	; and multiply phase by -1
	call	m_mult

testsquare_norm	m_stai cpti			; store current amplitude

	incsz	cpti
	jmp	testsquare_b	; and loop

	ret


;----------------------------------------------------------------------------
; test_triangle : Generate a triangle signal
;
; On input, step is in math register A, half-period in WREG
;----------------------------------------------------------------------------


test_triangle	clr	cpti	; cpti=index to data
	mov	test_halfp, W	; halfp=halfperiod
	clrb	ALUSTA.C
		rrcf WREG,W
	mov	cptj, W	; cptj=phase (initialised to 50%)
		m_sta test_step		; test_step=step
		m_ldaconst 0
		m_sta test_cval		; test_cval=current value

testtriangle_b	inc	cptj	; increment phase
		movfp cptj,WREG
		cpfseq test_halfp	; equal to half-period ?
	jmp	testtriang_norm
	clr	cptj	; if yes, reset phase
		m_lda test_step
		m_mvab
		m_ldaconst H'E000'	; and multiply step by -1
	call	m_mult
		m_sta test_step

testtriang_norm	m_lda test_cval		; increment value by step value
		m_mvab
		m_lda test_step
		m_add
		m_sta test_cval
		m_stai cpti		; store current amplitude

	incsz	cpti
	jmp	testtriangle_b	; and loop

	ret


;============================================================================
;                             - END OF FILE -
;============================================================================
;============================================================================
; PROJECT     : PIC'SPECTRUM
;
; FILE        : FFT.INC
;
; VERSION     : 1.0
;
; DESCRIPTION :
;
; 256 points FFT routines, using s/2/13 format for numeric computations
; (through the fixed.inc library). All data are stored in the internal
; registers of the 17C756 (array DATA).
;
; Execution time on a PIC17C756/32MHz : around 50ms without concurrent
; video generation (resulting in a 90-100ms refresh time with spectrum
; power calculation, analog acquisition and video refresh)
;
;============================================================================
;                Developped & Copyrighted by Robert LACOSTE
;============================================================================



;----------------------------------------------------------------------------
; Complex FFT, radix-1, decimation in place, 128 points
;
; Algorithm from "Numerical recipes in C", manually compiled in assembler
; and adapted...
;
; Input : 128 complex values (each on 4 bytes), stored in data[0..511]
;         For each data : byte 0 = MSB of real part
;                         byte 1 = LSB of real part
;                         byte 2 = MSB of complex part
;                         byte 3 = LSB of complex part
;
; Replace data[0..511] by its FFT (128 frequencies, complex values)
;----------------------------------------------------------------------------


fft	nop	; Control point : Input FFT

; ------> initialisation
	clr	j	; j=0
					; nn=128 (implicit), n=256 (implicit)

; ------> bit reversal
	clr	i	; for(i=0;i<n-1;i+=2) {
iloop1	nop

if1	movfp i,WREG			; if (j>i) {
	cpfsgt j
	jmp	endif1

	m_ldai j			; m_ldai(j)
	m_ldbi i			; m_ldbi(i)
	m_stai i			; m_stai(i)
	m_mvba				; m_mvba()
	m_stai j			; m_stai(j);
	inc	j
	inc	i
	m_ldai j			; m_ldai(j+1)
	m_ldbi i			; m_ldbi(i+1)
	m_stai i			; m_stai(i+1)
	m_mvba				; m_mvba()
	m_stai j			; m_stai(j+1)
	dec	j
	dec	i

endif1	nop	; } endif

	mov	W, #128	; m=n>>1
	mov	m, W

while1	mov	W, #2	; while(m>=2 && j>=m) {
	cpfslt m
	jmp	$+2
	jmp	wend1
	movfp m,WREG
	cpfslt j
	jmp	$+2
	jmp	wend1

 	movfp m,WREG			; j-=m
	sub	j, W

	clrb	ALUSTA.C	; m>>=1
	rrcf m,F

wloop1	jmp	while1	; }

wend1	movfp m,WREG			; j+=m
	add	j, W

inext1	inc	i	; } next i
	incsz	i
	jmp	iloop1


; ------> FFT itself
	mov	W, #2	; mmax=2
	mov	mmax, W

while2	tstfsz mmax			; while(n>mmax) {
	jmp	$+2
	jmp	wend2

	movfp mmax, WREG		; istep=mmax<<1
	clrb	ALUSTA.C
	rlcf WREG,F
	mov	istep, W

    	; theta=2pi/mmax
	m_ldaconst H'6488'		; m_ldaconst(3.14159265459)
	m_lddiv mmax			; m_lddiv(mmax>>1)
	clrb	ALUSTA.C
	rrcf rdiv,F
	call	m_divi	; m_divi()
	m_sta theta			; m_sta(&theta)

	; wpr=-2*sin(theta/2)^2
	mov	W, #2	; m_lddiv(2)
	mov	rdiv, W
	call	m_divi	; m_divi()
	call	m_sin	; m_sin()
	m_mvab				; m_mvab()
	call	m_mult	; m_mult()
	m_mvab				; m_mvab()
	m_ldaconst H'C000'		; m_ldaconst(-2.0)
	call	m_mult	; m_mult()
	m_sta wpr			; m_sta(&wpr)

	; wpi=n_sin(theta)
	m_lda theta			; m_lda(theta)
	call	m_sin	; m_sin()
	m_sta wpi			; m_sta(&wpi)

	; wr=1, wi=0
	m_ldaconst H'2000'		; m_ldaconst(1.0)
	m_sta wr			; m_sta(&wr)
	m_ldaconst H'0000'		; m_ldaconst(0.0)
	m_sta wi			; m_sta(&wi)

ffttst1	nop

	clr	m	; for(m=0;m<mmax-1;m+=2) {
mloop1	movfp mmax,WREG
	mov	W, --WREG
	cpfslt m
	jmp	mend1

ffttst2	nop

	movfp m,WREG			; for(i=m;i<n;i+=istep) {
	mov	i, W
iloop2	nop

	movfp i,WREG			; j=i+mmax
	mov	j, W
	movfp mmax,WREG
	add	j, W

ffttst3	nop

	; h1r=wr*data[j]-wi*data[j+1]
	m_lda wi			; m_lda(wi)
	inc	j	; m_ldbi(j+1)
	m_ldbi j
	dec	j
	call	m_mult	; m_mult()
	m_sta h1r			; m_sta(&h1r)
	m_lda wr			; m_lda(wr)
	m_ldbi j			; m_ldbi(j)
	call	m_mult	; m_mult()
	m_ldb h1r			; m_ldb(h1r)
	m_sub				; m_sub()
	m_sta h1r			; m_sta(&h1r)

	; h1i=wr*data[j+1]+wi*data[j]
	m_lda wi			; m_lda(wi)
	m_ldbi j			; m_ldbi(j)
	call	m_mult	; m_mult()
	m_sta h1i			; m_sta(&h1i)
	m_lda wr			; m_lda(wr)
	inc	j	; m_ldbi(j+1)
	m_ldbi j
	dec	j
	call	m_mult	; m_mult()
	m_ldb h1i			; m_ldb(h1i)
	m_add				; m_add()
	m_sta h1i			; m_sta(&h1i)

	; butterfly update, with in-place scaling

	; data[j]=(data[i]-h1r)/2
	m_ldai i			; m_ldai(i)
	m_ldb h1r			; m_ldb(h1r)
	m_sub				; m_sub()
	m_div2				; m_div2()
	m_stai j			; m_stai(j)

	; data[j+1]=(data[i+1]-h1i)/2
	inc	i	; m_ldai(i+1)
	m_ldai i
	dec	i
	m_ldb h1i			; m_ldb(h1i)
	m_sub				; m_sub()
	m_div2				; m_div2()
	inc	j	; m_stai(j+1)
	m_stai j
	dec	j

	; data[i]=(data[i]+h1r)/2
	m_ldai i			; m_ldai(i)
	m_ldb h1r			; m_ldb(h1r)
	m_add				; m_add()
	m_div2				; m_div2()
	m_stai i			; m_stai(i)

	; data[i+1]=(data[i+1]+h1i)/2
	inc	i	; m_ldai(i+1)
	m_ldai i
	dec	i
	m_ldb h1i			; m_ldb(h1i)
	m_add				; m_add()
	m_div2				; m_div2()
	inc	i	; m_stai(i+1)
	m_stai i
	dec	i

inext2	tstfsz istep			; } next i
	jmp	$+2
	jmp	iend2
	movfp istep,WREG
	add	i, W
	sb	ALUSTA.C
	jmp	iloop2

	; wtemp=wr
iend2	m_lda wr			; m_lda(wr)
	m_sta wtemp			; m_sta(&wtemp)

	; wr=wr*wpr-wi*wpi+wr
	m_lda wi			; m_lda(wi)
	m_ldb wpi			; m_ldb(wpi)
	call	m_mult	; m_mult()
	m_sta h1r			; m_sta(&h1r)
	m_lda wr			; m_lda(wr)
	m_ldb wpr			; m_ldb(wpr)
	call	m_mult	; m_mult()
	m_ldb h1r			; m_ldb(h1r)
	m_sub				; m_sub()
	m_ldb wr			; m_ldb(wr)
	m_add				; m_add()
	m_sta wr			; m_sta(&wr)

 	; wi=wi*wpr+wtemp*wpi+wi
	m_lda wtemp			; m_lda(wtemp)
	m_ldb wpi			; m_ldb(wpi)
	call	m_mult	; m_mult()
	m_sta h1i			; m_sta(&h1i)
	m_lda wi			; m_lda(wi)
	m_ldb wpr			; m_ldb(wpr)
	call	m_mult	; m_mult()
	m_ldb h1i			; m_ldb(h1i)
	m_add				; m_add()
	m_ldb wi			; m_ldb(wi)
	m_add				; m_add()
	m_sta wi			; m_sta(&wi)

mnext1	inc	m	; } next m
	inc	m
	jmp	mloop1
mend1	nop

	movfp istep,WREG		; mmax=istep
	mov	mmax, W

wloop2	jmp	while2	; } end while
wend2	ret


;----------------------------------------------------------------------------
; Real FFT
;
; Algorithm from "Numerical recipes in C", manually compiled in assembler
; and adapted...
;
; Calculate FFT of a set of 256 real values stored in data[0..511]
; (2 bytes per value, MSB first).
;
; Replace these data by the positive frequency half of the FFT
; (128 frequencies, complex values). First and last frequencies (which are
; real) are in data[1] and data[2] respectively.
;
; Method : consider the 256 real values as interleaved real/imaginary parts
; of 128 complex values. Do a complex 128 points FFT, and find back the
; FFT of the real numbers from the output of the complex FFT...
;
; Nota : this method allow to do a real FFT with 30-40% less calculations
; and, more important, 50% less RAM requirement.
;----------------------------------------------------------------------------

realfft	nop	; control point, N=256 (implicit)

; ------> do a complex FFT of half the number of points, odd real points
;         as real data, even real points as imaginary data

	call	fft

;-------> and find the good values from the result...

    	; theta=2pi/n
	m_ldaconst H'6488'		; m_ldaconst(3.14159265459)
	mov	W, #128	; m_lddiv(n>>1)
	mov	rdiv, W
	call	m_divi	; m_divi()
	m_sta theta			; m_sta(&theta)

	; wpr=-2*sin(theta/2)^2
	mov	W, #2	; m_lddiv(2)
	mov	rdiv, W
	call	m_divi	; m_divi()
	call	m_sin	; m_sin()
	m_mvab				; m_mvab()
	call	m_mult	; m_mult()
	m_mvab				; m_mvab()
	m_ldaconst H'C000'		; m_ldaconst(-2.0)
	call	m_mult	; m_mult()
	m_sta wpr			; m_sta(&wpr)

	; wpi=n_sin(theta)
	m_lda theta			; m_lda(theta)
	call	m_sin	; m_sin()
	m_sta wpi			; m_sta(&wpi)

	; wr=1+wpr, wi=wpi
	m_ldb wpr			; m_ldb(wpr)
	m_ldaconst H'2000'		; m_ldaconst(1.0)
	m_add				; m_add()
	m_sta wr			; m_sta(&wr)
	m_lda wpi			; m_lda(wpi)
	m_sta wi			; m_sta(&wi)

	mov	W, #2	; for(i=2;i<=(n>>2);i++) {
	mov	i, W
iloop3	mov	W, #64
	cpfsgt i
	jmp	$+2
	jmp	iend3

	movfp i,WREG			; i1=i+i-2
	mov	i1, W
	add	i1, W
	mov	W, #2
	sub	i1, W

	movfp i1,WREG			; i2=1+i1
	mov	i2, W
	inc	i2

	movfp i2,WREG			; i3=n-i2+1
	mov	W, /WREG
	mov	W, ++WREG
	mov	W, ++WREG
	mov	i3, W

	mov	W, ++WREG
	mov	i4, W	; i4=1+i3

	; h1r=(data[i1]+data[i3])/2
	m_ldai i1			; m_ldai(i1)
	m_ldbi i3			; m_ldbi(i3)
	m_add				; m_add()
	m_div2				; m_div2()
	m_sta h1r			; m_sta(&h1r)

	; h1i=(data[i2]-data[i4])/2
	m_ldai i2			; m_ldai(i2)
	m_ldbi i4			; m_ldbi(i4)
	m_sub				; m_sub()
	m_div2				; m_div2()
	m_sta h1i			; m_sta(&h1i)

	; h2r=(data[i2]+data[i4])/2
	m_ldai i2			; m_ldai(i2)
	m_ldbi i4			; m_ldbi(i4)
	m_add				; m_add()
	m_div2				; m_div2()
	m_sta h2r			; m_sta(&h2r)

	; h2i=-(data[i1]-data[i3])/2
	m_ldai i3			; m_ldai(i3)
	m_ldbi i1			; m_ldbi(i1)
	m_sub				; m_sub()
	m_div2				; m_div2()
	m_sta h2i			; m_sta(&h2i)

	; data[i1]=h1r+wr*h2r-wi*h2i
	m_lda wi			; m_lda(wi)
	m_ldb h2i			; m_ldb(h2i)
	call	m_mult	; m_mult()
	m_sta wtemp			; m_sta(&wtemp)
	m_lda wr			; m_lda(wr)
	m_ldb h2r			; m_ldb(h2r)
	call	m_mult	; m_mult()
	m_ldb wtemp			; m_ldb(wtemp)
	m_sub				; m_sub()
	m_ldb h1r			; m_ldb(h1r)
	m_add				; m_add()
	m_stai i1			; m_stai(i1)

	; data[i2]=h1i+wr*h2i+wi*h2r
	m_lda wi			; m_lda(wi)
	m_ldb h2r			; m_ldb(h2r)
	call	m_mult	; m_mult()
	m_sta wtemp			; m_sta(&wtemp)
	m_lda wr			; m_lda(wr)
	m_ldb h2i			; m_ldb(h2i)
	call	m_mult	; m_mult()
	m_ldb wtemp			; m_ldb(wtemp)
	m_add				; m_add()
	m_ldb h1i			; m_ldb(h1i)
	m_add				; m_add()
	m_stai i2			; m_stai(i2)

	; data[i3]=h1r-wr*h2r+wi*h2i
	m_lda wr			; m_lda(wr)
	m_ldb h2r			; m_ldb(h2r)
	call	m_mult	; m_mult()
	m_sta wtemp			; m_sta(&wtemp)
	m_lda wi			; m_lda(wi)
	m_ldb h2i			; m_ldb(h2i)
	call	m_mult	; m_mult()
	m_ldb wtemp			; m_ldb(wtemp)
	m_sub				; m_sub()
	m_ldb h1r			; m_ldb(h1r)
	m_add				; m_add()
	m_stai i3			; m_stai(i3)

	; data[i4]=-h1i+wr*h2i+wi*h2r
	m_lda wr			; m_lda(wr)
	m_ldb h2i			; m_ldb(h2i)
	call	m_mult	; m_mult()
	m_sta wtemp			; m_sta(&wtemp)
	m_lda wi			; m_lda(wi)
	m_ldb h2r			; m_ldb(h2r)
	call	m_mult	; m_mult()
	m_ldb wtemp			; m_ldb(wtemp)
	m_add				; m_add()
	m_ldb h1i			; m_ldb(h1i)
	m_sub				; m_sub()
	m_stai i4			; m_stai(i4)

	; wtemp=wr
	m_lda wr			; m_lda(wr)
	m_sta wtemp			; m_sta(&wtemp)

	; wr=wr*wpr-wi*wpi+wr
	m_lda wi			; m_lda(wi)
	m_ldb wpi			; m_ldb(wpi)
	call	m_mult	; m_mult()
	m_sta h1r			; m_sta(&h1r)
	m_lda wr			; m_lda(wr)
	m_ldb wpr			; m_ldb(wpr)
	call	m_mult	; m_mult()
	m_ldb h1r			; m_ldb(h1r)
	m_sub				; m_sub()
	m_ldb wr			; m_ldb(wr)
	m_add				; m_add()
	m_sta wr			; m_sta(&wr)

	; wi=wi*wpr+wtemp*wpi+wi
	m_lda wi			; m_lda(wi)
	m_ldb wpr			; m_ldb(wpr)
	call	m_mult	; m_mult()
	m_sta h1r			; m_sta(&h1r)
	m_lda wtemp			; m_lda(wtemp)
	m_ldb wpi			; m_ldb(wpi)
	call	m_mult	; m_mult()
	m_ldb h1r			; m_ldb(h1r)
	m_add				; m_add()
	m_ldb wi			; m_ldb(wi)
	m_add				; m_add()
	m_sta wi			; m_sta(&wi)


inext3	inc	i	; } next i
	jmp	iloop3
iend3	nop

; ------> special case of the 2 first data

	; h1r=data[0]
	mov	W, #0	; m_ldai(0)
	mov	i, W
	m_ldai i
	m_sta h1r			; m_sta(&h1r)

	; data[0]=h1r+data[1]
	mov	W, #1	; m_ldbi(1)
	mov	i, W
	m_ldbi i
	m_add				; m_add()
	mov	W, #0	; m_stai(0)
	mov	i, W
	m_stai i

	; data[1]=h1r-data[1]
	m_lda h1r			; m_lda(h1r)
	mov	W, #1	; m_ldbi(1)
	mov	i, W
	m_ldbi i
	m_sub				; m_sub()
	mov	W, #1	; m_stai(1)
	mov	i, W
	m_stai i

endrft	ret



;============================================================================
;                             - END OF FILE -
;============================================================================
;============================================================================
; PROJECT     : PIC'SPECTRUM
;
; FILE        : POWERS.INC
;
; VERSION     : 1.0
;
; DESCRIPTION :
;
; Power spectrum calculation starting with the result of the real FFT.
; Result power is scaled (lin or log) and stored in the display buffer
; area (dispbuf) : 1 byte per frequency (1 to 126)
;
; This file define also the routine used by the interrupt routine to
; access the display buffer (with is paged)
;
; The display buffer table ("dispbuf") is a 2x64 bytes array, each of the
; two blocks being at at fixed adress ($20 to $5F) in the banks 2 and 3.
;
; Nota : dispbuf(0) (DC frequency) is not displayed.
;
;============================================================================
;                Developped & Copyrighted by Robert LACOSTE
;============================================================================


;----------------------------------------------------------------------------
; dispbufwr :	Write a value in the given display buffer cell
;		On input : 	WREG = index (0 to 127)
;				RDIV = value (0 to MAXPIXVAL)
;		On output : bank selected = zone_main
;----------------------------------------------------------------------------

dispbufwr	macro
		movlr 2			; start with bank 2
	snb	WREG.6	; select the good bank
	setb	BSR.4	; based on 6th bit of index
	and	W, #%00111111	; clear 2 MSB bits
;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. 
;		addlw H'20'		; add $20 (data start at $20)
	mov	Hack, W
	mov	W, #$20	; add $20 (data start at $20)
	add	W, Hack
	mov	FSR0, W	; and use it as an index
		movfp rdiv,INDF0	; to store value
		BANKSEL zone_main	; reset bank register
		endm


;----------------------------------------------------------------------------
; dispbufrd :	Read a value from the given display buffer cell
;		On input : 	WREG = index (0 to 127)
;		On output : 	WREG = value (0 to MAXPIXVAL)
;				bank selected = zone_irq
;
; WARNING : 	Time critical routine ! In particular, execution time should
;		be always exactly the same (if not, pixels won't be aligned
;		anymore...)
;
; DURATION : 8 cycles (1.00 microsecond at 32MHz)
;----------------------------------------------------------------------------

dispbufrd	macro
		movlr 2			; start with bank 2
	snb	WREG.6	; select the good bank
	setb	BSR.4	; based on 6th bit of index
	and	W, #%00111111	; clear 2 MSB bits
;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. 
;		addlw H'20'		; add $20 (data start at $20)
	mov	Hack, W
	mov	W, #$20	; add $20 (data start at $20)
	add	W, Hack
	mov	FSR0, W	; and use it as an index
		movfp INDF0,WREG	; to read value
		BANKSEL zone_irq	; reset bank register
		endm


;----------------------------------------------------------------------------
; intpowerlin :	Calculate power spectrum for the complex value stored
;		in RA and RB, scale it with a linear scale (result from 0
;		to MAXPIXVAL) and store the result in RDIV
;----------------------------------------------------------------------------

		; A=(A/2)^2+(B/2)^2 (divide by 2 to exclude overflow)

intpowerlin	m_sta h1r		; m_sta(&h1r)
		m_mvba			; m_mvba()
		m_div2			; m_div2()
		m_mvab			; m_mvab()
	call	m_mult	; m_mult()
		m_sta h2r		; m_sta(&h2r)
		m_lda h1r		; m_lda(h1r)
		m_div2			; m_div2()
		m_mvab			; m_mvab()
	call	m_mult	; m_mult()
		m_ldb h2r		; m_ldb(h2r)
		m_add			; m_add()
	call	m_scalelin	; m_scalelin()
	ret


;----------------------------------------------------------------------------
; intpowerlog :	Calculate power spectrum for the complex value stored
;		in RA and RB, scale it with a log scale (result from 0
;		to MAXPIXVAL) and store the result in RDIV
;----------------------------------------------------------------------------

		; A=(A/2)^2+(B/2)^2 (divide by 2 to exclude overflow)

intpowerlog	m_sta h1r		; m_sta(&h1r)
		m_mvba			; m_mvba()
		m_div2			; m_div2()
		m_mvab			; m_mvab()
	call	m_mult	; m_mult()
		m_sta h2r		; m_sta(&h2r)
		m_lda h1r		; m_lda(h1r)
		m_div2			; m_div2()
		m_mvab			; m_mvab()
	call	m_mult	; m_mult()
		m_ldb h2r		; m_ldb(h2r)
		m_add			; m_add()
	call	m_scalelog	; m_scalelog()
	ret


;----------------------------------------------------------------------------
; powerlin :	Calculate power spectrum for the complex spectrum stored
;		in "data", scale it with a linear scale (result from 0
;		to MAXPIXVAL) and store the result in "dispbuf"
;
;		Nota : last frequency (number 128) is discarted
;----------------------------------------------------------------------------

powerlin	nop

;--------------> Special case of the first value (real)
	clr	rdiv
		m_ldai rdiv		; m_ldai(0)
		m_ldbi rdiv		; m_ldbi(0)
	call	intpowerlin	; intpower()
	mov	W, #0
		dispbufwr		; dispbuf[0]=(unsigned char)rdiv

;--------------> General case
	clr	i	; for (i=1;i<SLENGTH/2;i++) {
	inc	i
iloop4	nop

		movfp i,WREG		; i2=(i<<1)
	mov	i2, W
	clrb	ALUSTA.C
		rlcf i2,F

		m_ldai i2		; m_ldai(i2)
	inc	i2	; m_ldbi(i2+1)
		m_ldbi i2

	call	intpowerlin	; intpower();
		movfp i,WREG		; dispbuf[i]=(unsigned char)rdiv
		dispbufwr

inext4	inc	i	; } next i
	mov	W, #128
		cpfseq i
	jmp	iloop4

	ret


;----------------------------------------------------------------------------
; powerlog :	Calculate power spectrum for the complex spectrum stored
;		in "data", scale it with a log scale (result from 0
;		to MAXPIXVAL) and store the result in "dispbuf"
;----------------------------------------------------------------------------

powerlog	nop

;--------------> Special case of the first value (real)
	clr	rdiv
		m_ldai rdiv		; m_ldai(0)
		m_ldbi rdiv		; m_ldbi(0)
	call	intpowerlog	; intpower()
	mov	W, #0
		dispbufwr		; dispbuf[0]=(unsigned char)rdiv

;--------------> General case
	clr	i	; for (i=1;i<SLENGTH/2;i++) {
	inc	i
iloop5	nop

		movfp i,WREG		; i2=(i<<1)
	mov	i2, W
	clrb	ALUSTA.C
		rlcf i2,F

		m_ldai i2		; m_ldai(i2)
	inc	i2	; m_ldbi(i2+1)
		m_ldbi i2

	call	intpowerlog	; intpower();
		movfp i,WREG		; dispbuf[i]=(unsigned char)rdiv
		dispbufwr

inext5	inc	i	; } next i
	mov	W, #128
		cpfseq i
	jmp	iloop5

	ret


;============================================================================
;                             - END OF FILE -
;============================================================================
;============================================================================
; PROJECT     : UPS'SPECTRUM
;
; FILE        : IRQ.INC
;
; VERSION     : 1.0
;
; DESCRIPTION :
;
; Handler of the timer0 interrupt, in charge of all real time tasks,
; mainly analog signal acquisition and software video generation...
;
; WARNING : These routines are VERY time critical, in particular for the
; video generation. Do not change the duration of any routine (even by adding
; or deleting only one instruction) without a deep analysis. Effects can go
; from misaligned pixels to... loss of video synchronisation.
; The main time dependencies are indicated in the source (see "PT" checkpoints
; and "RT" comments) but I'm not sure that the list is complete !
;
; Comment : Some of the routines may seems a little "bulk force" and
; excessively rom expensive, but think twice about the performances required
; before replacing everything by loop ! In fact, we only do manually what
; modern compilers do as part as their optimization phase... loop unrolling !
;
;============================================================================
;                Developped & Copyrighted by Robert LACOSTE
;============================================================================


;----------------------------------------------------------------------------
; Management of analog acquisitions and generation of Hsync signal
;
; Check if an analog acquisition is requested by the main program.
; If so do the acquisition of 256 samples (one each 2 video scan lines,
; giving a sample rate of 31.5KHz/2=15.75KHz)
;
; Synchronisation with the main program is done through acq_request flag
; and num_sample register :
;
; Main program :
; - To launch a sampling, put acq_request=1 and reset num_sample
; - wait for acq_request to be back 0
;
; This interrupt routine :
; - if acq_request=0 => Nothing to do
; - if acq_request=1 => Launch acquisition and put acq_request=2
; - if acq_request=2 => Get result and store it in (num_sample)
;                       Increment num_sample
;                       If <256, put acq_request=1 (sampling period)
;                       else put acq_request=0
;
; The HSync signal is generated within this routine, insuring that its length
; is constant (=30 clock cycles) and its position fixed.
;
; Warning : The duration of this routine must be CONSTANT, whatever tests
; results are ! (now, its 37 cycles)
;
; Warning : on input, bankselect should be on zone_irq
;----------------------------------------------------------------------------

manage_adc	macro

	setb	RC.4	; set RC4 (HSync signal active)

;--> RT constraint !!! From PT1, delay >= 0.94µS=8 instr (pre-HSync blanking)
;                      and fixed (whatever test & branch are executed)

;--> RT checkpoint PT2 (start of HSync signal)

;--> RT checkpoint PT0A	(start of ADC management)

	mov	W, #2	; acq_request = 2 ?
		cpfseq acq_request
	jmp	adc_not2

;--> Acq_request=2

		; save RA (because we must use a non banked memory)

		movpf ra, tmpi
		movpf ra+1, tmpi+1

		; scale ADC value (0 to 653536 -> -8192 to +8192)

		movlb 5
		movpf ADRESL,ra+1	; get ADC value
		movpf ADRESH,ra		; and scale it to our floating format
	clrb	ALUSTA.C
		rrcf ra,F		; divide by 4
		rrcf ra+1,F
	clrb	ALUSTA.C
		rrcf ra,F
		rrcf ra+1,F
	mov	W, #$20	; substract H'2000'
	sub	ra, W	; it's now from -1.0 to +1.0

		; store ADC value in data(num_sample)

		movlb 5			; select register bank 5
		movfp num_sample, WREG
		movlr 0			; start with bank 0
	snb	WREG.7	; select the good bank
	setb	BSR.5
	snb	WREG.6	; based on 2 first bits of WREG
	setb	BSR.4
	clrb	ALUSTA.C	; multiply by 2
		rlcf WREG,1
	setb	WREG.7	; and set high bit (data start at $80)
	mov	FSR0, W	; and use it as an index
		movfp ra,INDF0		; to store msb value...

		movlb 1
	clrb	RC.4	; clear RC4 (HSync signal inactive)

;--> RT constraint !!! From PT2, delay = 3.77µS=30 instr (HSync duration)
;                      and fixed (whatever test & branch are executed)
;--> RT checkpoint PT3 (end of HSync signal)

	inc	FSR0
		movfp ra+1,INDF0	; ... and lsb value
		BANKSEL zone_irq	; reset bank register

		; increment num_sample and update aca_request

	clr	acq_request	; acq_request=0
	mov	W, #1
	incsz	num_sample	; increment num_sample
	mov	acq_request, W	; if <>0, acq_request=1

		; restore RA
		movfp tmpi, ra
		movfp tmpi+1, ra+1

	jmp	end_manage_adc

adc_not2	nop	; acq_request <> 2
	nop
	nop
	nop
	nop
	nop
	nop	; delay nop's in order to be in
	nop	; synch with the switch case above
	nop
	nop
	nop
	nop
	mov	W, #1
		cpfseq acq_request	; acq_request=1 ?
	jmp	adc_0
	jmp	adc_1

;--> Acq_request=0

adc_0	nop	; acq=request is 0. Nothing to do
	nop	; except wait...
	nop
	nop
	nop
	nop
	nop
	nop
		movlb 1
	clrb	RC.4	; clear RC4 (HSync signal inactive)

;--> RT constraint !!! From PT2, delay = 3.77µS=30 instr (HSync duration)
;                      and fixed (whatever test & branch are executed)

;--> RT checkpoint PT3 (end of HSync signal)

	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	jmp	end_manage_adc

;--> Acq_request=1

adc_1	nop

		movlb 5			; start ADC conversion
	setb	ADCON0.GO
	mov	W, #2	; acq_request=2
	mov	acq_request, W
	nop
	nop
		movlb 1
	clrb	RC.4	; clear RC4 (HSync signal inactive)

;--> RT constraint !!! From PT2, delay = 3.77µS=30 instr (HSync duration)
;                      and fixed (whatever test & branch are executed)

;--> RT checkpoint PT3 (end of HSync signal)

	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	; and wait

end_manage_adc	nop
		endm

;--> RT constraint !!! From PT0A, delay FIXED (now 42 instructions cycles)


;----------------------------------------------------------------------------
; Routine called on timer0 interrupt
;
; This routine is called at 31.5KHz (horizontal refresh rate for 640x350)
; and do the main real time tasks :
;
; - Registers saving
; - Analog acquisition
; - Video generation
; - Registers restoring
;
; Warning : Time from interrupt to video generation must be rigourously
; stable.
;----------------------------------------------------------------------------

it_timer	movpf BSR,sv_bsr	; save BSR

;--> RT checkpoint PT0 (start of interrupt routine)

		BANKSEL zone_irq
		movpf ALUSTA,sv_alusta	; save ALUSTA
	mov	sv_wreg, W	; save WREG
		movpf FSR0,sv_fsr0	; save FSR0

		movlb 0
	clr	RB	; switch video off

;--> RT checkpoint PT1 (start of horizontal blanking zone)

		movlb 1
	setb	RD.2	; set RD2 (debug line : IRQ going on)

	mov	W, #high INITTIM	; reload timer
	mov	tmpi, W
	mov	W, #low INITTIM
	mov	TMR0L, W
		movfp tmpi,TMR0H

		manage_adc		; ADC management, 35 clock cycles

	mov	W, #1	; increment scan_line
	add	scan_line+1, W	; (rollback to 0 done in the last's
	clr	WREG	; line sub-routine)
		addwfc scan_line,F

		movlb 0			; select registers bank 0 for video

		; Based on scan_line value (from 1 to 449), calculate
		; the address of the line management routine

	mov	W, #low jump_table	; calculate jump address
	add	W, scan_line+1
	mov	tmpi, W
	mov	W, #high jump_table
		addwfc scan_line,W
;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible
;		movwf PCLATH
	mov	PCLATH, W

;--> RT constraint !!! From PT3 to first pixel display,
;                      delay > 1.89µS=15 instr (post HSync blanking)

		movfp tmpi, PCL		; and jump to it !

		; at the end of the scan line display, the called routine
		; will jump back to resume_irq

resume_irq	movlb 1
	clrb	RD.2	; clear RD2 (debug line : IRQ going on)

		BANKSEL zone_irq
		movfp sv_alusta,ALUSTA	; restore ALUSTA
		movfp sv_fsr0,FSR0	; and FSR0
		movfp sv_wreg,WREG	; and WREG
		movfp sv_bsr,BSR	; and BSR

;*** WARNING: SX saves/restores W, STATUS, and FSR automatically.
;		retfie			; return from interrupt
	reti	; return from interrupt

;--> RT constraint !!! From PT0, delay < 30µS=240 instr (Timer0 irq period)
;                      it lets 240-71=169 instructions for the scan_x routines

;----------------------------------------------------------------------------
; Jump address table
;
; For each scan line (1 to 449), calculated jump to the good management
; routine, depending on the scan line number
;----------------------------------------------------------------------------

jump_table	jmp	scan_blanking	; scan 000, should not occur
	jmp	scan_vsynch_on	; scan 001, switch on VSynch
	jmp	scan_blanking	; scan 002, vertical blanking
	jmp	scan_vsynch_off	; scan 003, switch off VSynch
	jmp	scan_blanking	; scan 004, vertical blanking
	jmp	scan_blanking	; scan 005, vertical blanking
	jmp	scan_blanking	; scan 006, vertical blanking
	jmp	scan_blanking	; scan 007, vertical blanking
	jmp	scan_blanking	; scan 008, vertical blanking
	jmp	scan_blanking	; scan 009, vertical blanking
	jmp	scan_blanking	; scan 010, vertical blanking
	jmp	scan_blanking	; scan 011, vertical blanking
	jmp	scan_blanking	; scan 012, vertical blanking
	jmp	scan_blanking	; scan 013, vertical blanking
	jmp	scan_blanking	; scan 014, vertical blanking
	jmp	scan_blanking	; scan 015, vertical blanking
	jmp	scan_blanking	; scan 016, vertical blanking
	jmp	scan_blanking	; scan 017, vertical blanking
	jmp	scan_blanking	; scan 018, vertical blanking
	jmp	scan_blanking	; scan 019, vertical blanking
	jmp	scan_blanking	; scan 020, vertical blanking
	jmp	scan_blanking	; scan 021, vertical blanking
	jmp	scan_blanking	; scan 022, vertical blanking
	jmp	scan_blanking	; scan 023, vertical blanking
	jmp	scan_blanking	; scan 024, vertical blanking
	jmp	scan_blanking	; scan 025, vertical blanking
	jmp	scan_blanking	; scan 026, vertical blanking
	jmp	scan_blanking	; scan 027, vertical blanking
	jmp	scan_blanking	; scan 028, vertical blanking
	jmp	scan_blanking	; scan 029, vertical blanking
	jmp	scan_blanking	; scan 030, vertical blanking
	jmp	scan_blanking	; scan 031, vertical blanking
	jmp	scan_blanking	; scan 032, vertical blanking
	jmp	scan_blanking	; scan 033, vertical blanking
	jmp	scan_blanking	; scan 034, vertical blanking
	jmp	scan_blanking	; scan 035, vertical blanking
	jmp	scan_blanking	; scan 036, vertical blanking
	jmp	scan_blanking	; scan 037, vertical blanking
	jmp	scan_blanking	; scan 038, vertical blanking
	jmp	scan_blanking	; scan 039, vertical blanking
	jmp	scan_blanking	; scan 040, vertical blanking
	jmp	scan_blanking	; scan 041, vertical blanking
	jmp	scan_blanking	; scan 042, vertical blanking
	jmp	scan_blanking	; scan 043, vertical blanking
	jmp	scan_blanking	; scan 044, vertical blanking
	jmp	scan_blanking	; scan 045, vertical blanking
	jmp	scan_blanking	; scan 046, vertical blanking
	jmp	scan_blanking	; scan 047, vertical blanking
	jmp	scan_blanking	; scan 048, vertical blanking
	jmp	scan_blanking	; scan 049, vertical blanking
	jmp	scan_blanking	; scan 050, vertical blanking
	jmp	scan_blanking	; scan 051, vertical blanking
	jmp	scan_blanking	; scan 052, vertical blanking
	jmp	scan_blanking	; scan 053, vertical blanking
	jmp	scan_blanking	; scan 054, vertical blanking
	jmp	scan_blanking	; scan 055, vertical blanking
	jmp	scan_blanking	; scan 056, vertical blanking
	jmp	scan_blanking	; scan 057, vertical blanking
	jmp	scan_blanking	; scan 058, vertical blanking
	jmp	scan_blanking	; scan 059, vertical blanking
	jmp	scan_blanking	; scan 060, vertical blanking
	jmp	scan_blanking	; scan 061, vertical blanking
	jmp	scan_empty	; scan 062 (sl 000), empty line
	jmp	scan_empty	; scan 063 (sl 001), empty line
	jmp	scan_empty	; scan 064 (sl 002), empty line
	jmp	scan_empty	; scan 065 (sl 003), empty line
	jmp	scan_empty	; scan 066 (sl 004), empty line
	jmp	scan_empty	; scan 067 (sl 005), empty line
	jmp	scan_empty	; scan 068 (sl 006), empty line
	jmp	scan_empty	; scan 069 (sl 007), empty line
	jmp	scan_empty	; scan 070 (sl 008), empty line
	jmp	scan_empty	; scan 071 (sl 009), empty line
	jmp	scan_empty	; scan 072 (sl 010), empty line
	jmp	scan_empty	; scan 073 (sl 011), empty line
	jmp	scan_empty	; scan 074 (sl 012), empty line
	jmp	scan_empty	; scan 075 (sl 013), empty line
	jmp	scan_empty	; scan 076 (sl 014), empty line
	jmp	scan_empty	; scan 077 (sl 015), empty line
	jmp	scan_empty	; scan 078 (sl 016), empty line
	jmp	scan_empty	; scan 079 (sl 017), empty line
	jmp	scan_empty	; scan 080 (sl 018), empty line
	jmp	scan_empty	; scan 081 (sl 019), empty line
	jmp	scan_empty	; scan 082 (sl 020), empty line
	jmp	scan_empty	; scan 083 (sl 021), empty line
	jmp	scan_empty	; scan 084 (sl 022), empty line
	jmp	scan_hscalelong	; scan 085 (sl 023), h.scale long sep
	jmp	scan_hscalelong	; scan 086 (sl 024), h.scale long sep
	jmp	scan_hscalelong	; scan 087 (sl 025), h.scale long sep
	jmp	scan_hscalelong	; scan 088 (sl 026), h.scale long sep
	jmp	scan_hscalelong	; scan 089 (sl 027), h.scale long sep
	jmp	scan_hscalelong	; scan 090 (sl 028), h.scale long sep
	jmp	scan_hscalelong	; scan 091 (sl 029), h.scale long sep
	jmp	scan_hscalelong	; scan 092 (sl 030), h.scale long sep
	jmp	scan_hscaleshort	; scan 093 (sl 031), h.scale short sep
	jmp	scan_hscaleshort	; scan 094 (sl 032), h.scale short sep
	jmp	scan_hscaleshort	; scan 095 (sl 033), h.scale short sep
	jmp	scan_hscaleshort	; scan 096 (sl 034), h.scale short sep
	jmp	scan_hscaleshort	; scan 097 (sl 035), h.scale short sep
	jmp	scan_hscaleshort	; scan 098 (sl 036), h.scale short sep
	jmp	scan_hscaleshort	; scan 099 (sl 037), h.scale short sep
	jmp	scan_empty	; scan 100 (sl 038), empty line
	jmp	scan_empty	; scan 101 (sl 039), empty line
	jmp	scan_empty	; scan 102 (sl 040), empty line
	jmp	scan_hscaleline	; scan 103 (sl 041), h. plain line
	jmp	scan_sepline	; scan 104 (sl 042), frequencies sep.
	jmp	scan_freqline	; scan 105 (sl 043), freq 001
	jmp	scan_sepline	; scan 106 (sl 044), frequencies sep.
	jmp	scan_freqline	; scan 107 (sl 045), freq 002
	jmp	scan_sepline	; scan 108 (sl 046), frequencies sep.
	jmp	scan_freqline	; scan 109 (sl 047), freq 003
	jmp	scan_sepline	; scan 110 (sl 048), frequencies sep.
	jmp	scan_freqline	; scan 111 (sl 049), freq 004
	jmp	scan_sepline	; scan 112 (sl 050), frequencies sep.
	jmp	scan_freqline	; scan 113 (sl 051), freq 005
	jmp	scan_sepline	; scan 114 (sl 052), frequencies sep.
	jmp	scan_freqline	; scan 115 (sl 053), freq 006
	jmp	scan_sepline	; scan 116 (sl 054), frequencies sep.
	jmp	scan_freqline	; scan 117 (sl 055), freq 007
	jmp	scan_sepline	; scan 118 (sl 056), frequencies sep.
	jmp	scan_freqline	; scan 119 (sl 057), freq 008
	jmp	scan_sepline	; scan 120 (sl 058), frequencies sep.
	jmp	scan_freqline	; scan 121 (sl 059), freq 009
	jmp	scan_sepline	; scan 122 (sl 060), frequencies sep.
	jmp	scan_freqline	; scan 123 (sl 061), freq 010
	jmp	scan_sepline	; scan 124 (sl 062), frequencies sep.
	jmp	scan_freqline	; scan 125 (sl 063), freq 011
	jmp	scan_sepline	; scan 126 (sl 064), frequencies sep.
	jmp	scan_freqline	; scan 127 (sl 065), freq 012
	jmp	scan_sepline	; scan 128 (sl 066), frequencies sep.
	jmp	scan_freqline	; scan 129 (sl 067), freq 013
	jmp	scan_sepline	; scan 130 (sl 068), frequencies sep.
	jmp	scan_freqline	; scan 131 (sl 069), freq 014
	jmp	scan_sepline	; scan 132 (sl 070), frequencies sep.
	jmp	scan_freqline	; scan 133 (sl 071), freq 015
	jmp	scan_sepline	; scan 134 (sl 072), frequencies sep.
	jmp	scan_freqline	; scan 135 (sl 073), freq 016
	jmp	scan_vscaleshort	; scan 136 (sl 074), v.scale short s.
	jmp	scan_freqline	; scan 137 (sl 075), freq 017
	jmp	scan_sepline	; scan 138 (sl 076), frequencies sep.
	jmp	scan_freqline	; scan 139 (sl 077), freq 018
	jmp	scan_sepline	; scan 140 (sl 078), frequencies sep.
	jmp	scan_freqline	; scan 141 (sl 079), freq 019
	jmp	scan_sepline	; scan 142 (sl 080), frequencies sep.
	jmp	scan_freqline	; scan 143 (sl 081), freq 020
	jmp	scan_sepline	; scan 144 (sl 082), frequencies sep.
	jmp	scan_freqline	; scan 145 (sl 083), freq 021
	jmp	scan_sepline	; scan 146 (sl 084), frequencies sep.
	jmp	scan_freqline	; scan 147 (sl 085), freq 022
	jmp	scan_sepline	; scan 148 (sl 086), frequencies sep.
	jmp	scan_freqline	; scan 149 (sl 087), freq 023
	jmp	scan_sepline	; scan 150 (sl 088), frequencies sep.
	jmp	scan_freqline	; scan 151 (sl 089), freq 024
	jmp	scan_sepline	; scan 152 (sl 090), frequencies sep.
	jmp	scan_freqline	; scan 153 (sl 091), freq 025
	jmp	scan_sepline	; scan 154 (sl 092), frequencies sep.
	jmp	scan_freqline	; scan 155 (sl 093), freq 026
	jmp	scan_sepline	; scan 156 (sl 094), frequencies sep.
	jmp	scan_freqline	; scan 157 (sl 095), freq 027
	jmp	scan_sepline	; scan 158 (sl 096), frequencies sep.
	jmp	scan_freqline	; scan 159 (sl 097), freq 028
	jmp	scan_sepline	; scan 160 (sl 098), frequencies sep.
	jmp	scan_freqline	; scan 161 (sl 099), freq 029
	jmp	scan_sepline	; scan 162 (sl 100), frequencies sep.
	jmp	scan_freqline	; scan 163 (sl 101), freq 030
	jmp	scan_sepline	; scan 164 (sl 102), frequencies sep.
	jmp	scan_freqline	; scan 165 (sl 103), freq 031
	jmp	scan_sepline	; scan 166 (sl 104), frequencies sep.
	jmp	scan_freqline	; scan 167 (sl 105), freq 032
	jmp	scan_vscaleshort	; scan 168 (sl 106), v.scale short s.
	jmp	scan_freqline	; scan 169 (sl 107), freq 033
	jmp	scan_sepline	; scan 170 (sl 108), frequencies sep.
	jmp	scan_freqline	; scan 171 (sl 109), freq 034
	jmp	scan_sepline	; scan 172 (sl 110), frequencies sep.
	jmp	scan_freqline	; scan 173 (sl 111), freq 035
	jmp	scan_sepline	; scan 174 (sl 112), frequencies sep.
	jmp	scan_freqline	; scan 175 (sl 113), freq 036
	jmp	scan_sepline	; scan 176 (sl 114), frequencies sep.
	jmp	scan_freqline	; scan 177 (sl 115), freq 037
	jmp	scan_sepline	; scan 178 (sl 116), frequencies sep.
	jmp	scan_freqline	; scan 179 (sl 117), freq 038
	jmp	scan_sepline	; scan 180 (sl 118), frequencies sep.
	jmp	scan_freqline	; scan 181 (sl 119), freq 039
	jmp	scan_sepline	; scan 182 (sl 120), frequencies sep.
	jmp	scan_freqline	; scan 183 (sl 121), freq 040
	jmp	scan_sepline	; scan 184 (sl 122), frequencies sep.
	jmp	scan_freqline	; scan 185 (sl 123), freq 041
	jmp	scan_sepline	; scan 186 (sl 124), frequencies sep.
	jmp	scan_freqline	; scan 187 (sl 125), freq 042
	jmp	scan_sepline	; scan 188 (sl 126), frequencies sep.
	jmp	scan_freqline	; scan 189 (sl 127), freq 043
	jmp	scan_sepline	; scan 190 (sl 128), frequencies sep.
	jmp	scan_freqline	; scan 191 (sl 129), freq 044
	jmp	scan_sepline	; scan 192 (sl 130), frequencies sep.
	jmp	scan_freqline	; scan 193 (sl 131), freq 045
	jmp	scan_sepline	; scan 194 (sl 132), frequencies sep.
	jmp	scan_freqline	; scan 195 (sl 133), freq 046
	jmp	scan_sepline	; scan 196 (sl 134), frequencies sep.
	jmp	scan_freqline	; scan 197 (sl 135), freq 047
	jmp	scan_sepline	; scan 198 (sl 136), frequencies sep.
	jmp	scan_freqline	; scan 199 (sl 137), freq 048
	jmp	scan_vscaleshort	; scan 200 (sl 138), v.scale short s.
	jmp	scan_freqline	; scan 201 (sl 139), freq 049
	jmp	scan_sepline	; scan 202 (sl 140), frequencies sep.
	jmp	scan_freqline	; scan 203 (sl 141), freq 050
	jmp	scan_sepline	; scan 204 (sl 142), frequencies sep.
	jmp	scan_freqline	; scan 205 (sl 143), freq 051
	jmp	scan_sepline	; scan 206 (sl 144), frequencies sep.
	jmp	scan_freqline	; scan 207 (sl 145), freq 052
	jmp	scan_sepline	; scan 208 (sl 146), frequencies sep.
	jmp	scan_freqline	; scan 209 (sl 147), freq 053
	jmp	scan_sepline	; scan 210 (sl 148), frequencies sep.
	jmp	scan_freqline	; scan 211 (sl 149), freq 054
	jmp	scan_sepline	; scan 212 (sl 150), frequencies sep.
	jmp	scan_freqline	; scan 213 (sl 151), freq 055
	jmp	scan_sepline	; scan 214 (sl 152), frequencies sep.
	jmp	scan_freqline	; scan 215 (sl 153), freq 056
	jmp	scan_sepline	; scan 216 (sl 154), frequencies sep.
	jmp	scan_freqline	; scan 217 (sl 155), freq 057
	jmp	scan_sepline	; scan 218 (sl 156), frequencies sep.
	jmp	scan_freqline	; scan 219 (sl 157), freq 058
	jmp	scan_sepline	; scan 220 (sl 158), frequencies sep.
	jmp	scan_freqline	; scan 221 (sl 159), freq 059
	jmp	scan_sepline	; scan 222 (sl 160), frequencies sep.
	jmp	scan_freqline	; scan 223 (sl 161), freq 060
	jmp	scan_sepline	; scan 224 (sl 162), frequencies sep.
	jmp	scan_freqline	; scan 225 (sl 163), freq 061
	jmp	scan_sepline	; scan 226 (sl 164), frequencies sep.
	jmp	scan_freqline	; scan 227 (sl 165), freq 062
	jmp	scan_sepline	; scan 228 (sl 166), frequencies sep.
	jmp	scan_freqline	; scan 229 (sl 167), freq 063
	jmp	scan_sepline	; scan 230 (sl 168), frequencies sep.
	jmp	scan_freqline	; scan 231 (sl 169), freq 064
	jmp	scan_vscaleshort	; scan 232 (sl 170), v.scale short s.
	jmp	scan_freqline	; scan 233 (sl 171), freq 065
	jmp	scan_sepline	; scan 234 (sl 172), frequencies sep.
	jmp	scan_freqline	; scan 235 (sl 173), freq 066
	jmp	scan_sepline	; scan 236 (sl 174), frequencies sep.
	jmp	scan_freqline	; scan 237 (sl 175), freq 067
	jmp	scan_sepline	; scan 238 (sl 176), frequencies sep.
	jmp	scan_freqline	; scan 239 (sl 177), freq 068
	jmp	scan_sepline	; scan 240 (sl 178), frequencies sep.
	jmp	scan_freqline	; scan 241 (sl 179), freq 069
	jmp	scan_sepline	; scan 242 (sl 180), frequencies sep.
	jmp	scan_freqline	; scan 243 (sl 181), freq 070
	jmp	scan_sepline	; scan 244 (sl 182), frequencies sep.
	jmp	scan_freqline	; scan 245 (sl 183), freq 071
	jmp	scan_sepline	; scan 246 (sl 184), frequencies sep.
	jmp	scan_freqline	; scan 247 (sl 185), freq 072
	jmp	scan_sepline	; scan 248 (sl 186), frequencies sep.
	jmp	scan_freqline	; scan 249 (sl 187), freq 073
	jmp	scan_sepline	; scan 250 (sl 188), frequencies sep.
	jmp	scan_freqline	; scan 251 (sl 189), freq 074
	jmp	scan_sepline	; scan 252 (sl 190), frequencies sep.
	jmp	scan_freqline	; scan 253 (sl 191), freq 075
	jmp	scan_sepline	; scan 254 (sl 192), frequencies sep.
	jmp	scan_freqline	; scan 255 (sl 193), freq 076
	jmp	scan_sepline	; scan 256 (sl 194), frequencies sep.
	jmp	scan_freqline	; scan 257 (sl 195), freq 077
	jmp	scan_sepline	; scan 258 (sl 196), frequencies sep.
	jmp	scan_freqline	; scan 259 (sl 197), freq 078
	jmp	scan_sepline	; scan 260 (sl 198), frequencies sep.
	jmp	scan_freqline	; scan 261 (sl 199), freq 079
	jmp	scan_sepline	; scan 262 (sl 200), frequencies sep.
	jmp	scan_freqline	; scan 263 (sl 201), freq 080
	jmp	scan_vscalelong	; scan 264 (sl 202), v.scale long s.
	jmp	scan_freqline	; scan 265 (sl 203), freq 081
	jmp	scan_sepline	; scan 266 (sl 204), frequencies sep.
	jmp	scan_freqline	; scan 267 (sl 205), freq 082
	jmp	scan_sepline	; scan 268 (sl 206), frequencies sep.
	jmp	scan_freqline	; scan 269 (sl 207), freq 083
	jmp	scan_sepline	; scan 270 (sl 208), frequencies sep.
	jmp	scan_freqline	; scan 271 (sl 209), freq 084
	jmp	scan_sepline	; scan 272 (sl 210), frequencies sep.
	jmp	scan_freqline	; scan 273 (sl 211), freq 085
	jmp	scan_sepline	; scan 274 (sl 212), frequencies sep.
	jmp	scan_freqline	; scan 275 (sl 213), freq 086
	jmp	scan_sepline	; scan 276 (sl 214), frequencies sep.
	jmp	scan_freqline	; scan 277 (sl 215), freq 087
	jmp	scan_sepline	; scan 278 (sl 216), frequencies sep.
	jmp	scan_freqline	; scan 279 (sl 217), freq 088
	jmp	scan_sepline	; scan 280 (sl 218), frequencies sep.
	jmp	scan_freqline	; scan 281 (sl 219), freq 089
	jmp	scan_sepline	; scan 282 (sl 220), frequencies sep.
	jmp	scan_freqline	; scan 283 (sl 221), freq 090
	jmp	scan_sepline	; scan 284 (sl 222), frequencies sep.
	jmp	scan_freqline	; scan 285 (sl 223), freq 091
	jmp	scan_sepline	; scan 286 (sl 224), frequencies sep.
	jmp	scan_freqline	; scan 287 (sl 225), freq 092
	jmp	scan_sepline	; scan 288 (sl 226), frequencies sep.
	jmp	scan_freqline	; scan 289 (sl 227), freq 093
	jmp	scan_sepline	; scan 290 (sl 228), frequencies sep.
	jmp	scan_freqline	; scan 291 (sl 229), freq 094
	jmp	scan_sepline	; scan 292 (sl 230), frequencies sep.
	jmp	scan_freqline	; scan 293 (sl 231), freq 095
	jmp	scan_sepline	; scan 294 (sl 232), frequencies sep.
	jmp	scan_freqline	; scan 295 (sl 233), freq 096
	jmp	scan_vscaleshort	; scan 296 (sl 234), v.scale short s.
	jmp	scan_freqline	; scan 297 (sl 235), freq 097
	jmp	scan_sepline	; scan 298 (sl 236), frequencies sep.
	jmp	scan_freqline	; scan 299 (sl 237), freq 098
	jmp	scan_sepline	; scan 300 (sl 238), frequencies sep.
	jmp	scan_freqline	; scan 301 (sl 239), freq 099
	jmp	scan_sepline	; scan 302 (sl 240), frequencies sep.
	jmp	scan_freqline	; scan 303 (sl 241), freq 100
	jmp	scan_sepline	; scan 304 (sl 242), frequencies sep.
	jmp	scan_freqline	; scan 305 (sl 243), freq 101
	jmp	scan_sepline	; scan 306 (sl 244), frequencies sep.
	jmp	scan_freqline	; scan 307 (sl 245), freq 102
	jmp	scan_sepline	; scan 308 (sl 246), frequencies sep.
	jmp	scan_freqline	; scan 309 (sl 247), freq 103
	jmp	scan_sepline	; scan 310 (sl 248), frequencies sep.
	jmp	scan_freqline	; scan 311 (sl 249), freq 104
	jmp	scan_sepline	; scan 312 (sl 250), frequencies sep.
	jmp	scan_freqline	; scan 313 (sl 251), freq 105
	jmp	scan_sepline	; scan 314 (sl 252), frequencies sep.
	jmp	scan_freqline	; scan 315 (sl 253), freq 106
	jmp	scan_sepline	; scan 316 (sl 254), frequencies sep.
	jmp	scan_freqline	; scan 317 (sl 255), freq 107
	jmp	scan_sepline	; scan 318 (sl 256), frequencies sep.
	jmp	scan_freqline	; scan 319 (sl 257), freq 108
	jmp	scan_sepline	; scan 320 (sl 258), frequencies sep.
	jmp	scan_freqline	; scan 321 (sl 259), freq 109
	jmp	scan_sepline	; scan 322 (sl 260), frequencies sep.
	jmp	scan_freqline	; scan 323 (sl 261), freq 110
	jmp	scan_sepline	; scan 324 (sl 262), frequencies sep.
	jmp	scan_freqline	; scan 325 (sl 263), freq 111
	jmp	scan_sepline	; scan 326 (sl 264), frequencies sep.
	jmp	scan_freqline	; scan 327 (sl 265), freq 112
	jmp	scan_vscaleshort	; scan 328 (sl 266), v.scale short s.
	jmp	scan_freqline	; scan 329 (sl 267), freq 113
	jmp	scan_sepline	; scan 330 (sl 268), frequencies sep.
	jmp	scan_freqline	; scan 331 (sl 269), freq 114
	jmp	scan_sepline	; scan 332 (sl 270), frequencies sep.
	jmp	scan_freqline	; scan 333 (sl 271), freq 115
	jmp	scan_sepline	; scan 334 (sl 272), frequencies sep.
	jmp	scan_freqline	; scan 335 (sl 273), freq 116
	jmp	scan_sepline	; scan 336 (sl 274), frequencies sep.
	jmp	scan_freqline	; scan 337 (sl 275), freq 117
	jmp	scan_sepline	; scan 338 (sl 276), frequencies sep.
	jmp	scan_freqline	; scan 339 (sl 277), freq 118
	jmp	scan_sepline	; scan 340 (sl 278), frequencies sep.
	jmp	scan_freqline	; scan 341 (sl 279), freq 119
	jmp	scan_sepline	; scan 342 (sl 280), frequencies sep.
	jmp	scan_freqline	; scan 343 (sl 281), freq 120
	jmp	scan_sepline	; scan 344 (sl 282), frequencies sep.
	jmp	scan_freqline	; scan 345 (sl 283), freq 121
	jmp	scan_sepline	; scan 346 (sl 284), frequencies sep.
	jmp	scan_freqline	; scan 347 (sl 285), freq 122
	jmp	scan_sepline	; scan 348 (sl 286), frequencies sep.
	jmp	scan_freqline	; scan 349 (sl 287), freq 123
	jmp	scan_sepline	; scan 350 (sl 288), frequencies sep.
	jmp	scan_freqline	; scan 351 (sl 289), freq 124
	jmp	scan_sepline	; scan 352 (sl 290), frequencies sep.
	jmp	scan_freqline	; scan 353 (sl 291), freq 125
	jmp	scan_sepline	; scan 354 (sl 292), frequencies sep.
	jmp	scan_freqline	; scan 355 (sl 293), freq 126
	jmp	scan_sepline	; scan 356 (sl 294), frequencies sep.
	jmp	scan_freqline	; scan 357 (sl 295), freq 127
	jmp	scan_sepline	; scan 358 (sl 296), frequencies sep.
	jmp	scan_empty	; scan 359 (sl 297), empty line
	jmp	scan_empty	; scan 360 (sl 298), empty line
	jmp	scan_empty	; scan 361 (sl 299), empty line
	jmp	scan_empty	; scan 362 (sl 300), empty line
	jmp	scan_empty	; scan 363 (sl 301), empty line
	jmp	scan_empty	; scan 364 (sl 302), empty line
	jmp	scan_empty	; scan 365 (sl 303), empty line
	jmp	scan_empty	; scan 366 (sl 304), empty line
	jmp	scan_empty	; scan 367 (sl 305), empty line
	jmp	scan_empty	; scan 368 (sl 306), empty line
	jmp	scan_empty	; scan 369 (sl 307), empty line
	jmp	scan_empty	; scan 370 (sl 308), empty line
	jmp	scan_empty	; scan 371 (sl 309), empty line
	jmp	scan_empty	; scan 372 (sl 310), empty line
	jmp	scan_empty	; scan 373 (sl 311), empty line
	jmp	scan_empty	; scan 374 (sl 312), empty line
	jmp	scan_empty	; scan 375 (sl 313), empty line
	jmp	scan_empty	; scan 376 (sl 314), empty line
	jmp	scan_empty	; scan 377 (sl 315), empty line
	jmp	scan_empty	; scan 378 (sl 316), empty line
	jmp	scan_empty	; scan 379 (sl 317), empty line
	jmp	scan_empty	; scan 380 (sl 318), empty line
	jmp	scan_empty	; scan 381 (sl 319), empty line
	jmp	scan_empty	; scan 382 (sl 320), empty line
	jmp	scan_empty	; scan 383 (sl 321), empty line
	jmp	scan_empty	; scan 384 (sl 322), empty line
	jmp	scan_empty	; scan 385 (sl 323), empty line
	jmp	scan_empty	; scan 386 (sl 324), empty line
	jmp	scan_titlempty	; scan 387 (sl 325), empty title
	jmp	scan_titlempty	; scan 388 (sl 326), empty title
	jmp	scan_titlempty	; scan 389 (sl 327), empty title
	jmp	scan_titlempty	; scan 390 (sl 328), empty title
	jmp	scan_titlempty	; scan 391 (sl 329), empty title
	jmp	scan_titlempty	; scan 392 (sl 330), empty title
	jmp	scan_title0	; scan 393 (sl 331), title line 0
	jmp	scan_title0	; scan 394 (sl 332), title line 0
	jmp	scan_title1	; scan 395 (sl 333), title line 1
	jmp	scan_title1	; scan 396 (sl 334), title line 1
	jmp	scan_title2	; scan 397 (sl 335), title line 2
	jmp	scan_title2	; scan 398 (sl 336), title line 2
	jmp	scan_title3	; scan 399 (sl 337), title line 3
	jmp	scan_title3	; scan 400 (sl 338), title line 3
	jmp	scan_title4	; scan 401 (sl 339), title line 4
	jmp	scan_title4	; scan 402 (sl 340), title line 4
	jmp	scan_title5	; scan 403 (sl 341), title line 5
	jmp	scan_title5	; scan 404 (sl 342), title line 5
	jmp	scan_title6	; scan 405 (sl 343), title line 6
	jmp	scan_title6	; scan 406 (sl 344), title line 6
	jmp	scan_titlempty	; scan 407 (sl 345), empty title
	jmp	scan_titlempty	; scan 408 (sl 346), empty title
	jmp	scan_titlempty	; scan 409 (sl 347), empty title
	jmp	scan_titlempty	; scan 410 (sl 348), empty title
	jmp	scan_titlempty	; scan 411 (sl 349), empty title
	jmp	scan_blanking	; scan 412, vertical blanking
	jmp	scan_blanking	; scan 413, vertical blanking
	jmp	scan_blanking	; scan 414, vertical blanking
	jmp	scan_blanking	; scan 415, vertical blanking
	jmp	scan_blanking	; scan 416, vertical blanking
	jmp	scan_blanking	; scan 417, vertical blanking
	jmp	scan_blanking	; scan 418, vertical blanking
	jmp	scan_blanking	; scan 419, vertical blanking
	jmp	scan_blanking	; scan 420, vertical blanking
	jmp	scan_blanking	; scan 421, vertical blanking
	jmp	scan_blanking	; scan 422, vertical blanking
	jmp	scan_blanking	; scan 423, vertical blanking
	jmp	scan_blanking	; scan 424, vertical blanking
	jmp	scan_blanking	; scan 425, vertical blanking
	jmp	scan_blanking	; scan 426, vertical blanking
	jmp	scan_blanking	; scan 427, vertical blanking
	jmp	scan_blanking	; scan 428, vertical blanking
	jmp	scan_blanking	; scan 429, vertical blanking
	jmp	scan_blanking	; scan 430, vertical blanking
	jmp	scan_blanking	; scan 431, vertical blanking
	jmp	scan_blanking	; scan 432, vertical blanking
	jmp	scan_blanking	; scan 433, vertical blanking
	jmp	scan_blanking	; scan 434, vertical blanking
	jmp	scan_blanking	; scan 435, vertical blanking
	jmp	scan_blanking	; scan 436, vertical blanking
	jmp	scan_blanking	; scan 437, vertical blanking
	jmp	scan_blanking	; scan 438, vertical blanking
	jmp	scan_blanking	; scan 439, vertical blanking
	jmp	scan_blanking	; scan 440, vertical blanking
	jmp	scan_blanking	; scan 441, vertical blanking
	jmp	scan_blanking	; scan 442, vertical blanking
	jmp	scan_blanking	; scan 443, vertical blanking
	jmp	scan_blanking	; scan 444, vertical blanking
	jmp	scan_blanking	; scan 445, vertical blanking
	jmp	scan_blanking	; scan 446, vertical blanking
	jmp	scan_blanking	; scan 447, vertical blanking
	jmp	scan_blanking	; scan 448, vertical blanking
	jmp	scan_rstscanl	; scan 449, reset scan_line


;----------------------------------------------------------------------------
; Soft generation of a vertical blanking line
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_blanking	jmp	resume_irq	; Nothing to do as video already off !


;----------------------------------------------------------------------------
; Soft generation of a vertical blanking line with switch on of Vsynch
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_vsynch_on	movlb 1
	clrb	RC.6	; RC6=0 (Vsynch active)
	inc	frame_num	; increment frame number
	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of a vertical blanking line with switch off of Vsynch
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_vsynch_off	movlb 1
	setb	RC.6	; RC6=1 (Vsynch inactive)
	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of a blank screen line (background color)
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_empty	movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color
	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of a frequency line
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_freqline	movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color

	mov	W, #103	; calculate frequency number
	mov	W, scan_line+1-w	; (=(scan_line-103)/2)
	mov	tmpi, W
	clrb	ALUSTA.C
		rrcf tmpi,W

		dispbufrd		; read display buffer value (8 cycles)
	and	W, #%01111111	; be sure it is <128
	mov	tmpi, W	; and store it in tmpi

;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. 
		sublw low endfreqline	; calculate jump address
	mov	tmpi2+1, W	; (endfreqline-freq value)
	mov	W, #high endfreqline	; store msb in PCLATH and lsb in tmpi2+1
	mov	tmpi2, W
	clr	WREG
		subwfb tmpi2,F
		movfp tmpi2,PCLATH

	mov	W, #BKG_COLOR
	mov	tmpcolor, W
	mov	W, #SLINE_COLOR
	mov	RB, W	; draw vertical line
		movfp tmpcolor,PORTB	; and return to background color

	clr	WREG
		cpfsgt tmpi		; if value 0
	jmp	resume_irq	; return

	mov	W, #FREQ_COLOR	; else
	mov	RB, W	; draw frequency line

		movfp tmpi2+1,PCL	; and jump to precalculated address

	nop
	nop
start_wait128	nop
	nop	; 128 nop's
	nop	; in order to have a cycle per cycle
	nop	; delay, a jump is done to the
	nop	; precalculated nop in this list !
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
endfreqline	mov	W, #BKG_COLOR
	mov	RB, W	; and return to background color

	jmp	resume_irq

;----------------------------------------------------------------------------
; Soft generation of a separating line between 2 frequency lines
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_sepline	movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color

	nop
	nop
	nop	; serie of nop's in order to
	nop	; be sure that the vertical
	nop	; line will be aligned with
					; the one for frequency lines !
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	nop
	nop
	nop
	nop
	nop
	nop
	nop

	mov	W, #BKG_COLOR
	mov	tmpcolor, W
	mov	W, #SLINE_COLOR
	mov	RB, W	; draw vertical line
		movfp tmpcolor,PORTB	; and return to background color

	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of a separating line with a "short" scale indicator
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_vscaleshort movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color

	nop
	nop
	nop	; serie of nop's in order to
	nop	; be sure that the vertical
	nop	; line will be aligned with
					; the one for frequency lines !
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	nop
	nop
	nop
	nop
	nop
	mov	W, #SHORTS_COLOR
	mov	RB, W	; draw the small indicator
	nop

	mov	W, #BKG_COLOR
	mov	tmpcolor, W
	mov	RB, W	; return to background color
	mov	W, #SLINE_COLOR
	mov	RB, W	; draw vertical line
		movfp tmpcolor,PORTB	; and return to background color

	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of a separating line with a "long" scale indicator
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_vscalelong	movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color

	nop
	nop
	nop	; serie of nop's in order to
	nop	; be sure that the vertical
	nop	; line will be aligned with
					; the one for frequency lines !
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	mov	W, #LONGS_COLOR
	mov	RB, W	; draw the long indicator

	nop
	nop
	nop

	mov	W, #BKG_COLOR
	mov	tmpcolor, W
	mov	RB, W	; return to background color
	mov	W, #SLINE_COLOR
	mov	RB, W	; draw vertical line
		movfp tmpcolor,PORTB	; and return to background color

	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of the horizontal scale "long" steps
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_hscalelong	movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color

	mov	tmpi2, W	; save color for background
	mov	W, #LONGS_COLOR
	mov	tmpi, W	; save color for long steps drawing
	mov	W, #BKG_COLOR
	mov	tmpi+1, W	; save color for short steps drawing

		movlb 0
	snb	RB.7	; log mode ?
	jmp	scale_lin_m	; if not, draw lin scale
	jmp	scale_log_m	; else draw log scale

scale_lin_m	nop	; time correction for btfsc
scale_lin_m2	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
		movfp tmpi,PORTB	;col 0 -> long
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 10
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;-> short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col20
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col30
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 40
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 50
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi,PORTB	;col 60->long
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 70
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 80
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 90
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 100
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 110
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi,PORTB	;col 120->long
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 127

	jmp	resume_irq


scale_log_m	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

		movfp tmpi,PORTB	;col 0->long
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 10
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col20
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col30
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi,PORTB	;col 40->long
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 50
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 60
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 70
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi,PORTB	;col 80->long
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 90
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 100
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 110
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi+1,PORTB	;->short
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi,PORTB	;col 120->long
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB
		movfp tmpi2,PORTB	;col 127

	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of the horizontal scale "short" steps
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_hscaleshort movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color

	mov	tmpi2, W	; save color for background
	mov	W, #LONGS_COLOR
	mov	tmpi, W	; save color for long steps drawing
	mov	W, #SHORTS_COLOR
	mov	tmpi+1, W	; save color for short steps drawing

		movlb 0
	snb	RB.7	; log mode ?
	jmp	scale_lin_m	; if not, draw lin scale
	jmp	scale_log_m	; else draw log scale


;----------------------------------------------------------------------------
; Soft generation of the horizontal scale plain line
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_hscaleline	movlb 0
	mov	W, #BKG_COLOR
	mov	RB, W	; set background color

	nop
	nop
	nop	; serie of nop's in order to
	nop	; be sure that the vertical
	nop	; line will be aligned with
					; the one for frequency lines !
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	mov	W, #SLINE_COLOR
	mov	RB, W	; draw vertical line

	jmp	start_wait128	; and wait for end of active line


;----------------------------------------------------------------------------
; Soft generation of a blank screen line (background title color)
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_titlempty	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	; set background color
	jmp	resume_irq


;----------------------------------------------------------------------------
; Soft generation of the title lines
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

; Title content :
; *               ****   *****   ***    *  ***   *****   *****   ***   *****  ****   *   *  *   *               *
; ***             *   *    *    *   *  *  *   *  *    *  *      *   *    *    *   *  *   *  ** **             ***
; *****           *   *    *    *         *      *    *  *      *        *    *   *  *   *  * * *           *****
; *******         ****     *    *          ***   *****   ***    *        *    ****   *   *  *   *         *******
; *********       *        *    *             *  *       *      *        *    * *    *   *  *   *       *********
; ***********     *        *    *   *     *   *  *       *      *   *    *    *  *   *   *  *   *     ***********
; *************   *      *****   ***       ***   *       *****   ***     *    *   *   ***   *   *   *************
;
; Hold sign content :
;
;  * *   * *
; *  *   *  *
; *  *****  *
; *  *   *  *
;  * *   * *
;
; The following routines display each line of the previous strings, scan line
; per scan line. No other way to do cycle per cycle video generation (of course
; it's possible to implement a character set map, but not useful in this case)
;
; Of course the following routines where generated automaticaly ! (seems like a
; compiler job, no ?)


; Generation of title0

scan_title0	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	;set background color
	mov	W, #TITLE_COLOR	;store title color
	mov	tmpi+1, W	;in tmpi+1
	mov	W, #BKGTITLE_COLOR	;and background color
	mov	tmpi, W	;in tmpi

		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on

		movfp tmpi,PORTB		;reset to background color
	jmp	resume_irq	;and return

; Generation of title1

scan_title1	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	;set background color
	mov	W, #TITLE_COLOR	;store title color
	mov	tmpi+1, W	;in tmpi+1
	mov	W, #BKGTITLE_COLOR	;and background color
	mov	tmpi, W	;in tmpi

		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on

		movfp tmpi,PORTB		;reset to background color

		movlb 0
	snb	RB.6	;mode hold ?
	jmp	resume_irq	;if not, return
	snb	frame_num.5	;blinking test
	jmp	resume_irq	;if off return

	mov	W, #HOLD_COLOR	;store hold color
	mov	tmpi+1, W	;in tmpi+1
		movfp tmpi,PORTB		;and display "hold" sign
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

	jmp	resume_irq	;and return

; Generation of title2

scan_title2	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	;set background color
	mov	W, #TITLE_COLOR	;store title color
	mov	tmpi+1, W	;in tmpi+1
	mov	W, #BKGTITLE_COLOR	;and background color
	mov	tmpi, W	;in tmpi

		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on

		movfp tmpi,PORTB		;reset to background color

		movlb 0
	snb	RB.6	;mode hold ?
	jmp	resume_irq	;if not, return
	snb	frame_num.5	;blinking test
	jmp	resume_irq	;if off return

	mov	W, #HOLD_COLOR	;store hold color
	mov	tmpi+1, W	;in tmpi+1
		movfp tmpi,PORTB		;and display "hold" sign
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB

	jmp	resume_irq	;and return

; Generation of title3

scan_title3	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	;set background color
	mov	W, #TITLE_COLOR	;store title color
	mov	tmpi+1, W	;in tmpi+1
	mov	W, #BKGTITLE_COLOR	;and background color
	mov	tmpi, W	;in tmpi

		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on

		movfp tmpi,PORTB		;reset to background color

		movlb 0
	snb	RB.6	;mode hold ?
	jmp	resume_irq	;if not, return
	snb	frame_num.5	;blinking test
	jmp	resume_irq	;if off return

	mov	W, #HOLD_COLOR	;store hold color
	mov	tmpi+1, W	;in tmpi+1
		movfp tmpi,PORTB		;and display "hold" sign
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB

	jmp	resume_irq	;and return

; Generation of title4

scan_title4	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	;set background color
	mov	W, #TITLE_COLOR	;store title color
	mov	tmpi+1, W	;in tmpi+1
	mov	W, #BKGTITLE_COLOR	;and background color
	mov	tmpi, W	;in tmpi

		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on

		movfp tmpi,PORTB		;reset to background color

		movlb 0
	snb	RB.6	;mode hold ?
	jmp	resume_irq	;if not, return
	snb	frame_num.5	;blinking test
	jmp	resume_irq	;if off return

	mov	W, #HOLD_COLOR	;store hold color
	mov	tmpi+1, W	;in tmpi+1
		movfp tmpi,PORTB		;and display "hold" sign
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB

	jmp	resume_irq	;and return

; Generation of title5

scan_title5	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	;set background color
	mov	W, #TITLE_COLOR	;store title color
	mov	tmpi+1, W	;in tmpi+1
	mov	W, #BKGTITLE_COLOR	;and background color
	mov	tmpi, W	;in tmpi

		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on

		movfp tmpi,PORTB		;reset to background color

		movlb 0
	snb	RB.6	;mode hold ?
	jmp	resume_irq	;if not, return
	snb	frame_num.5	;blinking test
	jmp	resume_irq	;if off return

	mov	W, #HOLD_COLOR	;store hold color
	mov	tmpi+1, W	;in tmpi+1
		movfp tmpi,PORTB		;and display "hold" sign
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

	jmp	resume_irq	;and return

; Generation of title6

scan_title6	movlb 0
	mov	W, #BKGTITLE_COLOR
	mov	RB, W	;set background color
	mov	W, #TITLE_COLOR	;store title color
	mov	tmpi+1, W	;in tmpi+1
	mov	W, #BKGTITLE_COLOR	;and background color
	mov	tmpi, W	;in tmpi

		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB

		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi,PORTB
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on
		movfp tmpi+1,PORTB		;Pixel on

		movfp tmpi,PORTB		;reset to background color
	jmp	resume_irq	;and return


;----------------------------------------------------------------------------
; Soft generation of a vertical blanking line with scan_line reset
;
; Warning : all scan_X routines should execute in less than 169 instructions
;----------------------------------------------------------------------------

scan_rstscanl	clr	scan_line	; reset scanline (will be incremented
	clr	scan_line+1	; to 1 at next interrupt)
	jmp	resume_irq


;============================================================================
;                             - END OF FILE -
;============================================================================