; KCPSM3 PicoBlaze DIGITAL-OSZILLOSKOP by cm 5/2009

; Wave-RAM auslesen und anzeigen

; Referenz-Triggerpunkt wird von wave_ram berechnet,
; wir fangen immer bei Adresse 0 an
	
	; Port-Definitionen
	
;Eingangsports
	; STATUS Bit 0 GDONE, Bit 1 FRAMEDONE, Bit 2 trig_done, Bit 3 trig_ok
	CONSTANT in_status, 00	
	CONSTANT in_com_data, 01
	CONSTANT in_com_sel, 02
	CONSTANT in_scaled_y, 04
	CONSTANT in_read_y1, 06
	CONSTANT in_read_y2, 07

;Ports in parser.vhd
	CONSTANT out_adrlow, 10
	CONSTANT out_adrhi, 11
	CONSTANT out_data, 12
	
;Ports extern
	; TRIGCTRL Bit 0..2 trig_mode, Bit 3 Reset, Bit 4 select_Ch2, Bit 5 COM_WR, Bit 6 BUSREQ
	CONSTANT out_trigctrl, 40		
	CONSTANT out_com, 41

	CONSTANT out_triglevel, 42
	CONSTANT out_hystlevel, 43	
	CONSTANT out_fac, 44	
	CONSTANT out_sel_y, 45	; 0=wave1, 1=wave2, 2=hyst_level, 3=trig_level auf Multiplier

	CONSTANT out_wavelow, 46	;Wave-RAM-Adresse
	CONSTANT out_wavehi, 47
	
;Grafik-Befehle	
	CONSTANT gcmd_xdata, 00
	CONSTANT gcmd_ydata, 01
	CONSTANT gcmd_move, 02
	CONSTANT gcmd_point, 03
	CONSTANT gcmd_line, 04
	CONSTANT gcmd_rect, 05
	CONSTANT gcmd_fill, 06
	CONSTANT gcmd_small, 07
	CONSTANT gcmd_xstart, 08
	CONSTANT gcmd_ystart, 09
	CONSTANT gcmd_xsize, 0A
	CONSTANT gcmd_ysize, 0B
	CONSTANT gcmd_xgrid, 0C
	CONSTANT gcmd_ygrid, 0D
	CONSTANT gcmd_frameEna, 0E
	CONSTANT gcmd_color, 0F
	
	CONSTANT gcmd_xtrig, 20
	CONSTANT gcmd_ytrig, 21

;Scratchpad Memory, Interface to t65 Core

; Trigger-Modus mem_trigmode: 
; 0: Nicht auf Trigger warten
; 1: analog, positive Flanke	adc_wert > trig_level
; 2: analog, negative Flanke	adc_wert < hyst_level
; 3: exakter digitaler Wert		adc_wert = trig_level
; 4: positive Bit-Flanke, Maske in trig_level TBI!
; 5: negative Bit-Flanke, Maske in trig_level TBI!
; Bit 3 ist Trigger-Reset, Bit 4 ist Channel Select (0=CH1, 1=CH2)

	CONSTANT mem_cmd, 00	; ct-BASIC POKE 960,xx ($3C0)
	CONSTANT mem_trigmode, 01	; ct-BASIC POKE 961,xx ($3C1)
	CONSTANT mem_triglevel, 02	; ct-BASIC POKE 962,xx ($3C2)
	CONSTANT mem_hystlevel, 03	; ct-BASIC POKE 963,xx ($3C3)
	CONSTANT mem_y1base, 04		; ct-BASIC POKE 964,xx ($3C4)
	CONSTANT mem_y2base, 05		; ct-BASIC POKE 965,xx ($3C5)
	CONSTANT mem_offsetlow, 06	; ct-BASIC POKE 966,xx ($3C6)
	CONSTANT mem_offsethi, 07	; ct-BASIC POKE 967,xx ($3C7)
	CONSTANT mem_display, 08	; ct-BASIC POKE 968,xx ($3C8)
	
	CONSTANT mem_y1scale, 0A	; ct-BASIC POKE 970,xx ($3CA)	
	CONSTANT mem_y2scale, 0B	; ct-BASIC POKE 971,xx ($3CB)	
	CONSTANT mem_y1mid, 0C	; ct-BASIC POKE 970,xx ($3CA)	
	CONSTANT mem_y2mid, 0D	; ct-BASIC POKE 971,xx ($3CB)	

;Schnelle Register
; s0 temporär nur innerhalb einer Subroutine

; s3 und s4 reserviert für IRQ-Service
	NAMEREG s3, isema
	NAMEREG s4, itemp
	NAMEREG s5, y1base
	NAMEREG s6, y2base
	NAMEREG s7, running
	NAMEREG s8, x
	NAMEREG s9, y
	NAMEREG sA, y1
	NAMEREG sB, y2
	NAMEREG sC, acc		; meist Übergabe-Parameter
	NAMEREG sD, mode	; Plot-Mode
	NAMEREG sE, color	; Plot-Color
	NAMEREG sF, mask	; für Logic-Darstellung
	;


;=========================================================================
;Hauptschleife
;=========================================================================

cold_start: 
	DISABLE INTERRUPT
	LOAD isema, 00	
	LOAD running, 00	
	CALL init
	LOAD s0, 00
	STORE s0, mem_trigmode
	STORE s0, mem_cmd
	ENABLE INTERRUPT
warm_start:
	CALL disable_trigger
	CALL setlevels
	CALL refresh
	COMPARE isema, 00
	JUMP Z, warm_start
	LOAD isema, 00
	
	FETCH s0, mem_trigmode
	;AND s0, 0F
	COMPARE s0, 00			; Trigger aus?		
	JUMP Z, warm_start
	
cont_loop:
	CALL setlevels
	CALL reset_trigger
	CALL aquire
	CALL disable_trigger
	CALL refresh
	FETCH s0, mem_trigmode
	AND s0, 80			; Repeat-Bit in mem_trigmode gesetzt?
	JUMP NZ, cont_loop
	LOAD isema, 00
	JUMP warm_start
	
aquire:	
	COMPARE running, 40	; running-Flag evt. durch PS2-Event gelöscht?
	RETURN NZ
	INPUT s0, in_status ; Trigger DONE true abwarten
	TEST s0, 04
	JUMP Z, aquire
	RETURN
	
setlevels:
	FETCH acc, mem_y1base
	LOAD y1base, 00
	SUB acc, y1base
	LOAD y1base, acc
	FETCH acc, mem_y2base
	LOAD y2base, 00
	SUB acc, y2base
	LOAD y2base, acc
	
	FETCH acc, mem_hystlevel
	OUTPUT acc, out_hystlevel
	FETCH acc, mem_triglevel
	OUTPUT acc, out_triglevel
	
; neue Mittellinie berechnen
	FETCH acc, mem_y1scale		; Mittellinie = halber Skalenendwert
	SR0 acc
	LOAD s0, 60	; Endwert Screen $C0/2
	SUB s0, acc
	FETCH acc, mem_y1base		; Mittellinie verschieben
	ADD acc, A0			; Korrekturwert $60=96=Mitte
	ADD s0, acc
	STORE s0, mem_y1mid
	FETCH acc, mem_y2scale
	SR0 acc
	LOAD s0, 60	; Endwert Screen $C0/2
	SUB s0, acc
	FETCH acc, mem_y2base		; Mittellinie verschieben
	ADD acc, A0
	ADD s0, acc
	STORE s0, mem_y2mid
	
	CALL set_trigline
	
	LOAD acc, 80
	OUTPUT acc, gcmd_xtrig
	FETCH s0, mem_display
	COMPARE s0, 00
	JUMP NZ, frameOn
	OUTPUT s0, gcmd_frameEna	
	RETURN	
frameOn:
	LOAD s0, 07
	OUTPUT s0, gcmd_frameEna
	RETURN	
	
;=========================================================================
;Screen-Hilfsroutinen
;=========================================================================
	
setReadAddr:
	LOAD s0, 00
	FETCH acc, mem_offsetlow
	ADD acc, x
	OUTPUT acc, out_wavelow
	FETCH acc, mem_offsethi
	ADDCY acc, s0
	OUTPUT acc, out_wavehi
	RETURN
	
set_trigline:
; Position der Trigger-Hilslinie berechnen inkl. yNbase
	LOAD acc, 02	; trig_level Multiplier select
	OUTPUT acc, out_sel_y
	FETCH acc, mem_trigmode	; welcher Kanal?
	TEST acc, 10	; Bit 4 übrig lassen, Channel select im Z-Flag
	JUMP NZ, set_trigline2	; wenn CH 2
	
set_trigline1:	
	FETCH acc, mem_y1scale
	OUTPUT acc, out_fac
	TEST acc, 00	; NOP dummy, Zeit für Multiplier
	INPUT y1, in_scaled_y
	CALL y1offset
	OUTPUT y, gcmd_ytrig
	RETURN
	
set_trigline2:
; Position der Trigger-Hilslinie berechnen inkl. y2base
	FETCH acc, mem_y2scale
	OUTPUT acc, out_fac
	TEST acc, 00	; NOP dummy, Zeit für Multiplier
	INPUT y2, in_scaled_y
	CALL y2offset
	OUTPUT y, gcmd_ytrig
	RETURN
	
y1offset:
; skaliertes Byte y1 negieren und mit Offset versehen, Ergebnis in y
	FETCH s0, mem_y1mid
	ADD y1, s0
	LOAD y, BF	; von 192 abziehen (Nullpunkt oben), y max=191=$BF
	SUB y, y1	; Wert in y jetzt zwischen 0 (oben) und 191 (unten)
	RETURN NC
; wenn Carry gesetzt, ist Limit erreicht
	COMPARE s0, 80	; ist noch mem_y1mid
	JUMP NC, ysetlower
	LOAD y, 00
	RETURN

y2offset: 
; skaliertes Byte y2 negieren und mit Offset versehen, Ergebnis in y
	FETCH s0, mem_y2mid
	ADD y2, s0
	LOAD y, BF	; von 192 abziehen (Nullpunkt oben), y max=191=$BF
	SUB y, y2
	RETURN NC
; wenn Carry gesetzt, ist Limit erreicht
	COMPARE s0, 80	; ist noch mem_y2mid
	JUMP NC, ysetlower
	LOAD y, 00
	RETURN
	
ysetlower:
	LOAD y, BF
	RETURN


;=========================================================================
;1 oder 2 Kanäle darstellen, je nach mem_display-Inhalt
;=========================================================================

refresh:
	CALL wait_framedone
	CALL gclear
	FETCH s0, mem_display
	AND s0, 01
	CALL NZ, y1display
	FETCH s0, mem_display
	AND s0, 02
	CALL NZ, y2display
	FETCH s0, mem_display
	AND s0, 04
	CALL NZ, y1logic
	RETURN

;=========================================================================
;Samples von Kanal 1 als Logiksignale darstellen, 256 Bytes
;=========================================================================

y1logic:
	LOAD x, 00
	CALL setReadAddr
	LOAD color, 03
	OUTPUT color, gcmd_color
	LOAD mask, 01
	LOAD y1base, 08
y1logictraceloop:
	LOAD x, 00
	LOAD y, y1base
	INPUT y1, in_read_y1
	AND y1, mask	
	JUMP NZ, y1logic0prep
	ADD y, 08
y1logic0prep:	
	LOAD mode, gcmd_move	; Startpunkt links
	CALL plotxy
	LOAD mode, gcmd_point	
y1logicloop:
	CALL setReadAddr
	LOAD y, y1base
	LOAD color, 03
	OUTPUT color, gcmd_color
	INPUT y1, in_read_y1
	AND y1, mask	
	JUMP NZ, y1logic0
	LOAD color, 01
	OUTPUT color, gcmd_color
	ADD y, 04
y1logic0:		
	CALL plotxy
	ADD x, 01
	COMPARE x, FF	
	JUMP NZ, y1logicloop
	SL0 mask
	ADD y1base, 10
	COMPARE y1base, 88
	JUMP NZ, y1logictraceloop	
	RETURN

;=========================================================================
;Samples von Kanal 1 analog darstellen, 256 Bytes
;=========================================================================
	
y1display:
	LOAD y, BF
	FETCH acc, mem_y1base
	SUB y, acc
	
	LOAD mode, gcmd_point	; Startpunkt links
	LOAD x, 00
	LOAD color, 02
	OUTPUT color, gcmd_color
y1midline:
	CALL plotxy
	ADD x, 04
	COMPARE x, 00
	JUMP NZ, y1midline

	LOAD acc, 00
	OUTPUT acc, out_sel_y	; Multiplexer auf Kanal 1 setzen
	FETCH acc, mem_y1scale	; Hardware-Multiplier über Multiplexer
	OUTPUT acc, out_fac
	LOAD x, 00
	CALL setReadAddr
	INPUT y1, in_scaled_y
	CALL y1offset
	LOAD mode, gcmd_move	; Startpunkt links
	CALL plotxy
	LOAD mode, gcmd_line	
y1refreshloop:
	ADD x, 01
	CALL setReadAddr
	INPUT y1, in_scaled_y
	CALL y1offset
	CALL plotxy
	COMPARE x, FF	
	JUMP NZ, y1refreshloop
	RETURN

;=========================================================================
;Samples von Kanal 2 analog darstellen, 256 Bytes
;=========================================================================

y2display:
	LOAD y, BF
	FETCH acc, mem_y2base
	SUB y, acc
	
	LOAD mode, gcmd_point	; Startpunkt links
	LOAD x, 02
	LOAD color, 01
	OUTPUT color, gcmd_color
y2midline:
	CALL plotxy
	ADD x, 04
	COMPARE x, 02
	JUMP NZ, y2midline

	LOAD acc, 01
	OUTPUT acc, out_sel_y	; Multiplexer auf Kanal 2 setzen
	FETCH acc, mem_y2scale	; Hardware-Multiplier über Multiplexer
	OUTPUT acc, out_fac
	LOAD x, 00
	CALL setReadAddr
	INPUT y2, in_scaled_y
	CALL y2offset
	LOAD mode, gcmd_move	; Startpunkt links
	CALL plotxy
	LOAD mode, gcmd_line	
y2refreshloop:
	ADD x, 01
	CALL setReadAddr
	INPUT y2, in_scaled_y
	CALL y2offset
	CALL plotxy
	COMPARE x, FF	
	JUMP NZ, y2refreshloop
	RETURN

	
	
;=========================================================================
;Grafik- und Text-Subroutinen
;=========================================================================

plotxy:
;plot at point x,y with mode (MOVE, POINT, LINE etc).
	INPUT s0, in_status 	; letzter Befehl fertig?
	TEST s0, 01
	JUMP Z, plotxy
	OUTPUT x, gcmd_xdata
	OUTPUT y, gcmd_ydata
	LOAD s0, 00
	OUTPUT s0, (mode)	; Befehl triggern 
	RETURN


;=========================================================================
;Steuerungs-Subroutinen
;=========================================================================

; STATUS Bit 0 GDONE, Bit 1 FRAMEDONE, Bit 2 trig_done, Bit 3 trig_ok

; Ende der Frame-Anzeige abwarten (Flicker!)
wait_framedone:
	INPUT s0, in_status ; FRAMEDONE false abwarten
	TEST s0, 02
	JUMP NZ, wait_framedone
frame_done2:
	INPUT s0, in_status ; FRAMEDONE true abwarten
	TEST s0, 02
	JUMP Z, frame_done2
	RETURN
	
sdelay: 	
	LOAD s0, FF
sdelay_loop: 	
	SUB s0, 01
	JUMP NZ, sdelay_loop
	RETURN

wait_key_release:
	INPUT s0, in_status ; Key losgelassen abwarten
	TEST s0, 08
	JUMP NZ, wait_key_release
	RETURN

; Trigger-Modus (trig_mode): 
; 0: Nicht auf Trigger warten
; 1: analog, positive Flanke
; 2: analog, negative Flanke
; 3: exakter digitaler Wert adc_wert = trig_level
; 4: positive Bit-Flanke, Maske in trig_level
; 5: negative Bit-Flanke, Maske in trig_level
; +16 dez: Select Channel 2 (sonst 1)

; TRIG_CTRL Bit 0..2 trig_mode, Bit 3 Reset, Bit 4 select_Ch2, Bit 5 COM_WR, Bit 6 BUSREQ
disable_trigger:
	LOAD running, 00	
	FETCH s0, mem_trigmode	; trig_reset
	AND s0, 07	; 0 bis 2 übrig lassen
	JUMP reset_trigger1
	
reset_trigger:
	LOAD running, 40	; wird Bit 6 von trig_ctrl BUSREQ
	LOAD s0, 08	; trig_reset
	FETCH acc, mem_trigmode	; trig_reset
	AND acc, 17	; Bit 4  und 0 bis 2 übrig lassen
	OR s0, acc
	OR s0, running	; Bit 6 von trig_ctrl BUSREQ setzen
reset_trigger1:	
	OUTPUT s0, out_trigctrl
	AND s0, 17	; Bit 4 (trig_ch)  und 0 bis 2 übrig lassen
	OUTPUT s0, out_trigctrl
	RETURN
	
init:	CALL sdelay
	LOAD s0, 80
	STORE s0, mem_triglevel
	STORE s0, mem_y1base
	STORE s0, mem_y2base
	LOAD s0, 60
	STORE s0, mem_hystlevel
	LOAD s0, C0	; Screen-Höhe 192 Pixel dez.
	STORE s0, mem_y1scale
	STORE s0, mem_y2scale

	LOAD s0, 10
	OUTPUT s0, gcmd_xgrid
	OUTPUT s0, gcmd_ygrid
	LOAD s0, 36
	OUTPUT s0, gcmd_xstart
	LOAD s0, 24
	OUTPUT s0, gcmd_ystart
	LOAD s0, 80
	OUTPUT s0, gcmd_xsize
	LOAD s0, 60
	OUTPUT s0, gcmd_ysize
	LOAD s0, 00
	OUTPUT acc, gcmd_frameEna
	LOAD s0, 00	; Anzeige abschalten
	STORE s0, mem_display

gclear:		; Grafikfenster löschen: Rechteck mit Farbe 0 zeichnen
	LOAD x, 00
	LOAD y, 00
	LOAD mode, gcmd_move
	CALL plotxy
	
	LOAD s0, 00
	OUTPUT s0, gcmd_color

	LOAD x, ff
	LOAD y, bf
	LOAD mode, gcmd_fill
	CALL plotxy
gclear_wait:	
	INPUT s0, in_status 	; letzter Befehl fertig?
	TEST s0, 01
	JUMP Z, gclear_wait
	RETURN
	
IRQservice:	
; nach Tastendruck-IRQ BUSREQ sofort wieder freigeben, Running-Flag löschen
	LOAD running, 00	
	OUTPUT running, out_trigctrl

; eingehende Daten in Scratchpad Memory (erste 16 Bytes) ablegen
	INPUT itemp, in_com_sel
	INPUT isema, in_com_data
	AND itemp, 0F
	STORE isema, (itemp)

	FETCH itemp, mem_cmd	; Registerinhalt ausgeben
	FETCH isema, (itemp)
	OUTPUT isema, out_com
	LOAD isema, FF
	RETURNI ENABLE
	
	ADDRESS 3FF
	JUMP IRQservice