Subject: Re: Data Channels
From: Kevin Cameron x3251 (Kevin.Cameron@nsc.com)
Date: Fri Jul 26 2002 - 17:55:26 PDT
Steven Sharp wrote:
> >That would depend on what you mean by modern. HDLs are essentially
> >light-weight multi-threaded programming languages, and the only non-HDL
> >language of that type I know is Occam, and it has data channels like those
> >I described built into the language. The "channel" is a basic building block
> >for
> >CSP style programming, and CSP is probably the best hardware/software
> >design style for large systems (we discussed it at a TCC meeting at HDLCon
> >earlier this year).
>
> I don't know much about Occam, but my understanding is that it was designed
> specifically for programming arrays of Transputers. Transputers have
> communication channels hardwired into the CPU. With a communication channel
> accessible as a basic operation on the processor, it isn't surprising that
> it is accessible as a basic operation in the language.
The programming style Occam supported was a static array of processes which
communicate through "channels" rather than shared memory. The transputer
supported it by a) hardware links between the processors, and b) fast context
switching (it would swap from the writing thread to the reading thread automatically
when writing to a channel). Allocating which processes go where in the actual
processor array was a linker task.
The way HDLs work is very similar to Occam, except that the communication
between processes is via wires (and shared memory). For the sake of argument you
could consider a wire as a channel without storage.
> In SystemVerilog, a channel would be an abstract data type implemented in
> software. There is no reason that it should be treated differently from
> any of the other abstract data types that someone might want to use. The
> language should provide the building blocks to build arbitrary abstract
> data types. Then you can build your channels, and someone else who wants
> something different can build that instead.
It's not really a type, it's a primitive object like a buffer. You can build something
in SystemVerilog or C++ that looks similar, but you don't get the advantage of it
being a commonly understood abstraction.
If it is handled by the simulation kernel directly then you can optimize the execution
e.g. doing the write/read rollover that the transputers did, or using some host-native
pipe mechanism or shared memory and you can make it MT safe for parallel
processing.
I don't write my own "pipes" library when I'm programming for Unix, I don't see
why I should have to do it for SystemVerilog.
> >The internal NSC implementation in C++/Verilog we already have is unwieldy
> >and inefficient, I'd like to have a better solution.
>
> Can you explain why it is unwieldy and inefficient? And why building it
> into the language would make it somehow more wieldy and efficient? The
> same information has to be provided at the interface either way, and the
> same operations have to be performed in software either way. Why would
> having it built in make a difference? Is this due to some awkwardness and
> inefficiency in the C++/Verilog interface, which the C interface group might
> be able to tackle?
It was multi-threaded with a single thread of control, a Verilog test device
wanting to talk to its C++ controller required swapping control to a backplane
module which then swaps control to to the test controller and copies the data
each time - then control swaps back again through the backplane. Context
switches are not cheap, so it works a lot faster if you can do it all in the
simulator own thread. It was unwieldy because it was near impossible to debug.
> I don't see where an abstract data type written in SystemVerilog and
> using tasks/functions/methods would be any more unwieldy than your proposed
> solution that overloads some other syntax.
>
> Where you are suggesting:
>
> > > always @(clock) chp[1] <= 1'b00011000; // write (to bar)
>
> you could use:
>
> always @(clock) channel_write(chp[1], 8'b0001100);
>
> or in PLI:
>
> always @(clock) $channel_write(chp[1], 8'b0001100);
>
> Where you are suggesting:
>
> > > always @(chp[0]) // data ready ?
> > > data = chp[0];
>
> you could use a blocking read task:
>
> always
> channel_read(chp[0], data);
>
> or if you don't like a blocking interface, use a couple of separate routines:
>
> always wait(channel_ready(chp[0]))
> data = channel_read(chp[0]);
But you havn't supplied all the extra implementation code that my version
doesn't need (from a user perspective). Also the syntax I suggested is
deliberately polymorphic with respect to reg/wire data types so you can
swap from synchronous to asynchronous easily.
> It doesn't look any more unwieldy to me, and it won't get mistaken for a
> normal read or write of a simple variable. If you want some way of sending
> multiple packets in a single call, you need some way of passing arbitrary
> sized parameters to a task (e.g. pointers or variable-sized arrays).
>
> I'm sure that there are plenty of variations on how to do this. The
> nice thing is that the user can implement whatever variation is desired,
> instead of being stuck with a predefined built-in version. It keeps the
> language definition simpler, while giving the user full flexibility.
If it was added to the language you wouldn't have to use it :-)
Channels are simply an abstraction of a common hardware structure.
The reason for adding them is to support top-down design from the system
level with a more common methodology that we can build new tools on.
Kev.
> Steven Sharp
> sharp@cadence.com
-- National Semiconductor 2900 Semiconductor Drive, Mail Stop A1-520, Santa Clara, CA 95052-8090
This archive was generated by hypermail 2b28 : Fri Jul 26 2002 - 17:57:12 PDT