/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.std.memory;
import java.util.ArrayList;
import java.util.SortedMap;
import java.util.TreeMap;
import com.bfh.logisim.designrulecheck.Netlist;
import com.bfh.logisim.designrulecheck.NetlistComponent;
import com.bfh.logisim.fpgagui.FPGAReport;
import com.bfh.logisim.hdlgenerator.AbstractHDLGeneratorFactory;
import com.bfh.logisim.settings.Settings;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.std.wiring.ClockHDLGeneratorFactory;
public class RandomHDLGeneratorFactory extends AbstractHDLGeneratorFactory {
private static final String NrOfBitsStr = "NrOfBits";
private static final int NrOfBitsId = -1;
private static final String SeedStr = "Seed";
private static final int SeedId = -2;
@Override
public String getComponentStringIdentifier() {
return "RNG";
}
@Override
public SortedMap<String, Integer> GetInputList(Netlist TheNetlist,
AttributeSet attrs) {
SortedMap<String, Integer> Inputs = new TreeMap<String, Integer>();
Inputs.put("GlobalClock", 1);
Inputs.put("ClockEnable", 1);
Inputs.put("clear", 1);
Inputs.put("enable", 1);
return Inputs;
}
@Override
public ArrayList<String> GetModuleFunctionality(Netlist TheNetlist,
AttributeSet attrs, FPGAReport Reporter, String HDLType) {
ArrayList<String> Contents = new ArrayList<String>();
Contents.addAll(MakeRemarkBlock(
"This is a multicycle implementation of the Random Component",
3, HDLType));
Contents.add("");
if (HDLType.equals(Settings.VHDL)) {
Contents.add(" Q <= s_output_reg;");
Contents.add(" s_InitSeed <= X\"0005DEECE66D\" WHEN " + SeedStr
+ " = 0 ELSE");
Contents.add(" X\"0000\"&std_logic_vector(to_unsigned("
+ SeedStr + ",32));");
Contents.add(" s_reset <= '1' WHEN s_reset_reg /= \"010\" ELSE '0';");
Contents.add(" s_reset_next <= \"010\" WHEN (s_reset_reg = \"101\" OR");
Contents.add(" s_reset_reg = \"010\") AND");
Contents.add(" clear = '0' ELSE");
Contents.add(" \"101\" WHEN s_reset_reg = \"001\" ELSE");
Contents.add(" \"001\";");
Contents.add(" s_start <= '1' WHEN (ClockEnable = '1' AND enable = '1') OR");
Contents.add(" (s_reset_reg = \"101\" AND clear = '0') ELSE '0';");
Contents.add(" s_mult_shift_next <= (OTHERS => '0') WHEN s_reset = '1' ELSE");
Contents.add(" X\"5DEECE66D\" WHEN s_start_reg = '1' ELSE");
Contents.add(" '0'&s_mult_shift_reg(35 DOWNTO 1);");
Contents.add(" s_seed_shift_next <= (OTHERS => '0') WHEN s_reset = '1' ELSE");
Contents.add(" s_current_seed WHEN s_start_reg = '1' ELSE");
Contents.add(" s_seed_shift_reg(46 DOWNTO 0)&'0';");
Contents.add(" s_mult_busy <= '0' WHEN s_mult_shift_reg = X\"000000000\" ELSE '1';");
Contents.add("");
Contents.add(" s_mac_lo_in_1 <= (OTHERS => '0') WHEN s_start_reg = '1' OR");
Contents.add(" s_reset = '1' ELSE");
Contents.add(" '0'&s_mac_lo_reg(23 DOWNTO 0);");
Contents.add(" s_mac_lo_in_2 <= '0'&X\"00000B\"");
Contents.add(" WHEN s_start_reg = '1' ELSE");
Contents.add(" '0'&s_seed_shift_reg(23 DOWNTO 0) ");
Contents.add(" WHEN s_mult_shift_reg(0) = '1' ELSE");
Contents.add(" (OTHERS => '0');");
Contents.add(" s_mac_hi_in_2 <= (OTHERS => '0') WHEN s_start_reg = '1' ELSE");
Contents.add(" s_mac_hi_reg;");
Contents.add(" s_mac_hi_1_next <= s_seed_shift_reg(47 DOWNTO 24) ");
Contents.add(" WHEN s_mult_shift_reg(0) = '1' ELSE");
Contents.add(" (OTHERS => '0');");
Contents.add(" s_busy_pipe_next <= \"00\" WHEN s_reset = '1' ELSE");
Contents.add(" s_busy_pipe_reg(0)&s_mult_busy;");
Contents.add("");
Contents.add(" make_current_seed : PROCESS( GlobalClock , s_busy_pipe_reg , s_reset )");
Contents.add(" BEGIN");
Contents.add(" IF (GlobalClock'event AND (GlobalClock = '1')) THEN");
Contents.add(" IF (s_reset = '1') THEN s_current_seed <= s_InitSeed;");
Contents.add(" ELSIF (s_busy_pipe_reg = \"10\") THEN");
Contents.add(" s_current_seed <= s_mac_hi_reg&s_mac_lo_reg(23 DOWNTO 0 );");
Contents.add(" END IF;");
Contents.add(" END IF;");
Contents.add(" END PROCESS make_current_seed;");
Contents.add(" ");
Contents.add(" make_shift_regs : PROCESS(GlobalClock,s_mult_shift_next,s_seed_shift_next,");
Contents.add(" s_mac_lo_in_1,s_mac_lo_in_2)");
Contents.add(" BEGIN");
Contents.add(" IF (GlobalClock'event AND (GlobalClock = '1')) THEN");
Contents.add(" s_mult_shift_reg <= s_mult_shift_next;");
Contents.add(" s_seed_shift_reg <= s_seed_shift_next;");
Contents.add(" s_mac_lo_reg <= std_logic_vector(unsigned(s_mac_lo_in_1)+unsigned(s_mac_lo_in_2));");
Contents.add(" s_mac_hi_1_reg <= s_mac_hi_1_next;");
Contents.add(" s_mac_hi_reg <= std_logic_vector(unsigned(s_mac_hi_1_reg)+unsigned(s_mac_hi_in_2)+");
Contents.add(" unsigned(s_mac_lo_reg(24 DOWNTO 24)));");
Contents.add(" s_busy_pipe_reg <= s_busy_pipe_next;");
Contents.add(" END IF;");
Contents.add(" END PROCESS make_shift_regs;");
Contents.add("");
Contents.add(" make_start_reg : PROCESS(GlobalClock,s_start)");
Contents.add(" BEGIN");
Contents.add(" IF (GlobalClock'event AND (GlobalClock = '1')) THEN");
Contents.add(" s_start_reg <= s_start;");
Contents.add(" END IF;");
Contents.add(" END PROCESS make_start_reg;");
Contents.add("");
Contents.add(" make_reset_reg : PROCESS(GlobalClock,s_reset_next)");
Contents.add(" BEGIN");
Contents.add(" IF (GlobalClock'event AND (GlobalClock = '1')) THEN");
Contents.add(" s_reset_reg <= s_reset_next;");
Contents.add(" END IF;");
Contents.add(" END PROCESS make_reset_reg;");
Contents.add("");
Contents.add(" make_output : PROCESS( GlobalClock , s_reset , s_InitSeed )");
Contents.add(" BEGIN");
Contents.add(" IF (GlobalClock'event AND (GlobalClock = '1')) THEN");
Contents.add(" IF (s_reset = '1') THEN s_output_reg <= s_InitSeed( ("
+ NrOfBitsStr + "-1) DOWNTO 0 );");
Contents.add(" ELSIF (ClockEnable = '1' AND enable = '1') THEN");
Contents.add(" s_output_reg <= s_current_seed(("
+ NrOfBitsStr + "+11) DOWNTO 12);");
Contents.add(" END IF;");
Contents.add(" END IF;");
Contents.add(" END PROCESS make_output;");
} else {
Contents.add(" assign Q = s_output_reg;");
Contents.add(" assign s_InitSeed = (" + SeedStr + ") ? "
+ SeedStr + " : 48'h5DEECE66D;");
Contents.add(" assign s_reset = (s_reset_reg==3'b010) ? 1'b1 : 1'b0;");
Contents.add(" assign s_reset_next = (((s_reset_reg == 3'b101)|");
Contents.add(" (s_reset_reg == 3'b010))&~clear) ? 3'b010 :");
Contents.add(" (s_reset_reg==3'b001) ? 3'b101 : 3'b001;");
Contents.add(" assign s_start = ((ClockEnable&enable)|((s_reset_reg == 3'b101)&~clear)) ? 1'b1 : 1'b0;");
Contents.add(" assign s_mult_shift_next = (s_reset) ? 36'd0 :");
Contents.add(" (s_start_reg) ? 36'h5DEECE66D : {1'b0,s_mult_shift_reg[35:1]};");
Contents.add(" assign s_seed_shift_next = (s_reset) ? 48'd0 :");
Contents.add(" (s_start_reg) ? s_current_seed : {s_seed_shift_reg[46:0],1'b0};");
Contents.add(" assign s_mult_busy = (s_mult_shift_reg == 0) ? 1'b0 : 1'b1;");
Contents.add(" assign s_mac_lo_in_1 = (s_start_reg|s_reset) ? 25'd0 : {1'b0,s_mac_lo_reg[23:0]};");
Contents.add(" assign s_mac_lo_in_2 = (s_start_reg) ? 25'hB :");
Contents.add(" (s_mult_shift_reg[0]) ? {1'b0,s_seed_shift_reg[23:0]} : 25'd0;");
Contents.add(" assign s_mac_hi_in_2 = (s_start_reg) ? 0 : s_mac_hi_reg;");
Contents.add(" assign s_mac_hi_1_next = (s_mult_shift_reg[0]) ? s_seed_shift_reg[47:24] : 0;");
Contents.add(" assign s_busy_pipe_next = (s_reset) ? 2'd0 : {s_busy_pipe_reg[0],s_mult_busy};");
Contents.add("");
Contents.add(" always @(posedge GlobalClock)");
Contents.add(" begin");
Contents.add(" if (s_reset) s_current_seed <= s_InitSeed;");
Contents.add(" else if (s_busy_pipe_reg == 2'b10) s_current_seed <= {s_mac_hi_reg,s_mac_lo_reg[23:0]};");
Contents.add(" end");
Contents.add("");
Contents.add(" always @(posedge GlobalClock)");
Contents.add(" begin");
Contents.add(" s_mult_shift_reg <= s_mult_shift_next;");
Contents.add(" s_seed_shift_reg <= s_seed_shift_next;");
Contents.add(" s_mac_lo_reg <= s_mac_lo_in_1+s_mac_lo_in_2;");
Contents.add(" s_mac_hi_1_reg <= s_mac_hi_1_next;");
Contents.add(" s_mac_hi_reg <= s_mac_hi_1_reg+s_mac_hi_in_2+s_mac_lo_reg[24];");
Contents.add(" s_busy_pipe_reg <= s_busy_pipe_next;");
Contents.add(" s_start_reg <= s_start;");
Contents.add(" s_reset_reg <= s_reset_next;");
Contents.add(" end");
Contents.add("");
Contents.add(" always @(posedge GlobalClock)");
Contents.add(" begin");
Contents.add(" if (s_reset) s_output_reg <= s_InitSeed[("
+ NrOfBitsStr + "-1):0];");
Contents.add(" else if (ClockEnable&enable) s_output_reg <= s_current_seed[("
+ NrOfBitsStr + "+11):12];");
Contents.add(" end");
}
return Contents;
}
@Override
public SortedMap<String, Integer> GetOutputList(Netlist TheNetlist,
AttributeSet attrs) {
SortedMap<String, Integer> Outputs = new TreeMap<String, Integer>();
Outputs.put("Q", NrOfBitsId);
return Outputs;
}
@Override
public SortedMap<Integer, String> GetParameterList(AttributeSet attrs) {
SortedMap<Integer, String> Parameters = new TreeMap<Integer, String>();
Parameters.put(NrOfBitsId, NrOfBitsStr);
Parameters.put(SeedId, SeedStr);
return Parameters;
}
@Override
public SortedMap<String, Integer> GetParameterMap(Netlist Nets,
NetlistComponent ComponentInfo, FPGAReport Reporter) {
SortedMap<String, Integer> ParameterMap = new TreeMap<String, Integer>();
int seed = ComponentInfo.GetComponent().getAttributeSet()
.getValue(Random.ATTR_SEED);
if (seed == 0)
seed = (int) System.currentTimeMillis();
ParameterMap.put(NrOfBitsStr, ComponentInfo.GetComponent()
.getAttributeSet().getValue(StdAttr.WIDTH).getWidth());
ParameterMap.put(SeedStr, seed);
return ParameterMap;
}
@Override
public SortedMap<String, String> GetPortMap(Netlist Nets,
NetlistComponent ComponentInfo, FPGAReport Reporter, String HDLType) {
SortedMap<String, String> PortMap = new TreeMap<String, String>();
Boolean GatedClock = false;
Boolean HasClock = true;
Boolean ActiveLow = false;
String ZeroBit = (HDLType.equals(Settings.VHDL)) ? "'0'" : "1'b0";
String BracketOpen = (HDLType.equals(Settings.VHDL)) ? "(" : "[";
String BracketClose = (HDLType.equals(Settings.VHDL)) ? ")" : "]";
if (!ComponentInfo.EndIsConnected(Random.CK)) {
Reporter.AddSevereWarning("Component \"Random\" in circuit \""
+ Nets.getCircuitName() + "\" has no clock connection");
HasClock = false;
}
String ClockNetName = GetClockNetName(ComponentInfo, Random.CK, Nets);
if (ClockNetName.isEmpty()) {
GatedClock = true;
Reporter.AddError("Found a gated clock for component \"Random\" in circuit \""
+ Nets.getCircuitName() + "\"");
Reporter.AddError("This RNG will not work!");
}
if (ComponentInfo.GetComponent().getAttributeSet()
.containsAttribute(StdAttr.EDGE_TRIGGER)) {
ActiveLow = ComponentInfo.GetComponent().getAttributeSet()
.getValue(StdAttr.EDGE_TRIGGER) == StdAttr.TRIG_FALLING;
}
if (!HasClock || GatedClock) {
PortMap.put("GlobalClock", ZeroBit);
PortMap.put("ClockEnable", ZeroBit);
} else {
PortMap.put(
"GlobalClock",
ClockNetName
+ BracketOpen
+ Integer
.toString(ClockHDLGeneratorFactory.GlobalClockIndex)
+ BracketClose);
if (Nets.RequiresGlobalClockConnection()) {
PortMap.put(
"ClockEnable",
ClockNetName
+ BracketOpen
+ Integer
.toString(ClockHDLGeneratorFactory.GlobalClockIndex)
+ BracketClose);
} else {
if (ActiveLow)
PortMap.put(
"ClockEnable",
ClockNetName
+ BracketOpen
+ Integer
.toString(ClockHDLGeneratorFactory.NegativeEdgeTickIndex)
+ BracketClose);
else
PortMap.put(
"ClockEnable",
ClockNetName
+ BracketOpen
+ Integer
.toString(ClockHDLGeneratorFactory.PositiveEdgeTickIndex)
+ BracketClose);
}
}
PortMap.putAll(GetNetMap("clear", true, ComponentInfo, Random.RST,
Reporter, HDLType, Nets));
PortMap.putAll(GetNetMap("enable", false, ComponentInfo, Random.NXT,
Reporter, HDLType, Nets));
String output = "Q";
if (HDLType.equals(Settings.VHDL)
& (ComponentInfo.GetComponent().getAttributeSet()
.getValue(StdAttr.WIDTH).getWidth() == 1))
output += "(0)";
PortMap.putAll(GetNetMap(output, true, ComponentInfo, Random.OUT,
Reporter, HDLType, Nets));
return PortMap;
}
@Override
public SortedMap<String, Integer> GetRegList(AttributeSet attrs,
String HDLType) {
SortedMap<String, Integer> Regs = new TreeMap<String, Integer>();
Regs.put("s_current_seed", 48);
Regs.put("s_reset_reg", 3);
Regs.put("s_mult_shift_reg", 36);
Regs.put("s_seed_shift_reg", 48);
Regs.put("s_start_reg", 1);
Regs.put("s_mac_lo_reg", 25);
Regs.put("s_mac_hi_reg", 24);
Regs.put("s_mac_hi_1_reg", 24);
Regs.put("s_busy_pipe_reg", 2);
Regs.put("s_output_reg", NrOfBitsId);
return Regs;
}
@Override
public String GetSubDir() {
return "memory";
}
@Override
public SortedMap<String, Integer> GetWireList(AttributeSet attrs,
Netlist Nets) {
SortedMap<String, Integer> Wires = new TreeMap<String, Integer>();
Wires.put("s_InitSeed", 48);
Wires.put("s_reset", 1);
Wires.put("s_reset_next", 3);
Wires.put("s_mult_shift_next", 36);
Wires.put("s_seed_shift_next", 48);
Wires.put("s_mult_busy", 1);
Wires.put("s_start", 1);
Wires.put("s_mac_lo_in_1", 25);
Wires.put("s_mac_lo_in_2", 25);
Wires.put("s_mac_hi_1_next", 24);
Wires.put("s_mac_hi_in_2", 24);
Wires.put("s_busy_pipe_next", 2);
return Wires;
}
@Override
public boolean HDLTargetSupported(String HDLType, AttributeSet attrs) {
return true;
}
}