6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Sep 29, 2024 7:30 am

All times are UTC




Post new topic Reply to topic  [ 48 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
PostPosted: Mon Nov 04, 2013 10:30 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
BigDumbDinosaur wrote:
Simon wrote:
Ah. I did know about the SEI and had removed it previously. Sometimes I really mess up and revert to a previous version of the code. That version had it back in there. That's that only change one things at a time thing.

The only interrupt I have enabled is the ACIA receive one at the moment. I was going to enable and disable individual interrupts eventually but was cheating here and enabling/disabling them all.

I see what you mean though. I fixed that. I can still break things by really throwing lots of data at it so I have something else going on.

There's no harm in leaving the RxD IRQ enabled at all times. The UART won't interrupt you if there's no datum in the receive buffer.

Also, BITting the status registers might not be a sound programming technique. A BIT instruction counts as read of the status register and hence clears some status bits. You may be inadvertently tossing away information that could be important.

I wondered about that myself. According to the datasheet a read of the status register only clears the interrupt bit.

I think now I actually have the serial side of things working well. I never seem to overflow the circular buffer. And what I get echoed back is exactly right, no errors at all. I made my interrupt routine do what it says in the datasheet. Check the status bit first, then the receive data register full then for errors.

If I keep pasting lines though into the terminal program eventually my machine gets stuck ina loop somehwere and stops polling the keyboard. I think now the problem is somewhere in the code in Basic. If I skip the bit that parses the lines that are being read in the serial side of things works great.

Progress I think. But need to go do something else for a while!

Simon

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


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 05, 2013 12:09 am 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
OK, I found another dumb error that explains why my flow control never worked. I had RTS and CTS wired to the wrong buffers on the MAX232. I had the direction right, just used the wrong drivers.

Simon

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


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 05, 2013 6:02 am 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
I think I should stick to still I am good at like building cars. I just found another silly mistake. I was never initialisating the stack pointer. Oops.

I am making progress though. I have now implemented interrupt driven serial sending and that seems to be working.... mostly.

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


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 05, 2013 12:58 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
Simon wrote:
I think I should stick to still I am good at like building cars. I just found another silly mistake. I was never initialisating the stack pointer. Oops.

I am making progress though. I have now implemented interrupt driven serial sending and that seems to be working.... mostly.

That isn't as fatal on the 6502 as it is on other microprocessors. As long as all of page 1 is mapped to RAM the stack can start at any position and can wrap round the page boundary (from $100 to $1ff). Just as long as your don't exceed 256 bytes of pushes.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 05, 2013 3:07 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
BitWise wrote:
That isn't as fatal on the 6502 as it is on other microprocessors ...

Agreed. WOZMON got away with it, and I believe that it's completely harmless, as long as you don't incorporate any
TOS-relative addressing with "tsx : lda $01xx,X" or use parts of page 1 for other things.

Mike


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 05, 2013 5:30 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
The stack is initialised inside the Basic code actually (in the cold start routine). It does it after some JSRs though.

What I see now is like memory is getting corrupted. It sometimes works but then all kind of odd things happens. Random errors (like syntax errors on non existent lines), garbage characters and complete lockups. Will work it out eventually!

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


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 05, 2013 5:45 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Simon wrote:
...What I see now is like memory is getting corrupted. It sometimes works but then all kind of odd things happens. Random errors (like syntax errors on non existent lines), garbage characters and complete lockups. Will work it out eventually!

I suspect indirect-indexed writing issue (STA ($xx),y) overwriting the 'OS', or power supply noise. Good luck!

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 05, 2013 6:46 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
Interestingly Microsoft Basic has the stack top at $FC not $FF. It seems to use the two bytes after that for something but I haven't worked out what yet inside the STKINI code which gets called on errors.

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


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 06, 2013 8:30 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
Hmm, the issue seems to be something to do with the interrupt handler. I think something happens in there that corrupts memory eventually.

If I don't use interrupt based transmit (instead just poll) then it seems quite stable. Once I enable loading and enable the receive interrupt it will run fine for a while then eventually start going wrong.

If I use transmit interrupts (which happen all the time) it falls over almost immediately.

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


Top
 Profile  
Reply with quote  
PostPosted: Sat Nov 09, 2013 8:15 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
I don't know if anyone if following all this but for the sake of completeness here is where I am up to.

I've done lots of testing the last few days. What I have found is if I send data slow enough everything works fine. I ran a test overnight loading the same code over and over again. That ran 33000 times! And it all worked fine. I stopped loading and actually ran the program fine.

If I up the data rate eventually everything falls over and memory gets corrupted. I tested that by outputting the stack pointer inside my ISR to my debug LEDs. When all is working well you can see the stack point go up and down a little but it's pretty constant. When it all goes wrong it suddenly jumps to a low value.

At first I thought it was the ACIA somehow getting errors then falling over but I can't see any way that the ACIA could affect memory. My ISR does nothing that could affect memory. So now I believe it is the other way around. Memory gets corrupted and then it all goes wrong. I think the ACIA might even be getting written too causing it to go into an odd state which would explain why then everything it receives is an error.

I wrote a test file that I could upload in a loop that sent it hex values from $00 to $FF (except $03 which breaks it out of loading mode) and that also ran fine overnight so I don't think it is some bad byte that Basic sees that breaks it (a few characters are 'special' ones it uses to do certain things).

I also wrote test code that just does ACIA send and receive using the circular buffer and that also works fine. It receives the resends. If I run that flat out I get the odd overflow error but it all still works. A 1mS intercharacter delay gets rid of all errors.

So my thought now is somehow Basic goes wrong when parsing some line of code. Perhaps that line has errors in it due to overrun errors and it's some combination of bytes in that line that makes it all go wrong. How the heck I will work out what that is I don't know!

I know most people would say well, just don't send it data too fast and it's fine but I hate knowing there is a bug in there and not knowing what it is. Even if I know how to avoid it!

Simon

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


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 10, 2013 1:40 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
Simon, am I correct in deducing that your ISR is implemented in BASIC? If so, then it seems to me that you may have reached BASIC's response-time limit (regardless of buffer size), and will have to re-code it to be faster (or just re-do it in assembly). In other words, your ISR could be getting interrupted before it can finish its job properly, and stack overflow would be an expected result in that case. The 'RTI' with a fresh IRQ pending might not be letting BASIC resume itself completely.

You seem to have the ability to fine-tune the transfer rate. Perhaps you could do an experiment by intentionally making your ISR take a bit longer (by sticking in a 'ZZ = SIN(1)' or something), and seeing if BASIC chokes at a lower cps threshold.

Mike

[Edit: Nevermind! I missed your assembly code sample, but somehow kept seeing you mention 'Basic routine'. I think that I need to go to bed early tonight ... it's been a rough day!]


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 10, 2013 2:44 am 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
Sorry, yes it's all in assembler. It's just I am tacking bits onto the original MS Basic. I should take a look at the original Applesoft or OSI or Commodore basics to see how they did their load routines.

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


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 10, 2013 10:49 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
Simon wrote:
So my thought now is somehow Basic goes wrong when parsing some line of code. Perhaps that line has errors in it due to overrun errors and it's some combination of bytes in that line that makes it all go wrong. How the heck I will work out what that is I don't know!

Simon,

I had similar problems when uploading large programs to EhBASIC through the RS232 connection. Not crashing like in your case but corrupting the uploaded program.

With 38400 Baud and 256 bytes of FIFO it would work O.K. if the BASIC program would contain ascending line numbers only and a NEW command was issued prior to upload, so no lines would have to be inserted. Just loading a modified program over an existing one would corrupt some lines. On insertion BASIC has to move all higher numbered lines and needs to rebuild the next line address chain, which may take too much time.

So I played with some modifications to the FIFO. I added x-off/x-on flow control and set the high watermark (x-off) at 192 bytes, the low watermark (x-on) at 128 bytes. That would work O.K. when using the PC's built in serial port, but still not O.K. with a USB to serial converter. USB converters seem to have a higher latency.

Now I changed the watermarks to 128 and 64. Then it would work O.K. over USB with Tera Term but still not with PUTTY. PUTTY seems to have a larger block size and probably requires a larger FIFO.

So it makes a big difference how you feed the beast. Even after flow control stops the other side, it will still send its remaining hardware buffer. If you can't fix it from this side, you need to log what is sent to BASIC in order to make it corrupt memory and then try to find the bad combination of characters causing BASIC to crash. Good luck!

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


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 10, 2013 8:37 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
I have one of those USB to serial things. Never could get it to work! It just says it's not working right (on two different machines now). My PC died a few weeks back and luckily the new MB I got has on board serial so I just broke that out to a DB9 on the back.

I've tried a few other things. I only enabled the interrupt for receiving serial data right at the point it needs a new character. That still has the issue. I tried not echoing anything while receiving and it still breaks.

Basic echoes back what it received and I also tried outputting the last byte received from the ACIA on my output LEDs. It seems random what I get there. Sometimes rubbish and sometimes valid data. I can't trust what is echoed back though since the corruption might be subtle and it's is reporting back bad data for a while before the machine falls over.

The ISR doesn't store any bad bytes in the buffer. That is it only stores the bytes it receives if there was no error reported. My understanding of the datasheet is if an error is detected then the data register isn't updated anyway. It holds the last good byte received.

I can't see any obvious errors in the proceeding lines it has sent. The way MS Basic works is it receives characters into a buffer (which you can't overflow) then once it gets the CRLF it processes the entire line. It echoes characters though as it receives them. A bad line should cause a syntax error just as if you were typing it in manually.

Is it possible though that if characters are missed or garbled I read in a line without a line number and so Basic interprets it as a immediate command? If that command is a Poke and it pokes into random memory that might explain what's happening. So if I send it a program with no pokes in it what happens....

Back in a sec!

EDIT: Back. Nope, still falls over even with this code:

10 REM

I couldn't think of a simpler Basic program that works!

Back to thinking.

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


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 10, 2013 9:18 pm 
Offline

Joined: Mon Apr 16, 2007 6:04 am
Posts: 155
Location: Auckland, New Zealand
OK, more info.

I don't think it's to do with the MS Basic parsing/storing code.

Sending it a file that just contains "10" over and over falls over too although not with total corruption. That command should simply remove line 10 if it's not there. Typing a "10" should never cause an error. If the line isn't there it just returns OK.

Same if I send it "REM" over and over. At slow speeds it works fine. It receives the command, runs it (which just return OK) and keeps going. If I up the speed eventually I get SN ERRORs. That's what I expect if characters are being missed. Eventually though (several seconds) the machine gets corrupted again.

This is my ISR and associated code as it is now. Perhaps someone can see some thing really obvious I am missing? The ACIA rx interrupt is the only one in the system.

Code:
; =============================================================================
; ACIA write buffer.
; =============================================================================

ACIA_Wr_Buffer:
    LDX     acia1_wr_ptr         ; Get the current index.
    STA     acia1_rx_buffer, X   ; Get the pointer value and store the data where it says
    INC     acia1_wr_ptr         ; then increment the pointer for the next write.
    RTS

; =============================================================================
; ACIA read buffer.
; =============================================================================

ACIA_Rd_Buffer:
    TXA                          ; Store X.
    PHA
    LDX     acia1_rd_ptr         ; Ends with A containing the byte just read from buffer.
    LDA     acia1_rx_buffer, X   ; Get the pointer value and read the data it points to.
    STA     acia1_rx_byte        ; Store the data temporarily.
    INC     acia1_rd_ptr         ; Then increment the pointer for the next read.
    PLA                          ; Restore X.
    TAX
    LDA     acia1_rx_byte
    RTS

; =============================================================================
; ACIA buffer difference.
; =============================================================================

ACIA_Buffer_Diff:
    LDA     acia1_wr_ptr        ; Find difference between number of bytes written
    SEC                         ; and how many read.
    SBC     acia1_rd_ptr        ; Ends with A showing the number of bytes left to read.
    RTS

; =============================================================================
; ACIA buffer get character.
; =============================================================================

ACIA_Buffer_Get:     
       
    JSR     ACIA_Buffer_Diff     ; See if there is any serial data.
    BEQ     ACIA_Buffer_None     ; No data so exit.   
    JSR     ACIA_Rd_Buffer       ; There is data so get it.

    JSR     ACIA_Buffer_Diff     ; How many bytes are left to read?
    CMP     #$E0                 ; Is it at least 224?
    BCS     ACIA_Buffer_Get_Done ; If so, leave the sending end turned off.
    LDA     #%00001001           ; Set up N parity/echo off/tx int off/rts low/rx int on/dtr active.
    STA     acia1_cm             ; Write to ACIA command register to re-enable receiving.
   
ACIA_Buffer_Get_Done:
    LDA     acia1_rx_byte        ; Retrieve the data into A.
    SEC                          ; Carry set if character available.
    RTS
ACIA_Buffer_None:
    CLC                          ; Carry clear if no character available.
    RTS   
   
   
; =============================================================================
; ACIA Interrupt.
; =============================================================================

ACIA_Interrupt:
   
    PHA                             ; Store A.   
    TXA                             ; Store X.
    PHA 
    TYA                             ; Store Y.
    PHA 
           
    LDA     acia1_s
    AND     #%00001000              ; Check for the receive data buffer full.
    BEQ     ACIA_Interrupt_Done     ; If empty we are done.
   
    LDA     acia1_s
    AND     #%00000111              ; Check for error conditions (lower 3 bits of status).
    BNE     ACIA_Interrupt_Error    ; If there was any error go report it.
   
    LDA     acia1_d                 ; Get the data from the ACIA.
    STA     IO
    JSR     ACIA_Wr_Buffer          ; Write it to the buffer. 

    JSR     ACIA_Buffer_Diff        ; Now see how full the buffer is.
    CMP     #$F0                    ; If it has less than 240 bytes unread
    BCC     ACIA_Interrupt_Done     ; just exit the ISR here.

    LDA     #%00000001              ; Else, tell the other end to stop sending data before
    STA     acia1_cm                ; Write to ACIA command register to re-enable receiving.
 
    JMP     ACIA_Interrupt_Done
   
ACIA_Interrupt_Error:                 
    ;JSR     SAVE                    ; Go out of load mode.   
         
ACIA_Interrupt_Done:     
    LDA     acia1_d                 ; Read the data register to clear it out.
    PLA                             ; Restore Y.
    TAY           
    PLA                             ; Restore X.
    TAX
    PLA                             ; Restore A.
   
    RTI

; =============================================================================
; ISR
; =============================================================================

ISR:
    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

; =============================================================================

_________________
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  [ 48 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 30 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: