;Chris Ward's 6502 System ;System/test software ;1/6/99 DTA EQU $80 ;page zero variable space ACIA EQU $D000 ;6551 ACIA VIA1 EQU $D100 ;6522 VIA #1 VIA2 EQU $D200 ;6522 VIA #2 LCD EQU $D300 ;LCD interface ; ACIA ORG ACIA ATXD .ds 1 ;transmit data register (write) ARXD EQU ATXD ;receive data register (read) ARES .ds 1 ;programmed reset (write) ASTS EQU ARES ;status register (read) ACMD .ds 1 ;command register (r/w) ACTL .ds 1 ;control register (r/w) ; VIA #1 ORG VIA1 PORT1B .ds 1 PORT1A .ds 1 DDR1B .ds 1 DDR1A .ds 1 ; VIA #2 ORG VIA2 PORT2B .ds 1 PORT2A .ds 1 DDR2B .ds 1 DDR2A .ds 1 ; LCD ORG LCD LCD0 .ds 1 LCD1 .ds 1 ; connected hardware LEDPORT EQU PORT1B ;LEDs on VIA #1 port B LEDDDR EQU DDR1B KEYPORT EQU PORT1A ;keypad on VIA #1 port A KEYDDR EQU DDR1A ; variables ORG $DTA KEYCOL .ds 1 ;\ KEYCOLN .ds 1 ; }temp variables used by keypad scanning routine KEYROW .ds 1 ;/ KEYNEW .ds 1 ;flag indicates key has been pressed KEYVAL .ds 1 ;value of last key pressed MSGBASE .ds 2 ;address of message to print ; ***** CODE ***** ORG $E000 ; *** IRQ service routine IRQSRV PHA ;save A, X, Y to stack TXA PHA TYA PHA LDA ASTS ;interrupt from ACIA? BMI ASRV IRQSR1 PLA ;restore A, X, Y TAY PLA TAX PLA RTI ; *** ACIA interrupt service routine ASRV AND #$08 ;byte received? BEQ IRQSR1 LDA ARXD ;get byte STA LEDPORT ;for now, just display byte on LEDs JMP IRQSR1 ; *** Entry point on reset RESET NOP NOP NOP NOP JSR INIT RESET1 JSR KEYSCAN LDA KEYNEW BEQ RESET1 ;wait for keypress LDA KEYVAL ;display value on LEDs STA LEDPORT CLC ADC #$30 ;convert to ASCII CMP #$3A BMI RESET2 CLC ADC #$07 RESET2 JSR LCDPRINT ;print value on the LCD JSR TXBYTE ;transmit value on RS232 port DEC KEYNEW JMP RESET1 ; *** Initialise devices and variables INIT CLD LDA #$00 ;clear key press flag STA KEYNEW LDA #$0F ;set DDR for keypad (iiiioooo) STA KEYDDR STA KEYPORT ;set keypad columns high LDA #$FF ;set DDR for LEDs (oooooooo) STA LEDDDR LDA #$00 ;turn LEDs off STA LEDPORT JSR AINIT ;setup ACIA JSR LINIT ;setup LCD display JSR MEMTEST ;perform memory test RTS ; *** ACIA initialisation AINIT STA ARES ;reset LDA #$09 ;set options STA ACMD LDA #$1A ;8-N-1, 2400 baud STA ACTL RTS ; *** LCD initialisation LINIT LDX #$04 ;do function set 4 times LINIT0 LDA #$38 ;function set: 8 bit, 2 lines, 5x7 STA LCD0 JSR LCDBUSY ;wait for busy flag to clear DEX BNE LINIT0 LDA #$06 ;entry mode set: increment, no shift STA LCD0 JSR LCDBUSY LDA #$0E ;display on, cursor on, blink off STA LCD0 JSR LCDBUSY LDA #$01 ;clear display STA LCD0 JSR LCDBUSY LDA #$80 ;DDRAM address set: $00 STA LCD0 JSR LCDBUSY RTS LINITMSG fcs "LCD init done. " .byte $00 ; *** Memory test MEMMSG1 fcs "Memory test... " .byte $00 MEMMSG2 fcs "OK" .byte $00 MEMMSG3 fcs "fail at $" .byte $00 MEMTEST LDX #$01 ;X=high byte LDY #$FF ;Y=low byte LDA #MEMMSG1 ;print message STA MSGBASE LDA #MEMMSG1/256 STA MSGBASE+1 JSR LCDSTRING MEMLOOP INY BNE MEMTST INX CPX #$80 ;reached $8000? no more RAM... BNE MEMTST LDA #$00 ;turn all LEDs off STA LEDPORT LDA #MEMMSG2 ;print 'OK' STA MSGBASE LDA #MEMMSG2/256 STA MSGBASE+1 JSR LCDSTRING RTS MEMTST STX $0001 STX LEDPORT ;display high byte on LEDs LDA #$FF STA ($0000),Y CMP ($0000),Y BNE MEMFAIL LDA #$00 STA ($0000),Y CMP ($0000),Y BNE MEMFAIL JMP MEMLOOP MEMFAIL STY $0000 ;store high (x) and low (y) bytes of fail address STX $0001 LDA #MEMMSG3 ;print 'fail at $' STA MSGBASE LDA #MEMMSG3/256 STA MSGBASE+1 JSR LCDSTRING LDA $0001 ;print high byte JSR LCDHEX LDA $0000 ;print low byte JSR LCDHEX MEMFAI1 LDA $0001 ;display high byte on leds STA LEDPORT JSR DLY00 LDA $0000 ;display low byte on leds STA LEDPORT JSR DLY00 JSR KEYSCAN ;check for keypress LDA KEYNEW BEQ MEMFAI1 RTS ; *** Wait for LCD busy bit to clear LCDBUSY PHA LCDBUSY0 LDA LCD0 ;read from LCD register 0 AND #$80 ;check bit 7 (busy) BNE LCDBUSY0 PLA RTS ; *** Print character on LCD LCDPRINT STA LCD1 JSR LCDBUSY LDA LCD0 ;get current DDRAM address AND #$7F CMP #$14 ;wrap from pos $13 (line 1 char 20)... BNE LCDPRINT0 LDA #$C0 ;...to $40 (line 2 char 1) STA LCD0 JSR LCDBUSY LCDPRINT0 RTS ; *** Print 2 digit hex number on LCD LCDHEX PHA LSR LSR LSR LSR ORA #$30 JSR LCDPRINT PLA PHA AND #$0F JSR LCDPRINT PLA RTS ; *** Print string on LCD LCDSTRING PHA ;save A, Y to stack TYA PHA LDY #$00 LCDSTR0 LDA (MSGBASE),Y BEQ LCDSTR1 JSR LCDPRINT INY BNE LCDSTR0 LCDSTR1 PLA ;restore A, Y TAY PLA RTS ; *** Send byte on RS232 interface TXBYTE PHA LDA #$50 ;retry counter TAY TXBYT1 LDA ASTS AND #$10 ;trasmit register empty? BNE TXOUT ;yes, output byte DEY BNE TXBYT1 ;try again BEQ TXFAIL TXOUT PLA STA ATXD LDA #$00 ;return 0 for success RTS TXFAIL PLA ;transmit failed, return byte RTS ; *** Keypad matrix scanning routine KEYSCAN LDA KEYNEW BEQ KEYSCAN1 ;only continue if key press flag is cleared RTS KEYSCAN1 LDA #$EF ;init variables STA KEYCOL LDA #$04 STA KEYCOLN NEXTCOL DEC KEYCOLN ;next column LDA KEYCOLN CMP #$FF BNE TESTCOL RTS TESTCOL LSR KEYCOL ;rotate column-test bit pattern LDA KEYCOL STA KEYPORT LDA KEYPORT AND #$F0 ;select top 4 bits from port (rows) EOR #$F0 ;invert top 4 bits BEQ NEXTCOL ;no keys pressed in this column STA KEYROW AND #$10 ;test row 0 BEQ KEYROW1 LDA #$00 JMP KEYCODE KEYROW1 LDA KEYROW AND #$20 ;test row 1 BEQ KEYROW2 LDA #$04 JMP KEYCODE KEYROW2 LDA KEYROW AND #$40 ;test row 2 BEQ KEYROW3 LDA #$08 JMP KEYCODE KEYROW3 LDA #$0C ;must be row 3 KEYCODE CLC ADC KEYCOLN TAX LDA KEYTAB,X STA KEYVAL INC KEYNEW DEBOUNCE LDA KEYPORT AND #$F0 EOR #$F0 BNE DEBOUNCE RTS KEYTAB .byte $0C, $0B, $00, $0A ;scancode to key value table .byte $0D, $09, $08, $07 .byte $0E, $06, $05, $04 .byte $0F, $03, $02, $01 ; *** Delay routines DLY00 LDX #$80 LDY #$00 DLY00A DEY BNE DLY00A DEX BNE DLY00A RTS DLY01 LDY #$00 DLY01A DEY BNE DLY01A RTS ; *** Reset, NMI & IRQ vectors ORG $FFFA .word IRQSRV ;FIXME: should be NMI service routine .word RESET .word IRQSRV .end