This is a little tricky to explain but I can't see what is going on and am hoping I am missing something really obvious that someone else will point out to me.
I have been upgrading the video in my Orwell machine to use Grant's 80 column ATMega video controller. I made just the video part and tested it by driving it in 4 bit mode from an Arduino. With that working (and it works VERY well thanks Grant!) I modified my machine to drive it using pins on my VIA port B. I use port B for controlling the keyboard scanning too as well as having a piezo hanging off pin 7.
I am using 4 data pins and CB1 and CB2 for the control lines.
This was all working, mostly. The issue I was having was even though the display was working something was getting corrupted and the behaviour on the machine was it was doing CRLFs in odd places. Once past the start up stuff (with one odd CRLF in the startup message) it would do one after every key presses so all I got was syntax errors from MS Basic.
All my output is echoed to the serial port (since my old video output was serial driven). If I commented out the video part but left in the serial output it all worked fine so it was definitely my video driving code. By a long process of elimination I finally worked out it is something to do with the X and Y registers changing. If I save/restore my X and Y around the video outputting code it all works fine. What I don't understand is that code doesn't use X or Y so I don't understand what's changing them.
I am using interrupts to do the control but I only enable the via interrupts inside the video output function and then I effectively block in that function waiting for a flag to change (which happens inside the interrupt handler).
This is where I output character to both serial and video:
Code:
; =============================================================================
; Output a character.
;==============================================================================
MONCOUT:
PHA ; Push the value to send.
STA char_to_send ; Store the character we are sending.
LDA #$80 ; If we are in a flow control condition we can't
AND load_mode ; transmit so don't try sending anything or we
BNE MONCOUT_DONE ; get stuck polling for the transmitter to be free.
LDA #$02 ; If we are in silent load mode don't echo to the screen.
CMP load_mode
BEQ MONCOUT_DONE
PLA ; Pop the value and send it.
JSR Send_Char
JSR Send_Char_Screen ; Send the character to the video output.
RTS
MONCOUT_DONE:
PLA ; Pop the value (even though it was never used if silent).
RTS
This is the actual video outputting code:
Code:
; =============================================================================
; Video send char. Character is in char_to_send.
; =============================================================================
Send_Char_Screen:
TXA ; Preserve X.
PHA
TYA ; Preserve Y.
PHA
LDA char_to_send ; Get the character we are sending.
AND #$F0 ; Get top nibble.
LSR ; Shift one bit to the right.
STA via1_b ; Push it to port B of the VIA.
LDA #%10010000 ; Set up the interrupt for CB1 change.
STA via1_ier ; Write to VIA interrupt enable register.
LDA #%11110000 ; Set up for CB2 high, CB1 interrupt on positive.
STA via1_pcr ; Write to VIA control register.
LDA #$00 ; Set the waiting flag to 0.
STA char_sending
Send_Char_Wait_First_Nib:
LDA char_sending ; Check the char sending flag.
BEQ Send_Char_Wait_First_Nib
LDA char_to_send ; Get the character we are sending.
AND #$0F ; Get bottom nibble.
CLC
ROL ; Shift 3 bits left.
ROL
ROL
STA via1_b ; Push it to port B of the VIA.
LDA #%11000000 ; Set up for CB2 low, CB1 interrupt on negative.
STA via1_pcr ; Write to VIA control register.
LDA #$00 ; Set the waiting flag to 0.
STA char_sending
Send_Char_Wait_Second_Nib:
LDA char_sending ; Check the char sending flag.
BEQ Send_Char_Wait_Second_Nib
LDA #%00000000 ; Turn off all interrupts on VIA.
STA via1_ier ; Write to VIA interrupt enable register.
LDA #$00 ; Clear the port.
STA via1_b
Send_Char_Screen_Done:
PLA ; Restore Y.
TAY
PLA ; Restore X.
TAX
RTS ; Return
And this is my interrupt handling:
Code:
; =============================================================================
; VIA Interrupt.
; =============================================================================
VIA_Interrupt:
PHA ; Store A.
LDA via1_ifr ; Check which interrupt fired.
ASL A
ASL A
ASL A
BMI VIA_Interrupt_CB1
JMP VIA_Interrupt_Done
VIA_Interrupt_CB1:
LDA via1_b ; Read the port to clear the interrupt.
INC char_sending ; Make the flag non zero.
VIA_Interrupt_Done:
PLA ; Restore A.
RTI
; =============================================================================
; ISR
; =============================================================================
ISR:
BIT via1_ifr ; Check 6522 VIA1's status register without loading.
BMI VIA_Interrupt ; Result negative (bit 7 set) so service VIA.
BIT acia1_s ; Check the status register (loads bit 7 into N and bit 6 into V).
BMI ACIA_Interrupt ; Result negative (bit 7 set) so service ACIA.
RTI
; =============================================================================
That code works. If I remove the preserve X and Y code in the send_char_screen code it doesn't. But why? I'm not using X and Y anywhere there?
Simon