private void addAcc(MemoryAccessBlock acc) { LogicalMemory mem = acc.getLogicalMemoryPort().getLogicalMemory(); assert mem != null; Set<MemoryAccessBlock> accesses = memToAcc.get(mem); if (accesses == null) { accesses = new LinkedHashSet<MemoryAccessBlock>(); memToAcc.put(mem, accesses); } accesses.add(acc); // Register the access by task and memory Map<Task, Set<MemoryAccessBlock>> accessMap = taskToAcc.get(mem); if (accessMap == null) { accessMap = new HashMap<Task, Set<MemoryAccessBlock>>(); taskToAcc.put(mem, accessMap); } accesses = accessMap.get(currentTask); if (accesses == null) { accesses = new LinkedHashSet<MemoryAccessBlock>(); accessMap.put(currentTask, accesses); } accesses.add(acc); }
@Override public void visit(Design des) { final GenericJob gj = EngineThread.getGenericJob(); final boolean allowDPLutMem = gj.getUnscopedBooleanOptionValue(OptionRegistry.ALLOW_DUAL_PORT_LUT); memToAcc = new HashMap<LogicalMemory, Set<MemoryAccessBlock>>(); super.visit(des); for (LogicalMemory mem : memToAcc.keySet()) { boolean readOnlyPort = false; if (!allowDPLutMem && mem.getImplementation().isLUT()) { continue; } if (allowDPLutMem && mem.getImplementation().isLUT()) { readOnlyPort = true; } // Find one task with more than one access. If the memory // implementation // has one port as read-only, then ensure that the found task has at // least // one read. boolean validForDualPorting = false; for (Set<MemoryAccessBlock> mabs : taskToAcc.get(mem).values()) { if (mabs.size() < 2) { continue; } if (readOnlyPort) { for (MemoryAccessBlock mab : mabs) { if (mab.getMemoryAccess().isReadAccess()) { validForDualPorting = true; break; } } } else { validForDualPorting = true; break; } } if (validForDualPorting) { if (mem.getLogicalMemoryPorts().size() < 2) { mem.createLogicalMemoryPort(); String id = mem.getSourceName() == null ? mem.toString() : mem.getSourceName(); gj.info("Created a second memory port for " + id); } gj.info("\tReallocating accesses to memory"); // Do the re-allocation by task so that multiple accesses in a // task are split across the dual ports Map<Task, Set<MemoryAccessBlock>> accessMap = taskToAcc.get(mem); for (Set<MemoryAccessBlock> accesses : accessMap.values()) { for (MemoryAccessBlock mab : accesses) { mem.removeAccessor(mab); } Iterator<LogicalMemoryPort> portIter = mem.getLogicalMemoryPorts().iterator(); LogicalMemoryPort port1 = portIter.next(); LogicalMemoryPort port2 = portIter.next(); boolean evenReadOnly = false; if (mem.getImplementation().isLUT()) { final boolean port1readOnly = port1.isReadOnly(); final boolean port2readOnly = port2.isReadOnly(); assert port1readOnly || port2readOnly : "LUT memories must have at least 1 read only port"; evenReadOnly = true; if (!port1readOnly) { // Port 2 must be read only, thus switch them. LogicalMemoryPort p = port2; port2 = port1; port1 = p; } } boolean even = true; for (MemoryAccessBlock mab : accesses) { if (even) { if (evenReadOnly && !mab.getMemoryAccess().isReadAccess()) { port2.addAccess(mab); // dont switch 'even' since we've not yet added // to port 1 } else { port1.addAccess(mab); even = !even; } } else { port2.addAccess(mab); even = !even; } } } } } }