1Mhz 6502 bitbang 57kbaud

Programming the 6502 microprocessor and its relatives in assembly and other languages.
syscall
Posts: 12
Joined: 26 Mar 2010

1Mhz 6502 bitbang 57kbaud

Post by syscall »

Hey,

I'm doing a software serial routines for a 1Mhz 65xx device that needs to communicate at 57600 bit/s. But my receive code does not work.

57600 gives 17 cycles per bit.

Data comes in negated and it comes in on portb's D6. Protocol is
Startbit-Databits-Stopbit (8N1)
#cycle is a macro that inserts n cycles of code (not touching registers, flags may be touched) and .rept is a repeating macro.

Here's the code. Resulting byte should be in A. Bit sampling is always at 17 cycle interval (or so I believe)

Anyone can see where I've gone wrong?

Code: Select all

readbyte               bit     portb           ; data comes in on portb.6
                       bvc     readbyte     ; startbit?

                       #cycle #25              ; wait ~ 1,5 bit time

                       .rept 8  ;read the bits 

                       bit     portb
                       bvc     ?bt1
                       clc
                       ror     @
                       bvs     ?nx
?bt1                   sec
                       ror     @

                       #cycle #3
?nx
                       #cycle #4
                      .endr

                       rts
Any hints would be appreciated.
Cheers
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post by 8BIT »

Can you give some samples, i.e.:

expect $41 but get $28

Try sending A,B,D,H which are $41,$42,$44,$48.

That will help decode the bit manipulation that's going on.

Daryl
syscall
Posts: 12
Joined: 26 Mar 2010

Post by syscall »

Hi Daryl,

Thanks for reply. Here's the bytes.

sent: 0x41
rcvd: 0x00

sent: 0x42
rcvd: 0x80

sent: 0x44
rcvd: 0x00

sent: 0x48
rcvd: 0x80
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

Do you get the same result every time?  Are there interrupts that could be cutting in on your cycle count?  What is being done with each byte as it comes in, and is that action quick enough to get back to being ready for the next byte coming in?  I see you're doing a JSR-RTS for each byte.  That alone takes most of the time of a stop bit, leaving you with almost no time to store one received byte in an array and get back to watching for the start bit of the next byte.  17 cycles is a little off, but not really enough to cause problems.  If it were, then since you're straightlining it, you could vary the delays a little bit from one bit to the next so the error would not accumulate.  Edit: I meant to add:  Do any branches cross page boundaries?  That adds another cycle too.

A 6551 adds parts but sure makes it easier for the computer to do other things in the background at the same time.  Although it won't do that bit rate from the internal clock generated from the 1.8432MHz crystal, it is able to go much faster than that with an external clock source, like a 6522's PB7 set up to toggle automatically on each T1 timeout with a free-running T1.
Last edited by GARTHWILSON on Sun Feb 12, 2012 1:55 am, edited 1 time in total.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
User avatar
Dr Jefyll
Posts: 3525
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Post by Dr Jefyll »

It looks to me as if

Code: Select all

                       #cycle #3 
should be

Code: Select all

                       #cycle #2 
-- Jeff
leeeeee
In Memoriam
Posts: 347
Joined: 30 Aug 2002
Location: UK
Contact:

Post by leeeeee »

I make the two paths through the macro one cycle different.

Also, depending on exactly when the start bit starts, you could already be 3 to 7 cycles into the bit before you get to #cycle #25 and then another 3 or 4 cycles before the bit instruction in the macro tests the port again.

Lee.
syscall
Posts: 12
Joined: 26 Mar 2010

Post by syscall »

Thanks for the replies...

Garth: There's no concern about jsr/rts because this does not even happen. I send the bytes through the terminal from the keyboard. One at a time.
So the routine waits for my byte forever, reads it bit by bit when it comes and exits. then again waits for the byte, I send the byte etc. This isn't real stream of bytes at the moment. Just one byte. then another.
Also I made sure bvc and bvs branches do not cross pages.
No interrupts as well.

DrJefyll: Did you count the loops right? bxx branches take 2 or 3 cycles depending on taken/not taken condition. #3 cycle seems right to me. But please elaborate,perhaps I'm missing something.

leeeeee: that's a good point. I'll try to account for that.
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

You could replace the bit setting code with a straight sequence, like

Code: Select all

lda portb           ; Fetch inverted signal into A
eor #$40
asl a               ; Shift bit into C
asl a
ror @               ; And into result byte
Might make the timing easier to calculate.
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
User avatar
Dr Jefyll
Posts: 3525
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: 1Mhz 6502 bitbang 57kbaud

Post by Dr Jefyll »

These are all good points that've been made. There are a few details I'd like to clarify.
Regarding the instruction

Code: Select all

                       bit     portb           ; data comes in on portb.6
...I assume Absolute addressing mode is used -- that the IO port is not located in Zero Page. In other words the instruction consumes 4 cycles (not 3) -- is that right?

Also, I'm a little uncertain about

Code: Select all

                       ror     @
Are you RORing the Accumulator or a memory location? If memory, is the addressing mode Absolute or Zero-Page? I will use the assumption it's the Accumulator. (I think Bitwise assumes it's memory, which also would work. (And I like his branch-less approach!)


As for timing with your original routine, I've marked below the cycle counts for both paths:

Code: Select all

readbyte               bit     portb           ; data comes in on portb.6
                       bvc     readbyte     ; startbit?

                       #cycle #25              ; wait ~ 1,5 bit time

                       .rept 8  ;read the bits 

         4  4          bit     portb
         3  2          bvc     ?bt1
         -  2          clc
         -  2          ror     @
         -  3          bvs     ?nx
?bt1     2  -          sec
         2  -          ror     @

         3  -          #cycle #3          ;<---- ???
?nx
         4  4          #cycle #4
                      .endr

                       rts
If you add up the totals you'll see they differ by one cycle -- hence my suggestion to change #cycle #3 to #cycle #2.


Following up on leeeeee's second point, I'd suggest that

Code: Select all

                       #cycle #25              ; wait ~ 1,5 bit time
be changed to

Code: Select all

                       #cycle #16              ; wait ~ 1,5 bit time minus 9~
Waiting for the Start Bit is an uncertain business. By the time the code notices it's arrived, up to 6 cycles may already have elapsed. I don't know any perfect way to deal with that -- I would simply average that uncertainty for a "typical" figure of 3. Then add the final (successful) test for the Start Bit, which consumes 4~ for bit portb and 2~ for bvc readbyte. That brings us up to 9 cycles. Add #cycle #16 and you get 25 -- the 1.5 bit-times you wanted.

cheers,

Jeff
User avatar
Arlet
Posts: 2353
Joined: 16 Nov 2010
Location: Gouda, The Netherlands
Contact:

Post by Arlet »

Code: Select all

lda portb           ; Fetch inverted signal into A
eor #$40
asl a               ; Shift bit into C
asl a
ror @               ; And into result byte
You could also leave out the eor #$40, and invert the byte at the end.
syscall
Posts: 12
Joined: 26 Mar 2010

Post by syscall »

Thank you all...

Dr Jefyll: ror @ is accumulator. portb is absolute on non-zero page. your assumptions were ok. The missing cycle is also correct.
Thanks.

BTW, i've managed to do it with branchless approach as BitWise suggested, and used the Alert's tip. It works now for single bytes.
Now I need to throw it into a tight loop of reading N bytes.
But that's easier.

Code: Select all

; pom is a zpage 1 byte variable

?r              bit     portb   
                bvc     ?r              

                #cycle #15

                .rept 8

                lda     portb   ;4
                asl     @       ;2
                asl     @       ;2
                ror     pom     ;5
                #cycle #4
                .endr
                lda     pom
                eor     #$ff
                rts
cheers
bogax
Posts: 250
Joined: 18 Nov 2003

Re: 1Mhz 6502 bitbang 57kbaud

Post by bogax »

Dr Jefyll wrote:
Waiting for the Start Bit is an uncertain business. By the time the code notices it's arrived, up to 6 cycles may already have elapsed.
Shouldn't that be 7 cycles (the branch would have been taken on the previous pass)?
User avatar
Dr Jefyll
Posts: 3525
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: 1Mhz 6502 bitbang 57kbaud

Post by Dr Jefyll »

bogax wrote:
Shouldn't that be 7 cycles (the branch would have been taken on the previous pass)?
Thanks, Bogax. Yes, certainly each unsuccessful iteration takes 7 cycles total -- I don't have an issue with that. But for the maximum resulting delay I got six by thinking, "there's the bus cycle during which the port reads false -- and we count the six cycles it takes to loop around and try again." Silly me -- that's incorrect. The deadline or decision point is of infinitesimal duration; it doesn't occupy a complete bus cycle. :oops:

Therefore the time before the Start Bit is recognized ranges from virtually 0~ to virtually 7~, for a typical delay of 3.5. For our calculations we can round that up to 4~ or down to 3~. If we're being fussy, the choice to round up or down should be aimed at canceling whatever other fractional-cycle timing error we can identify. For example we're using 25~ to represent 1.5 bit-times, when in fact 1.5 * 17 = 25.5 cycles. Since 25.5 got rounded down to 25 (an error of -0.5), 3.5 should get rounded up to 4 (for a complementary error of +0.5).

-- Jeff
leeeeee
In Memoriam
Posts: 347
Joined: 30 Aug 2002
Location: UK
Contact:

Post by leeeeee »

I would suggest the following changes ..

Code: Select all

; pom is a zpage 1 byte variable

?r              bit     portb
                bvc     ?r

                #cycle #11

                .rept 8

                #cycle #4
                lda     portb   ;4
                asl     @       ;2
                asl     @       ;2
                ror     pom     ;5
                .endr

                lda     pom
                eor     #$ff
                rts
That will give you four extra cycles to do something with the byte once you have it.

Lee.
bogax
Posts: 250
Joined: 18 Nov 2003

Post by bogax »

Following on Leeeeee's suggestion.

IFF bit 6 is the only thing changing on the port you might be able to
do this:

Code: Select all

?r              bit     portb 
                bvc     ?r 

                #cycle #8

                .rept 7 

                #cycle #5 
                eor     portb   ;4 
                ora     #$40    ;2 
                eor     portb   ;4 
                ror     @       ;2 
                .endr 

                #cycle #5 
                eor     portb   ;4 
                ora     #$40    ;2 
                eor     portb   ;4 
                rol     @       ;2 

                rts
However it spreads the port read out over 6 cycles and reduces
the margin for jitter/misalignment
Post Reply