> > For maintaining source compatibility you can also use MACROs
> > or __inline__ routines to isolate machine dependencies
> > instead of millicode.
> The problem is unfortunately uglier than this, even for things as
> simple and common as LANCE ethernet drivers.
> Consider the case of a machine such as the Amiga. The Amiga has a
> 'native' LANCE ethernet controller. [etc.]
> Also consider the case of _two different_ ISA ethernet boards, each
> using a LANCE ethernet controller. [etc.]
I agree that the problem is ugly (even on one machine type
with multiple busses). Whether you use macros, inline
routines, millicode or some other technique is perhaps less
important than coming up with a flexible, efficient
architecture. May be you guys already have....
But I am not sure a frontend/backend arch. is flexible
enough... (if I understand your use of {front,back}end
right).
I hate to use an overused phrase but seems like ``object-
oriented architecture'' is one way to attack this complexity
[I mean this as a guiding principle, not as embodied in
C++]. In effect you have software analogs of LANCE, ISA
bus, PCI, VME, SBUS, bridge board, DMA engines of various
sorts etc. They are `connected' together by
procedure/macro/millicode calls. Their `state' is carried
in a data structure associated with each piece of hardware
(+ some state is stored in the h/w itself). Whether a
device is accessed via IO space, memory mapped etc. is
analogous to use of different H/W technology (TTL, ECL,
CMOS). I really should give a concrete example but
no time for that right now.
> As you note, having too wide an interface means that nobody (except
> perhaps its author 8-) will be to use it effectively.
That is why an object oriented interface is easier to
understand and use. It can be made quite coherent and
complete and it needs to only handle one type
ofdevice/IC/object at a time.
> However, each "machine-indepedent" driver back-end would need its own
> set of 'millicode' -- if your common access pattern is to write 4
> registers at a time in a specific order, what are the odds that any
> other driver is going to need to do exactly the same thing.
Agreed. But what I am suggesting now is that an interface
to a set of operations on a device (e.g. LANCE) be defined;
that is, each h/w device be modeled as an object. Then
depending on other factors (such as memory mapped, IO space
mapped, delays involbed in access, offsets to registers,
instruction set specifics, little/big endiannes) various
flavors of implementations can be generated for this h/w
device. I even envision using config to put together a
device driver from its parts but that's too blue sky right
now ;-)
> You'll note that I keep quoting "machine-independent." I think it's
> better to call them "machine and bus and ..." independent drivers, but
> that's too long and is the same to a 0th order approximation. 8-)
I think if you guys explain your goals in doing this, the
discussion will perhaps be more focused. It is likely I
don't have the same vision as you and we may be talking at
cross purposes.
If I were doing this, my goals would be
- performance
- allow multiple instances of devices/controllers/busses
- coherent interfaces and modular code (easy to understand,
maintain and extend)
- deal with 90% to 95% of known combinations cleanly.
100% would be nice but not a high priority.
- As far as possible use the same source for each module
on any machine/bus combination
- allow sharing of driver object code but not a high priority
And in this order.
--bakul
PS: an extreme test would be use of a SCSI drive attached
to a parallel-to-SCSI adpater, attached to an ISA bus via
a bridge board....:-)