6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Apr 27, 2024 7:49 pm

All times are UTC




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sat Sep 23, 2023 12:56 pm 
Offline

Joined: Sun Sep 19, 2021 11:21 am
Posts: 23
Hi all.

As per my last post (http://forum.6502.org/viewtopic.php?f=2&t=7750) I have a working system from a hardware perspective. I'm now concentrating on software and learning to extend Wozmon, understand how it works and use that knowledge to roll my own monitor. Ironing out the wrinkles is where I'm at currently, and I'm so grateful for the assistance with my LCD initialisation problem - that's one off my list of wrinkles!
My SBC specs are a 65C02 running at 3.6864Mhz with a 1x65C22 VIA and a 65C51. 16 kB of RAM and 32 kB ROM. The UART is connected via an FTDI to USB and I communicate through /dev/ttyUSB0 on my Linux box using minicom. The 65C51 is fed from the system oscillator at 3.6864Mhz.

One of the major milestones in my build (any build?) was being able to transfer a program from PC over serial to the SBC. I suppose there are lots of ways to do this. The way I have adopted it to develop my own "toolchain" of shell scripts and python apps that will assemble my source code, output a Motorola S19 format, process that S19 into a Wozmon friendly format and, finally, upload to the SBC.

Whilst this works, it is not without its wrinkles. In his YouTube videos, Ben Eater does something similar where he post-processed assembler output into a format identical to how one would type it into Wozman. However, when I did that and pasted into the terminal (like Ben did), it goes wrong - it is as if there's a "traffic jam" of characters.
For example, pasting a line like this...
Code:
0400:A0 00 20 15 FF C9 1B F0 F7 C9 08 F0 15 99 40 02 20 18 FF C9 0D F0 15 C8 10 E8 88 A9 08 20 18 FF
Becomes...
Code:
0400A0 0 0 1 F C91BF0 7 C 0 F01599 0 2 2 1 FFC9 D 0 1 C 10E888 9 0 2 18FF
The way I got around this was writing a python app to do the uploading instead which included delays - snippet here...
Code:
for line in data:
    for c in line:
        sbc.write(c.encode('utf-8'))
        time.sleep(0.001) # wait between sending characters.
    sbc.write(b'\x0D')    # send a CR at the end of each line.
    time.sleep(0.01)      # wait a bit longer between sending lines.
Introducing a 1ms delay between sending characters and a further 10ms after sending a CR does the trick. But why does this happen?
Is it because there is no flow control? Should I hook up RTS/CTS? (I don't know how, BTW!). The 65C51 datasheet shows the baudrates for a 1.8432Mhz oscillator. As I am at 2x this, I understand that when selecting 19200, I am actually running at 38400. That's what minicom is set to and there is no problem in communicating with my SBC ordinarily. It's just when I attempt to push a lot of data at it.
Is RTS/CTS the answer? Is there a lot of software required to make that work? Do I leave well alone? Maybe rewrite/extend Wozmon to turn off echo when uploading?
I can't help but think I'm not the first to have come across this problem.
As ever, any pointers most welcome.

Thanks in advance.

Dave


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 1:52 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
The issue is probably that your 6502 code is not ready for the next character. How is the code written, are you polling for characters and then processing them? How much work do you do in between characters? You can calculate how many CPU cycles you can spend before the next character would be lost.

Or if you're using interrupts, make sure the ISR exits quickly enough and doesn't get caught up doing longer term processing.

Flow control will only really help if you have either a hardware or software buffer, as it doesn't immediately stop the flow. You need a buffer so that you can trigger flow control when the buffer is nearly full and still have a bit of space left to receive the last few characters before the sender notices your flow control signal (whether that's hardware or software flow control).

I believe the 65C51 doesn't have an internal FIFO, so no hardware buffering, but newer alternatives do. You can still implement a software buffer if you use interrupts to receive characters - the interrupt handler puts them in the buffer and can enable/disable flow control based on how full the buffer is.

Edit: by the way, rough calculation - 1000000/38400 is about 26us per bit, so about 260us per 10-bit frame for an 8N1 byte. At 3.6MHz that's nearly 1000 cycles per bit that you could spend - quite a lot. Maybe you are waiting for low speed hardware though, which would burn a lot of cycles. There's no free lunch, you need to not try to do more work between bytes than there is time available.


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 2:06 pm 
Offline

Joined: Mon Jan 19, 2004 12:49 pm
Posts: 660
Location: Potsdam, DE
Flow control or not: the FTDI uart adaptor behaves in such a way that it queues characters and sends them in a rush unless it's explicitly told otherwise - I think it sends them eight at a time. With a tool like Bray's Terminal you can send single characters with a delay between them; I suspect it does it by flushing the output buffer between each character.

Neil


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 2:31 pm 
Offline

Joined: Fri Dec 21, 2018 1:05 am
Posts: 1076
Location: Albuquerque NM USA
I would definitely turn off echo when uploading.
Bill


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 2:34 pm 
Offline

Joined: Sun Sep 19, 2021 11:21 am
Posts: 23
gfoot: I did think about that. I'm aware of the 65C51 Tx bug, but as I'm concentrating on Rx, I thought that the code that Ben Eater used and incorporated into his modifications for Wozmon to get data from the 65C61 was the fastest it could be (constantly polling)...
Code:
acia_getchar:
                ; A modified. X & Y preserved.
                LDA     ACIA_STATUS               ; Check status.
                AND     #$08                      ; Character ready?
                BEQ     acia_getchar              ; Loop until ready.
                LDA     ACIA_DATA                 ; Load character.
                RTS   

From there, at 38400 baud and an 8N1 setting, I reasoned one character sent would take 10 bits/38400 bits/second seconds i.e. 260us. With a 65C02 clocked at 3.6864Mhz, that equates to 958 cycles. Using an average of 4 cycles per instruction would give around 240 instructions per character. How many does Wozman require? Using the Kowalski 6502 Simulator, only 57 cycles (around 15 instructions) are required between ACIA reads and storing in the text input buffer.
My (potentially incorrect) reading of Wozmon is that it waits for a CR (i.e. reading a line into a buffer) before doing any processing. Hence, I didn't see a timing problem.

barnacle: That's an interesting lead. I'll research that.


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 3:08 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3346
Location: Ontario, Canada
DRG wrote:
the fastest it could be (constantly polling)...
Yup -- polling is fast. FWIW, this trifling mod will tighten the loop, on average resulting in even less delay.

Code:
acia_getchar:
                ; A modified. X & Y preserved.
                LDA     #$08               ; bit mask
            L1: BIT     ACIA_STATUS        ; Character ready?
                BEQ     L1                 ; Loop until ready.
                LDA     ACIA_DATA          ; Load character.
                RTS   

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 3:18 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1681
Location: Sacramento, CA
Dave,

My SBC's Monitor was loosely based on the Apple 2 monitor (Woz Monitor). Whenever I fed it characters via a serial text transfer, I used a 1ms character delay and 10ms line delay in the terminal software. This gave the monitor time to process the input line. The big issue for me was allowing enough time at the end of line (CR) for the monitor to process the input line and be ready for the next line. In other words, it was not a UART overrun, but a Monitor overrun.

Hope this helps!
Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 3:30 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
For my system to transfer code to the 6502 I use a custom Python program to manage the link, and can do my own handshaking to avoid this sort of thing - it can then run at the full link speed without any other flow control. My receiving code is also custom and optimised for this transfer, very tight with just a simple checksum-like calculation.

But even with an unmodified Wozmon you could presumably still make a sending program that waits for the next prompt after sending each line - maybe you'd still need character delays as Daryl said though.


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 3:40 pm 
Offline

Joined: Sun Sep 19, 2021 11:21 am
Posts: 23
Thanks everyone for your input. It's really improving my understanding of the problem which, necessarily, is the only way I'll arrive at a solution. It's what I like about this forum - the "teach a man to fish" approach. :)
I was searching the forum and found this post -> http://forum.6502.org/viewtopic.php?f=4&t=7594&start=15#p101420. I'm going to look for this article of Garth's so I can potentially write an interrupt driven receive and implement a software 256 byte FIFO.

Daryl: This was the conclusion I was zeroing in on too - which was 180 degrees from my initial thinking. :roll:

gfoot: I'm going to have a think about how to incorporate an upload command into my Wozmon based monitor that turns echo off. Or maybe just write a separate 6502 routine for reading in programs. How do you do it? ASCII code or binary? Is your python software online somewhere to look at?


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 4:47 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
DRG wrote:
gfoot: I'm going to have a think about how to incorporate an upload command into my Wozmon based monitor that turns echo off. Or maybe just write a separate 6502 routine for reading in programs. How do you do it? ASCII code or binary? Is your python software online somewhere to look at?

I haven't shared them before so they might be a bit raw as they were a means to an end, but I've attached them here. It's a binary protocol initially that switches into a two-way interactive mode after the code is executed. The protocol only has three commands - set address, load a page of code at the preloaded address, and execute from the preloaded address. There's some error checking of each command, but not much in the way of recovery, and it would be possible to make it much more resilient. It's written for my own serial device, not the 65C51, but the interface is very similar to the 65C51 so should be familiar.


Attachments:
File comment: Host-side server code
serialserver.py.txt [3.09 KiB]
Downloaded 55 times
File comment: 6502-side ROM source
boot64.s [1.81 KiB]
Downloaded 58 times
Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 7:18 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Echo shouldn't be a concern if the Tx and Rx sides of the UART are running at the same speed. You're just polling for data ready, reading from the Rx latch, then writing that same data straight back into the Tx latch. Provided the echo is the only output, there should be no Tx overrun problem, despite the Tx status bug on the W65C51, and it's a matter of probably one extra 6502 instruction which is unlikely to be the final straw for performance.

The newer and more sophisticated UARTs usually have both a reasonably sized FIFO for both Tx and Rx buffers, and selectable automatic control and recognition of RTS/CTS for flow control. It would be reasonable to set it to trigger at the half-full mark of the Rx FIFO, allowing for some delay in recognition by the sender. The Intel "PC type" UARTs however have the FIFOs but not the automatic flow control; it is the sender's responsibility to check the handshake signal before transmitting. Something like the 28L92 or Z83C50 would be a better choice, if you can find them.

To eliminate processing delay as the cause of trouble, you could select a slower speed such as 9600 baud. This would give your routines four times as long to turn things around.


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 23, 2023 7:42 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
DRG wrote:
I'm going to look for this article of Garth's so I can potentially write an interrupt driven receive and implement a software 256 byte FIFO.

The 6502 Interrupts Primer?  The part specific to writing the code for a receive buffer is at http://wilsonminesco.com/6502interrupts/#3.1 .  I feed the workbench computer from different computers, different OSs, and have never had a problem.

_________________
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?


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 23, 2024 3:14 am 
Offline

Joined: Sun Feb 22, 2004 9:01 pm
Posts: 78
I've been looking through the 6551 documentation due to it being used on the BenEater SBC, with it's notorious TxRDY hardware bug. Universally, the work-around for TxRDY not working is a software delay to just do nothing until any data that may be in the Tx register will have gone out.

That seems so clunky to me. It means that there s a fixed delay every time a byte is sent, regardless of how much time the rest of the code may have used up in which that byte might already have been sent. I've been reading the datasheets on and off over a few weeks and wondering if a hardware fix could be finagled.

There are three status input lines to the 6551: CTS, DSR, DCD. The majority of simple serial applications only use CTS, so that leaves DSR and DCD as generic input pins that can be read by the driver code. Checking the datasheet they do not modify any functionality of the ACIA, they just control bits in the status register. So, would there be some way of wiring TxD out back into DSR or DCD in, and the driver code monitor DSR or DCD for the TxD line being idle? My thought is that it would also have to include the CTS line as that is not visible to the software.

There's always a start bit of the opposite sense to line idle, and a maximum of 9 bitlengths to be sure it's gone back to idle, and isn't just START,1,1,1,1... BenEater has done a similar concept of monitoring a data line for idle with a PS2 keyboard interface, so the concept looks initially workable. Has anybody ever looked into this?

Something like:
Code:
   |
TxD+-----+---->-
   |     |
DSR+--<--+
   |
DCD+--<--+
   |     |
CTS+--<--+----<-
   |     
and the driver code does something along the lines of:
Code:
wait:
LDA aciaStatus
AND #%01100000 ; DCD and DSR
BNE wait
AND #%01000000 ; DSR
; something to ensure idle for 9 bits
BNE wait
STX aciaData

_________________
--
JGH - http://mdfs.net


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 23, 2024 3:44 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
jgharston wrote:
I've been looking through the 6551 documentation due to it being used on the BenEater SBC, with its notorious TxRDY hardware bug.

Note that that bug is only in WDC's 65c51.  No others have it.

Quote:
Universally, the work-around for TxRDY not working is a software delay to just do nothing until any data that may be in the Tx register will have gone out.

That seems so clunky to me.

In the 6502-oriented RS-232 primer, there are other workarouds, about 1/3 of the way down the page.  They're also near the bottom of the I/O ICs page of the 6502 primer, with an added short paragraph about multitasking and using a timer so you can avoid the do-nothing delay loop and have the computer do something useful while the byte is being shifted out the ACIA instead of twiddling its thumbs for the duration.

As for the ideas you present, they're interesting, but I think the hardware complexity would justify going to a different UART or just using one of the workarounds presented in the articles linked above.

_________________
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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 25, 2024 7:55 pm 
Offline

Joined: Sun Feb 22, 2004 9:01 pm
Posts: 78
GARTHWILSON wrote:
As for the ideas you present, they're interesting, but I think the hardware complexity would justify going to a different UART or just using one of the workarounds presented in the articles linked above.

Well, I would use different hardware if I could, but the BenEater uses a 6551, so the 6551 is what is used. My personal preference is the 6850.

_________________
--
JGH - http://mdfs.net


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

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