I think it's a great idea for somebody learning assembly programming to be able to use actual real-world data-sheets for reference, and get a feel for what low-level programming is actually like. On the other hand, the whole reason we want to use an emulator to begin with is because real-world hardware is awkward and inconvenient in many ways, so there are good reasons to not implement every quirk of some piece of hardware. However, if the implemented hardware differs from the behaviour described in the data-sheet, it's good to document that so that people know what to expect.
This issue is about deciding how much actual 6551 behaviour Symon should implement, and then making sure that behaviour is implemented, and the remaining differences are documented.
I've been tinkering with Symon's emulated 6551, examining data-sheets and sample code I found online to figure out how it worked and what was going on. The first issue is that there are several data-sheets online for 6551-related chips, and it wasn't clear which one Symon was trying to match:
The original MOS 6551 data-sheet specifies (on page 7) that the power-on state of the the Command register is $02
, i.e. with the receiver interrupt disabled. The power-on state of the Command register in Symon is $00
, so it can't be emulating an original MOS 6551.
The W65C51N data-sheet documents (on page 9) that due to a design fault, the "Transmitter Data Register Empty" bit in the status register is broken and can't be relied upon, and that seems the kind of behaviour that's more annoying than educational, so I think Symon shoudn't emulate the W65C51N.
By elimination, that means Symon emulates the W65C51S.
Comparing Symon's behaviour to the W65C51S data-sheet, I note the following discrepancies:
- The ACIA exposes the state of the "Data Carrier Detect" and "Data Set Ready" serial-port pins in the status register, and it is supposed to generate an interrupt when either one changes state. However, in Symon the ACIA is permanently wired to the VT100 terminal in the main window, so it is impossible for them to change state
- Wikipedia tells me that for half-duplex communication the local computer should activate the "Ready To Send" pin, and wait for the "Clear To Send" pin to be raised by the remote side before sending. For full-duplex communication, the local computer is assumed to always be ready to send, and the RTS pin means "ready to receive" instead. There are bits in the ACIA command register to activate or deactivate the RTS pin, but both sending and receiving work just fine when it's inactive.
- The ACIA has an internal clock generator that can be configured to a number of different baud-rates, or it can be configured to use an external clock. Symon does not mention that it implements an external clock, so I worried that configuring the ACIA to use it might prevent anything from being transmitted. However, "external clock" mode is special-cased to mean "as fast as possible"
- The ACIA can be configured to send a different number of bits per character. However, Symon always sends 8 bits.
- There's a bit in the Command register that controls the "Data Terminal Ready" serial-port pin. The W65C51S data-sheet documents (on page 12) that it "enables all selected interrupts". The MOS 6551 data-sheet describes that flag as "enable receiver/transmitter". It seems like this should be a master switch for the entire ACIA, but in Symon everything works perfectly regardless of the state of this bit.
- Although bit 1 of the Command register defaults to 0 ("rx interrupts enabled"), the ACIA's power-on state is "rx interrupts disabled", which means the should-be-noop instructions
lda $8802; sta $8802
actually result in rx interrupts being enabled