spin is an experimental project and far from beeing available for commercial usage. If you are interrested in spin: mailto://spin@toem.de.

Concepts

Java code often assumes similar to C or C++, but in fact, the concepts are very different. So the systemC patterns developed in C++ do not really fit into this different world. On the otherhand, there are a lot of useful mechansims in java that might be useful for prototyping. As a result, spin got patterns that look similar to systemC, and new mechanisms that look very different.


Goals & Keys

 

  • Simplify Prototyping.
  • OS  and machine independency.
  • Fast design-compile-debug cycles and easy refactoring.
  • Integrated in eclipse.
  • Improve simulation speed by using  optimal design patterns.
  • Prefer non-threaded approach for synchronous processes.
  • Add means to simplify non-threaded processes.
  • Add means to simplify parallisation (real threads).
  • Provide process patterns to be filled by users.

 


Modules

Like in systemC, modules are the basic building blocks of a design hierarchy. A model usually consists of several modules which communicate via ports (connectors).

A module contains:

  • Connectors (A port is a connector)

  • Processes

  • Any other java code

     

public class AModule extends Module {

	// Connectors
	public IIn<Integer> in1, in2;
	public IOut<Integer> out;

	// Constructor
	public AModule(String name, IModule parent) {
		super(name, parent);
		final int MASK = 0xff;

		// Process
		new Process(null, this) {

			public void initialize() {
				out.init(0);
				sensitive(in1.changed(), in2.changed());
			}

			public void run(IRunInfo info) {
				out.write(((in1.val() + in2.val()) & MASK));
			}
		};
	}
} 

Connectors

A port in spin is just a kind of connector. Connectors in spin are elements that can be connected with the connectTo method. There are no wireing elements like systemC signals needed. Instead connectors (e.g ports) are connected directly. Here are all connectors in a table.

  Port  
Input IIn/In  
Output IOut/Out  
Logic Input/Output IInOut/InOut  
Channels IPort/Port  
public class Connections extends Module {

	// module
	AModule adder = new AModule("myAdder", this);

	// Connectors
	protected IIn<Integer> s1, s2;
	protected IOut<Integer> r;

	// Constructor
	public Connections() {

		s1.connectTo(adder.in1);
		s2.connectTo(adder.in2);
		adder.out.connectTo(r);

		s1.init(4);
		s2.init(6);
	}
}

Processes

Processes in spin are represented by objects. So a process can have its own data and methods encapsulated in a class. Like in systemC there are 2 basic types of processes represented by 2 base classes:

  • Normal Process (similar to SC_METHOD)

  • Threaded Process (similar to SC_THREAD)

New Processes are usually defined as anonymous classes, deriving 1 or more given methods:

public class Generator extends Module {

	public IOut<Logic> out;

	public Generator(Module parent) {
		super(parent);

		new ThreadedProcess("Generator Process", this) {

			public void initialize() {
				out.init(Logic.FALSE);
			}

			public void run(IRunInfo info) {

				while (true) {
					sleep(Time.ns(100));
					out.write(Logic.TRUE);
					sleep(Time.ns(400));
					out.write(Logic.FALSE);
				}
			}
		};
	}
}

Dedicated Processes & Process Patterns

Beside these two, there are other specialized processes (e.g. Statemachine) available in spin. Reasons are:

  • Simplify non-threaded Processes.

  • Ready to use patterns to ease development.

  • Force the the user to use special patterns to enable transformation of the prototyping code into hardware patterns.

Threaded process are often just used to simplify development, but have the drawback of overhead in execution. spin tries to simplify development using non-threaded processes and enables the use of threads for parallelisation (async proclets).

new Statemachine(null, this) {

	@Override
	public void initialize() {
		schedule(0, start);
	}

	State start = new State() {

		public State enter(IRunInfo info) {
			log("Entered start");
			sensitive(in1.changed());
			return null;
		}

		public State handle(IRunInfo info) {
			if (info.getSensitivity() == in1.changed()) {
				insensitive(in1.changed());
				log("handle in1.changed -> change state to gotIn1");
				return gotIn1;
			}
			return null;
		}
	};

Proclets

Proclets are 2nd level processes initiated within a threaded or normal process. There are two basic flavours available:

Synchronous Proclets

Proclets simplify writing values into ports or executing a pieces of code at a defined point of time. These proclets are getting executed synchronous to other processes.

// 100 ns rectangle
out.write(true, Time.ns(100));
out.write(false, Time.ns(200));

// execute in 300 ns
schedule(Time.ns(300), new IRunnable() {

	public void run(IRunInfo info) {
		out.write(in.val());
	}
});
Asynchronous Proclets

Asynchronous proclets are processes that run for a given time in parallel to normal (synchronous) processes driven by the the scheduler. They are useful to parallelise and speed up computations. Async proclets can be initiated within threaded or non-threaded processes.

runAsync(Time.ns(500), new IAsync() {

	Boolean val = in.val();
	
	public void run(IRunInfo info) {
		// compute - dont touch ports
		for (int i=0;i<10000000;i++)
			val = ! val;
	}

	public void sync(IRunInfo info) {
		// 500 ns later 
		// run has finished
		// write results into ports
		out.write(val);
	}
});

Sensitivity

Processes are driven by time and/or sensitivity.  Default sensitivity allows to trigger a process when a port has changed or modified  its value. By deriving the default Sensitivity class, the developer can define more concrete conditions when to trigger a certain process.

ISensitivity<Integer> s2 = new Sensitivity<Integer>(in2){
	@Override
	public void onChanged() {
		if (isEnabled()){
			int val = in2.read();
			if (val> 100)
				fire();								
		}						
	}				
};

Scalability

Instead of bit range types (sc_int<4>), spin supports a scaling mechanism. Developers can apply sclaing value to modules or connectors. These scaling values get propagated via their connections. Connectors with different scaling value can not be connected (will throw an error when silulation starts). The meaning of a sclaing value is type dependend. So it can be used for bit range types using the Integer type as a basis. Processes need to put scaling values into account (e.g. mask the output value).

// Connectors
public IIn<Integer> in1, in2; // 2 in-ports
public IOut<Integer> out; // 1 out-port

// Constructor
public AModule(String name, IModule parent, Scale scale) {
	this(name, parent,scale);
}

....

public void run(IRunInfo info) {
	log("run");
	out.write(((in1.read() + in2.read()) & scale.intMask));
}

Trace, Interfaces and Instrumentation

Tracing is done by connecting the relevant connectors to a trace module.

Trace trace = Trace.create("trace.vcd", this,Trace.VCD);
trace.connectTo(gen.s1, gen.s2, adder3.out, gen.s3);

spin defines a bunch of Interfaces for all main elements. This enables the user to develop own implementations for ports, modules and processes, even without using the base classes. Additionally spin allows the user to set default classes to be used for connectors.

 

Print

User Rating: 0 / 5

Star InactiveStar InactiveStar InactiveStar InactiveStar Inactive