Earlier I mentioned that I had encountered a weird bug in my POC unit which seemed to be related to the use of STA $ABS,X to write into the DUART registers. Several here had come close to guessing the possible cause:
BigEd wrote:
It is possible that the extra read access which occurs in the dead cycle is having a side-effect?
You're getting extremely warm.
kc5tja wrote:
He is using a 65816, which while it has all the timing characteristics of a 6502, it makes detecting "internal operation" easier thanks to the VPA and VDA signals. If (VPA,VDA) = internal_operation, then you can inhibit the generation of chip select signals.
Bingo!
Recall I mentioned the watchdog timer (WTD) was working properly using the STA $ABS,X method to load its registers and that the scope confirmed that the WDT was behaving as it should. That started me thinking about the DUART and how it may react to invalid address bus conditions. This prompted me to do some more digging and analysis of the DUART's timing characteristics, which ultimately pointed me to the cause of the problem and the solution.
The DUART is clocked by a 3.6864 MHz signal which, in the POC, is derived from a TTL can oscillator—a crystal could also be used. The DUART clock not only drives the baud rate generator (BRG) and a 32 bit counter/timer (which I am not using), it produces the internal timing signals that regulate the entire device's operation, much as the Ø2 clock regulates the MPU's operation. Considering this, although write operations to the DUART's setup registers are in sync with Ø2, the device's reaction to them is slaved to the 3.6864 MHz clock. This behavior explains why consecutive writes to the same register must, in some cases, be separated by a delay—it is conceivable that if the MPU is fast enough, the second write may occur before the DUART has reacted to the first one, due to the latency of the DUART's clock signal.
Analysis of the DUART's timing diagram caused me to suspect that the problem was occurring late in the third clock cycle of the STA $ABS,X operation, a time when the address bus is being diddled by the MPU and is not yet valid. Latency within the DUART, coupled with a possibly invalid A0-A7 after A8-A15 had been asserted, could cause first one register and then another to be selected, totally confusing the DUART. This would not occur with STA $ABS, as no effective address computation is required for the latter instruction.
Therefore, it seemed prudent to qualify device selection so it could only occur after the fourth cycle had started and at a time when A0-A15 would truly be valid and reflect the final address. My
original I/O decoding logic selected a device only according to the address, using an 74AC138 decoder. The
revised decoding logic still uses the 'AC138, but qualifies its selection with the MPU's VDA (valid data address) and VPA (valid program address) outputs, preventing selection until after the fourth cycle of the STA $ABS,X instruction has started, at which time a valid address is guaranteed.
The following information is in the '816 data sheet and is what I used to work out the logic:
Code:
VDA VPA BUS STATE
0 0 Internal Operation Address and Data Bus available. The Address Bus may be invalid.
0 1 Valid program address-may be used for program cache control.
1 0 Valid data address-may be used for data cache control.
1 1 Opcode fetch-may be used for program cache control and single step control.
From the perspective of selecting devices for I/O, the third condition is the one to use. Condition one (both VDA and VPA low) is where the trouble was occurring, as that was when the MPU was fiddling with the address bus and confusing the DUART.
A little PCB surgery set up the new logic. First I tested with a ROM having ordinary STA $ABS code to verify that the POC was still upright with a pulse following surgery. Once that had been established, I modified the code to use STA $ABS,X, using identical parameters and in the exact same order:
Code:
1324 ;CONFIGURE DUART
1325 ;
1326 E264 A2 05 cfgacia ldx #dr_imr
1327 E266 A9 00 lda #%00000000
1328 E268 9D 00 D0 sta io_acia,x ;mask all IRQ sources
1329 E26B A2 02 ldx #dr_cra
1330 E26D A9 20 lda #%00100000
1331 E26F 9D 00 D0 sta io_acia,x ;reset RxD
1332 E272 20 EE E2 jsr tmstd ;10 ms time delay
1333 E275 A2 02 ldx #dr_cra
1334 E277 A9 30 lda #%00110000
1335 E279 9D 00 D0 sta io_acia,x ;reset TxD
1336 E27C 20 EE E2 jsr tmstd
1337 E27F A2 02 ldx #dr_cra
1338 E281 A9 10 lda #%00010000
1339 E283 9D 00 D0 sta io_acia,x ;reset MSR pointer
1340 E286 20 EE E2 jsr tmstd
1341 E289 A2 00 ldx #dr_msra
1342 E28B A9 93 lda #%10010011
1343 E28D 9D 00 D0 sta io_acia,x ;mode 1...
1344 ;
1345 ; [7] 1: enable RTS mode
1346 ; [6] 0: IRQ on RxD ready
1347 ; [5] 0: character error mode
1348 ; [4,3] 10: no parity check
1349 ; [3] 0: even parity (not checked)
1350 ; [2,1] 11: 8 bit data format
1351 ;
1352 E290 A2 00 ldx #dr_msra
1353 E292 A9 17 lda #%00010111
1354 E294 9D 00 D0 sta io_acia,x ;mode 2...
1355 ;
1356 ; [7,6] 00: duplex channel mode
1357 ; [5] 0: TxD RTS mode off
1358 ; [4] 1: TxD CTS mode on
1359 ; [3-0] 0111: stop bit
1360 ;
1361 E297 A2 01 ldx #dr_csra
1362 E299 A9 CC lda #%11001100
1363 E29B 9D 00 D0 sta io_acia,x ;clock select...
1364 ;
1365 ; [7-4] 1100: 38.4 Kb/s TxD
1366 ; [3-0] 1100: 38.4 Kb/s RxD
1367 ;
1368 E29E A2 02 ldx #dr_cra
1369 E2A0 A9 80 lda #%10000000
1370 E2A2 9D 00 D0 sta io_acia,x ;assert RTS
1371 E2A5 20 EE E2 jsr tmstd
1372 E2A8 A2 02 ldx #dr_cra
1373 E2AA A9 05 lda #%00000101
1374 E2AC 9D 00 D0 sta io_acia,x ;command...
1375 ;
1376 ; [7-4] 0000: no operation
1377 ; [3,2] 01: enable transmitter
1378 ; [1,0] 01: enable receiver
1379 ;
1380 E2AF A2 04 ldx #dr_acr
1381 E2B1 A9 00 lda #%00000000
1382 E2B3 9D 00 D0 sta io_acia,x ;aux control...
1383 ;
1384 ; [7] 0: select BRG #1 (38.4 Kbps max)
1385 ; [6-4] 000: C/T setup (not used)
1386 ; [3-0] 0000: IP[0-3] IRQs disabled
1387 ;
1388 E2B6 A2 0D ldx #dr_opcr
1389 E2B8 A9 00 lda #%00000000
1390 E2BA 9D 00 D0 sta io_acia,x ;output port config
1391 E2BD A2 05 ldx #dr_imr
1392 E2BF A9 03 lda #%00000011
1393 E2C1 9D 00 D0 sta io_acia,x ;enabled IRQ sources...
1394 ;
1395 ; [7] 0: IP0-IP3 state change off
1396 ; [6] 0: ch B break change off
1397 ; [5] 0: ch B RHR ready/FIFO full off
1398 ; [4] 0: ch B THR ready off
1399 ; [3] 0: C/T ready off
1400 ; [2] 0: ch A break change off
1401 ; [1] 1: ch A RHR ready/FIFO full on
1402 ; [0] 1: ch A THR ready on
1403 ;
1404 E2C4 60 rts
The board booted with the above code, displayed the POST screen and cheerfully accepted typed input. This was with the POC running on a 1 MHz Ø2 clock. Next, I changed the oscillator and boosted Ø2 to 8 MHz. Everything worked fine. In fact, I programmed one of the function keys on the Wyse 60 to emit a complete sentence as fast as the terminal could physically send the characters and held the key down to ram data through the POC as fast as possible (about 200 chars per sec). Every line of text was echoed error free.
With the CBAT I/O test confirming that the new logic was working, I replaced the above setup code with the data tables and register loading loop. It all appears to work as it should.
The interesting question is why was only the DUART affected? I concluded it was a combination of it being driven by a clock signal that is asynchronous to Ø2, as well as the device's inherently slow operation when writing to the setup registers. You may well ask why didn't I slow down Ø2 to see if it was a case of a slow device not reacting quickly enough to A0-A15. Well, I went so far as to put a 1 MHz oscillator in the board, which resulted in Ø2 being 500 KHz. The error persisted, although in a different way, which is what ultimately pointed me in the right direction.
I think the conclusion that can be drawn from this little
contretemps is that the VDA and VPA outputs should be part of the address decoding logic of any '816 design. Clearly, Bill Mensch anticipated some address bus hinkiness with the '816 when he designed it, and decided to provide outputs that would unambiguously indicate when it was safe to select hardware.
Looks like it's time for me to permanently revise the schematic and the board layout.