; --------------------------------------------------------------------------
;
; Basic routines and demo for the 68332 board with the QuickCam.
;
; This program is a complete version to be flashed into the
; ROM of the board, it will run on its own.
;
; This code will ONLY run on the new hardware (with extra PCB
; for the keys), trying to use it on the old hardware will
; cause the system to hang.
;
; Author:               Gerrit Heitsch (gerrit@laosinh.s.bawue.de)
;                                      (heitscgt@mondrian)
;
;
; Last changes:     15-Nov-96
; Version:               1.2
;
; ---------------------------------------------------------------------------



	cpu     68332

	include reg683xx        ; Registerdefinitionen laden


	org $000000

; Startadressen (z.B. fuer Stack und PC setzen)
ROMbase = $00000500
Excebase = $00000400
RAMbase = $00001800

	dc.l    $0003fffc               ; Stack Pointer (Anfang vom RAM)
	dc.l    ROMbase                 ; Startadresse PC 
	dc.l    Excebase                ; Bus Error
	dc.l    Excebase                ; Adress Error
	dc.l    Excebase                ; Illegal Instruction
	dc.l    Excebase                ; Zero Division
	dc.l    Excebase                ; CHK, CHK2 Instrution
	dc.l    Excebase                ; TRAPcc, TRAPV Instruction
	dc.l    Excebase                ; Privilege Violation
	dc.l    Excebase                ; Trace
	dc.l    Excebase                ; Line 1010 Emu
	dc.l    Excebase                ; Line 1111 Emu
	dc.l    Excebase                ; HW Breakpoint
	dc.l    Excebase                ; res
	dc.l    Excebase                ; Format Err and Uninit. Int
	dc.l    Excebase                ; dito
	dc.l [240] Excebase             ; Rest der Vectortabelle


	org Excebase
	rte             ; sofort zurueck, keine Ausnahmebehandlung


	org ROMbase



; Register vorbelegen
		; SIMCR - Module Configuration Register
;               move.w  #%0000000001001111, SIMCR

		; SYNCR - Clock Synthesizer Control Register
		 move.w #%0111111100010000, SYNCR       
			; 0                     base VCO  frequency
			;  1                    VCO divided by- two
			;   111111              Y[5:0]  ==> 16777kHz


		; SYPCR - System Protection Control Register
		move.b  #%00000000, SYPCR
		   ;      0             SW watchdog disabled    
		

		; PFPAR - Port F Pin Assignment Register
		move.b  #%00001010, PFPAR
			;     1 1       PF1 und PF3 als IRQ-Eingaenge

		; DDRF - Port F Data Direction Register
		move.b  #$00, DDRF              ; DDF[0:7] als Eingabepin
		
		




		; 
		move.w  #%0010101110111110, CSPAR0
		move.w  #%0000001010101111, CSPAR1



		; CSBARBT - Chip Select Base Adress Register Boot ROM
		move.w  #%0000000000000100, CSBARBT
		   ;                   100      128K Boot ROM ab $00000000
		   ;                                            -$0001ffff

		; CSBAR[0:10] - Chip Select Base Adress Registers
		move.w  #%0000000000000111, CSBAR0
		   ;                   111      1M lower RAM ab $100000
		move.w  #%0000000000000111, CSBAR1
		   ;                   111      1M upper RAM ab $100000

		move.w  #%1110000000000000, CSBAR2
		   ;                   000      2K LCD-Register ab $e00000

		move.w  #%1110000000001000, CSBAR4
		   ;                    2K 8Bit-Port Ausgabe ab $e00800
		move.w  #%1110000000010000, CSBAR5
		   ;                    2K 8Bit-Port Eingabe ab $e01000

		move.w  #%1110000000011000, CSBAR8
		   ;                    2K-Block Parallelport 16C552 ab $e01800
		move.w  #%1110000000100000, CSBAR9
		   ;                    2K-Block Seriellport 1 16C552 ab $e02000
		move.w  #%1110000000101000, CSBAR10
		   ;                    2K-Block Seriellport 2 16C552 ab $e02800
		
		

		
		

		; CSORBT - Chip Select Option Register Boot ROM
		move.w  #%0110100100110000, CSORBT
		   ;      async. 

		; CSOR[0:10] - Chip Select Option Register
		move.w  #%0101000000110000, CSOR0       ; RAM
		   ;      0                     asynchronous mode 
		   ;       10                   upper byte
		   ;         11                 chip select for read and write
		   ;           0                        adress strobe
		   ;            0000            0 wait state insertion
		   ;                11          S/U adress space
		move.w  #%0011000000110000, CSOR1       ; RAM
		   ;       01                   lower byte

		move.w  #%0111100001110000, CSOR2       ; LCD
		   ;                            LCD_Modul 1 wait

		move.w  #%0111000000110000, CSOR4       ; Port Ausgabe
		move.w  #%0110100000110000, CSOR5       ; Port Eingabe
		move.w  #%0111100010110000, CSOR8       ; 552 Parallel 3 Wait
		move.w  #%0111100010110000, CSOR9       ; 552 Seriell 1  "
		move.w  #%0111100010110000, CSOR10      ; 552 Seriell 2  "
		

		; TRAMMCR - TPURAM Module Configuration Register
		move.w  #%0000000000000000, TRAMMCR
		   ;            0               sv oder user Zugriff

		; TRAMBAR - TPURAM Base Address and Status Register
		move.w  #%1010000000000000, TRAMBAR
		   ;                            2K TPURAM ab $00a00000

		; TPUMCR - TPU Module Configuration Register
		move.w  #%1000000000000000, TPUMCR
		   ;      1                     TPU abschalten


; Schleife, die das ROM komplett ins RAM kopiert und dann das ROM
; nach $00C00000 ummapped.

		move.l #$000027Fe, d1   ; Laufvariable fuer $5000 Bytes
		move.l #$00000000, a0   ; 0 Ins Adressregister
copy_mem:       move.w (a0), (a0)+      ; Speicher kopieren
		dbra d1, copy_mem       ; d1 runterzaehlen.


; Die Reihenfolge der folgenden 2 Befehle ist wichtig, eine
; Aenderung fuehrt zur Nichtfunktion des Programmes!

		move.w  #%0011100000110000, CSOR1       ; RAM lesbar machen
		move.w  #%0101100000110000, CSOR0       ; RAM lesbar machen

		move.w  #%1100000000000100, CSBARBT     ; ROM nach $c0 mappen

		jmp     main            ; zum Hauptprogramm


adr_lcd         equ     $00e00000       ; Basisadresse LCD
adr_cam         equ     $00e01800       ;       "      Kameraport



		; Die Variablendefinitionen fuer die Bildfelder
		; sind ans Ende des Programmes verlegt worden

varl_fieldend:  dc.l    $0
varl_char_pos:  dc.l    $0
varl_temp:      dc.l    $0
varl_row:       dc.l    $0
varl_done:      dc.l    $0
varl_field:     dc.l    $0
varl_end:       dc.l    $0

varl_graphic	dc.l	$00001338	; Default fuer Grafikausgabe
					; Dieser Wert wird von
					; sub_graphic benutzt und kann
					; geaendert werden.

varl_graphic1	dc.l	$00001338	; Default fuer Grafikausgabe
					; Dieser Wert darf nicht
					; geaendert werden!

varb_bright     dc.b    $80
varb_offset     dc.b    $3C
varb_contrast	dc.b	$68
varb_bright_d1  dc.b    $0
varb_bright_d2  dc.b    $0
varb_bright_d3  dc.b    $0
varb_b_count    dc.b    $0      ; Laufvariable fuer Helligkeit.
varb_b_count1   dc.b    $0      ; Laufvariable fuer Helligkeit.

varb_algo1      dc.b    $0      ; Variable fuer Tastenauswertung.
				; 0 = Normalbild
				; 1 = Laplace
				; 2 = Sobel
				; 3 = Dither
				; 4 = Differenzbild

varb_algo2      dc.b    $1      ; Flag fuer Tastenauswertung.

varb_last_key   dc.b    $5      ; Flag fuer Textausgabe.

varw_text_start dc.w    $1710   ; Startadresse Textspeicher des LCD
varw_text_now   dc.w    $0      ; aktuelle Zeichenposition.

varb_text_row   dc.b    $0      ; Aktuelle Zeile
varb_text_col   dc.b    $0      ; Aktuelle Spalte

varb_hardware	dc.b	$0	; Zeigt Version der Hardware an,
				; $0 = Neue Hardware
				; $1 = Alte Hardware
				; Wird fuers Tastenremapping gebraucht.

varb_key_last   dc.b    $00     ; Variable fuer letzten Tastenstatus

varb_prog_load  dc.b    $00     ; Variable fuer 'Programm geladen'
                                ; $00 = Kein Programm geladen, alle
                                ; anderen Werte = Programm geladen.

hexchars:       dc.b "0123456789ABCDEF"

hexstring:      dc.b "  ",0     ; Platzhalter fuer Stringberechnung


	
text0:
		dc.b "Normal", 0

text1:
		dc.b "Laplac", 0

text2:
		dc.b "Sobel ", 0

text3:
		dc.b "Dither", 0

text4:
		dc.b "Differ", 0


usage_text:
		     ;1234567890123456
		dc.b "          Next  "
		dc.b "          Algo.:"
		dc.b "          Key 0 "
		dc.b "          Curr. "
		dc.b "          Algo.:",0

copy_text:      ; Ausgabe auf LCD beim Start


	;             1234567890123456   (Zeichenzaehler fuer Eingabe)

                dc.b " E Y E - B O T  "
                dc.b "                "
                dc.b "Uni Stuttgart 96"
                dc.b "Sautter, Henne  "
                dc.b "Heitsch, Braunl "
                dc.b "V1.2 15-Nov-96  "
                dc.b "                "
                dc.b "Adj. DL RUN Demo",0


bright_text:
                     ;1234567890123456
                dc.b "          Offs. "
                dc.b "           $    "
                dc.b "          Bright"
                dc.b "           $    "
                dc.b "          Cont. "
                dc.b "           $    "
                dc.b "                "
                dc.b "Back [+] [-] OBC",0


warning1_text:
                     ;1234567890123456
                dc.b " W A R N I N G !"
                dc.b "                "
                dc.b "  Starting the  "
                dc.b "Demo will erase "
                dc.b "   the loaded   "
                dc.b "    program!    "
                dc.b "                "
                dc.b "Back --  OK  -- ",0

warning2_text:

                     ;1234567890123456
                dc.b " W A R N I N G !"
                dc.b "                "
                dc.b "No program has  "
                dc.b "been loaded!    "
                dc.b "Trying to 'run' "
                dc.b "would crash the "
                dc.b "system!         "
                dc.b "Back --  --  -- ",0

varb_bright_flag:   dc.b        $00     ; Flag fuer Unterscheidung zwischen
                                        ; Einstellung Helligkeit/Offset/
					; Contrast

bright_1:	dc.b " "		; Zeichen fuer Markierung
bright_2:	dc.b ">"		; Der aktuellen Einstellung

proc_table:	dc.l [100]		; Pointertabelle


                ; Texte fuer die Einstellung von Helligkeit und
                ; Offset.
                ; Ausgabe der Werte auf den Positionen:
                ; (11,2) und (11,4) fuer Zahlen und (10,6)
                ; fuer Text


rawkey:         ; Fragt die Tasten ab
                ; und liefert das Ergebnis in D0
                ; in folgender Form zurueck:
                ; Bit 0 = 1  Taste ganz links (gelb) gedrueckt
                ; Bit 2 = 1  2. Taste von links (rot) gedrueckt
                ; Bit 4 = 1  3. Taste von links (blau) gedrueckt
                ; Bit 6 = 1  Taste ganz rechts (gruen) gedrueckt
                ; Alle anderen Bits von D0 sind immer 0

                move.b  PORTF0, d0      ; Port laden
                andi.b  #$55, d0        ; Unbenutzte Bits maskieren
                eori.b  #$55, d0        ; Wert invertieren da die
                                        ; Hardware 0 meldet wenn
                                        ; Taste gedrueckt
		move.b	varb_hardware, d1	; Hardwareversion testen
		beq.s	newhard			;
		ror.b #$02, d0			; Bits rotieren
		
newhard:	rts                     ;


bufkey:         ; Benutzt rawkey fuer Abfrage und vergleicht mit
                ; dem letzten Resultat. Wenn gleich oder aktueller
                ; Wert 0 fuer diese Taste wird 0 gemeldet. Wenn
                ; letzter Wert und und aktueller Wert 1 wird 1
                ; gemeldet.
                ; Verwendete Register:
                ; D0 : Rueckgabe von rawkey und Rueckgabe von bufkey
                ; D1 : Zwischenspeicher


                jsr     rawkey            ; Aktuelle Tastenwerte holen
                move.b  varb_key_last, d1 ; Letzten Wert holen
                move.b  d0, varb_key_last ; Aktuellen Wert speichern.
                eori.b  #$55, d1          ; Invertieren
                and.b   d1, d0            ; Mit AND verknuepfen, Bit fuer
                                          ; Taste kann nur 1 sein wenn
                                          ; Sie beim letzten mal NICHT
                                          ; gedrueckt war.
                rts                       ; Ende



sub_init_lcd:           ; initialisiert das LCD Modul */
			; Verwendete Register:
			; d0 : $00 fuer Loeschen LCD
			; d1 : Laufvariable fuer Loeschen LCD



		jsr     check           ; Displaystatus pruefen */

		move.b  #$80, adr_lcd+1 ; Display auf ROM und OR-Mode 
					; dem Display uebergeben */
		jsr     check
		
		move.b  #$00, adr_lcd
		jsr     check

		move.b  #$00, adr_lcd   ; Home-Adresse $0000 ergibt effektive 
					; Adresse $0010 */
		jsr     check

		move.b  #$42, adr_lcd+1 ; Graphic home position setzen */
		jsr     check

		move.b  #$10, adr_lcd   ; Dieser Wert muss u.U. noch 
					; angepasst werden! */
		jsr     check

		move.b  #$00, adr_lcd
		jsr     check

		move.b  #$43, adr_lcd+1 ; Number of graphics and text area */
		jsr     check

		move.b  #$00, adr_lcd
		jsr     check
	
		move.b  #$17, adr_lcd   ; Ergibt Adresse $1700, der nutzbare 
					; Bereich beginnt */       
		jsr     check

		move.b  #$40, adr_lcd+1 ; Text Home position */
		jsr     check

		move.b  #$10, adr_lcd   ; Muss auf $10 stehen, sonst werden 
					; Zeichen abgeschnitten */
		jsr     check

		move.b  #$00, adr_lcd   
		jsr     check

		move.b  #$41, adr_lcd+1 ; Number of text area */
		jsr     check

		move.b  #$03, adr_lcd
		jsr     check

		move.b  #$00, adr_lcd
		jsr     check

		move.b  #$22, adr_lcd+1 ; Offset Register setzen */
		
		jsr     clear_lcd  ; LCD loeschen.

		jsr     check
		move.b  #$9f, adr_lcd+1 ; Display aktivieren  (Alle Modi) */
		rts                     ; Ende der Initialisierung */

clear_lcd:      ; Diese Routine loescht einfach den ganzen Speicher                
		; des LCD, z.B. um den Bildschirm zu loeschen.
		; Verwendete Register:                
		; d0: Nullwert
		; d1: Laufvariable
		; d2: In Subroutine 'check' verwendet.
		
		jsr     check
		move.b  #$00, adr_lcd
		jsr     check
		move.b  #$00, adr_lcd
		jsr     check
		move.b  #$24, adr_lcd+1
		jsr     check
		move.b  #$b0, adr_lcd+1 ; Automode aktivieren, ab jetzt 
					; folgen Daten */       
		jsr     check
		move.l  #$2000-1, d1    ; Adressbereich des RAMs vom LCD */
		moveq   #$00, d0        ; Wert mit dem das RAM des LCD 
					; gefuellt wird */
   erase:       move.b  d0, adr_lcd     ; Schleife, zum LCD-RAM fuellen
		jsr     check2          ; Display bereit
		dbra    d1, erase

		move.b  #$b2, adr_lcd+1 ; Automode abschalten */
		rts                     ; Ende Loeschen.


reset_char_pos: ; Diese Routine setzt die aktuelle Zeichenposition
		; im LCD und in der Variablen 'varw_text_now' wieder
		; auf den Anfangswert.
		; Verwendete Register:
		; d0 : Nullwert
		; In Subroutine 'check' noch:
		; d2 : Fuer Test der Flags.


		move.w varw_text_start, varw_text_now
		move.b #$00, varb_text_row  ; Zeile = 0
		move.b #$00, varb_text_col  ; Spalte = 0
		move.w varw_text_start, d0      ; Startadresse fuer LCD holen
		jsr check
		move.b d0, adr_lcd              ; untere 8 Bit schreiben
		lsr #$08, d0                    ; um 8 Stellen schieben.
		jsr check
		move.b d0, adr_lcd              ; Obere 8 Bit schreiben
		jsr check
		move.b #$24, adr_lcd+1          ; Adresspointer setzen.
		rts



	; Die Routinen 'check' und 'check2' ueberpruefen das LCD
	; darauf ob Daten geschrieben werden duerfen
	; 'check' ist fuer den Normalmode zustaendig
	; 'check2' fuer den Automode


check:                                  ; Verwendete Register:
					; d2 : Statusregister LCD


		move.b  adr_lcd+1, d2   ; Statusregister lesen */
		andi.b  #$03, d2        ; Bit 0 und 1 maskieren */
		cmpi.b  #$03, d2
		bne.s   check           ; Wenn nicht BEIDE Bits gesetzt sind */
		rts


check2:         btst    #$03, adr_lcd+1
		beq     check2          ; wiederholen solange Bit 3 = 0 */
		rts


; Tabelle und Code fuer Zeichenwandlung */



LCD_trans:      ; dezimal und ASCII
		dc.b    0,   1,   2,   3,   4,   5,   6,   7
		dc.b    8,   9,  10,  11,  12,  13,  14,  15
		dc.b   16,  17,  18,  19,  20,  21,  22,  23
		dc.b   24,  25,  26,  27,  28,  29,  30,  31
		dc.b   32,  33,  34,  35,  36,  37,  38,  39
		dc.b   40,  41,  42,  43,  44,  45,  46,  47
		dc.b   "0",   "1",   "2",   "3",   "4",   "5",   "6",   "7"
		dc.b   "8",  "9",  58,  59,  60,  61,  62,  63
		dc.b   64,  "A",   "B",   "C",   "D",   "E",   "F",   "G"
		dc.b   "H",   "I",   "J",   "K",   "L",   "M",   "N",   "O"
		dc.b   "P",   "Q",   "R",   "S",   "T",   "U",   "V",   "W"
		dc.b   "X",   "Y",  "Z",  91,  92,  93,  94,  95
		dc.b   96,  97,  98,  99, 100, 101, 102, 103
		dc.b  104, 105, 106, 107, 108, 109, 110, 111
		dc.b  112, 113, 114, 114, 116, 117, 118, 119
		dc.b  120, 121, 122, 123, 124, 125, 126, 127


put_char:       ; Diese Routine gibt das in d0 uebergebene Zeichen
		; an die aktuelle Char-Position im Display aus.
		; Vor der Ausgabe wird der Zeichencode ueber die
		; Ersetzungstabelle korrigiert.
		; Verwendete Register:
		; d0 : auszugebendes Zeichen.
		; a2 : Adresse Zeichentabelle

		cmpi    #$20, d0        ; gleich ausgeben wenn kleiner */
		blt     putcharlcd      ; als 32
		cmpi    #$7f, d0        ; gleich ausgeben wenn grosser 
		bgt     putcharlcd      ; als 127 */
		subi    #$20, d0        ; 32 abziehen */
		
		lea     LCD_trans, a2   ; Adresse Uebersetzungstabelle laden */
		adda    d0, a2          ; Zeichencode dazuaddieren */
		move.b  (a2), d0        ; neuen Code laden */
putcharlcd:     jsr check
		move.b  d0, adr_lcd     ; RAM-Bereich des LCD */
		jsr check
		move.b #$c4, adr_lcd+1  ; Kommando fuer 'write' ohne
					; Inkrement des Adresspointers
		rts



set_char:       ; Diese Routine erwartet in d1 und d2 die Zeile bzw.
		; Spalte in der das Zeichen ausgegeben werden soll.
		; Diese Daten werden dann in die Speicheradresse des
		; LCD verwandelt und ins LCD uebergeben.
		; Verwendete Register:
		; d0 : Zwischenspeicher der am Ende die Adresse enthaelt
		; d1 : Zeile
		; d2 : Spalte

		move.w varw_text_start, d0      ; Basisadresse laden.
		move.b d2, varb_text_row
		move.b d1, varb_text_col  
		lsl.b #$04, d1          ; Zeile mit 16 multiplizieren
		add.b d1, d0            ; Zeile addieren.
		add.b d2, d0            ; Spalte addieren.

		move.w d0, varw_text_now ; In Variable speichern.

		jsr check
		move.b d0, adr_lcd              ; untere 8 Bit schreiben
		lsr #$08, d0                    ; um 8 Stellen schieben.
		jsr check
		move.b d0, adr_lcd              ; Obere 8 Bit schreiben
		jsr check
		move.b #$24, adr_lcd+1          ; Adresspointer setzen.
		rts
		


adjust_char:    ; Zaehlt die Zeichenposition um 1 hoch wobei die
		; fehlerhaften Positionen (die 17. jeder Zeile)
		; uebersprungen werden. Dies passiert in den
		; Variablen und im LCD.
		; Verwendete Register:
		; d0 : Aktuelle Adresse im LCD
		; d2 : Fuer Adresscheck

		move.w varw_text_now, d0        ; Adresse holen
		addq #$01, d0                   ; Um 1 hochzaehlen
		move.w varw_text_start, d2      ; Basisadresse holen

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq.s pos_not_ok

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq.s pos_not_ok

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq.s pos_not_ok

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq.s pos_not_ok

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq.s pos_not_ok

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq.s pos_not_ok

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq.s pos_not_ok

		addi.w #$10, d2                 ; 16 hinzuaddieren
		cmp.w d2, d0                    ; Mit akt. Adresse vergleichen
		beq reset_char_pos      ; Wir sind am Ende des Textbereiches
					; des LCD angekommen, also zurueck
					; an Anfang.

		addi #$01, varb_text_col        ; Spalte hochzaehlen
		move d0, varw_text_now          ; aktuelle Adresse speichern
		move.b d0, adr_lcd              ; untere 8 Bit schreiben
		lsr #$08, d0                    ; um 8 Stellen schieben.
		jsr check
		move.b d0, adr_lcd              ; Obere 8 Bit schreiben
		jsr check
		move.b #$24, adr_lcd+1          ; Adresspointer setzen.
		bra.s ok_fertig

pos_not_ok:
		move.b #$00, varb_text_col      ; Spalte auf 0 setzen
		addi.b #$01, varb_text_row      ; Zeile hochzaehlen
		move d0, varw_text_now          ; aktuelle Adresse speichern
		move.b d0, adr_lcd              ; untere 8 Bit schreiben
		lsr #$08, d0                    ; um 8 Stellen schieben.
		jsr check
		move.b d0, adr_lcd              ; Obere 8 Bit schreiben
		jsr check
		move.b #$24, adr_lcd+1          ; Adresspointer setzen.

ok_fertig:      rts


put_string:     ; Diese Routine gibt einen Textstring auf das LCD
		; ab der aktuellen Position aus. Es wird solange
		; ausgegeben, bis ein Nullbyte erkannt wird.
		; Verwendete Register:
		; a0 : Anfangsadresse des Strings.
		; d0 : auszugebendes Zeichen


		move.b (a0)+, d0        ; Erstes Zeichen des Strings holen
	;       cmpi.b #$00, d0         ; Nullbyte ist Endezeichen
		beq stringende
		jsr put_char            ; Zeichen ausgeben
		jsr adjust_char         ; Aktuelle Position hochzaehlen
		bra.s put_string        ; naechstes Zeichen holen

stringende:     rts


hex2lcd:        ; Konvertiert das in D0 uebergebene Byte in eine
                ; Hex-Zahl und gibt diese an der aktuellen Position
                ; auf dem LCD aus.
                ; Verwendete Register:
                ; D0: Uebergebenes Byte
                ; D1: Zwischenspeicher
                ; A0: Adresse von Tabelle
                ; A1: Adresse von temporaerem String
                ; A2: Adresse von Tabelle

                andi.l #$000000FF, d0   ; Sicherstellen, dass obere Bits 0 sind
                move.l d0, d1           ; Zeichen kopieren
                andi.b #$0f, d0         ; Obere 4 Bits ausblenden
                andi.b #$f0, d1         ; untere 4 Bits ausblenden
                lsr.b #$04, d1          ; Nach unten schieben
                lea hexchars, a0        ; Adresse der Tabelle nach A0
                lea hexstring, a1       ; Adresse von String nach A1
                move.l a0, a2           ; Adresse kopieren
                adda.l d1, a2           ; Index auf Tabelle bilden
                move.b (a2), (a1)+      ; Zeichen holen und in String
                                        ; schreiben, Adresse hochzaehlen
                adda.l d0, a0           ; Index bilden
                move.b (a0), (a1)       ; Zeichen holen und in String
                                        ; schreiben
                lea hexstring, a0       ; Adresse von String
                jsr put_string          ; String auf LCD ausgeben
                rts                     ; Ende.



sub_graphic:            ; Bildfeld als Grafik auf LCD ausgeben
			; Verwendete Register:
			; a0 : Anfangsadresse vom Bild
			; d0 : Aktuelles Pixel
			; d1 : 1 Byte = 8 Pixel fuer LCD
			; d3 : Laufvariable fuer Bytes / Zeile
			; d4 : Laufvariable fuer Zeilen
			; d7 : Endadresse Bildfeld.

		
		addq.l  #$2, a0         ; Auf Arrayanfang */
		adda.l  #$53, a0        ; Oberen Rand ueberspringen.
		move.l  a0, d7          ; Adresse sichern */
		move.l	varl_graphic, d1 ; Bildgroesse laden
		add.l   d1, d7		; 82*62 Pixel Bildgroesse =
					;   Endadresse vom Bildfeld
		jsr     check
		move.b  #$10, adr_lcd
		jsr     check
		move.b  #$00, adr_lcd
		jsr     check
		move.b  #$24, adr_lcd+1 ; Adresszeiger fuer Grafik
					;   auf $0010
		
		jsr     check
		move.b  #$b0, adr_lcd+1 ; Automode aktivieren, ab jetzt 
					;   folgen Daten */
   loop4:       moveq   #$0a-1, d3      ; 10 Bytes pro Zeile
   loop5:       moveq   #$08-1, d4      ;  8 Pixel pro Zeichen */
					; ==> 80 Pixel
   loop2:       move.b  (a0)+, d0       ; Pixel holen
		andi.b  #$0f, d0        ; nur niederwertiges Nibble */
		cmpi.b  #$08, d0        ; Threshold  fuer Darstellung */
		blt     out             ; Wenn kleiner => Pixel setzen */
		andi    #%01111, ccr    ; Extent-Flag loeschen
		roxl.b  #$01, d1        ; in d1 Byte erstellen
		bra     pixel_reset
   out:         ori     #%10000, ccr    ; Extent-Flag setzen
		roxl.b  #$01, d1        ; in d1 Byte sammeln
   pixel_reset:	cmpa.l  d7, a0          ; Endadresse vom Feld erreicht ?
		bge     fertig          ; groesser-gleich
		
		dbra    d4, loop2       ; alle 8 Pixel, d4 ist Pixelzaehler
		
		jsr     check2  
		move.b  d1, adr_lcd     ; Byte mit 8 Pixeln ausgeben
		moveq   #$00, d1        ; d1 loeschen
		
		dbra    d3, loop5       ; alle 10 Bytes pro Zeile
		
		; LCD erwartet 128 Pixel pro Zeile, bekommt aber nur
		;   80 vom Bild. Rest von 48 Pixel (=6 Bytes) 
		;   0 (=weiss) auffuellen.
		moveq   #$05, d3        ; Bytezaehler
   loop3:       jsr     check2
		move.b  #$00, adr_lcd           
		dbra    d3, loop3
		addq    #$2, a0         ; Korrektur wegen Rand im Array */
					;   (Pro Randseite 1 Pixel) */
		jmp     loop4           ; Naechste Zeile */   

   fertig:      jsr     check2
		move.b  #$b2, adr_lcd+1 ; Automode abschalten */
		rts   




init_ports:     ; Parallelport des 16C552 initialisieren */

		move.b  #$00, adr_cam   ; Portregister loeschen
		move.b  #$00, adr_cam+2 ; Control Register loeschen
		; SLCTIN Leitung loschen, da im Chip dieses Signal 
		;   invertiert wird             
		ori.b   #%00001000, adr_cam+2   


		move.l	#$00002000, d0  ; Extra lange Schleife
init_loop:	nop			; Damit die Kamera den
		dbra d0, init_loop	; Reset auch erkennt.
	

		ori.b   #%00000100, adr_cam+2   ; Reset beenden

		rts



		
	  



send_byte:      ; Byte an Kamera senden
		; d0 : zu sendendes Byte
		;    Entgegen der Doku scheint die Kamera zuerst Bit 4-7 
		;    und dann Bit 0-3 zu echo'en */
		; Benutzte Register: D0, D2, D3

		move.b  d0, adr_cam
		nop                     ; warten, bis Daten stabil
		nop
		nop
		nop
		nop
		
		; SLCTN-Leitung auf 1 setzen (dazu SLCTN-Bit auf 0)
		andi.b  #%11110111, adr_cam+2   

		; warten, bis Kamera handshake (ERROR-Leitung) auf 1 setzt
   status1:     btst    #$03, adr_cam+1 ; Statusreg. ERROR-Bit testen
		beq.s   status1

		
		; Echo von der Kamera holen und auf Uebereinstimmung
		;   pruefen. Bei einem Byte also 2 Nibbles.
		
		move.b  adr_cam+1, d2
		andi.b  #$f0, d2                ; Nibble kommt auf D7-D4
		ori.b   #%00001000, adr_cam+2   ; SLCTN-Leitung auf 0 setzen
		
   status2:     btst    #$03, adr_cam+1 ; Statusreg. ERROR-Bit testen
		bne.s   status2

		move.b  adr_cam+1, d3
		andi.b  #$f0, d3                ; Nibble kommt auf D7-D4
		ori.b   #%00001000, adr_cam+2   ; SLCTN-Leitung auf 0 setzen
		lsr.l   #$4, d3                 ; 2. Nibble auf D3-D0 schieben
		or.b    d2, d3                  ; 1. Nibble dazuschreiben
		
		; jetzt kann geprueft werden, ob original-Byte (d0) mit
		;    geechotem Byte uebereinstimmt.
		cmp.b   d0, d3
		bne     send_byte       ; nochmal, da falsches Echo

		rts






init_camera:

		MOVE.B  #$19, d0       ; Kommando fuer 'Contrast' 25 */
		JSR send_byte   ; And die Kamera schicken */
		MOVE.B  varb_contrast, d0        ;  Der Wert */
		JSR send_byte

		MOVE.B  #$1F, d0     ; Kommando fuer 'SetOffset' 31 */
		JSR send_byte
		MOVE.B varb_offset, d0 ; Errechnete Helligkeit */
		JSR send_byte

		move.b  #$0b, d0        ; Kommando fuer 'Exposure' 11 */
		jsr     send_byte       ; An die Kamera schicken */
		MOVE.B  varb_bright, d0      ; Der Wert */
		JSR send_byte

		MOVE.B  #$0D, d0      ; Kommando fuer 'SetTop' 13 */
		JSR send_byte   ; And die Kamera schicken */
		MOVE.B  #$01, d0       ; Der Wert */
		JSR send_byte

		MOVE.B  #$0F, d0      ; Kommando fuer 'SetLeft' 15 */
		JSR send_byte   ; And die Kamera schicken */
		MOVE.B  #$04, d0        ; Der Wert */
		JSR send_byte

		MOVE.B  #$11, d0  ; Kommando fuer 'Lines To Transfer' 17 */
		JSR send_byte   ; And die Kamera schicken */
		MOVE.B  #$3C, d0        ; Der Wert, 60 */
		JSR send_byte

		MOVE.B  #$13, d0    ; Kommando fuer 'Transfers Per Line' 19 */
		JSR send_byte   ; And die Kamera schicken */
		MOVE.B  #$28, d0        ; Der Wert, 80/2 */
		JSR send_byte


		rts     ; Kamera sollte initialisiert sein */


bright_adjust:  ; Mit dieser Routine stellt man die Helligkeit ein und
                ; zwar fuer Belichtung und Offset getrennt. Obere und
                ; untere Grenzen sind nicht vorgesehen. Die Darstellung erfolgt
                ; auf dem LCD bei laufendem Kamerabild im Normalmode, also
                ; ohne jegliche Bildverarbeitung.

                ; Verwendete Register: Alle


                jsr     reset_char_pos  ; Cursor auf 0 setzen
                lea     bright_text, a0 ; Adresse Textfeld laden
                jsr     put_string      ; Aufs LC ausgeben
bright_loop:    lea     var_bild, a0    ; Adresse Bildfeld laden
                jsr     get_frame       ; Bild holen
                lea     var_bild, a0    ; Adresse Bildfeld laden

                jsr     s_graphic	; Bild ausgeben (gekuerzt)
                jsr     bufkey          ; Tasten abfragen
                move.b  d0, d1
                andi.b  #$01, d1        ; Nur bit 0 unversehrt lassen
                bne     bright_ende     ; Taste 0? Ja -> Ende
                move.b  d0, d1
                andi.b  #$04, d1        ; Bit 2 (+) pruefen
                beq     bright_weiter1  ; Also nicht..
                move.b  varb_bright_flag, d2 ; Flag testen
                beq     b_offset1       ; Je nachdem was sich aendern soll
		cmpi.b	#$02, d2	; Check fuer Contrastaenderung
		bne.s	b_bright1
		addq.b	#$01, varb_contrast ; Contrast hochzaehlen
		bra.s	bright_output	    ; Zur Ausgabe
b_bright1:      cmpi.b  #$A0, varb_bright   ; Test auf Maximum
		beq	bright_output       ; Wenn ja -> skip
		addq.b  #$01, varb_bright  ; Brightness hochzaehlen
                bra.s   bright_output      ; Zur Ausgabe
b_offset1:      addq.b  #$01, varb_offset  ; Offset hochzaehlen
                bra.s   bright_output      ; Zur Ausgabe
bright_weiter1: move.b  d0, d1          ; Tastaturwert holen
                andi.b  #$10, d1        ; Auf Bit 4 (-) testen
                beq     bright_weiter2  ; Also nicht..
                move.b  varb_bright_flag, d2 ; Flag testen
                beq     b_offset2       ; Je nachdem was sich aendern soll
		cmpi.b	#$02, d2	; Contrastaenderung?
		bne.s	b_bright2	; Nein, nur Brightness
		subq.b	#$01, varb_contrast  ; Contrast runterzaehlen
		bra.s	bright_output	     ; Zur Ausgabe
b_bright2:	cmpi.b  #$00, varb_bright    ; Test auf Minimum
		beq.s	bright_output        ; Wenn ja -> skip
      		subq.b  #$01, varb_bright  ; Brightness runterzaehlen
                bra.s   bright_output      ; Zur Ausgabe
b_offset2:      subq.b  #$01, varb_offset  ; Offset runterzaehlen
                bra.s   bright_output      ; Zur Ausgabe
bright_weiter2: move.b  d0, d1
                andi.b  #$40, d1        ; Auf Bit 6 (B/O) testen
                beq     bright_output
                addq.b  #$01, varb_bright_flag	; Um 1 hochzaehlen
		cmpi.b  #$03, varb_bright_flag	; Groesse Testen
		blt.s	bright_output		; Noch OK?
		move.b	#$00, varb_bright_flag	; Auf 0 zuruecksetzen

bright_output:  moveq #$03, d1          ; Zeile laden
                moveq #$0C, d2          ; Spalte laden
                jsr set_char            ; Ans LCD weitergeben
                move.b varb_bright, d0  ; Wert laden
                jsr hex2lcd             ; Als Hex-Wert aufs LCD

                moveq #$01, d1          ; Zeile laden
                moveq #$0C, d2          ; Spalte laden
                jsr set_char            ; Ans LCD weitergeben
                move.b varb_offset, d0  ; Wert laden
                jsr hex2lcd             ; Als Hex-Wert aufs LCD

                moveq #$05, d1          ; Zeile laden
                moveq #$0C, d2          ; Spalte laden
                jsr set_char            ; Ans LCD weitergeben
		move.b varb_contrast, d0  ; Wert laden
		jsr hex2lcd		  ; Kontrastwert ins LCD schreiben
		
		moveq #$01, d1
		moveq #$0A, d2
		jsr set_char
		move.b varb_bright_flag, d2
		bne.s bright_skip1
		move.b bright_2, d0
		bra.s bright_skip12
		
bright_skip1:	move.b bright_1, d0
bright_skip12:	jsr put_char

		moveq #$03, d1
		moveq #$0A, d2
		jsr set_char
		move.b varb_bright_flag, d2
		cmpi.b #$01, d2
		bne.s bright_skip2
		move.b bright_2, d0
		bra.s bright_skip22
		
bright_skip2:	move.b bright_1, d0
bright_skip22:	jsr put_char

		moveq #$05, d1
		moveq #$0A, d2
		jsr set_char
		move.b varb_bright_flag, d2
		cmpi.b #$02, d2
		bne.s bright_skip3
		move.b bright_2, d0
		bra.s bright_skip32
		
bright_skip3:	move.b bright_1, d0
bright_skip32:	jsr put_char

                bra     bright_loop     ; Schleife.


bright_ende:	rts                     ; Ende der Routine..



get_frame:      ; Holt ein Bild von der Kamera und speichert es */
			  ; im Feld  */         `
		; Feldadresse wird in a0 uebergeben
		; Verwendete Register:
		; a0 : aktuelle Adresse Bildfeld
		; a1 : Adresse Bildfeld
		; d0 : Universalregister / Puffer
		; d2 : (Unnoetig, ASAP entfernen) 
		; d3 : Zaehler fuer Transfers / Zeile
		; d4 : Zeilenzaehler
		
		move.l  a0, a1          ; Feldanfang sichern
		addq.l  #$2, a0         ; Auf Arrayanfang */
	;       move.l  a0, d2          ; Adresse sichern */
		adda.l  #$53, a0        ; 1. Zeile ist noch Rahmen
					; $53 deshalb weil erstes
					; Pixel einer Zeile auch
					; noch Rahmen ist.
	;       add.l   #$1338-$52, d2  ; 82*62 Pixel Bildgroesse =
					;   Endadresse vom Bildfeld
		moveq	#$3B, d4	; Zaehler fuer 60 Zeilen


		jsr     init_camera       ; Kamera voreinstellen */
		

		move.b  #$07, d0        ; Kommando 'getframe' */
		JSR send_byte

		move.b  #$08, d0  ; Parameter fuer Nibble bus, 1:4, 4 bit, 
					; kein Test pattern */
		jsr     send_byte

	
		; mit jedem Pegel-Wechsel der handshake-Leitung
		;   liefert die Kamera ein Pixel (statt 80 nur 40
		;   Schleifendurchlaeufe)
	
   line:        moveq   #$27, d3        ; d3 ist Schleifenzaehler
		
   go_on:       ; SLCTN-Leitung auf 1 setzen (dazu SLCTN-Bit auf 0)
		andi.b  #%11110111, adr_cam+2   

		; warten, bis Kamera handshake (ERROR-Leitung) auf 1 setzt
   shake1:      btst    #$03, adr_cam+1 ; Statusreg. ERROR-Bit testen
		beq.s   shake1

		move.b  adr_cam+1, d0   ; Nibble abholen
		andi.b  #$f0, d0        ; nur Nibble verwenden
		lsr.b #$04, d0          ; Bits schieben da Pixel
					; in D4 bis D7 kommt
		move.b  d0, (a0)+       ; Nibble im Feld speichern

		ori.b   #%00001000, adr_cam+2   ; SLCTIN auf 0
   shake2:      btst    #$03, adr_cam+1 ; Statusreg. ERROR-Bit testen
		bne.s   shake2

		move.b  adr_cam+1, d0   ; Nibble abholen
		andi.b  #$F0, d0        ; nur Nibble verwenden
		lsr.b #$04, d0          ; Bits schieben da Pixel
					; in D4 bis D7 kommt
		move.b  d0, (a0)+       ; Nibble im Feld speichern

		dbra d3, go_on          ; Schleifenzaehler fuer Pixel

		move.b #$08, (a0)+      ; Feldrand schwarz setzen
		move.b #$08, (a0)+      ; Feldrand schwarz setzen und

	;       addq.l  #$02, a0        ; Rand links und rechts ueberspringen

		dbra d4, line           ; Test ob alle Zeilen geholt wurden      
		
		; Der Kamera am Ende einen mehr als 3 Mikrosekunden */
		     ; langen Puls von PC_ACK schicken, damit
		;   sie zurueck in Kommandomodus geschaltet wird
		
		; SLCTN-Leitung auf 1 setzen (dazu SLCTN-Bit auf 0)
		andi.b  #%11110111, adr_cam+2   
		nop             ; warten
		nop
		nop     
		nop
		nop
		nop
		nop             ; warten
		nop
		nop     
		nop
		nop
		nop
		nop             ; warten
		nop
		nop     
		nop
		nop
		nop

		ori.b   #%00001000, adr_cam+2   ; SLCTIN auf 0

		rts

convert_pic:    ; Einfacher Laplace-Filter fuer Kantenerkennung.

		; Verwendete Register:
		; a0 = aktuelles Pixel Feld 1
		; a1 = Adresse Feld 1
		; a2 = aktuelles Pixel Feld 2
		; a3 = Adresse Feld 2
		; d0 = Zu bearbeitendes Pixel
		; d1 = Geladenes Pixel fuer Subtraktion
		; d2 = Endadresse Feld 1




		move.l  a0, a1          ; Feldanfang 1 sichern
		move.l  a2, a3          ; Feldanfang 2 sichern
		addq.l  #$2, a0         ; Auf Arrayanfang */
		addq.l  #$2, a2         ; Auf Arrayanfang
		move.w  #$1337, d2      ; Arrayende berechnen

loopx:          move.b $53(a0), d0      ; Pixel in der Mitte laden
		lsl.b #$02, d0          ; Entspricht ' * 4 '

		move.b $52(a0), d1      ; Pixel links daneben
		sub.b d1, d0

		move.b $54(a0), d1      ; Pixel rechts daneben
		sub.b d1, d0
			
		move.b $01(a0), d1      ; Pixel darueber
		sub.b d1, d0

		move.b $A5(a0), d1      ; Pixel darunter
		sub.b d1, d0

		bpl.s skip_norm0


		neg.b d0                ; Zweierkomplement bilden
					; (Vorzeichen umdrehen)
skip_norm0      cmpi.b #$10, d0
		blt.s is_smaller0       ; Wertebereich testen
		moveq #$0F, d0          ; Obere Grenze laden wenn groesser
is_smaller0:    eori.b #$0f, d0         ; Bild invertieren
		move.b d0, $53(a2)      ; Ins Ergebnisfeld speichern
		addq.l #$01, a2         ; und dessen Adresse hochzaehlen
		addq.l #$01, a0         ; Adresse des Quellfeldes
					; hochzaehlen
		dbra d2, loopx          ; Ende des Feldes erreicht?
		move.l a1, a0           ; Adressen zuruecksichern
		move.l a3, a2           ;
		rts                     ; Ende der Routine


sobel:          ; Kantenerkennung nach Sobel.

		; Verwendete Register:
		; a0 = aktuelles Pixel Feld 1
		; a1 = Adresse Feld 1
		; a2 = aktuelles Pixel Feld 2
		; a3 = Adresse Feld 2
		; d0 = Zu bearbeitendes Pixel
		; d1 = Geladenes Pixel fuer Subtraktion
		; d2 = Anzahl Pixel
		; d3 = temporaere Daten




		move.l  a0, a1          ; Feldanfang 1 sichern
		move.l  a2, a3          ; Feldanfang 2 sichern
		addq.l  #$2, a0         ; Auf Arrayanfang
		addq.l  #$2, a2         ; Auf Arrayanfang 
		move.w #$1337, d2       ; Anzahl Pixel im Array */

loop_sobel:     move.b $54(a0), d0      ; Pixel holen
		lsl.b #$01, d0          ; Wert verdoppeln
		add.b $02(a0), d0       ; Wert hinzuaddieren
		add.b $A6(a0), d0       ; Wert hinzuaddieren
		move.b d0, d1           ; Wert sichern

		move.b $52(a0), d0      ; Pixel holen
		lsl.b #$01, d0          ; Wert verdoppeln
		add.b (a0), d0          ; Wert hinzuaddieren
		add.b $A4(a0), d0       ; Wert hinzuaddieren

		sub.b d0, d1            ; 1. Endwert ausrechnen
		move.b d1, d3           ; In Sicherheit bringen.
		bpl.s skip_norm1        ; Noetig fuer Absolutwert
		neg.b d3

skip_norm1:     move.b $01(a0), d0      ; Pixel holen
		lsl.b #$01, d0          ; Wert verdoppeln
		add.b (a0), d0          ; Wert hinzuaddieren
		add.b $02(a0), d0       ; Wert hinzuaddieren
		move.b d0, d1           ; Wert sichern

		move.b $A5(a0), d0      ; Pixel holen
		lsl.b #$01, d0          ; Wert verdoppeln
		add.b $A4(a0), d0       ; Wert hinzuaddieren
		add.b $A6(a0), d0       ; Wert hinzuaddieren

		sub.b d0, d1            ; 2. Endwert ausrechnen
		bpl.s skip_norm2        ; Noetig fuer Absolutwert
		neg.b d1

skip_norm2:     add.b d3, d1            ; Zusammenaddieren.
		cmp.b #$10, d1          ; Wertebereich pruefen
		blt.s is_smaller1       ; Wenn kleiner nix tun
		moveq #$0F, d1          ; Wertebereich laden
is_smaller1:    eori.b #$0F, d1         ; Bild invertieren

		move.b d1, $53(a2)      ; Pixel speichern
		addq.l #$01, a0         ; Adresse Quellfeld hochzaehlen
		addq.l #$01, a2         ; Adresse Zielfeld hochzaehlen.

		dbra d2, loop_sobel     ; Schleife runterzaehlen.

		move.l a1, a0           ; Adressen zuruecksichern
		move.l a3, a2           ;
		rts                     ; Ende der Routine


dither:         ; Diese Routine fuehrt ein einfaches ordered Dithering
		; mit 2 x 2 Muster auf das Bild auf. Dadurch reduziert
		; sich natuerlich die Aufloesung von 80 x 60 auf jeweils
		; die Haelfte, also 40 x 30.
		; Verwendete Register:
		; a0 : Pointer auf aktuelles Pixel im Originalbild
		; a2 : Pointer auf aktuelles Pixel im Zielbild
		; d0 : Zu bearbeitende Daten
		; d1 : Hilfsvariable (enthaelt 0)
		; d2 : Hilfsvariable (enthaelt 15 = $0F)
		; d3 : Zaehler um Ende zu finden.
		; d5 : Zaehler fuer Bytes pro Zeile.

		add.l   #$55, a0        ; Auf 1. Pixel ($53 + $2)
		add.l   #$55, a2        ; Auf 1. Pixel ($53 + $2)
		moveq #$00, d3          ; Laufvariable fuer Arrayende
		moveq #$00, d1          ; Konstante 0 laden
		moveq #$0F, d2          ; Konstante 15 laden

loop_d1:        moveq #$27, d5          ; Zaehler fuer Bytes pro Zeile. 

loop_d2:        move.b (a0), d0         ; Byte holen
		cmpi.b #$03, d0         ; Vergleich ob groesser 3
		bgt.s greater_3         ; 
		move.b d1, (a2)         ; Dithern indem die passenden
		move.b d1, $01(a2)      ; Werte ins Zielfeld
		move.b d1, $52(a2)      ; geschrieben werden
		move.b d1, $53(a2)      ;
		jmp adjust_adr          ; 

greater_3:
		cmpi.b #$06, d0         ; Vergleich ob groesser 6
		bgt.s greater_6         ; 
		move.b d1, (a2)         ; Dithern indem die passenden
		move.b d1, $01(a2)      ; Werte ins Zielfeld
		move.b d2, $52(a2)      ; geschrieben werden
		move.b d1, $53(a2)      ;
		jmp adjust_adr          ; 

greater_6:
		cmpi.b #$09, d0         ; Vergleich ob groesser 9
		bgt.s greater_9         ; 
		move.b d1, (a2)         ; Dithern indem die passenden
		move.b d2, $01(a2)      ; Werte ins Zielfeld
		move.b d2, $52(a2)      ; geschrieben werden
		move.b d1, $53(a2)      ;
		jmp adjust_adr          ; 

greater_9:
		cmpi.b #$0C, d0         ; Vergleich ob groesser 12
		bgt.s greater_12        ; 
		move.b d1, (a2)         ; Dithern indem die passenden
		move.b d2, $01(a2)      ; Werte ins Zielfeld
		move.b d2, $52(a2)      ; geschrieben werden
		move.b d2, $53(a2)      ;
		jmp adjust_adr          ; 

greater_12:
		move.b d2, (a2)         ; Dithern indem die passenden
		move.b d2, $01(a2)      ; Werte ins Zielfeld
		move.b d2, $52(a2)      ; geschrieben werden
		move.b d2, $53(a2)      ;

adjust_adr:     addq.l #$02, a0         ; Adressen hochzaehlen
		addq.l #$02, a2         ; Adressen hochzaehlen
		addq.w #$02, d3         ; Zaehler hochzaehlen
		dbra d5, loop_d2        ; Zeile beenden.
		add.l  #$54, a0         ; 1 Zeile ueberspringen
		add.l  #$54, a2         ; 1 Zeile ueberspringen
		add.w  #$54, d3         ; Zaehler hochzaehlen.
		cmpi.w #$1337, d3       ; Mit Endwert vergleichen
		blt    loop_d1          ; Weitermachen.

		rts                     ; Ende der Routine.


differ:         ; Diese Routine fuehrt eine Differenzbildund
		; ueber das aktuelle und das vorherige Bild
		; aus.
		; Verwendete Register:
		; a0 : Pointer auf aktuelles Bildfeld
		; a1 : Pointer auf letztes Bildfeld
		; a2 : Pointer auf Hilfsfeld
		; a3 : Sicherheitskopie von a0 vor Routine
		; a4 : Sicherheitskopie von a1 vor Routine
		; d0 : Pixel aktuelles Bild
		; d1 : Pixel altes Bild und Resultat
		; d2 : Laufvariable

		add.l   #$55, a0        ; Auf 1. Pixel
		add.l   #$55, a1        ; Auf 1. Pixel
		add.l   #$55, a2        ; Auf 1. Pixel 
		move.l  a0, a3          ; Feldanfang 1 sichern
		move.l  a1, a4          ; Feldanfang 2 sichern
		move.w  #$1337, d2      ; Anzahl relevante Pixel im Array

do_differ:      move.b (a0)+, d0        ; Pixel akt. Bild holen
		move.b (a1)+, d1        ; Pixel letztes Bild holen
		subb.b d0, d1           ; Subtrahieren
		bpl.s is_ok             ; Wenn OK nix machen
		neg.b d1                ; Vorzeichen umdrehen
is_ok:          andi.b #$0f, d1         ; Wertebereich korrigieren
		eori.b #$0f, d1         ; Pixel invertieren
		move.b d1, (a2)+        ; Speichern
		dbra d2, do_differ      ; Solange bis fertig

		move.w  #$1337, d2      ; Anzahl relevante Pixel im Array
copy_pic:       move.b (a3)+, (a4)+     ; Kopierschleife, kopiert
		dbra d2, copy_pic       ; aktuelles Bild nach altes Bild
					; fuer naechstes Mal.
		rts                     ; Ende



check_key:      ; Diese Routine testet ob die aktuell gueltige Taste
		; mit der zuletzt gedrueckten uebereinstimmt. Wenn
		; ja passiert nichts, sonst wird das der momentan
		; gueltigen Taste entsprechende Textfeld ins LCD
		; geschrieben.
		; Verwendete Register:
		; a0: Adresse des auszugebenden Strings.
		; d0: Letzte gedrueckte Taste.
		; d1, d2: Parameter fuer put_char

		move.b varb_last_key, d1                ; Tastenwert laden
		cmp.b varb_algo1, d1                    ; Tasten vergleichen
		beq das_wars_schon                      ; Wenn gleich: raus
		move.b varb_algo1, varb_last_key        ; Wenn ungleich
							; gleichmachen

		moveq #$00, d1          ; Den kurzen Text fuer
		moveq #$00, d2          ; Bedienung ausgeben
		jsr set_char            ; Zeile und Spalte setzen
		lea usage_text, a0      ; Adresse Textfeld
		jsr put_string          ; Text ausgeben

		move.b varb_algo1, d0   ; Momentan gueltige Taste holen
		bne.s weiter1           ; Wenn nicht null, weiter.
		moveq #$06, d1          ; Zeile laden
		moveq #$0A, d2          ; Spalte laden
		jsr set_char            ; Ans LCD weitergeben
		lea text0, a0           ; Adresse Textfeld laden
		jsr put_string          ; String ausgeben
		bra.s das_wars_schon    ; Ende

weiter1:        cmpi.b #$01, d0
		bne.s weiter2
		moveq #$06, d1
		moveq #$0A, d2
		jsr set_char
		lea text1, a0
		jsr put_string          
		bra.s das_wars_schon

weiter2:        cmpi.b #$02, d0
		bne.s weiter3
		moveq #$06, d1
		moveq #$0A, d2
		jsr set_char
		lea text2, a0
		jsr put_string          
		bra.s das_wars_schon

weiter3:        cmpi.b #$03, d0
		bne.s weiter4
		moveq #$06, d1
		moveq #$0A, d2
		jsr set_char
		lea text3, a0
		jsr put_string          
		bra.s das_wars_schon

weiter4:        moveq #$06, d1
		moveq #$0A, d2
		jsr set_char
		lea text4, a0
		jsr put_string          

das_wars_schon:	rts







umschalt:
		; Verwendete Register:
		; d0 : Daten von Port F holen
		; d2 : Nur zum Testen.
		; 
		; Diese Routine hat ungefaehr die dieselbe
		; Funktion wie ein D-FlipFlop, Aenderungen
		; passieren nur, wenn die Taste (ganz links
		; auf der Platine) beim letzten Aufruf der
		; Routine nicht gedrueckt war und jetzt
		; gedrueckt ist.

		move.b  PORTF0, d0      ; Port F holen
		andi.b  #$10, d0        ; eine bestimme Taste pruefen
		bne.s ende1             ; Keine Taste gedrueckt
		move.b varb_algo2, d2   ; Taste ist gedrueckt, letzten
					; Zustand holen und auswerten
		bne.s ende              ; War Taste beim letzten Aufruf
					; gedrueckt passiert nichts

		move.b varb_algo1, d1   ; Tastenwert holen
		addq.b #01, d1          ; 1 dazuaddieren
		cmpi.b #$05, d1         ; Taste mit Maximalwert vergleichen
		bne.s skip_it           ; Wenn kleiner nichts tun
		moveq #$00, d1          ; Taste auf 0 setzen
skip_it:        move.b d1, varb_algo1   ; Abspeichern.

		
		move.b #$01, varb_algo2 ; Flag fuer 'Taste gedrueckt'
					; setzen.
		bra.s ende



ende1:          move.b #$00, varb_algo2 ; Flag fuer 'Taste gedrueckt'
					; zuruecksetzen, ab jetzt
					; sind wieder Aenderungen
					; moeglich.
ende:           rts


set_camera:	; Setzen der Kameraeinstellungen die der User
		; veraendern kann.
		; Verwendete Register:
		; D0 : Brightness (Werte oberhalb von $A0 werden ignoriert)
		; D1 : Offset
		; D2 : Kontrast

		cmpi.b	#$A1, d0
		bgt.s	set_c_skip
		move.b	d0, varb_bright
set_c_skip:	move.b	d1, varb_offset
		move.b	d2, varb_contrast
		rts

s_graphic:	; Ruft sub_graphic auf, nachdem die Anzahl auszugebender
		; Bytes korrigiert wurde. Damit kann man die Bildgroesse
		; so aendern, dass unter dem Bild noch Platz fuer die
		; 4 Tasten ist.
		; Verwendete Register:
		; A0 : Pointer aufs Bildfeld.

		move.l	#$0000114C, varl_graphic
		jsr	sub_graphic
		move.l	varl_graphic1, varl_graphic
		rts
		

makejumptable:	; Diese Routine produziert eine Tabelle in der Pointer
		; auf alle Prozeduraufrufe gespeichert sind.
		; Ein Zeiger auf diese Tabelle wird dann beim
		; Start des Programmes uebergeben. Es werden nur
		; Pointer generiert, die Prozeduren betreffen, die
		; fuer den User bestimmt sind.
		; Parameter: Keine

		lea	proc_table, a1
		move.l	a1, $00000410
		lea	rawkey, a0
		move.l	a0, (a1)+
		lea	bufkey, a0
		move.l	a0, (a1)+
		lea	sub_init_lcd, a0
		move.l	a0, (a1)+
		lea	clear_lcd, a0
		move.l	a0, (a1)+
		lea	reset_char_pos, a0
		move.l	a0, (a1)+
		lea	put_char, a0
		move.l	a0, (a1)+
		lea	set_char, a0
		move.l	a0, (a1)+
		lea	put_string, a0
		move.l	a0, (a1)+
		lea	hex2lcd, a0
		move.l	a0, (a1)+
		lea	sub_graphic, a0
		move.l	a0, (a1)+
		lea	init_ports, a0
		move.l	a0, (a1)+
		lea	bright_adjust, a0
		move.l	a0, (a1)+
		lea	get_frame, a0
		move.l	a0, (a1)+
		lea	convert_pic, a0
		move.l	a0, (a1)+
		lea	sobel, a0
		move.l	a0, (a1)+
		lea	dither, a0
		move.l	a0, (a1)+
		lea	differ, a0
		move.l	a0, (a1)+
		lea	set_camera, a0
		move.l	a0, (a1)+
		lea	s_graphic, a0
		move.l	a0, (a1)+
		lea	main, a0
		move.l	a0, (a1)+
		lea	download, a0
		move.l	a0, (a1)+
		lea	demo_start, a0
		move.l	a0, (a1)+
		lea	adjust_char, a0
		move.l	a0, (a1)+
		rts


main:           ; Hauptprogramm mit Menu usw.
		; Verwendete Register:
		; a0 : Adresse 1. Bildfeld
		; a2 : Adresse 2. Bildfeld
		; d1 : Bit 0 ist Flag fuer Entscheidung
		;      welches Bild dargestellt wird.

		jsr makejumptable ; Tabelle erzeugen.
		jsr bufkey	; Wegen Initroutine und Taste 0
		jsr init_ports  ; Ports initalisieren
		jsr sub_init_lcd ; LCD Modul initalisieren
		

start_sc:       ; Diese Routine gibt den Startscreen aus und
                ; verzweigt dann in die verschiedenen Unterroutinen,
                ; Helligkeitseinstellung, Softwaredownload und
                ; Demo. Alle Software sollte beim Beenden entweder
                ; einen kompletten Reset durchfuehren oder mit
                ; einem RTS wieder in diese Routine zurueckkehren.
                ; Vor dieser Routine laufen nur Initalisierungen
                ; fuer Ports und LCD.
                ; Verwendete Register: Alle

		jsr	clear_lcd	; LCD loeschen
                jsr     reset_char_pos  ; Cursor auf LCD zuruecksetzen.
                lea     copy_text, a0   ;
                jsr     put_string      ; Text ausgeben
start_loop:     jsr     bufkey          ; Tasten abfragen

                move.b  d0, d1          ; In Sicherheit kopieren
                andi.b  #$01, d1        ; Auf Taste 0 pruefen
                bne.s   start1          ; Adjustroutine rufen
                move.b  d0, d1          ; Auf Taste 1 pruefen
                andi.b  #$04, d1        ;
                bne.s   start2          ; Download rufen
                move.b  d0, d1
                andi.b  #$10, d1        ; Auf Taste 2 pruefen
                bne.s   start3          ; Programm starten.
                move.b  d0, d1          ;
                andi.b  #$40, d1        ; Auf Taste 3 pruefen
                bne.s   start4          ; Demo aufrufen
                bra.s   start_loop      ; Keine Taste? Warten...

start1:         jsr     bright_adjust   ; Helligkeit einstellen 
                bra     start_sc        ;

start2:         jsr     download        ; Download
                bra     start_sc        ;

start3:         move.b  varb_prog_load, d0      ; Testen ob Programm
                                                ; geladen wurde
                bne.s   start3_1                ; Programm starten
                jsr     reset_char_pos          ; 
                lea     warning2_text, a0       ; Adresse des Textes
                                                ; laden
                jsr     put_string              ; Ausgeben
start3_2:       jsr     bufkey                  ; Tasten abfragen
                andi.b  #$01, d0        ; Taste 0 ausmaskieren
                beq.s   start3_2
                bra     start_sc        ; 
start3_1:       jsr     clear_lcd       ; LCD loeschen
		lea	proc_table, a0	; Adresse Tabelle laden
                jsr     start_prog      ; Programm starten
                bra     start_sc        ; Nach Ende zurueck zum Start.

start4:         move.b  varb_prog_load, d0      ; Testen ob Programm
                                                ; geladen wurde
                beq.s   start4_1                ; Nein.. Demo starten
                jsr     reset_char_pos          ;
                lea     warning1_text, a0       ; Adresse des Textes
                jsr     put_string              ; Ausgeben.
start4_2:       jsr     bufkey                  ; Tasten abfragen
                move.b  d0, d1                  ; In Sicherheit kopieren
                andi.b  #$01, d0                ; Taste 0 pruefen
                bne     start_sc                ; Zurueck zum Hauptmenue
                andi.b  #$10, d1                ; Taste 4 pruefen
                bne.s   start4_1                ; Demo starten
                bra.s   start4_2                ; Weder noch - Schleife
start4_1:       jmp     demo_start              ; Demo starten

download:       move.b  #$ff, varb_prog_load    ; Flag fuer
                                                ; Programm geladen
                                        ; Hier S-Rekord-Download einbauen
                rts                     ; Zurueck.



demo_start:	jsr     clear_lcd	; LCD loeschen.
		move.b	#$05, varb_last_key ; Sicherstellen, dass Thomas
					    ; sich nicht beschwert.


forever:
	        lea     var_bild, a0
		jsr     get_frame       ; Bild holen


		jsr     umschalt        ; Taste 6 abfragen

		jsr     check_key       ; Taste checken, wenn neuer
					; Wert, Text aktualisieren.
		move.b varb_algo1, d0   ; Taste holen

		bne.s nicht_gleich0     ; Nicht 0? Weiter...

		lea     var_bild, a0    ; Normalbild anzeigen
		jsr     sub_graphic
		jmp     forever

nicht_gleich0:  cmpi.b #$01, d0
		bne.s nicht_gleich1
		lea     var_bild, a0
		lea     var_bild1, a2
		jsr     convert_pic     ; Laplace auf das Bildfeld
					; anwenden

		lea     var_bild1, a0   ; Bild nach Laplace anzeigen
		jsr     sub_graphic
		jmp     forever

nicht_gleich1:  cmpi.b #$02, d0
		bne.s nicht_gleich2
		lea     var_bild, a0
		lea     var_bild1, a2
		jsr     sobel           ; Sobel auf das Bildfeld
					; anwenden
		lea     var_bild1, a0   ; Bild nach Sobel anzeigen
		jsr     sub_graphic
		jmp     forever

nicht_gleich2:  cmpi.b #$03, d0
		bne.s nicht_gleich3
		lea     var_bild, a0
		lea     var_bild1, a2
		jsr     dither          ; Dithering auf das Bildfeld
					; anwenden
		lea     var_bild1, a0   ; Bild nach Dither anzeigen
		jsr     sub_graphic
		jmp     forever



nicht_gleich3:  ; Einfaches Dithering auf das Bild anwenden.
		
		lea     var_bild, a0    ; Adressen laden.
		lea     var_bild1, a1   ;
		lea     var_bild2, a2   ; 
		jsr     differ          ; Differenz bilden
		lea     var_bild2, a0   ; 
		jsr     sub_graphic     ; Bild anzeigen
		jmp     forever


		org $00005000
	

start_prog:	; Dies ist das Startlabel fuer ein geladenes
		; Programm. Es liegt so, dass bei einem
		; geladenen Programm die 4 Bildfelder a
		; 5.5 KB fuer Programmcode benutzt werden
		; Spart 20 KB und vor dem Aufruf der Demo
		; wird bei einem geladenen Programm eine
		; Warnung ausgegeben.
	
var_bild:       ds.b 5500               ; Feld fuer ein Bild
var_bild1:      ds.b 5500               ; Feld fuer konvertiertes Bild1
var_bild2:      ds.b 5500               ; Feld fuer konvertiertes Bild2
var_bild3:      ds.b 5500               ; Feld fuer konvertiertes Bild2


; Diese Variablen landen am Ende des Programmes, erleichtert das
; programmieren des Flash-ROMs ungemein.
