8-Bit-Breadboard-Computer auf Basis einer 6502-CPU - Assembler-Programmierung: Dezimal Hexadezimal Binär Konverter und Spiel

Bisherige Artikel dieser Serie - hier könnt ihr nochmal alle Grundlagen nachlesen, falls ihr jetzt erst einsteigt: Die Software für den Bin/Dez/Hex-Converter für meinen Breadboard-Computer ist fertig geworden.

Was soll die Software leisten?

Das Programm soll ein Menü anzeigen, aus dem ein Menüpunkt durch Druck auf die Tasten 1 bis 3 ausgewählt werden kann. Nicht gültige Tasten sollen nicht angenommen werden.

Beim hexadezimal zu dezimal Konverter wird eine zweistellige Hexadezimalzahl (gegebenenfalls mit führenden Nullen) eingegeben. Ungültige Tasten sind abzuweisen. Die Hex-Zahl wird intern zu Binär umgerechnet und auf der LED-Ausgabe angezeigt. Außerdem wird sie nach dezimal umgerechnet und die Dezimalzahl auf der 7-Segment-Anzeige angezeigt.

Beim dezimal zu hexadezimal Konverter wird eine dreistellige Dezimalzahl (gegebenenfalls mit führenden Nullen) eingegeben. Ungültige Tasten sind abzuweisen. Die Dezimal-Zahl wird intern zu Binär umgerechnet und auf der LED-Ausgabe angezeigt. Außerdem wird sie nach hexadezimal umgerechnet und die Hex-Zahl auf der 7-Segment-Anzeige angezeigt.

Im dritten Modus werden Pseudozufallszahlen der Reihe nach auf der LED-Ausgabe in binärer Darstellung angezeigt. Der Spieler soll diese im Kopf nach hexadezimal umrechnen (kleiner Tipp: jeweils 4 LEDs zu einem Nibble gruppieren) und dann zweistellig ggf. mit führender Null) eingeben. Intern wird die Binärzahl nach hexadezimal umgerechnet und mit der Eingabe verglichen. Ist die Eingabe richtig, erhält der Spielen eine Rückmeldung und einen Punkt. Der aktuelle Punktestand wird auf der 7-Segment-Anzeige angezeigt. Ist eine Eingabe falsch, erhält der Spieler die Meldung "Game over" und das Spiel endet.

"Abweisen" einer ungültigen Taste meint: Der Tastendruck wird ignoriert und nicht verwertet. Er wird auch nicht angezeigt. Nur gültige Tastendrucke werden duch Ausgabe des eingegebenen Tastenwertes bestätigt. Für die Eingabe einer Dezimalzahl (maximal 255) muss zum Beispiel folgendes sichergestellt werden:

Demonstration des Programmes

Ich will einmal mit dem Ergebnis, dem fertigen Programm anfangen und dies in einem Video zeigen. So ist am einfachsten zu erklären und zu sehen, was das Program leisten soll:



Source-Code

8-hex-dec-bin-spiel.asm (klicken, um diesen Abschnitt aufzuklappen)
; bin-dec-hex Umrechner bzw. kleines Spielchen ; 1. hex to dec/bin (errechnet 6502) ; 2. dec to hex/bin (errechnet 6502) ; 3. bin (LED) to hex (Spieleraufgabe) ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-11 CHIP W65C02S ; (default) ORG $8000 ; Programmstartadresse (von der CPU aus gesehen) startvektor: jmp reset ; !!! === Hinweise === !!!! ; - max 5.3V, sonst kippende Bits in der LED-Ausgabe (und woanders?) ; - max 2Khz, damit der Sniffer noch funktioniert (mitkommt) ; - immer noch ein ungelöstes Problem: Spannungsabfall zwischen den oberen und ; unteren Breadboards, besonders, wenn Verbraucher wie Sniffer angeschaltet sind ; --- Konstanten: Timing --- ; 200 nF Kondensator von 7 Hz bis 2 KHz ; Ein Takt sind 0.5 ms, ein NOP sind zwei Takte sind 1 ms NopsPerMs: equ 1 ; wieviele NOPs braucht es, um eine Millisek. voll zu machen? ; --- Makro-Definitionen --- INCLUDE macros.inc ; --- Speicherort-Definitionen --- INCLUDE io-defs.inc INCLUDE zeropage-defs.inc INCLUDE ram-defs.inc ; --- Standard-Definitionen für IO-Geräte --- INCLUDE seg-defs.inc INCLUDE lcd-defs.inc INCLUDE key-defs.inc ; --- allgemeine Unterprogramme und Makros --- INCLUDE seg.inc ; für 7-Segment-Anzeige INCLUDE lcd.inc ; für LCD INCLUDE key.inc ; für 4x4 Keypad INCLUDE io.inc ; io_init etc. INCLUDE convert.inc ; valToDez INCLUDE debug.inc ; Tools zum Debugging ; --- Hauptprogramm --- reset: jsr ioInit menu: LCD_PRINT msgMenu ; Makro-Aufruf, siehe macros.inc eingabeMenu: LCD_CURSOR_ON ; Cursor blinken lassen (Makro) tasteMenu: jsr getKey ; speichert Tasten-Bitmuster in keyIn jsr keyToVal ; liefert in Akku zurück ; richtige Taste gedrückt (1...3) ? (wird nicht extra angezeigt), Cursor lassen wir an cmp #1 beq startHexToDecBin cmp #2 beq jmpStartDecToHexBin cmp #3 beq jmpStartBinToHex ; startBinToHex ist zu weit weg für bra bra tasteMenu ; falsche Taste: nochmal eingeben jmpStartBinToHex: jmp startBinToHex jmpStartDecToHexBin jmp startDecToHexBin startHexToDecBin: ; erledigt der Computer -------------------------------------------- ; Hex-Wert eingeben, Dec Wert auf 7-Segment, Bin auf LED-Leiste LCD_CLEAR ; LCD löschen (Makro) LCD_PRINT msgEingabeHexToDecBin ; Makro-Aufruf, siehe macros.inc LCD_POS #26 ; LCD-Cursor positionieren (Makro) eingabeHexToDecBin: ; gültig 0...F ; 1. Nibble jsr getKey ; speichert Tasten-Bitmuster in keyIn ldx keyIn lda KEY_ASC,x LCD_CHAR_AKKU ; gibt das ASCII-Zeichen im Akku aufs LCD aus (Makro) jsr keyToVal ; liefert in Akku zurück sta val ; Highbyte speichern asl val ; 4x shift left asl val asl val asl val ; 2. Nibble jsr getKey ; speichert Tasten-Bitmuster in keyIn ldx keyIn lda KEY_ASC,x LCD_CHAR_AKKU ; gibt das ASCII-Zeichen im Akku aufs LCD aus (Makro) LCD_CURSOR_OFF ; Cursor blinken aus (Makro) jsr keyToVal ; liefert in Akku zurück ora val ; Low-Byte dazu (ORA = Or mit Akku) sta val ; Ergebnis zurück nach val schreiben ; in val steht jetzt der Wert in Binär lda val sta LED ; den schon mal auf die LEDs ausgeben jsr valToDez ; und dann in dezimal umrechnen und in dez1...dez3 speichern jsr dezToSeg ; und auf 7-Segment ausgeben wai jmp reset startDecToHexBin: ; erledigt der Computer -------------------------------------------- ; Dez-Wert eingeben, Hex Wert auf 7-Segment, Bin auf LED-Leiste LCD_CLEAR ; LCD löschen (Makro) LCD_PRINT msgEingabeDecToHexBin ; Makro-Aufruf, siehe macros.inc LCD_POS #25 ; LCD-Cursor positionieren (Makro) eingabeDecToHexBin: ; max 255 als Eingabe zulässig ; 1. Ziffer max 2 jsr getKey ; speichert Tasten-Bitmuster in keyIn ldx keyIn lda KEY_VAL, x ; Wert für Taste holen cmp #3 bge eingabeDecToHexBin ; Taste >= 3 (bge==bcs) ; Wert für Key-Muster holen ($0...$F bzw. 0 bis 15) sta dez1 tax lda nibble_ASC, x LCD_CHAR_AKKU ; gibt das ASCII-Zeichen im Akku aufs LCD aus (Makro) ; 2. Ziffer max 9 bzw. 5 (wenn 1. Ziffer 2) lda dez1 cmp #2 bne eingabeDecToHexBin2 lda #6 sta zptmp bra eingabeDecToHexBin3 eingabeDecToHexBin2: lda #$A sta zptmp eingabeDecToHexBin3: jsr getKey ; speichert Tasten-Bitmuster in keyIn ldx keyIn lda KEY_VAL, x ; Wert für Taste holen ldy zptmp cmp zptmp bge eingabeDecToHexBin3 ; taste >= 6 bzw. A sta dez2 tax lda nibble_ASC, x ; Wert für Key-Muster holen ($0...$F bzw. 0 bis 15) LCD_CHAR_AKKU ; gibt das ASCII-Zeichen im Akku aufs LCD aus (Makro) ; 3. Ziffer max 9 bzw. 5 (wenn 1. und 2. Ziffer 2 und 5) ; steht in zptpm noch 5 drin? dann müssen die ersten 2 Ziffern 25 sein lda zptmp cmp #6 beq eingabeDecToHexBin4 ; ersten zwei Ziffern = 25 lda #$A sta zptmp bra eingabeDecToHexBin5 eingabeDecToHexBin4: lda #6 sta zptmp eingabeDecToHexBin5: jsr getKey ; speichert Tasten-Bitmuster in keyIn ldx keyIn lda KEY_VAL, x ; Wert für Taste holen cmp zptmp bge eingabeDecToHexBin5 ; taste >= 6 bzw. A sta dez3 tax lda nibble_ASC, x LCD_CHAR_AKKU ; gibt das ASCII-Zeichen im Akku aufs LCD aus (Makro) LCD_CURSOR_OFF ; Cursor blinken aus (Makro) jsr dezToVal ; wandelt dez1...dez3 in Wert in val um lda val sta LED ; schon mal auf LED ausgeben jsr valToSegInHex ; nimmt Wert aus Val und gibt ihn als 2 Hex-Ziffern aus wai jmp reset ; "Zufallszahlen" zwischen 1 und 255 zufall: BYTE 238, 217, 161, 74, 27, 237, 50, 152, 68, 66, 4, 4, 138, 247, 106, 176, 85, 238, 169 BYTE 189, 61, 55, 42, 12, 170, 155, 12, 43, 164, 192, 241, 43, 111, 183, 34, 41, 155, 203 BYTE 178, 67, 144, 33, 131, 226, 198, 146, 46, 158, 161, 153, 177, 104, 69, 105, 50, 114 BYTE 110, 189, 207, 221, 248, 115, 190, 153, 76, 242, 253, 151, 36, 58, 126, 177, 25, 159 BYTE 96, 29, 162, 17, 11, 201, 110, 195, 126, 146, 18, 147, 15, 240, 75, 60, 172, 24, 197 BYTE 158, 139, 196, 24, 97, 15 BYTE 0, 0, 0, 0, 0, 0, 0, 0, 0 binToHexScore: equ $1000 binToHexRichtig: equ $1001 binToHexEingabe: equ $1002 startBinToHex: ; Spielchen für den User ------------------------------------------- ; eine Zufallszahl wird geholt und in LED angezeigt und in HEX umgerechnet ; der User gibt sein Rechenergebnis ein, ist es richtig, gibt es einen ; Punkt, ansonsten endet das Spiel stz binToHexScore; startBinToHex2a: LCD_CLEAR ; LCD löschen (Makro) LCD_PRINT msgEingabeBinToHex ; Makro-Aufruf, siehe macros.inc LCD_POS #26 ; LCD-Cursor positionieren (Makro) startBinToHex2: ldy binToHexScore lda zufall, y ; Zufallszahl holen und auf LED anzeigen sta LED beq gewonnenBinToHex ; Zufallszahlen sind mir ausgegangen sta binToHexRichtig eingabeBinToHex: ; 1. Nibble jsr getKey ; speichert Tasten-Bitmuster in keyIn ldx keyIn lda KEY_ASC,x LCD_CHAR_AKKU ; gibt das ASCII-Zeichen im Akku aufs LCD aus (Makro) jsr keyToVal ; liefert in Akku zurück sta val ; Highbyte speichern asl val ; 4x shift left asl val asl val asl val ; 2. Nibble jsr getKey ; speichert Tasten-Bitmuster in keyIn ldx keyIn lda KEY_ASC,x LCD_CHAR_AKKU ; gibt das ASCII-Zeichen im Akku aufs LCD aus (Makro) LCD_CURSOR_OFF ; Cursor blinken aus (Makro) jsr keyToVal ; liefert in Akku zurück ora val ; Low-Byte dazu (ORA = Or mit Akku) sta val ; Ergebnis zurück nach val schreiben sta binToHexEingabe cmp binToHexRichtig ; war das richtig? bne endeBinToHex LCD_PRINT msgEingabeBinToHexRichtig SED lda binToHexScore adc #1 sta binToHexScore sta val CLD jsr valToSegInHex ; neuen Score auf 7-Segmentanzeige ausgeben wai ; warten auf Cont. jmp startBinToHex2a ; nächste Runde gewonnenBinToHex: LCD_CLEAR LCD_PRINT msgBinToHexGewonnen stp endeBinToHex: LCD_PRINT msgEingabeBinToHexFalsch stp stop: STP ; Hält die CPU an ; --- Unterprogramme --- delay: ; 1 delay ca. 5 ms NOP ; Zeit verschwenden, NOP = 2 Taktzyklen NOP dec A bne delay rts ; --- im ROM abgelegte Konstanten --- msgMenu: ; 1234567890123456 Spaces am Ende gelten auch, auch wenn man sie nicht sieht ASCII 1. hex BYTE lcd_pfeil_r ASCII dec/bin C ASCII 2. dec BYTE lcd_pfeil_r ASCII hex/bin C ASCII 3. bin BYTE lcd_pfeil_r ASCII hex (Du) BYTE 0 msgEingabeHexToDecBin: ; 1234567890123456 ASCII hex BYTE lcd_pfeil_r ASCII dec/bin CPU ASCII Hex-Wert: $__ BYTE 0 msgEingabeDecToHexBin: ; 1234567890123456 ASCII dec BYTE lcd_pfeil_r ASCII hex/bin CPU ASCII Dez-Wert: ___ BYTE 0 msgEingabeBinToHex: ; 1234567890123456 ASCII bin BYTE lcd_pfeil_r ASCII hex Du ASCII Hex-Wert: $__ BYTE 0 msgEingabeBinToHexRichtig: BYTE 32,32,32 ASCII RICHTIG! +1 Pkt. BYTE 0 msgEingabeBinToHexFalsch: BYTE 32,32,32 ASCII FALSCH,GAME OVER BYTE 0 msgBinToHexGewonnen: ; 1234567890123456 ASCII ALLE ACHTUNG! ASCII Du hast alle Auf ASCII gaben gel BYTE lcd_oe ASCII st. ASCII Gratulation! BYTE 0 ; --- Interrupt-Routinen --- ; bei einkommenden IRQ-Signal (Taster an NMI) springt er kurz hier rein und ; macht dann im Code weiter ORG $FFD0 ; NMI -> Debug-Ausgabe php jsr debug plp wai rti ; spring zurück, ohne etwas zu tun ; so kann ich BRK als Breakpoints in den Source einbauen, bei dem die CPU stoppt ORG $FFE0 ; BRK/IRQ -> Continue rti ; --- Sprungvektoren --- ORG $FFFA word $FFD0 ; NMI bei $FFFA/B word $8000 ; Programmstartadresse bei $FFFC/D word $FFE0 ; BRK/IRQ bei $FFFE/F

convert.inc (klicken, um diesen Abschnitt aufzuklappen)
; bin-dec-hex Umrechen-Routinen ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-11 ; --- Funktionen: ; ; valToDez: ; holt sich Wert aus Var. val und liefert in dez1...dez3 zurück ; dezToVal: ; holt sich Ziffern aus Wert aus dez1...dez3 und gibt Wert in Var. val zurück ; ----------------------------------------------------------------------------------------- dezToVal: ; holt sich Ziffern aus Wert aus dez1...dez3 und gibt Wert in Var. val zurück phx lda #0 ; Wert im Akku aus dez1...dez3 aufaddieren ldx dez1 beq dezToVal2a dezToVal1: adc #100 dex bne dezToVal1 dezToVal2a: ldx dez2 beq dezToVal3 dezToVal2b: adc #10 dex bne dezToVal2b dezToVal3: adc dez3 sta val plx rts ; ----------------------------------------------------------------------------------------- valToDez: ; holt sich Wert aus Var. val und liefert in dez1...dez3 zurück sed ; Dezimal-Modus einschalten ($10+$10 sind dann z. B. $20!) ; damit passt aber max $99 in ein Byte, dann geschieht ein ; Überlauf und wir brauchen ein weiteres Byte für 100...255, ; in dem dann die führende 1 oder 2 steht stz dezL ; low und High-Byte der BCD-Darstellung auf 0 stz dezH lda val ; umzurechnenden Binärwert holen ($00...$FF) sta zptmp lda #0 ; Dezimalwert wird im Akku aufaddiert. convBit0: bbr0 zptmp, convBit1 ; wenn bit nicht gesetzt --> zum nächsten Bit springen clc adc #$1 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBit1 ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBit1: bbr1 zptmp, convBit2 ; wenn bit nicht gesetzt --> zum nächsten Bit springen clc adc #$2 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBit2 ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBit2: bbr2 zptmp, convBit3 ; wenn bit nicht gesetzt --> zum nächsten Bit springen clc adc #$4 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBit3 ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBit3: bbr3 zptmp, convBit4 ; wenn bit nicht gesetzt --> zum nächsten Bit springen clc adc #$8 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBit4 ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBit4: bbr4 zptmp, convBit5 ; wenn bit nicht gesetzt --> zum nächsten Bit springen clc adc #$16 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBit5 ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBit5: bbr5 zptmp, convBit6 ; wenn bit nicht gesetzt --> zum nächsten Bit springen clc adc #$32 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBit6 ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBit6: bbr6 zptmp, convBit7 ; wenn bit nicht gesetzt --> zum nächsten Bit springen clc adc #$64 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBit7 ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBit7: bbr7 zptmp, convBitDone; wenn bit nicht gesetzt --> fertig inc dezH clc adc #$28 ; in decimal mode sind dezimalzahlen als Hex-Wert anzugeben bcc convBitDone ; kein Übertrag (<=99) --> zum nächsten Bit springen inc dezH convBitDone: sta dezL ; die addierten Bitwerte nach dezL sichern cld ; Dezimalmode wieder verlassen ; die BCD-Werte ($01 $23) in 3 Ziffern (1, 2, 3) portieren lda dezH ; Ziffer 1 sta dez1 lda dezL ; Ziffer 2 lsr A ; 4x rechts shiften lsr A lsr A lsr A sta dez2 lda dezL ; Ziffer 3 and #%00001111 sta dez3 rts

debug.inc (klicken, um diesen Abschnitt aufzuklappen)
; Unter-Routinen fürs Debugging ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-06 ; Aufruf: ; ------- ; php ; Prozessor Status sichern ; jsr debug ; plp ; und wieder herstellen debug: sta regA ; Register retten stx regX sty regY pla ; Rücksprungadresse (=PC) von jsr-Einsprung holen und retten sta regPCL pla sta regPCH pla sta regP ; dann liegt P-Register von PHP oben, holen und retten debug2: lda regP ; P-Register wieder auf den Stack pha lda regPCH ; und dann die Rücksprungadresse pha ; wieder auf den Stack lda regPCL pha debug3: LCD_CLEAR ; --- auf LCD ausgeben: NV1BDIZC A=$xx LCD_PRINT msgDebug1 LCD_HEX regA LCD_CHAR #32 ; --- auf LCD ausgeben: NV1BDIZC - Registerwerte S, wenn set; leer, wenn reset lda regP sta zptmp pst7: bbs7 zptmp, pst7set LCD_CHAR #32 'leer bra pst6 pst7set: LCD_CHAR #83 'ASC S pst6: bbs6 zptmp, pst6set LCD_CHAR #32 'leer bra pst5 pst6set: LCD_CHAR #83 'ASC S pst5: bbs5 zptmp, pst5set LCD_CHAR #32 'leer bra pst4 pst5set: LCD_CHAR #83 'ASC S pst4: bbs4 zptmp, pst4set LCD_CHAR #32 'leer bra pst3 pst4set: LCD_CHAR #83 'ASC S pst3: bbs3 zptmp, pst3set LCD_CHAR #32 'leer bra pst2 pst3set: LCD_CHAR #83 'ASC S pst2: bbs2 zptmp, pst2set LCD_CHAR #32 'leer bra pst1 pst2set: LCD_CHAR #83 'ASC S pst1: bbs1 zptmp, pst1set LCD_CHAR #32 'leer bra pst0 pst1set: LCD_CHAR #83 'ASC S pst0: bbs0 zptmp, pst0set LCD_CHAR #32 'leer bra pstdone pst0set: LCD_CHAR #83 'ASC S pstdone: LCD_CHAR #32 'leer LCD_CHAR #32 'leer ; --- auf LCD ausgeben: X=$xx LCD_PRINT msgDebug2 LCD_HEX regX LCD_CHAR #32 ; --- auf LCD ausgeben: PC=$ LCD_PRINT msgDebug3 LCD_HEX regPCH LCD_HEX regPCL LCD_CHAR #32 LCD_CHAR #32 ; --- auf LCD ausgeben: Y=$xx LCD_PRINT msgDebug4 LCD_HEX regY LCD_CHAR #32 ; register wieder herstellen lda regA ldx regX ldy regY wai ; auf Cont-Taste warten rts msgDebug1: ASCII NV1BDIZC A=$ BYTE 0 msgDebug2: ASCII X=$ BYTE 0 msgDebug3: ASCII PC=$ BYTE 0 msgDebug4: ASCII Y=$ BYTE 0

io-defs.inc (klicken, um diesen Abschnitt aufzuklappen)
; IO-Geräte-Adressen ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-08-31 ; --- Konstanten: IO-Adressen --- ; --- OUTPUT --- OUTPUT1: equ $4000 LED: equ OUTPUT1+$0 ; 8-LED-Ausgabe SEGL: equ OUTPUT1+$1 ; linke 7-Segment-Anzeige SEGM: equ OUTPUT1+$2 ; mittlere 7-Segment-Anzeige SEGR: equ OUTPUT1+$3 ; rechte 7-Segment-Anzeige LCD: equ OUTPUT1+$4 ; DOGM163 LCD mit 3*16 Zeichen OUTPUT2: equ $5000 ; Output #2: für zukünftige Verwendung ; --- 6522er --- VIA: equ $6000 ; 6522 #1: 4x4 Keypad VIA_PORTB: equ VIA+$0 ; Port B VIA_PORTA: equ VIA+$1 ; Port A VIA_DDRB: equ VIA+$2 ; Data Direction Port B VIA_DDRA: equ VIA+$3 ; Data Direction Port A VIA_T1CL: equ VIA+$4 ; Timer 1 Low Order Latches (W) / Counter (R) VIA_T1CH: equ VIA+$5 ; T1 High-Order Counter VIA_T1LL: equ VIA+$6 ; T1 Low-Order Latches VIA_T1LH: equ VIA+$7 ; T1 High-Order Latches VIA_T2CL: equ VIA+$8 ; Timer 2 Low Order Latches (W) / Counter (R) VIA_T2CH: equ VIA+$9 ; T2 High-Order Counter VIA_SR: equ VIA+$A ; Shift Register VIA_ACR: equ VIA+$B ; Auxiliary Control Register VIA_PCR: equ VIA+$C ; Peripheral Control Register VIA_IFR: equ VIA+$D ; Interrupt Flag Register VIA_IER: equ VIA+$E ; Interrupt Enable Register VIA_PA_No_SHAKE: equ VIA+$F ; Same as Reg 1 except no "Handshake" VIA2: equ $7000 ; 6522 #2: für zukünftige Verwendung

io.inc (klicken, um diesen Abschnitt aufzuklappen)
; Funktionen, die IO betreffend ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-03 ioInit: ; LED-Ausgabe löschen stz LED ; das gleiche wie lda #0, sta LED ; Segment-Ausgabe löschen lda #$FF sta SEGL sta SEGM sta SEGR init_LCD: ; Reset an LCD (Bit 0 auf Low für ein paar ms) stz LCD ; das gleiche wie lda #0, sta LCD lda #5 jsr delay ; wieder auf high und min 50 ms warten lda #1 sta LCD lda #10 jsr delay jsr lcdInit jsr test_keypad rts

key-defs.inc (klicken, um diesen Abschnitt aufzuklappen)
; 4x4 Keypad Definitionen ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-01 KEY_VAL: BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $01, $FF, $FF, $FF, $04, $FF, $07, $0E, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $02, $FF, $FF, $FF, $05, $FF, $08, $00, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $03, $FF, $FF, $FF, $06, $FF, $09, $0F, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $0A, $FF, $FF, $FF, $0B, $FF, $0C, $0D, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF KEY_ASC: BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $31, $FF, $FF, $FF, $34, $FF, $37, $45, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $32, $FF, $FF, $FF, $35, $FF, $38, $30, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $33, $FF, $FF, $FF, $36, $FF, $39, $46, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $41, $FF, $FF, $FF, $42, $FF, $43, $44, $FF BYTE $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF

key.inc (klicken, um diesen Abschnitt aufzuklappen)
; Tastendrücke vom 4x4 Keypad entgegennehmen ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-02 ; ----------- ; Funktionen: ; ----------- ; test_keypad: ; checkt, ob Kurzschluss in Tastatur ; getKey: Wartet auf Tastendruck (+loslassen) und schreibt Tasten-Muster nach keyIn ; in: - ; out: Key-Bitmuster in Var. keyIn ; keyToLCD: gibt die gedrückte Taste als ASCII auf dem LCD aus ; in: - (keyIn) ; out: - ; keyToSeg: gibt die gedrückte Taste auf der 7-Segment-Anzeige aus ; in: - (keyIn) ; out: - ; keyToVal: gibt die gedrückte Taste als Wert im Akku zurück ; in: - (keyIn) ; out: TastenWert ($0...$F) in Akku ; ------------------------------------------------------------------------------------------ test_keypad: ; checkt, ob Kurzschluss in Tastatur ; oberen 4 Bits Port A Output, unteren 4 Bits Port Input ; standardmäßig sind die Leitungen auf High, wir müssen also auf low prüfen lda #%11110000 sta VIA_DDRA lda #$0F ; alle Output-Leitungen auf low sta VIA_PORTA lda VIA_PORTA ; sollte $0F bleiben, sonst hängt eine Taste cmp #$0F beq test_keypad_done ; alles okay ; Eine Taste hängt. Meldung ausgeben LCD_CLEAR LCD_PRINT msgTastaturKlemmt ; welche Taste(n) hängt? Durchtesten und ausgeben lda #%11101111 sta keyOut ldx #4 ; 4 Output-Leitungen nacheinander mit LOW versorgen... nextKeyOutTest: lda keyOut sta VIA_PORTA ; und schauen, ob das bei einer der 4 Input-Leitungen ankommt... lda VIA_PORTA sta keyIn ; ein unteres Bit auf 0? Dann Taste gedrückt and #%00001111 cmp #$0F ; $0F = Standardwert = nichts gedrückt beq keinHaengerHier ; Hänger ausgeben ldy keyIn lda KEY_ASC, y LCD_CHAR_AKKU keinHaengerHier: dex beq test_nextKeyOutTest_done; wenn 4x durch, raus rol keyOut ; bits eins nach links schieben = nächste Leitung bra nextKeyOutTest test_nextKeyOutTest_done: wai ; auf Cont.-Taste warten LCD_CLEAR ; LCD wieder leeren test_keypad_done: rts msgTastaturKlemmt: ;1234567890123456 ASCII WARNUNG! Key-Pad BYTE lcd_ue ASCII berpr BYTE lcd_ue ASCII fen! Eine ASCII Taste h BYTE lcd_ae ASCII ngt: BYTE 0 keyToLCD: ; --- gibt die gedrückte Taste als ASCII auf dem LCD aus phx ; Register X auf Stack retten lda #1 ; ist ein zeichen sta lcdrs ; ASCII-Zeichen für Key-Muster holen ("0"..."9" und "A"..."F") ldx keyIn lda KEY_ASC, x jsr lcdByte plx ; Register X wieder herstellen rts keyToSeg: ; --- gibt die gedrückte Taste auf der 7-Segment-Anzeige aus phx ; Register X auf Stack retten lda #1 ; ist ein zeichen sta lcdrs ; Wert für Key-Muster holen ($0...$F bzw. 0 bis 15) ldx keyIn lda KEY_VAL, x ; erst das Key-Bitmuster zuordnen tax lda SEG, x ; dann dafür das Segment-Muster holen sta SEGR plx ; Register X wieder herstellen rts keyToVal: ; --- gibt die gedrückte Taste als Wert im Akku zurück phx ; Register X auf Stack retten ; Wert für Key-Muster holen ($0...$F bzw. 0 bis 15) ldx keyIn lda KEY_VAL, x ; das Key-Bitmuster dem Wert zuuordnen plx ; Register X wieder herstellen rts getKey: ; --- Wartet auf Tastendruck (+loslassen) und schreibt Tasten-Muster nach keyIn phx ; Register X auf Stack retten ; oberen 4 Bits Port A Output, unteren 4 Bits Port Input ; standardmäßig sind die Leitungen auf High, wir müssen also auf low prüfen lda #%11110000 sta VIA_DDRA getKey2: lda #%11101111 sta keyOut ldx #4 ; 4 Output-Leitungen nacheinander mit LOW versorgen... nextKeyOut: lda keyOut sta VIA_PORTA ; und schauen, ob das bei einer der 4 Input-Leitungen ankommt... lda VIA_PORTA sta keyIn ; ein unteres Bit auf 0? Dann Taste gedrückt and #%00001111 cmp #$0F ; $0F = Standardwert = nichts gedrückt bne getKeyDone ; es wurde etwas gedrückt rol keyOut ; bits eins nach links schieben = nächste Leitung dex beq getKey2 ; wenn 4x durch, dann nochmal von vorne bra nextKeyOut getKeyDone: ; Ergebnis steht in keyIn ; warten, bis die Taste wieder losgelassen wurde loslassen: NOP NOP NOP NOP NOP lda VIA_PORTA and #%00001111 cmp #$0F ; $0F = Standardwert = nichts gedrückt bne loslassen plx ; Register X wieder herstellen rts ; gedrückte Taste steht in keyIn

lcd-defs.inc (klicken, um diesen Abschnitt aufzuklappen)
; LCD Definitionen für DOGM163-LCD ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-08-30 ; --- Konstanten für LCD opLCD_Clear: equ %00000001 opLCD_Home: equ %00000010 opLCD_DispOn: equ %00001100 opLCD_DispOff: equ %00001000 opLCD_CursorOn: equ %00001111 opLCD_CursorOff: equ %00001100 ; --- Kontanten: Bitpositionen --- bitLCD_Reset: equ 1 ; Bit 0 = Reset (0) / normal (1) bitLCD_RS: equ 2 ; Bit 1 = RS = Command (0) / Character (1) bitLCD_RW: equ 4 ; Bit 2 = RW = Write (0, normal) / Read (1, nicht benutzt) bitLCD_E: equ 8 ; Bit 3 = Ena ble (pulse=1, normal=0) ; bit 4 bis 7 = Datenbits D4 bis D7 ; --- Sonderzeichen --- lcd_ae: equ %10000100 lcd_oe: equ %10010100 lcd_ue: equ %10000001 lcd_AE: equ %10001110 lcd_OE: equ %10011001 lcd_UE: equ %10011010 lcd_grad: equ %11011111 lcd_durchschn: equ %11101110 lcd_wurzel: equ %11111110 lcd_ungleich: equ %11111101 lcd_pfeil_l: equ %01111111 lcd_pfeil_r: equ %01111110 lcd_ecke_lo: equ %00001001 lcd_ecke_ro: equ %00001010 lcd_ecke_lu: equ %00001011 lcd_ecke_ru: equ %00001100 lcd_strich_o: equ %11111111 lcd_strich_u: equ %01011111 lcd_mittelpkt: equ %00001101 lcd_mult: equ %11110111 lcd_div: equ %11111000 lcd_alpha: equ %00011111 lcd_pi: equ %00011001 lcd_sigma: equ %00011010 lcd_phi: equ %00011100 lcd_psi: equ %00011101 lcd_ohm: equ %00011111 lcd_ypsilon: equ %00011011 lcd_xi: equ %00011000 lcd_lambda: equ %00010111 lcd_theta: equ %00010110 lcd_delta: equ %00010101 nibble_ASC: BYTE $30, $31, $32, $33, $34, $35, $36, $37, $38, $39 ; ASCII Ziffern 0...9 BYTE $41, $42, $43, $44, $45, $46 ; ASCII Bst. A...F

lcd.inc (klicken, um diesen Abschnitt aufzuklappen)
; Unterprogramme für DOGM163-LCD ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-12 ; Funktionen / Makros: ; LCD_POS CURSOR_POS ; LCD-Cursor positionieren (0...47) ; LCD_CHAR ; Druckt 1 Zeichen, darf Speicheradresse oder auch #Wert sein ; LCD_CHAR_AKKU ; Druckt 1 Zeichen, ASCII-Wert steht schon im Akku ; LCD_PRINT ADDRMSG ; gibt ein Null-terminierten String aus ; LCD_CLEAR ; LCD_CURSOR_ON ; LCD_CURSOR_OFF ; lcdByte: ; Übergabe Bytewert in Akku, Command (0) / Character (1) in lcdrs ; lcdInit: ; LCD initialisieren LCD_CHAR MACRO CHAR_OR_ADDR ; darf Speicheradresse oder auch #Wert sein lda #1 ; ist ein Zeichen sta lcdrs lda CHAR_OR_ADDR jsr lcdByte ; druckt, was im Akku steht MACEND LCD_CHAR_AKKU MACRO ; ASCII-Wert steht schon im Akku ldy #1 ; ist ein Zeichen sty lcdrs jsr lcdByte ; druckt, was im Akku steht MACEND LCD_HEX MACRO BYTE_OR_ADDR ; darf Speicheradresse oder auch #Wert sein lda #1 ; ist ein Zeichen sta lcdrs lda BYTE_OR_ADDR lsr A lsr A lsr A lsr A tax lda nibble_ASC, x jsr lcdByte ; druckt, was im Akku steht lda BYTE_OR_ADDR and #%00001111 tax lda nibble_ASC, x jsr lcdByte ; druckt, was im Akku steht MACEND ; eine Message (Null-terminierten String) auf dem LCD anzeigen -------------- LCD_PRINT MACRO ADDRMSG lda #1 ; sind Zeichen sta lcdrs ldx #0 print# ; # = für Makro individuelles Label ldy ADDRMSG, x ; X. Buchstaben aus Message in Y-Register laden beq print_done# ; Null-Byte = String-Ende tya jsr lcdByte inx bra print# print_done# ; Ausgabe fertig, weiter im Takt MACEND LCD_CLEAR MACRO stz lcdrs ; ist ein Befehl (0) lda #opLCD_Clear jsr lcdByte MACEND LCD_CURSOR_ON MACRO stz lcdrs ; ist ein Befehl (0) lda #opLCD_CursorOn jsr lcdByte MACEND LCD_CURSOR_OFF MACRO stz lcdrs ; ist ein Befehl (0) lda #opLCD_CursorOff jsr lcdByte MACEND LCD_POS MACRO CURSOR_POS ; LCD-Cursor positionieren stz lcdrs ; ist ein Befehl (0) lda CURSOR_POS adc #$80 ; $80 für Pos.-Command dazu addieren jsr lcdByte MACEND lcdByte: ; Übergabe Bytewert in Akku, Command (0) / Character (1) in lcdrs sta lcdhb ; Übergabe aus Akku speichern -> Highbyte kommt zuerst dran sta lcdlb ; Übergabe aus Akku speichern -> schon mal Lowbyte speichern asl lcdlb ; unteren 4 Bit nach links nach oben schieben asl lcdlb asl lcdlb asl lcdlb smb0 lcdhb ; Reset aus smb0 lcdlb rmb2 lcdhb ; Write rmb2 lcdlb rmb3 lcdhb ; Enable erst einmal auf low rmb3 lcdlb ; command (lcdrs=0) oder Character (lcdrs=1) lda lcdrs bne lcdByteCmd rmb1 lcdhb ; Command (0) / Character (1) rmb1 lcdlb ; Command (0) / Character (1) bra lcdByteCmd_after lcdByteCmd: smb1 lcdhb ; Command (0) / Character (1) smb1 lcdlb ; Command (0) / Character (1) lcdByteCmd_after: ; High-Byte übertragen und pulsen (E-Leitung auf High für ein paar ms, min. 2 ms) lda lcdhb sta LCD ;sta LED nop smb3 lcdhb ; E-Leitung kurz auf High pulsen lda lcdhb sta LCD ;sta LED nop rmb3 lcdhb ; E-Leitung wieder auf Low lda lcdhb sta LCD ;sta LED nop ; Low-Byte übertragen und pulsen (E-Leitung auf High für ein paar ms, min. 2 ms) lda lcdlb sta LCD ;sta LED smb3 lcdlb ; E-Leitung kurz auf High pulsen lda lcdlb sta LCD ;sta LED nop rmb3 lcdlb ; E-Leitung wieder auf Low lda lcdlb sta LCD ;sta LED nop rts lcdInit: ; LCD initialisieren -------------------------------------------------------------- ; 8-Bit-Mode einschalten; nötig, um nach deinem Reset die Spur wieder zu finden stz lcdrs ;cmd lda #%00110000 jsr lcdByte ; nötig, um nach deinem Reset die Spur wieder zu finden ; weiterhin stz lcdrs ;cmd lda #%00110011 jsr lcdByte ; nötig, um nach deinem Reset die Spur wieder zu finden ; weiterhin stz lcdrs ;cmd lda #%00110010 jsr lcdByte ; 4-Bit-Mode einschalten; extended instruction table 1 setzen ; weiterhin stz lcdrs ;cmd lda #%00101001 jsr lcdByte ; bias set ; weiterhin stz lcdrs ;cmd lda #%00011101 jsr lcdByte ; Power/ICON control/Contrast set ; weiterhin stz lcdrs ;cmd lda #%01010011 jsr lcdByte ; Follower control ; weiterhin stz lcdrs ;cmd lda #%01101111 jsr lcdByte ; Contrast set(low byte) ; weiterhin stz lcdrs ;cmd lda #%01111111 jsr lcdByte ; es folgen nur noch Standard-Befehle: normal instruction table ; weiterhin stz lcdrs ;cmd lda #%00101000 jsr lcdByte ; Entry Mode Set ; weiterhin stz lcdrs ;cmd lda #%00000110 jsr lcdByte ; clear ; weiterhin stz lcdrs ;cmd lda #opLCD_Clear jsr lcdByte ; display on ; weiterhin stz lcdrs ;cmd lda #opLCD_DispOn jsr lcdByte rts

macros.inc (klicken, um diesen Abschnitt aufzuklappen)
; Makro-Funktionen ; werden vom Assembler ersetzt und belasten so nicht den Stack wie jsr-Aufrufe ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-07 ; vorhandene Makros: ; DEBUG ; gibt Prozessorstatus auf LCD aus und wartet auf Cont DEBUG MACRO ; gibt Prozessorstatus auf LCD aus und wartet auf Cont php jsr debug plp MACEND

ram-defs.inc (klicken, um diesen Abschnitt aufzuklappen)
; Definition von gemeinsamen RAM-Adressen außerhalb der ZeroPage ; $0200...$0FFF ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-08-31 keyOut: equ $200; keyIn: equ $201; val: equ $202 ; normaler Binärwert dezL: equ $203 ; BCD Darstellung low Byte dezH: equ $204 ; high Byte dez1: equ $205 ; Dezimalziffer 1 (0...2) (max 255) dez2: equ $206 ; Dezimalziffer 2 (0...9) dez3: equ $207 ; Dezimalziffer 3 (0...9) hex1: equ $208 ; Hexziffer 1 (0...F) hex2: equ $209 ; Hexziffer 2 (0...F) bitVal: equ $20A ; Hilfs.-Var zur Hex-Umrechnung testVal: equ $20B ; Hilfs.-Var zur Hex-Umrechnung regA: equ $20C ; Zwischenspeicher Akku regX: equ $20D ; Zwischenspeicher X-Register regY: equ $20E ; Zwischenspeicher Y-Register regP: equ $20F ; Zwischenspeicher Prozessorstatus-Register regPCL: equ $210 ; Program counter Low regPCH: equ $211 ; Program counter High regP2: equ $212 ; Prozessorstatus-Register Kopie regPCL2: equ $213 ; Program counter Low Kopie regPCH2: equ $214 ; Program counter High Kopie

seg-defs.inc (klicken, um diesen Abschnitt aufzuklappen)
; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-08-08 ; Definitionen für 7-Segment-Anzeige 5611 B (common Anode) ; ; 2 ; __ ; 4 | | 1 ; -- 8 ; 10 |__| 40 .=80 ; ; 20 ; 0...9 Ziffern, 11...36 Buchstaben SEG: BYTE $88, $BE, $C4, $94, $B2, $91, $81, $BC, $80, $90 ; 0 bis 9 = Ziffern 0 bis 9 BYTE $A0, $83, $C9, $86, $C1, $E1, $89, $A2, $BE, $9E ; 11 bis 20 = Buchst. A bis J BYTE $A1, $CB, $A5, $A8, $88, $E0, $B0, $E9, $91, $BC ; 21 bis 30 = Buchst. K bis T BYTE $8A, $DA, $D2, $D5, $92, $C4 ; 31 bis 36 = Buchst. U bis Z ; Abbildung der wichtigsten ASCII-Zeichen an der ASCII-Position SEG_ASC: ; ersten 32 Bytes leer, weil Steuerzeichen BLKB 32, $FF ; SPC ! " # $ % & ' ( ) * + , - . / BYTE $FF, $3E, $FA, $AA, $91, $E6, $C0, $FE, $C9, $9C, $B6, $E3, $BF, $F7, $7F, $E6 ; 0 1 2 3 4 5 6 7 8 9 : ; < = > ? BYTE $88, $BE, $C4, $94, $B2, $91, $81, $BC, $80, $90, $3F, $3F, $C7, $D7, $97, $44 ; @ A B C D E F G H I J K L M N O BYTE $84, $A0, $83, $C9, $86, $C1, $E1, $89, $A2, $BE, $9E,$A1, $CB, $A5, $A8, $88 ; P Q R S T U V W X Y Z [ \ ] ^ _ BYTE $E0, $B0, $E9, $91, $BC, $8A, $DA, $D2, $D5, $92, $C4, $C9, $B3, $9C, $F8, $DF ; ` a b c d e f g h i j k l m n o BYTE $FB, $A0, $83, $C9, $86, $C1, $E1, $89, $A2, $BE, $9E,$A1, $CB, $A5, $A8, $88 ; p q r s t u v w x y z { | } ~ DEL BYTE $E0, $B0, $E9, $91, $BC, $8A, $DA, $D2, $D5, $92, $C4, $C9, $B3, $9C, $F8, $FF ; ASCII 128-255 = 128 Bytes leer BLKB 128, $FF

seg.inc (klicken, um diesen Abschnitt aufzuklappen)
; Unter-Routinen für 7-Segment-Anzeige ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-09-06 ; Funktionen: ; ; dezToSeg: ; gibt eine Dezimalzahl auf der 7-Segment-Anzeige aus valToSegInHex: ; gibt einen Speicherinhalt auf der 7-Segment-Anzeige in Hex aus phx ; links immer leer lda #$FF sta SEGL ; mittig High-Nibble lda val lsr lsr lsr lsr tax lda SEG, x ; Muster für Wert ($0...$F) holen sta SEGM ; rechts High-Nibble lda val and #%00001111 tax lda SEG, x ; Muster für Wert ($0...$F) holen sta SEGR plx rts dezToSeg: ; gibt eine Dezimalzahl auf der 7-Segment-Anzeige aus phx ; und auf 7-Segment ausgeben ldx dez1 beq SEGL_leer lda SEG, x sta SEGL bra SEGM_weiter SEGL_leer: lda #$FF sta SEGL ; 2. ziffer auch 0? dann auch leer lassen lda dez2 bne SEGM_weiter lda #$FF sta SEGM bra SEGR_weiter SEGM_weiter: ldx dez2 lda SEG, x sta SEGM SEGR_weiter: ldx dez3 lda SEG, x sta SEGR plx rts

zeropage-defs.inc (klicken, um diesen Abschnitt aufzuklappen)
; Definition von festen ZeroPage- Adressen ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-08-11 ; --- Speicheradressen RAM Zeropage $00...$FF ; --- lcd --- lcdhb: equ $00 lcdlb: equ $01 lcdrs: equ $02 ; 1= char, 0= cmd, vor jsr lcdByte setzen ; --- allgemeine temporäre Verwendung zptmp: equ $03 zptmp2: equ $04 zptmp3: equ $05

Der Source-Code ist - wie gewohnt - gut dokumentiert und kommentiert. Eine Erklärung des Programmes und der neuen Funktionen findet sich in folgendem Video. Das ist einfach anschaulicher als mit viel Text.



Ausblick

Wenn man das Spiel häufiger spielt, wird man die angezeigten Zahlen, zumindestens die ersten, bald auswendig kennen, denn es sind immer die gleichen. Und eigentlich soll beim Spiel ums Kopfrechnen und nicht ums Auswendiglernen gehen.

Ein Pseudozufallszahlengenerator wäre also etwas tolles, damit immer wieder andere Zahlen kommen. Der wäre auch für zukünftige Programme, insbesondere Spiele nützlich.