package net.sf.orcc.tools.merger.actor;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import net.sf.orcc.df.Action;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.Connection;
import net.sf.orcc.df.Network;
import net.sf.orcc.df.Port;
import net.sf.orcc.ir.Var;
import net.sf.orcc.ir.IrFactory;
import net.sf.orcc.util.OrccLogger;
/**
* This analyzes a given schedule to discover
* feedback edges (FIFOs).
*
* @author Jani Boutellier
*
*/
public class ScheduleAnalyzer extends BufferSizer {
protected Map<Port, Var> buffersMap = new HashMap<Port, Var>();
int totalBalance = 0;
Copier copier;
public ScheduleAnalyzer(Network network, Copier copier) {
super(network);
this.copier = copier;
}
public boolean analyze(Actor superActor, Schedule schedule) {
createBuffers(getMaxTokens(schedule));
createBuffers(getMinTokens(schedule));
for (Iterand iterand : schedule.getIterands()) {
processInputs(iterand.getAction());
processOutputs(iterand.getAction());
}
return totalBalance < 0;
}
private void createBuffers(Map<Connection, Integer> maxTokens) {
int index = 0;
for (Connection conn : maxTokens.keySet()) {
int size = maxTokens.get(conn);
if (size != 0) {
String name = "buffer_" + index++;
Var buffer = IrFactory.eINSTANCE.createVar(
IrFactory.eINSTANCE.createTypeList(size,
conn.getSourcePort().getType()), name, true, 0);
buffer.addAttribute("rwBalance");
buffer.setAttribute("rwBalance", new Integer(0));
buffersMap.put(conn.getSourcePort(), buffer);
buffersMap.put(conn.getTargetPort(), buffer);
}
}
}
private void processInputs(Action action) {
for (Port port : action.getInputPattern().getPorts()) {
accessBuffer(port, false, action.getInputPattern().getNumTokens(port));
}
}
private void processOutputs(Action action) {
for (Port source : action.getOutputPattern().getPorts()) {
accessBuffer(source, true, action.getOutputPattern().getNumTokens(source));
}
}
private void accessBuffer(Port port, boolean write, int count) {
if (buffersMap.containsKey(port)) {
Var memVar = buffersMap.get(port);
if (write) {
incrementBufferAccess(memVar, count);
} else {
decrementBufferAccess(memVar, count);
}
}
}
private void incrementBufferAccess(Var var, int count) {
var.setAttribute("rwBalance", new Integer((
(Integer)var.getValueAsObject("rwBalance")).intValue() + count));
totalBalance += count;
}
private void decrementBufferAccess(Var var, int count) {
var.setAttribute("rwBalance", new Integer((
(Integer)var.getValueAsObject("rwBalance")).intValue() - count));
totalBalance -= count;
}
public void markInternalFifos(Actor superActor, boolean fullFifos) {
for (Actor actor : network.getAllActors()) {
for (Port port : actor.getOutputs()) {
Var buffer = buffersMap.get(port);
if (buffer != null) {
if (queryBufferAccess(buffer) > 0) {
if (fullFifos) {
OrccLogger.traceln("Info: generating feedback FIFO starting from "
+ port.getName());
} else {
OrccLogger.traceln("Info: generating feedback variable starting from "
+ port.getName());
}
externalizeConnection(superActor, actor, port, fullFifos);
}
}
}
}
}
private int queryBufferAccess(Var var) {
if (var.hasAttribute("rwBalance")) {
return ((Integer)var.getValueAsObject("rwBalance")).intValue();
}
return 0;
}
private void externalizeConnection(Actor superActor, Actor actor,
Port port, boolean fullFifos) {
Connection connection = actor.getOutgoingPortMap().get(port).get(0);
// this is the 'port' of 'actor'
copyOutputPortIfNotFound(superActor, actor, connection.getSourcePort(),
fullFifos, connection.getTargetPort(), connection.getSize());
// this is the remote port of another actor
copyInputPortIfNotFound(superActor,
connection.getTarget().getAdapter(Actor.class),
connection.getTargetPort(), fullFifos);
}
private void copyInputPortIfNotFound(Actor superActor, Actor actor,
Port port, boolean fullFifos) {
for (Port in : superActor.getInputs()) {
if (in.getName().equals(port.getName())) {
return;
}
}
port.addAttribute("externalized");
if (fullFifos) {
port.addAttribute("externalFifo");
superActor.getInputs().add((Port)copier.copy(port));
}
}
private void copyOutputPortIfNotFound(Actor superActor, Actor actor,
Port port, boolean fullFifos, Port target, Integer size) {
for (Port out : superActor.getOutputs()) {
if (out.getName().equals(port.getName())) {
return;
}
}
port.addAttribute("externalized");
if (fullFifos) {
port.addAttribute("externalFifo");
port.setAttribute("externalFifo", size);
port.addAttribute("targetPort");
port.setAttribute("targetPort", target.getName());
superActor.getOutputs().add((Port)copier.copy(port));
}
}
}