6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 1:10 pm

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Thu Apr 10, 2014 8:45 am 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
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

_________________
My 6502 related blog: http://www.asciimation.co.nz/bb/category/6502-computer


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 10, 2014 10:53 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
Even if you don't modify X anywhere, the final PLA TAX means that A is identical to X and the processor status has S & Z set according to X. Not saving X & Y would return with A=$00, S=0, Z=1.

Otherwise I don't see any reason why saving X & Y would make a difference unless you are doing some nasty tricks with the stack.

You could try replacing the save/restore X & Y part with a simple TXA at the end causing the same A, S & Z and see if that makes a difference or not.

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 10, 2014 11:28 am 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
Klaus2m5 wrote:
Even if you don't modify X anywhere, the final PLA TAX means that A is identical to X and the processor status has S & Z set according to X. Not saving X & Y would return with A=$00, S=0, Z=1.

Otherwise I don't see any reason why saving X & Y would make a difference unless you are doing some nasty tricks with the stack.

You could try replacing the save/restore X & Y part with a simple TXA at the end causing the same A, S & Z and see if that makes a difference or not.


I tried exactly that and that also works. That's with only the TXA at the end. I need to look at the rest of the code to get my head around what that means but that's a step forward thanks! I do use X a lot in my keyboard scanning routines and have been bitten by this before.

Simon

_________________
My 6502 related blog: http://www.asciimation.co.nz/bb/category/6502-computer


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 10, 2014 5:07 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8509
Location: Midwestern USA
Are you certain that your interrupt handler isn't touch those registers?

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 10, 2014 9:58 pm 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
It could be a subtle timing bug. The pushes & pulls might add delays that make it work. Try replacing them with NOPs that take the same amount of time and see if those have the same effect when included vs excluded. Or, it could be that the presence of those instructions changes where page crossings occur.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 10, 2014 10:05 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
BigDumbDinosaur wrote:
Are you certain that your interrupt handler isn't touch those registers?

Pretty sure. That's all the code for them above. I have a handler for the ACIA interrupt too but I can comment out that code so it's not being hit and that makes no difference.

I did remember I have been caught by this before. I even wrote about it in my own blog! MS Basic uses the X register as it's index into it's input buffer. So messing with that will cause the behaviour I was seeing where it does CRs in weird places. It thinks the buffer is full.

That explains why changing it causes odd behaviour (and in other parts of my code I save/restore X too). But I still don't understand what's changing it in my code though?

Simon

_________________
My 6502 related blog: http://www.asciimation.co.nz/bb/category/6502-computer


Top
 Profile  
Reply with quote  
PostPosted: Fri Apr 11, 2014 7:28 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
Simon wrote:
Klaus2m5 wrote:
Even if you don't modify X anywhere, the final PLA TAX means that A is identical to X and the processor status has S & Z set according to X. Not saving X & Y would return with A=$00, S=0, Z=1.

Otherwise I don't see any reason why saving X & Y would make a difference unless you are doing some nasty tricks with the stack.

You could try replacing the save/restore X & Y part with a simple TXA at the end causing the same A, S & Z and see if that makes a difference or not.


I tried exactly that and that also works. That's with only the TXA at the end. I need to look at the rest of the code to get my head around what that means but that's a step forward thanks! I do use X a lot in my keyboard scanning routines and have been bitten by this before.

Simon


Well, I thought it would be simple to debug after that. So I didn't comment any further...

If a simple TXA can make it work then the X register is not your problem! The content of the A register or the processor status of S & Z on return is causing the bug. That should lead you to look at all JSRs to Send_Char_Screen and the code after the JSR assuming a certain return value in A, S & Z.

It could be a flag based branch on S or Z without the flags beeing modified or the uninitialized accumulator beeing used to perform any logic, arithmetic or compare operation. IF you are trying to pass A & PS from before the JSR, the subroutine needs PHP PHA ... PLA PLP.

Is it really that hard to see?

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Fri Apr 11, 2014 8:12 am 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
Klaus2m5 wrote:
Simon wrote:
Klaus2m5 wrote:
Even if you don't modify X anywhere, the final PLA TAX means that A is identical to X and the processor status has S & Z set according to X. Not saving X & Y would return with A=$00, S=0, Z=1.

Otherwise I don't see any reason why saving X & Y would make a difference unless you are doing some nasty tricks with the stack.

You could try replacing the save/restore X & Y part with a simple TXA at the end causing the same A, S & Z and see if that makes a difference or not.


I tried exactly that and that also works. That's with only the TXA at the end. I need to look at the rest of the code to get my head around what that means but that's a step forward thanks! I do use X a lot in my keyboard scanning routines and have been bitten by this before.

Simon


Well, I thought it would be simple to debug after that. So I didn't comment any further...

If a simple TXA can make it work then the X register is not your problem! The content of the A register or the processor status of S & Z on return is causing the bug. That should lead you to look at all JSRs to Send_Char_Screen and the code after the JSR assuming a certain return value in A, S & Z.

It could be a flag based branch on S or Z without the flags beeing modified or the uninitialized accumulator beeing used to perform any logic, arithmetic or compare operation. IF you are trying to pass A & PS from before the JSR, the subroutine needs PHP PHA ... PLA PLP.

Is it really that hard to see?


It is when I only get a little time now and then to play with this stuff :) Too many (very varied) hobbies so when I do 6502 work there is a lot or re-learning to be done.

You're right about the code needing A after the JSR to the send char routines. The original routine in MS Basic is MONCOUT and that preserves A which it then used after the routine. I've changed my code so this is how it behaves now and is working well.

Thanks!

Simon

_________________
My 6502 related blog: http://www.asciimation.co.nz/bb/category/6502-computer


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: handyandy and 19 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: