Joined: Thu May 28, 2009 9:46 pm Posts: 8504 Location: Midwestern USA
|
REATTACHING SCSI
Thanks to an increasing tendency for my heart to go into arrhythmia, requiring rescue therapy at least once in the last several weeks, I've had to lay low for a while. That means more time spent at home with light physical activity, which in turn, means I have a good excuse to devote quite a bit time to hobby computing—without my wife objecting too strenuously. Some software development is needed involving bare-metal code, which is my favorite kind of programming. With POC V1.3 now running in a stable fashion with firmware using interrupt-driven API calls, I decided to see about getting SCSI working on the unit.
A key component of SCSI is, of course, the host bus adapter (HBA), of which I have one. That HBA, illustrated below, was designed to work with POC V1.1—its prototype was developed in 2011 to work with POC V1.0.
Attachment:
File comment: POC V1.1 SCSI Host Adapter
hba01.jpg [ 3.78 MiB | Viewed 166751 times ]
The V1.1 HBA is electrically compatible with POC V1.2 and V1.3, but none of the mounting holes align with their equivalents on those two units. The mounting differences were not a design goof. I decided starting with POC V1.2 that a different layout was best. Among other things, the new layout would use four screws to secure the HBA to the rest of the unit, thus eliminating a tendency for the HBA to occasionally unseat from the mainboard expansion socket. Also, during the layout work on V1.2, I had found it expedient to relocate the expansion socket to accommodate the two DUARTs that would give me four TIA-232 channels.
The plan was to build a mechanically-compatible HBA as soon as V1.2 was up-and-running. What derailed this plan was a change in status of the Mill-Max 351-10-114-type extender pin assemblies used to connect the HBA to the expansion socket. See below.
Attachment:
File comment: HBA-to-Expansion Socket Interface
poc_v1_reissue_side_hba.jpg [ 430.03 KiB | Viewed 166751 times ]
These assemblies were production items at the time I designed V1.2 but went to "special order" status right after I had completed V1.2 and had it operational. I had finished the new HBA layout and immediately before I placed an order for PCBs was when I discovered I could no longer order the extender pin assemblies from distribution. A query to Mill-Max confirmed that the part was now special-order and could be had in a 50-piece minimum order—which amounted to over 700 USD. So much for that idea! At least I discovered this before I had placed a PCB order.
I also did a search for compatible alternatives, but ran into the same problem: non-stock parts with a minimum order requirement. Evidently, everyone decided at the same time that no one needed these parts anymore. Almost makes me wish I had stocked up on them when they were readily available.
Meanwhile, I had commenced work on the design of POC V2.0, which was planned to use the same mechanical layout as V1.3, including the DIP28 expansion socket. That the extender pin assemblies had effectively become “unobtanium” prompted me to come up with a different expansion connector arrangement for V2.0. That, however, wasn't going to be helpful with V1.2 or V1.3. So what to do?
The “solution” was to monkey-rig the V1.1 HBA onto V1.3 with some long, skinny cable ties cinched so the extender pins would stay seated in the expansion socket. The only bad thing about this arrangement is the ties pass over the socket into which the real-time clock (RTC) plugs in (originally, the expansion socket was the RTC socket). Okay, I can live without the RTC; nothing in the firmware is dependent on its presence. It's an ugly arrangement but it mostly keeps the HBA in place, as long as I'm careful with handling the unit.
Anyhow, with the HBA more-or-less “installed,” I can commence work on some code. The SCSI driver I have is relatively old in the scheme of things. I started on it back when I had built the prototype HBA, and when I designed the current HBA unit with a more technically-advanced host interface, I patched the prototype driver and added features to support quasi-DMA. By then, it was getting very crowded in the 8KB of ROM that V1.1 had, so no more SCSI features could be added. The last significant change to the driver was made more than seven years ago.
With the driver being a mélange of prototype code and a bunch of patches, frankly it’s a mess. Furthermore, the driver doesn't know anything about extended RAM, limiting SCSI transactions to bank $00. Ergo the code sections that access command descriptor blocks and I/O buffers have to be reworked, either with more patches (which tactic is possible with V1.3 due to its 12KB of ROM) or with fresh code. I cogitated on both approaches for a while, contemplated my past work, cringed while reading some of what I had done, and decided to write a whole new driver from scratch. The concepts behind the design of the original driver were fine, the execution not so much.
As was the case with the original's development, this new driver will be run entirely in RAM while testing and debugging. This approach means I can quickly and easily upload test content to V1.3—no ROM swapping required. It also means if a driver error puts the machine into the ditch, I can press the “panic button” (NMI push button) to try to regain control or if that doesn't work, hit reset and start over. The test code loads at $00A000 and occupies about 1KB. RAM in the range $000200-$00B6FF will survive a reset (as will all extended RAM), so I should be able to conduct a post mortem following a major wreck, which will help with the debugging process.
The SCSI driver primitives are interrupt-driven, as are BIOS API calls, including those that access SCSI services. This means the test environment has to patch into the firmware's interrupt processing. So the first step in writing the new driver was to develop “wedge” and “unwedge” functions to make the test environment part of the interrupt system.
Code: ;wedge: WEDGE PATCHES INTO INTERRUPT SYSTEM ; wedge rep #m_seta ;16-bit accumulator lda ivcop ;current COP vector cmp !#newcop ;already wedged? beq .0000010 ;yes, skip ; sta ivspareb ;no, save old vector &... lda !#newcop ;set... sta ivcop ;new vector ; .0000010 lda ivirq ;current IRQ vector cmp !#newirq ;already wedged? beq .0000020 ;yes ; sta ivsparea ;no lda !#newirq sta ivirq ; .0000020 sep #m_setr brk ; ;=============================================================================== ; ;unwedge: UNWEDGE PATCHES FROM INTERRUPT SYSTEM ; unwedge rep #m_seta ;16-bit accumulator lda ivcop ;current COP vector cmp !#newcop ;wedged? bne .0000010 ;no, skip ; lda ivspareb ;yes, get original vector beq .0000010 ;not valid! ; sta ivcop ;put it back stz ivspareb ;invalidate alternate vector ; .0000010 lda ivirq ;current IRQ vector cmp !#newirq ;wedged? bne .0000020 ;no ; lda ivsparea beq .0000020 ; sta ivirq stz ivsparea ; .0000020 sep #m_setr brk Here I take advantage of the page $01 indirect vectors that are set up during POST. I also take advantage of the fact that a 16-bit fetch or store is an atomic operation—no need to bracket the IRQ vector changes with SEI and CLI. Incidentally, the !# notation tells the Kowalski assembler to assemble immediate-mode operands as 16-bit quantities.
The IRQ patch itself is straightforward and checks for an interrupt generated by the HBA. If no HBA IRQ has occurred execution will continue with the ROM-resident IRQ handler. Otherwise, the 53CF94 SCSI controller registers that are of interest are read and returned to the foreground via the stack. Also, the return address that the 65C816 pushed while servicing the interrupt is modified so the foreground code is routed according to why the HBA interrupted.
Code: ;PATCH TO IRQ SERVICE ROUTINE ; newirq phk ;select kernel's... plb ;data bank sep #m_setr ;8-bit registers ldy io_scsi+sr_stat ;get HBA general status bpl iirq0500 ;HBA not interrupting ; tsc ;make IRQ stack frame... tcd ;the local direct page ldx io_scsi+sr_isr ;get HBA command status lda io_scsi+sr_irqst ;get HBA interrupt status ; ; —————————————————————————————————————————————————————————————————————— ; The following code modifies the stack frame that was pushed by the IRQ ; preamble, thus affecting the behavior of the foreground code that was ; interrupted. The changes are as follows: ; ; Frame MPU ; Offset Register Description ; —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-— ; irq_arx .C HBA interrupt status ; irq_xrx .X HBA command status ; irq_yrx .Y HBA general status ; irq_pcx PC SCSI foreground execution vector ; irq_srx SR C & D cleared, m & x set ; —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-— ; ; No analysis of status is made here; the foreground handles that. ; —————————————————————————————————————————————————————————————————————— ; rep #m_setr ;16-bit registers and !#%11111111 ;squelch noise in .B sta irq_arx ;interrupt status stx irq_xrx ;command status sty irq_yrx ;general status lda ivscsi ;get “next” driver vector &... sta irq_pcx ;reroute foreground sep #m_seta ;8-bit accumulator lda irq_srx ;entry SR ora #m_setr ;exit with m & x set and #~{sr_bdm|sr_car} ;exit with d & c cleared sta irq_srx ;exit SR ; ; ****************************************************** ; next code segment is only for testing——it replaces the ; CRTI function in the firmware ISR... ; ****************************************************** ; rep #m_seta ;16-bit accumulator ply ;restore MPU state plx pla pld plb rti ; iirq0500 jmp (ivsparea) ;goto regular IRQ The COP wedge basically duplicates the firmware's COP handler so the API calls associated with SCSI services are intercepted and directed to the test environment—I won't display that code here, since it is described in previous posts. Were the COP wedge not there, the SCSI API calls would be intercepted in the firmware and fail with “undefined API” errors.
The above patching has been tested and, astonishingly, worked on the first try. It always seems when I write an IRQ patch, I make a silly typo, e.g., TXA when I meant TAX, and when the patch gets wedged, the system crashes and burns.
Next step is to flesh out the body of the driver.
_________________ x86? We ain't got no x86. We don't NEED no stinking x86!
|
|