Ruud's Commodore Site: Template Home Email

Source code KIM-1





;
; Last update: 5 March 2004
;
;
; The source code is copied from 'KIM-1 MANUAL' released by MOS Technologies. 
;
;
; I have checked the SRC line by line and added some comment of my own. I 
; have compiled the SRC and found no differences with the original BIN. But 
; this does not mean that it is without faults. 
;
;
; The SRC can be assembled with my own programmed assembler. This assembler 
; for the PC is available as freeware, including source code for FPC, the
; Free Pascal Compiler: http://www.freepascal.org/. 
;
;
; Source code of the KIM-1
;
.eq PCL         = $EF                   ; programcounter low
.eq PCH         = $F0                   ; programcounter high
.eq PREG        = $F1                   ; statusregister
.eq SPUSER      = $F2                   ; stackpointer

.eq ACC         = $F3
.eq YREG        = $F4
.eq XREG        = $F5
.eq CHKHI       = $F6
.eq CHKSUM      = $F7

.eq INL         = $F8                   ; inputbuffer low
.eq INH         = $F9                   ; inputbuffer high
.eq POINTL      = $FA                   ; addressL on display
.eq POINTH      = $FB                   ; addressH on display
.eq TEMP        = $FC
.eq TMPX        = $FD
.eq CHAR        = $FE
.eq MODE        = $FF

.eq INL_A       = $00F8                 ; INL as absolute address

.eq CHKL        = $17E7
.eq CHKH        = CHKL+1
.eq SAVX        = CHKL+2
.eq VEB         = CHKL+5
.eq CNTL30      = CHKL+11
.eq CNTH30      = CHKL+12
.eq TIMH        = CHKL+13
.eq SAL         = CHKL+14
.eq SAH         = CHKL+15
.eq EAL         = CHKL+16
.eq EAH         = CHKL+17
.eq ID          = CHKL+18
.eq NMIV        = CHKL+19               ; NMI-vector
.eq RSTV        = CHKL+21               ; RESET-vector
.eq IRQV        = CHKL+23               ; IRQ-vector

.eq SAD         = $1740
.eq PADD        = SAD+1
.eq SBD         = SAD+2
.eq PBDD        = SAD+3
.eq CLK1T       = SAD+4
.eq CLK8T       = SAD+5
.eq CLK64T      = SAD+6
.eq CLKRDT      = SAD+6                 ; Read time
.eq CLKKT       = SAD+7
.eq CLKRDI      = SAD+7                 ; Read time out bit

;
;
.ba $1800
;
; Dump memory on tape
DUMPT           lda     #$AD            ; load absolute inst
                sta     VEB
                jsr     INTVEB
;
                lda     #$27            ; turn off datainput PB5
                sta     SBD
                lda     #$BF            ; PB7 := output
                sta     PBDD
;
                ldx     #100            ; 100 characters
DUMPT1          lda     #$16            ; sync chars
                jsr     OUTCHT
                dex
                bne     DUMPT1
;
                lda     #$2A            ; start char
                jsr     OUTCHT
;
                lda     ID              ; output ID
                jsr     OUTBT
;
                lda     SAL             ; output start address
                jsr     OUTBTC
                lda     SAH
                jsr     OUTBTC
;
DUMPT2          lda     VEB+1           ; compare for last data byte
                cmp     EAL
                lda     VEB+2
                sbc     EAH
                bcc     DUMPT4
;
                lda     #$2F            ; output EndOfData-char
                jsr     OUTCHT
                lda     CHKL            ; output checksum
                jsr     OUTBT
                lda     CHKH
                jsr     OUTBT
;
                ldx     #2              ; 2 chars
DUMPT3          lda     #4              ; EOT-char
                jsr     OUTCHT
                dex
                bne     DUMPT3
;  
                lda     #0              ; display 0000
                sta     POINTL
                sta     POINTH
                jmp     START
;
DUMPT4          jsr     VEB             ; output data byte
                jsr     OUTBTC
                jsr     INCVEB
                jmp     DUMPT2
;
; Load from tape into memory
TAB             .wo     LOAD12
LOADT           lda     #$8D            ; initialize volatile execution
                sta     VEB             ; block with sta abs
                jsr     INTVEB
;
                lda     #$4C            ; code for JMP
                sta     VEB+3
                lda     TAB
                sta     VEB+4
                lda     TAB+1
                sta     VEB+5
;
; result: jmp LOAD12 (= $190F)
;
                lda     #7              ; reset PB5
                sta     SBD
;
SYNC            lda     #$FF            ; clear SAVX for SYNC-area
                sta     SAVX
;
SYNC1           jsr     RDBIT           ; get a bit
                lsr     SAVX
                ora     SAVX
                sta     SAVX
                lda     SAVX            ; get new char
                cmp     #$16            ; SYNC-char?
                bne     SYNC1
;
                ldx     #10             ; test for 10 SYNC-char
SYNC2           jsr     RDCHT
                cmp     #$16            ; SYNC-char?
                bne     SYNC

                dex
                bne     SYNC2

LOADT4          jsr     RDCHT           ; look for start of
                cmp     #$2A            ;  start char
                beq     LOAD11          ; yes ->

                cmp     #$16            ; SYNC-char?
                bne     SYNC            ; no ->

                beq     LOADT4          ; always ->
;
LOAD11          jsr     RDBYT           ; read ID
                cmp     ID              ; requested ID?
                beq     LOADT5          ; yes ->

                lda     ID
                cmp     #0              ; ignore ID?
                beq     LOADT5          ; yes ->

                cmp     #$FF            ; ignore start address?
                beq     LOADT6          ; yes ->

                bne     LOADT           ; next program, always ->
;
LOADT5          jsr     RDBYT           ; get SA from tape
                jsr     CHKT
                sta     VEB+1
                jsr     RDBYT
                jsr     CHKT
                sta     VEB+2
                jmp     LOADT7
;
LOADT6          jsr     RDBYT           ; get SA from tape
                jsr     CHKT            ;  but ignore
                jsr     RDBYT
                jsr     CHKT
;
LOADT7          ldx     #2
LOAD13          jsr     RDCHT
                cmp     #$2F            ; last char?
                beq     LOADT8          ; yes ->

                jsr     PACKT           ; convert to hex
                bne     LOADT9          ; Y=1, non-hex char

                dex                     ; 2 chars?
                bne     LOAD13          ; no -> next one

                jsr     CHKT            ; compute checksum
                jmp     VEB
;
LOAD12          jsr     INCVEB          ; increment datapointer
                jmp     LOADT7
;
LOADT8          jsr     RDBYT           ; EOD compare checksum
                cmp     CHKL
                bne     LOADT9

                jsr     RDBYT
                cmp     CHKH
                bne     LOADT9

                lda     #0
                beq     LOAD10          ; normal exit, always ->
;
LOADT9          lda     #$FF            ; error exit
LOAD10          sta     POINTL
                sta     POINTH
                jmp     START           ; display values
;
; Move start address to VEB+1,2
INTVEB          lda     SAL
                sta     VEB+1
                lda     SAH
                sta     VEB+2
                lda     #$60            ; code for RTS
                sta     VEB+3
                lda     #0
                sta     CHKL
                sta     CHKH
                rts
;
; Compute checksum for tape load
CHKT            tay
                clc
                adc     CHKL
                sta     CHKL
                lda     CHKH
                adc     #0
                sta     CHKH
                tya
                rts
;
; Output one byte
OUTBTC          jsr     CHKT
OUTBT           tay
                lsr
                lsr
                lsr
                lsr
                jsr     HEXOUT          ; output MSD
                tya
                jsr     HEXOUT          ; output LSD
                tya
                rts
;
; Convert LSD of A to ASCII
HEXOUT          and     #$0F
                cmp     #10
                clc
                bmi     HEX1

                adc     #7
HEX1            adc     #$30
;
; Output to tape 1 ASCII
OUTCHT          stx     SAVX
                sty     SAVX+1
                ldy     #8              ; startbit
CHT1            jsr     ONE
                lsr                     ; get data bit
                bcs     CHT2

                jsr     ONE
                jmp     CHT3

CHT2            jsr     ZRO
CHT3            jsr     ZRO
                dey                     ; all bits?
                bne     CHT1            ; no ->
                ldx     SAVX
                ldy     SAVX+1
                rts
;
; Output a 1 to tape: 9 pulses of 138 us each
ONE             ldx     #9
                pha
ONE1            bit     CLKRDI          ; wait for timeout
                bpl     ONE1

                lda     #126
                sta     CLK1T
                lda     #$A7
                sta     SBD             ; PB7 := 1
ONE2            bit     CLKRDI          ; wait for timeout
                bpl     ONE2

                lda     #126
                sta     CLK1T
                lda     #$27
                sta     SBD             ; PB7 := 0
                dex                     ; all pulses?
                bne     ONE1            ; no ->

                pla
                rts
;
; Output a 0 to tape: 6 pulses of 207 us each
ZRO             ldx     #6
                pha
ZRO1            bit     CLKRDI          ; wait for timeout
                bpl     ZRO1

                lda     #195
                sta     CLK1T
                lda     #$A7
                sta     SBD             ; PB7 := 1
ZRO2            bit     CLKRDI          ; wait for timeout
                bpl     ZRO2

                lda     #195
                sta     CLK1T
                lda     #$27
                sta     SBD             ; PB7 := 0
                dex                     ; all pulses?
                bne     ZRO1            ; no ->

                pla
                rts
;
; Increment VEB+1,2
INCVEB          inc     VEB+1
                bne     INCVE1

                inc     VEB+2
INCVE1          rts
;
; Read byte from tape
RDBYT           jsr     RDCHT
                jsr     PACKT
RDBYT2          jsr     RDCHT
                jsr     PACKT
                rts
;
; Pack ASCII in A as hex data
PACKT           cmp     #$30            ; ASCII ?
                bmi     PACKT3          ; no ->

                cmp     #$47
                bpl     PACKT3          ; no ->

                cmp     #$40            ; > '9' ?
                bmi     PACKT1          ; no ->

                clc
                adc     #9
PACKT1          rol
                rol
                rol
                rol
                ldy     #4
PACKT2          rol
                rol     SAVX
                dey
                bne     PACKT2

                lda     SAVX
;
; At this point Y already is 0 (= valid hex char)
                ldy     #0              ; set the zero flag
                rts
;
; Y=0 at this point, done in label RDBIT4 
PACKT3          iny                     ; Y:=1 = invalid hex char
                rts
;
; Get 1 char from tape in A
RDCHT           stx     SAVX+2
                ldx     #8              ; read 8 bits
RDCHT1          jsr     RDBIT
                lsr     SAVX+1
                ora     SAVX+1
                sta     SAVX+1
                dex
                bne     RDCHT1
;
                lda     SAVX+1
                rol
                lsr
                ldx     SAVX+2
                rts
;
; Get 1 bit from tape and return it in bit 7 of A
RDBIT           bit     SBD             ; wait for end of startbit
                bpl     RDBIT

                lda     CLKRDT          ; get start bit time
                ldy     #$FF            ; A := 256 - T1
                sty     CLK64T
;
                ldy     #$14
RDBIT3          dey                     ; delay 100 us
                bne     RDBIT3

RDBIT2          bit     SBD
                bmi     RDBIT2          ; wait for next start bit
;
                sec
                sbc     CLKRDT
                ldy     #$FF
                sty     CLK64T
;
                ldy     #7
RDBIT4          dey                     ; delay 50 us
                bne     RDBIT4
;
                eor     #$FF            ; complement sign
                and     #$80            ; mask sign
                rts
;
; output 166 us pulse string for testing purposes
;  No documentation found about this. I think it is used to
;  calibrate the 565
PLLCALL         lda     #$27
                sta     SBD             ; turn off datin PB5=1
                lda     #$BF
                sta     PBDD
;
PLL1            bit     CLKRDI
                bpl     PLL1

                lda     #154            ; wait 166 us
                sta     CLK1T
                lda     #$A7            ; output PB7=1
                sta     SBD
;
PLL2            bit     CLKRDI
                bpl     PLL2
                lda     #154
                sta     CLK1T
                lda     #$27            ; output PB7=0
                sta     SBD
                jmp     PLL1


.fb $FF, 356
NMIP27          .wo     PLLCALL
RSTP27          .wo     PLLCALL
IRQP27          .wo     PLLCALL


;
;
;
; KIM-entry via NMI or IRQ                                              [1C00]
SAVE            sta     ACC
                pla
                sta     PREG
;
; KIM-entry via JSR
SAVEA           pla
                sta     PCL
                sta     POINTL
                pla
                sta     PCH
                sta     POINTH
;
SAVEB           sty     YREG
                stx     XREG
                tsx
                stx     SPUSER
                jsr     INITS
                jmp     START
;
; NMI and IRQ are called via RAM vector. This enables the programmer
; to insert his own routines.
; Comment: is not initialized anywhere, so any accidental NMI or IRQ  
;  can lead to disaster !
NMIT            jmp     (NMIV)
IRQT            jmp     (IRQV)
;
; The KIM starts here after a reset
RESET           ldx     #$FF
                txs                     ; set stack
                stx     SPUSER 
                jsr     INITS
;
; Determine characters per second
DETCPS          lda     #$FF            ; count startbit
                sta     CNTH30          ; zero CNTH30
;
; Test first keyboard or teleprinter
                lda     #1              ; mask bit 0
DET1            bit     SAD             ; test for teleprinter
                bne     START           ; no ->

                bmi     DET1            ; no startbit, wait for it ->

                lda     #$FC
DET3            clc                     ; this loop counts startbit time
                adc     #1              ; A=0 ?
                bcc     DET2            ; no ->

                inc     CNTH30

DET2            ldy     SAD             ; check for end of startbit
                bpl     DET3            ; no ->

                sta     CNTL30
                ldx     #8
                jsr     GET5            ; get rest of char
;
; Make TTY/KB selection
START           jsr     INIT1
                lda     #1              ; read jumper
                bit     SAD             ; TTY ?
                bne     TTYKB           ; no -> keyboard/display routine

                jsr     CRLF            ; print return/linefeed
                ldx     #$0A
                jsr     PRTST           ; print 'KIM'
                jmp     SHOW1
;
;
CLEAR           lda     #0
                sta     INL             ; clear inputbuffer
                sta     INH
;
READ            jsr     GETCH           ; get char from TTY
                cmp     #1              ; 1 has no meaning for TTY
                beq     TTYKB           ; 1 = KB-mode ->

                jsr     PACK
                jmp     SCAN
;
; Main routine for keyboard and display
TTYKB           jsr     SCAND           ; wait until NO key pressed
                bne     START           ; if pressed, wait again ->
TTYKB1          lda     #1              ; check KB/TTY mode
                bit     SAD             ; TTY?
                beq     START           ; yes ->

                jsr     SCAND           ; Wait for key...
                beq     TTYKB1          ; no key ->

                jsr     SCAND           ; debounce key
                beq     TTYKB1          ; no key ->
;
GETK            jsr     GETKEY
                cmp     #$15            ; >= $15 = illegal
                bpl     START           ; yes ->

                cmp     #$14
                beq     PCCMD           ; display Program Counter

                cmp     #$10
                beq     ADDRM           ; Addressmode

                cmp     #$11
                beq     DATAM           ; datamode

                cmp     #$12
                beq     STEP            ; step

                cmp     #$13
                beq     GOV             ; execute program
;
; One of the hexadecimal buttons has been pushed
DATA            asl                     ; move LSB key number to MSB
                asl
                asl
                asl
                sta     TEMP            ; store for datamode
                ldx     #4

DATA1           ldy     MODE            ; part of address?
                bne     ADDR            ; yes ->

                lda     (POINTL),Y      ; get data
                asl     TEMP
                rol                     ; MSB-TEMP = MSB-key -> A
                sta     (POINTL),Y      ; store new data
                jmp     DATA2

ADDR            asl                     ; TEMP not needed here
                rol     POINTL          ; MSB-key -> POINTL
                rol     POINTH          ; POINTL -> POINTH

DATA2           dex                     ; 4 times = complete nibble?
                bne     DATA1           ; no ->

                beq     DATAM2          ; -> always
;
; Switch to address mode
ADDRM           lda     #1
                bne     DATAM1          ; -> always
;
; Switch to data mode
DATAM           lda     #0
DATAM1          sta     MODE
DATAM2          jmp     START
;
; Increment address on display
STEP            jsr     INCPT
                jmp     START
;
GOV             jmp     GOEXEC
;
; Display PC by moving it to POINT
PCCMD           lda     PCL
                sta     POINTL
                lda     PCH
                sta     POINTH
                jmp     START
;
; Load papertape from TTY
LOAD            jsr     GETCH
                cmp     #$3B            ; ":", semicolon?
                bne     LOAD            ; No -> again

LOADS           lda     #0
                sta     CHKSUM
                sta     CHKHI
;
                jsr     GETBYT          ; get byte CNT
                tax
                jsr     CHK             ; Compute checksum
;
                jsr     GETBYT          ; get address HI
                sta     POINTH
                jsr     CHK             ; Compute checksum
;
                jsr     GETBYT          ; get address LO
                sta     POINTL
                jsr     CHK             ; Compute checksum
;
                txa                     ; CNT = 0 ?
                beq     LOAD3
;
LOAD2           jsr     GETBYT          ; get DATA
                sta     (POINTL),y      ; store data
                jsr     CHK
                jsr     INCPT
                dex
                bne     LOAD2

                inx                     ; X=1 = data record
                                        ; X=0 = last record
;
LOAD3           jsr     GETBYT          ; compare checksum
                cmp     CHKHI
                bne     LOADE1

                jsr     GETBYT
                cmp     CHKSUM
                bne     LOADER
;
                txa                     ; X=0 = last record
                bne     LOAD
;
LOAD7           ldx     #$0C            ; X-OFF KIM
LOAD8           lda     #$27
                sta     SBD             ; disable data in
                jsr     PRTST
                jmp     START
;
LOADE1          jsr     GETBYT          ; dummy
LOADER          ldx     #$11            ; X-OFF error KIM
                bne     LOAD8           ; always ->
;
; Dump to TTY from open cell address to LIMHL, LIMHH
DUMP            lda     #0
                sta     INL
                sta     INH             ; clear record count
DUMP0           lda     #0
                sta     CHKHI           ; clear checksum
                sta     CHKSUM
;
DUMP1           jsr     CRLF
                lda     #$3B            ; ":"
                jsr     OUTCH
;
; Check if POINTL/H >= EAL/H
                lda     POINTL
                cmp     EAL
; 
                lda     POINTH
                sbc     EAH
                bcc     DUMP4           ; no ->
;
                lda     #0              ; print last record
                jsr     PRTBYT          ; 0 bytes
                jsr     OPEN
                jsr     PRTPNT ;
                lda     CHKHI           ; print checksum
                jsr     PRTBYT          ;  for last record
                lda     CHKSUM
                jsr     PRTBYT
                jmp     CLEAR
;
DUMP4           lda     #$18            ; print 24 bytes
                tax                     ; save as index
                jsr     PRTBYT
                jsr     CHK
                jsr     PRTPNT
;
DUMP2           ldy     #0
                lda     (POINTL),y
                jsr     PRTBYT          ; print data
                jsr     CHK
                jsr     INCPT
                dex                     ; Printed everything?
                bne     DUMP2           ; No ->
;
                lda     CHKHI
                jsr     PRTBYT          ; print checksum
                lda     CHKSUM
                jsr     PRTBYT
                inc     INL             ; increment record counter
                bne     DUMP3

                inc     INH
DUMP3           jmp     DUMP0
;
SPACE           jsr     OPEN            ; open new cell
SHOW            jsr     CRLF
SHOW1           jsr     PRTPNT
                jsr     OUTSP           ; print space
                ldy     #0
                lda     (POINTL),y      ; print data
                jsr     PRTBYT
                jsr     OUTSP           ; print space
                jmp     CLEAR
;
RTRN            jsr     INCPT           ; next address
                jmp     SHOW

; Start a program at displayed address. RTI is used as a comfortable 
; way to define all flags in one move.
GOEXEC          ldx     SPUSER          ; user defined stack
                txs
                lda     POINTH          ; program runs from
                pha                     ;  displayed address
                lda     POINTL
                pha
                lda     PREG            ; user defined Flag register
                pha
                ldx     XREG
                ldy     YREG
                lda     ACC
                rti                     ; start program
;
; Take care if TTY input
SCAN            cmp     #$20            ; open new cell
                beq     SPACE

                cmp     #$7F            ; rub out, restart KIM
                beq     STV

                cmp     #$0D            ; next cell
                beq     RTRN

                cmp     #$0A            ; prev cell
                beq     FEED

                cmp     #$2E            ; "." = modify cell
                beq     MODIFY

                cmp     #$47            ; "G" = exec program
                beq     GOEXEC

                cmp     #$51            ; "Q" = dump from open cell
                beq     DUMPV           ;  to HI limit

                cmp     #$4C            ; "L" = load tape
                beq     LOADV

                jmp     READ            ; ignore illegal CHAR
;
STV             jmp     START
DUMPV           jmp     DUMP
LOADV           jmp     LOAD
;
FEED            sec
                lda     POINTL          ; decrement POINTL/H
                sbc     #1
                sta     POINTL
                bcs     FEED1

                dec     POINTH
FEED1           jmp     SHOW
;
MODIFY          ldy     #0              ; get contents of input buffer
                lda     INL             ;  INL and store in location
                sta     (POINTL),y      ;  specified by POINT
                jmp     RTRN
;
; Subroutine to print POINT = address
PRTPNT          lda     POINTH
                jsr     PRTBYT
                jsr     CHK
                lda     POINTL
                jsr     PRTBYT
                jsr     CHK
                rts
;
; Print ASCII-string from TOP+X to TOP
CRLF            ldx     #7              ; output  and 
PRTST           lda     TOP,x
                jsr     OUTCH
                dex                     ; everything?
                bpl     PRTST           ; no ->

PRT1            rts
;
; Print 1 hex byte as 2 ASCII chars
PRTBYT          sta     TEMP            ; save A
                lsr                     ; shift A 4 times
                lsr
                lsr
                lsr
                jsr     HEXTA           ; convert bit 4..7 to HEX and print
                lda     TEMP
                jsr     HEXTA           ; convert bit 0..7 to HEX and print
                lda     TEMP            ; restore A
                rts
;
HEXTA           and     #$0F            ; mask bit 0..4
                cmp     #$0A            ; > 10 ?
                clc
                bmi     HEXTA1          ; no ->

                adc     #7              ; A..F
HEXTA1          adc     #$30            ; convert to ASCII-char...
                jmp     OUTCH           ;  ...and print it
;
; Get char from TTY in A
GETCH           stx     TMPX
                ldx     #8              ; count 8 bits
                lda     #1
GET1            bit     SAD             ; check if TTY-mode
                bne     GET6            ; no ->

; PA7 is input TTY
                bmi     GET1            ; wait for startbit

                jsr     DELAY           ; delay 1 bit
;
; By delaying another half bit time, you read the bit in the middle
; of every bit.
GET5            jsr     DEHALF          ; delay 1/2 bit time
GET2            lda     SAD
                and     #$80            ; mask bit 7
                lsr     CHAR            ; shift last result
                ora     CHAR            ; OR it with new bit
                sta     CHAR            ; and store it again
                jsr     DELAY
                dex

                bne     GET2            ; next bit

                jsr     DEHALF          ; why ????
;
                ldx     TMPX
                lda     CHAR
                rol                     ; shift off stopbit
                lsr
GET6            rts
;
; initialization of 6530                                                [1E88]
INITS           ldx     #1              ; set display to address mode
                stx     MODE
;
INIT1           ldx     #0
                stx     PADD            ; PA0..PA7 = input
                ldx     #$3F
                stx     PBDD            ; PB0..PB5 = output
                                        ; PB6, PB7 = input
                ldx     #7              ; enable 74145 output 3 to
                stx     SBD             ;  check KB/TTY-mode
                cld
                sei
                rts
;
; Output char in A to TTY                                               [1E9E]
OUTSP           lda     #" "            ; print space
OUTCH           sta     CHAR
                stx     TMPX
                jsr     DELAY
                lda     SBD
                and     #$FE            ; send startbit
                sta     SBD             ; PB0 = 0 -> TTY := (H)
                jsr     DELAY
;
                ldx     #8              ; send character
OUT1            lda     SBD
                and     #$FE            ; clear bit 0
                lsr     CHAR            ; shift byte
                adc     #0              ; add Carry = former bit 0
                sta     SBD             ; output bit
                jsr     DELAY
                dex                     ; all bits?
                bne     OUT1            ; no ->

                lda     SBD
                ora     #1
                sta     SBD             ; stop bit
                jsr     DELAY
                ldx     TMPX
                rts
;
; Delay 1 bit time as determined by DETCPS
DELAY           lda     CNTH30
                sta     TIMH
                lda     CNTL30
DE2             sec
DE4             sbc     #1
                bcs     DE3             ; A<>$FF ->

                dec     TIMH
DE3             ldy     TIMH            ; TIMH > 0 ?
                bpl     DE2             ; yes ->

                rts
;
; Delay half a bit time
DEHALF          lda     CNTH30
                sta     TIMH
                lda     CNTL30
                lsr
                lsr     TIMH
                bcc     DE2

                ora     #$80
                bcs     DE4             ; always ->
;
; Determine if key is depressed: NO -> A=0, YES -> A>0
AK              ldy     #3              ; 3 rows
                ldx     #1              ; select 74145 output 0

ONEKEY          lda     #$FF            ; initial value
;
AKA             stx     SBD             ; enable output = select row
                inx
                inx                     ; prepare for next row
                and     SAD             ; A := A && (PA0..PA7)
                dey                     ; all rows?
                bne     AKA             ; no ->

                ldy     #7
                sty     SBD             ; select 74145 output 3 (not used)
;
                ora     #$80            ; mask bit 7 of A
                eor     #$FF            ; if A still is $FF -> A := 0
                rts
;
; Output to 7-segment-display
SCAND           ldy     #0              ; POINTL/POINTH = address on display
                lda     (POINTL),Y      ; get data from this address
                sta     INH             ; store in INH =
SCANDS          lda     #$7F            ; PA0..PA6 := output
                sta     PADD

                ldx     #9              ; Start with display at output 4
                ldy     #3              ; 3 bytes to be shown
;
SCAND1          lda     INL_A,y         ; get byte
                lsr                     ; get MSD by shifting A
                lsr
                lsr
                lsr
                jsr     CONVD
                lda     INL_A,y         ; get byte again
                and     #$0F            ; get LSD
                jsr     CONVD
                dey                     ; all ?
                bne     SCAND1          ; no ->

                stx     SBD             ; all digits off
                lda     #0
                sta     PADD            ; PA0..PA7 := input
                jmp     AK
;
; Convert digit into 7-segment-value
CONVD           sty     TEMP
                tay
                lda     TABLE,Y
                ldy     #0
                sty     SAD             ; turn off segments
                stx     SBD             ; select 7-s-display
                sta     SAD             ; output code on display

                ldy     #$7F            ; delay ~500 cycles
CONVD1          dey
                bne     CONVD1

                inx                     ; next display
                inx
                ldy     TEMP
                rts
;
; Increment POINT = address on display
INCPT           inc     POINTL
                bne     INCPT2

                inc     POINTH
INCPT2          rts
;
; Get key from keyboard in A
GETKEY          ldx     #$21            ; row 0 / disable input TTY
GETKE5          ldy     #1              ; only one row in the time
                jsr     ONEKEY          ; key?
                bne     KEYIN           ; yes ->

                cpx     #$27            ; last row?
                bne     GETKE5          ; no, next one ->

                lda     #$15            ; 15 = no key
                rts
;
KEYIN           ldy     #$FF            ; Y := key number
KEYIN1          asl                     ; shift A until
                bcs     KEYIN2          ;  bit = 1 ->
;
; Comment: bit 7 is always 0 so Carry is always 0 the first time
;  and allowing Y to become 0 (key $FF does not exist)
                iny
                bpl     KEYIN1          ; always ->

KEYIN2          txa
                and     #$0F            ; strip bit4..7
                lsr                     ; A := row+1
                tax                     ; X := actual row+1
                tya
                bpl     KEYIN4          ; always, because Y<7 ->

;
; Add 7 to A for every row above 0 to get actual key number
KEYIN3          clc
                adc     #7              ; add (X-1) times 7 to A
KEYIN4          dex                     ; countdown to 0
                bne     KEYIN3

                rts                     ; A is always < 21 eg. < $15
;
; Compute checksum
CHK             clc
                adc     CHKSUM
                sta     CHKSUM
                lda     CHKHI
                adc     #0
                sta     CHKHI
                rts
;
; Get 2 hex-chars and pack into INL and INH
;  Non hex char will be loaded as nearsest hex equivalent
GETBYT          jsr     GETCH
                jsr     PACK
                jsr     GETCH
                jsr     PACK
                lda     INL
                rts
;
; Shift char in A into INL and INH
PACK            cmp     #$30            ; is hex?
                bmi     UPDAT2          ; < = no        ->

                cmp     #$47
                bpl     UPDAT2          ; > = no ->

HEXNUM          cmp     #$40            ; A..F ?
                bmi     UPDATE          ; no ->

HEXALP          clc
                adc     #9
UPDATE          rol                     ; shift to bit 4..7
                rol
                rol
                rol
                ldy     #4              ; shift into INL/INH
UPDAT1          rol
                rol     INL
                rol     INH
                dey                     ; 4 times?
                bne     UPDAT1          ; no ->

                lda     #0              ; if hex number -> A := 0
UPDAT2          rts
;
OPEN            lda     INL             ; move I/O-buffer to POINT
                sta     POINTL
                lda     INH
                sta     POINTH
                rts
;
; Tables
TOP
.by     0, 0, 0, 0, 0, 0, 10, 13
.tx     "MIK"                           ; KIM
.by     " ", $13
.tx     "RRE "                          ; ERRor
.by     $13

; Hex -> 7-segment       0    1    2    3    4    5    6    7
TABLE           .by     $BF, $86, $DB, $CF, $E6, $ED, $FD, $87
;                        8    9    A    B    C    D    E    F
.by     $FF, $EF, $F7, $FC, $B9, $DE, $F9, $F1

.by $FF, $FF, $FF
;
; Comment: if everything is compiled right, next vectors should
;  start at $FFFA
NMIENT          .wo     NMIT
RSTENT          .wo     RESET
IRQENT          .wo     IRQT
.en






Having questions or comment? You want more information?
You can email me here.