Okay, I figured that there had to be at least one hardware bug somewhere in the POC V1.0. Sure enough, I seem to have found one. It's kind of hard to explain...
Early in the reset handler, a bunch of parameters are written into the DUART registers. For the first version of the ROM, I just did a bunch of LDAs...STAs, figuring I'd devise a more elegant method later on. After getting all that EIA-232 stuff running to where I could do reliable CBAT I/O, I decided to clean up the DUART setup code by use of a pair of data tables, one a list of parameters and the other a list of the corresponding registers into which the parameters are to be written. A simple loop took care of everything.
Well, imagine my surprise when my new, improved DUART setup routine didn't work. Depending on the speed and direction of the wind, phase of the moon and the state of the economy, either the system would not boot at all, or it would come alive but random drivel would be scribbled on the screen. The behavior seemed to change each time I pressed the reset button.
Thinking the ROM was whacko, I burned a new one and manually verified it against the code buffer. I plugged it in and got the same results. I put in the last good ROM (the one with all the LDAs...STAs) and the POC fired up without a hitch. Okay, I had to have somehow made a serious coding error, as it was clear the DUART was being improperly set up. I must have stared at the code and data tables until my eyes were triangular, but could not see anything wrong. The code loop looks something like the following:
Code: Select all
inireg ldy #parmtab-regtab-1 ;registers to initialize -1
lda #$ff ;invalid register number
;
inireg01 cmp regtab,y ;register same as previous?
bne inireg02 ;no, no delay needed
;
jsr tmstd ;10 ms time delay
;
inireg02 ldx regtab,y ;register offset
lda parmtab,y ;register parameter
sta device,x ;write to device register
txa ;save last register
dey
bpl inireg01 ;next register
;
rts
;
;
;register data table...
;
regtab .byte reg4 ;a device register offset (e.g., $04)
.byte reg7 ;ditto
.byte reg2 ;ditto
;
;
;parameter data table...
;
parmtab .byte %01100011 ;some paramater
.byte %00001100 ;another parameter
.byte %10101010 ;and another
The time delay, by the way, takes care of the case where consecutive writes are made to the same register—in some cases, a delay is necessary to give the DUART time to react to the effect of the previous write.
Anyhow, if you can't see anything wrong with the above loop, it's because there is nothing wrong. I ran that code in the Kowalski simulator, step-by-step, and verified each register and parameter against what I knew worked. All was okay. Then it hit me. The only thing really different was that I was writing to the DUART using indexed addressing, whereas previously I was using absolute addressing. It seemed that the STA DEVICE,X instruction was malfunctioning.
To verify my suspicion, I wrote the following linear alternative to the above loop and burned it into another ROM:
Code: Select all
ldx #reg4 ;register offset
lda #%01100011 ;parameter
sta device,x
ldx #reg7 ;register offset
lda #%00001100 ;parameter
sta device,x
ldx #reg2 ;register offset
lda #%01100011 ;parameter
sta device,x
The results were the same: garbage on the screen, more garbage when typing, etc. It was patent that STA DEVICE,X was either writing bogus values into the DUART's registers, or was writing good values into the wrong registers.
Now here's the fun part: I was already using the loop and data table method of setting up the watchdog timer (WDT), which works fine. It's supposed to generate an IRQ 100 times per second, and according to the scope, it does. Unlike the DUART, the WDT has no problems with consecutive writes to the same register, so there's no 10 millisecond delay involved. So STA DEVICE,X
per se isn't the culprit, only the way in which the DUART reacts to it.
I have a vague idea as to what may be going on here, but haven't gotten it to fully gel in my mind as yet.