POC VERSION TWO
Re: POC VERSION TWO
BigDumbDinosaur wrote:
Note the trusty screwdriver next to the one logic probe. 
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: POC VERSION TWO
GaBuZoMeu wrote:
as well as the (always handy) DB-25-LED-Indicator - something I want to build in a DB-9 variant for years, but so far I still haven't

It seems awfully expensive to me at $59 but maybe you can find a cheaper one. You can build one for less, but you have to consider the value of your time as well.
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?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: POC VERSION TWO
GARTHWILSON wrote:
GaBuZoMeu wrote:
as well as the (always handy) DB-25-LED-Indicator - something I want to build in a DB-9 variant for years, but so far I still haven't
It seems awfully expensive to me at $59 but maybe you can find a cheaper one. You can build one for less, but you have to consider the value of your time as well.
As far as building one goes, I wouldn't bother, as they aren't that expensive. My time is more valuable to me these days than reasonable amounts of money, if you get my drift.
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: POC VERSION TWO
BigDumbDinosaur wrote:
My time is more valuable to me these days than reasonable amounts of money, if you get my drift. 
Re: POC VERSION TWO
Nowadays, all my boards have a 3 pin Molex connector with GND/RX/TX on 3.3V levels.
Last edited by Arlet on Thu May 11, 2017 8:06 pm, edited 1 time in total.
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: POC VERSION TWO
Arlet wrote:
Nowadays, all my boards have a 3 pin Molex connector with GND/RX/TX on 3.3V levels. This connects to a matching cable with USB converter. Saves me from having to put a bunch of components on the board, including bulky DB9 connector.
x86? We ain't got no x86. We don't NEED no stinking x86!
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: POC VERSION TWO, Revision One
BigDumbDinosaur wrote:
As I earlier posted, I slept on the PCB design for revsion 1 and decided I could do a better job of compacting the layout...I may make some further changes to the board layout, but I think this is substantially like what it will be when it is built.
x86? We ain't got no x86. We don't NEED no stinking x86!
-
EugeneNine
- Posts: 59
- Joined: 01 Nov 2016
Re: POC VERSION TWO
BigDumbDinosaur wrote:
GARTHWILSON wrote:
GaBuZoMeu wrote:
as well as the (always handy) DB-25-LED-Indicator - something I want to build in a DB-9 variant for years, but so far I still haven't
It seems awfully expensive to me at $59 but maybe you can find a cheaper one. You can build one for less, but you have to consider the value of your time as well.
As far as building one goes, I wouldn't bother, as they aren't that expensive. My time is more valuable to me these days than reasonable amounts of money, if you get my drift.
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: POC VERSION TWO
EugeneNine wrote:
in the 90's radio shack upped the price of theirs to unreasonable. I bought two db25's and a plastic shell and a pack of led's and resistors and used paperclips for solid wire between and made my own one evening.
x86? We ain't got no x86. We don't NEED no stinking x86!
-
EugeneNine
- Posts: 59
- Joined: 01 Nov 2016
Re: POC VERSION TWO
BigDumbDinosaur wrote:
EugeneNine wrote:
in the 90's radio shack upped the price of theirs to unreasonable. I bought two db25's and a plastic shell and a pack of led's and resistors and used paperclips for solid wire between and made my own one evening.
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
POC VERSION TWO, Revision One: TIA-232 Driver
BigDumbDinosaur wrote:
BigDumbDinosaur wrote:
As I earlier posted, I slept on the PCB design for revsion 1 and decided I could do a better job of compacting the layout...I may make some further changes to the board layout, but I think this is substantially like what it will be when it is built.
Since POC V1.1 also has a 28L92 and is working hardware, I decided to use it as the guinea pig for testing my new-and-improved driver. The first step was to figure how to arrange for vQUART register access using a simple, zero-based channel index—channel A's index would be 0, channel B's would be 1, and so forth. It was soon patent that a direct page pointer table would work well in this application, the table arranged so some basic indexing could select the correct register in the correct DUART, as well as the location in RAM (the "circular FIFOs," aka "CFIFOs") into which incoming data would be stored and from which outgoing data would be retrieved.¹
A little thought suggested that the pointer table be organized into a "register table" for accessing the vQUART and a "CFIFO table" for accessing the CFIFOs. Here's what the register table looks like as implemented in POC V1.1's firmware:
Code: Select all
02315 000E tiasr =tdsecct+s_tdcnt ;UART channel status
02316 0012 tiacr =tiasr+s_nxpchp ;UART channel command
02317 0016 tiafif =tiacr+s_nxpchp ;UART channel FIFO
02318 001A tiaisr =tiafif+s_nxpchp ;UART IRQ statusDuring POST, these pointers are loaded from a static data table that contains a list of DUART register absolute addresses. For example, location TIASR points at $D001, which is the status register for channel A of the DUART. Location TIASR+2 points at $D009, which is the status register for channel B of the DUART. In the same vein, TIAFIF points at $D003, which is the communications FIFO for channel A—the register through which incoming data is read and outgoing data is written. TIAFIF+2 points at $D00B, which is the communications FIFO for channel B.
The implementation in POC V2.1 will extend this pattern to account for the second DUART, which is wired to channels C and D. For example, TIASR+4, which is the status register for channel C, will point at $D101 and TIASR+6, which is the status register for channel D, will point at $D109.
The DUART only has one interrupt status register (DISR), which is wired to both channels, as well as to other features in the device, such as the counter/timer. Despite this, two pointers are used to access the DISR, which means TIAISR and TIAISR+2 both point at the DISR at $D005. In the case of POC V2.1 and its twin DUARTs, there will be two DISRs and therefore TIAISR+4 and TIAISR+6 (channels C and D, respectively) will point at the second DUART's DISR, which will be accessible at $D105. As will be seen, this little bit of redundancy makes for more efficient programming in the interrupt service routine part of the TIA-232 driver.
The CFIFO pointer table points to the CFIFOs, of which there are two per DUART channel, one for incoming data and the other for outgoing data. As the name suggests, each CFIFO is a "first-in, first-out" or queue data structure (compare that to a LIFO or "last-in, first-out" structure, which is usually a stack). Each CFIFO has two pointers associated with it, one pointing at where the next datum will be stored (called the "put" pointer) and the other pointing at where in the CFIFO from which the next datum will be retrieved (called the "get" pointer). Although the pointers are 16 bits, only the least significant byte (LSB) is manipulated as the CFIFO is accessed. The LSB simply wraps when the pointer is incremented while pointing at the far end of the CFIFO, which is why the CFIFO is "circular."
Here's what the CFIFO pointer table looks like in POC V1.1's firmware:
Code: Select all
02319 001E tiagetrx =tiaisr+s_nxpchp ;RxD CFIFO 'get'
02320 0022 tiaputrx =tiagetrx+s_nxpchp ;RxD CFIFO 'put'
02321 0026 tiagettx =tiaputrx+s_nxpchp ;TxD CFIFO 'get'
02322 002A tiaputtx =tiagettx+s_nxpchp ;TxD CFIFO 'put'During POST, the CFIFO pointers are initialized with the base addresses of the CFIFOs to which they point. For example, TIAGETRX will be initialized with $CC00 and TIAGETRX+2 will be initialized with $CD00 (each CFIFO is 256 bytes in size in POC V1.1). POST will also initialize the "put" pointers to the same addresses as the corresponding "get" pointers. The "get" pointer is postincremented by the driver when a datum is fetched from the CFIFO. If prior to the fetch operation, the "get" pointer is the same as the "put" pointer the driver will interpret it to mean the CFIFO is empty.
When storing a datum into a CFIFO, the driver will preincrement the "put" pointer and then compare it to the "get" pointer. If the two are equal it is interpreted to mean the CFIFO is full. Code fragments will illustrate this process.
In addition to the above pointer tables, there is a one byte bit field in direct page that is used to track the status of the DUART transmitters:
Code: Select all
02323 002E tiatxst =tiaputtx+s_nxpchp ;TxD status bit fieldIn order to access any DUART register or CFIFO the 65C816's X-register is used to index into the appropriate pointer table. For example, to read the status register of DUART channel B:
Code: Select all
lda #1 ;corresponds to channel B
asl a ;convert index to offset
tax ;.X is the main index register
lda (tiasr,x) ;read channel statusCode: Select all
pha ;protect datum
lda #3 ;corresponds to channel D
asl a ;convert index to offset
tax
pla ;recover datum &...
sta (tiafif,x) ;write to outputThe following code, which is executed when it has been determined that the DUART has interrupted, illustrates how incoming data flow from the DUART is put into the corresponding CFIFOs:
Code: Select all
04184 ;DUART RECEIVER IRQ PROCESSING
04185 ;
04186 E2A5 A0 01 iirq0200 ldy #n_nxpch-1 ;starting channel index
04187 ;
04188 ;
04189 ; start of channel processing loop...
04190 ;
04191 E2A7 98 .0000010 tya ;copy channel index
04192 E2A8 0A asl a ;channel pointer offset
04193 E2A9 AA tax
04194 E2AA A1 1A lda (tiaisr,x) ;get channel IRQ status
04195 E2AC 39 2C F8 and nxprqtab,y ;RxD interrupting?
04196 E2AF F0 1C beq .0000030 ;no, skip this channel
04197 ;
04198 E2B1 A9 40 lda #nxpcresr ;clear an RxD...
04199 E2B3 81 12 sta (tiacr,x) ;overrun error (really bad kludge)
04200 ;
04201 E2B5 A1 0E .0000020 lda (tiasr,x) ;get channel status
04202 E2B7 89 01 bit #nxprxdr ;UART FIFO empty?
04203 E2B9 F0 12 beq .0000030 ;yes, done with channel
04204 ;
04205 E2BB A1 16 lda (tiafif,x) ;load datum from...
04206 E2BD EB xba ;channel & hold it
04208 E2BE B5 22 lda tiaputrx,x ;CFIFO 'put' pointer
04209 E2C0 1A inc a ;bump
04210 E2C1 D5 1E cmp tiagetrx,x ;CFIFO 'get' pointer
04211 E2C3 F0 F0 beq .0000020 ;no room in CFIFO, discard datum
04212 ;
04213 E2C5 EB xba ;expose datum &...
04215 E2C6 81 22 sta (tiaputrx,x) ;store in CFIFO
04216 E2C8 EB xba ;expose adjusted pointer &...
04218 E2C9 95 22 sta tiaputrx,x ;save
04219 E2CB 80 E8 bra .0000020 ;loop
04220 ;
04221 E2CD 88 .0000030 dey ;all channels serviced?
04222 E2CE 10 D7 bpl .0000010 ;no
04223 ;
04224 ; ...end of channel processing loopThe 28L92 has 16-deep receiver FIFOs and is configured to only interrupt if a FIFO is full, or if a datum is in a FIFO and has not been retrieved within 64 bit intervals after its arrival, which is a period of approximately 556 microseconds at 115.2Kbps. This "RxD watchdog" feature is intended to prevent the accumulation of "stale" data in the FIFO, such as might happen if the user only strikes one key. Once it has been determined that the channel's receiver has interrupted, the loop bounded by labels .0000020 (lines 04201-04219, inclusive) repeatedly reads from the FIFO as long as the DUART indicates it has data.
Notice how starting at line 04205, the next datum is fetched from the DUART before the CFIFO pointers are tested to determine if there is room in the CFIFO—the datum will be discarded if there is no room. The alternative method would be to first test the CFIFO pointers and only if the CFIFO has room, read the DUART. The problem with doing so is once the DUART's FIFO has filled with data, subsequent data will be refused and RTS will be deasserted on the receipt of the next start bit. If the remote station fails to immediately respond to RTS an overrun error will occur, which must be cleared in order to resume reception. Hence the DUART is read regardless of whether or not the CFIFO has room. As a precaution, the channel is told to clear the overrun error flag (which sets a bit in the interrupt status register) each time the channel is serviced, an ugly kludge, since overrun errors should be reported to higher level functions.
A similar processing pattern is used to transmit data:
Code: Select all
04228 ;DUART TRANSMITTER IRQ PROCESSING
04229 ;
04230 E2D0 A0 01 iirq0300 ldy #n_nxpch-1 ;starting channel index
04231 ;
04232 ;
04233 ; start of channel processing loop...
04234 ;
04235 E2D2 98 .0000010 tya ;copy channel index
04236 E2D3 0A asl a ;channel pointer offset
04237 E2D4 AA tax
04238 E2D5 A1 1A lda (tiaisr,x) ;get channel IRQ status
04239 E2D7 39 2E F8 and nxptqtab,y ;TxD interrupting?
04240 E2DA F0 1D beq .0000040 ;no, skip this channel
04241 ;
04242 E2DC B5 26 .0000020 lda tiagettx,x ;CFIFO 'get' pointer
04243 E2DE D5 2A cmp tiaputtx,x ;CFIFO 'put' pointer
04244 E2E0 F0 0E beq .0000030 ;nothing to transmit
04245 ;
04246 E2E2 A1 0E lda (tiasr,x) ;get channel status
04247 E2E4 89 04 bit #nxptxdr ;TxD FIFO full?
04248 E2E6 F0 11 beq .0000040 ;yes, done for now
04249 ;
04250 E2E8 A1 26 lda (tiagettx,x) ;read CFIFO &...
04251 E2EA 81 16 sta (tiafif,x) ;write to TxD FIFO
04252 E2EC F6 26 inc tiagettx,x ;bump 'get' pointer
04253 E2EE 80 EC bra .0000020 ;loop
04254 ;
04255 E2F0 A9 08 .0000030 lda #nxpcrtxd ;tell DUART to...
04256 E2F2 81 12 sta (tiacr,x) ;disable transmitter
04257 E2F4 B9 30 F8 lda tiatstab,y ;flag it...
04258 E2F7 04 2E tsb tiatxst ;as well
04259 ;
04260 E2F9 88 .0000040 dey ;all channels serviced?
04261 E2FA 10 D6 bpl .0000010 ;no
04262 ;
04263 ; ...end of channel processing loopAs soon as the transmitter has sent the last datum in its FIFO it will again interrupt. If the corresponding CFIFO is empty the transmitter must be disabled. Otherwise, the system will deadlock, since /IRQ will be continuously held low due to the "transmitter empty" interrupt being asserted. Transmitter shutdown is handled at label .0000030 (line 04255) in two steps. First a command is issued to the channel telling the DUART to disable the transmitter. The command immediately clears the transmitter interrupt, but doesn't actually disable the transmitter until the final datum in the FIFO has been serialized and transmitted. A flag is set in the transmitter status bit field to indicating that the transmitter has been disabled. The data table TIASTAB (line 04257) is a set of masks that is used to select the appropriate bit in the status bit field that is to be manipulated. The TSB instruction is handy for this sort of thing.
In the foreground part of the driver, each submission of a datum for transmission will result in the TIATXST bit field being tested to see if the transmitter is disabled:
Code: Select all
03759 E1D0 B9 30 F8 lda tiatstab,y ;transmitter status bit mask
03760 E1D3 14 2E trb tiatxst ;transmitter enabled?
03761 E1D5 D0 0C bne .enabtxd ;no, must enable itCode: Select all
03782 ; enable transmitter...
03783 ;
03784 E1E3 A9 04 .enabtxd lda #nxpcrtxe
03785 E1E5 81 12 sta (tiacr,x)
03786 E1E7 80 EE bra .doneAll of this code has been tested on POC V1.1 and works as intended. I'm thinking I will be able to port it to POC V2.1's firmware, with the only changes being the number of channels being accessed. All I need are those PCBs...
———————————————————————————————————————————
¹If the discussion of FIFOs in the context of serial I/O processing is mystifying to you I suggest you check out Garth Wilson's serial I/O discussion on his interrupts article page—look here for the RS-232 stuff. Note that his page refers to the CFIFOs as "buffers," which they technically are not (no matter what Wikipedia says).
Last edited by BigDumbDinosaur on Thu Jun 01, 2017 3:46 am, edited 2 times in total.
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: POC VERSION TWO
A very nice piece of code and helpful commented too.
And the kludge isn't that bad. If there is an overrun or some other sort (e.g. parity, missing stopbit) error - the irq handler could only flag an issue and try to process what remains as good as possible. But how to flag, and is there additional code to process that? Usually this depends on what sort of information is received or transmitted. Things would become more and more complex..
The decision to drop that error as well as to drop characters when there is no more buffer space is consequent.
And the kludge isn't that bad. If there is an overrun or some other sort (e.g. parity, missing stopbit) error - the irq handler could only flag an issue and try to process what remains as good as possible. But how to flag, and is there additional code to process that? Usually this depends on what sort of information is received or transmitted. Things would become more and more complex..
The decision to drop that error as well as to drop characters when there is no more buffer space is consequent.
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: POC VERSION TWO
GaBuZoMeu wrote:
A very nice piece of code and helpful commented too.
Quote:
And the kludge isn't that bad. If there is an overrun or some other sort (e.g. parity, missing stopbit) error - the irq handler could only flag an issue and try to process what remains as good as possible. But how to flag, and is there additional code to process that? Usually this depends on what sort of information is received or transmitted. Things would become more and more complex..
The data format is 8-N-1, so a parity error cannot happen. The 28L92 has missing stop bit detection capability, but again, just flags it—the received datum immediately following the missing stop bit will be corrupted. As the UART driver is running in ROM and ROM space in POC V1.1 is at a premium, I elected to forego error checking in the driver itself. The Motorola S-record transfer function does perform error checking on each received record, so corrupted data transfers are not likely to occur.
In any case, a closely-wired setup like what I have (no more than three meters of cable between serial endpoints) is unlikely to encounter transmission errors.
Quote:
Te decision to drop that error as well as to drop characters when there is no more buffer space is consequent.
x86? We ain't got no x86. We don't NEED no stinking x86!
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: POC VERSION TWO, Revision One: TIA-232 Driver
BigDumbDinosaur wrote:
During POST, these pointers are loaded from a static data table that contains a list of DUART register absolute addresses...The CFIFO pointer table points to the CFIFOs, of which there are two per DUART channel...During POST, the CFIFO pointers are initialized with the base addresses of the CFIFOs to which they point.
My first cut of this driver worked that way. Each pass through the interrupt service routine (ISR) loop would use the zero-based channel index to compute the DUART register pointers—the CFIFO pointers were initialized during POST, since their state had to be maintained from one driver access to the next. Computing pointers on the fly was chosen to prove that my methods were viable. However, it was apparent even without doing any cycle counting that the pointer computation that was carried out during each pass through the ISR was eating up quite a bit of processing time. Whether a specific channel was interrupting or not, the pointer to the interrupt status register had to be set up on every pass through the ISR in order to make that determination—the rest of the register pointers were set up once it was known the channel had interrupted.
My second cut of this driver did away with computing the DUART register pointer addresses and instead got them from a data table in ROM. This change reduced "parasitic" processing, but was still using more cycles than I liked. That led me to conclude that a much more efficient driver would be realized by setting up the DUART register pointer tables during POST, in essence exchanging direct page space for a reduction in clock cycles. The result was the driver that is now running on POC V1.1 and will soon (it is hoped) be running on POC V2.1.
Although POC V1.1 was the test-bed for this driver, the real target is POC V2.1, which has a block of RAM that is reserved for the firmware's use. One page of that RAM will be the firmware's private direct page, which will be automatically "mapped in" when an IRQ occurs or a BIOS API function is invoked. This is important in the scheme of things, as a total 50 direct page addresses will be consumed just by the serial I/O routines, with more direct page space earmarked for the SCSI driver and the software clocks. User applications that use the physical zero page as direct page will have all 256 addresses available to them. The 65C816's ability to address direct page anywhere in the first 64KB makes this practical and convenient.
How much of a performance gain did the final driver version achieve over the original version? A worst-case cycle count indicates a three-to-one improvement, which is a significant gain when one considers that POC V2.1 has four serial channels and thus will demand a lot more out of the ISR, especially if all those channels are simultaneously active.
x86? We ain't got no x86. We don't NEED no stinking x86!
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: POC VERSION TWO, Revision One
BigDumbDinosaur wrote:
I made some minor detail changes to some trace routing and have called it a done deal.
x86? We ain't got no x86. We don't NEED no stinking x86!