Proper reset generation
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Fri, 16 Dec 2011 21:25:26 +0000 (22:25 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Fri, 16 Dec 2011 21:25:26 +0000 (22:25 +0100)
build.py
constraints.py
milkymist/m1reset/__init__.py [new file with mode: 0644]
milkymist/norflash/__init__.py
top.py
verilog/m1reset/m1reset.v [new file with mode: 0644]

index 661114f73a09f434267af471c1676fdd5658b46d..5e1f007b281ebfeb0adc0d86978304244d557466 100644 (file)
--- a/build.py
+++ b/build.py
@@ -10,6 +10,7 @@ def add_core_dir(d):
 def add_core_files(d, files):
        for f in files:
                verilog_sources.append(os.path.join("verilog", d, f))
+add_core_dir("m1reset")
 add_core_files("lm32", ["lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
        "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v",
        "lm32_shifter.v", "lm32_multiplier_spartan6.v", "lm32_mc_arithmetic.v",
index 12eba657ff196e86c9b598062155f69fa15bb010..8ffd501d7b913b29939190bd130c6d2d4c2c9f8a 100644 (file)
@@ -1,4 +1,4 @@
-def get(ns, norflash0, uart0):
+def get(ns, reset0, norflash0, uart0):
        constraints = []
        def add(signal, pin, vec=-1, iostandard="LVCMOS33", extra=""):
                constraints.append((ns.get_name(signal), vec, pin, iostandard, extra))
@@ -8,6 +8,11 @@ def get(ns, norflash0, uart0):
                        add(signal, p, i, iostandard, extra)
                        i += 1
        
+       add(reset0.trigger_reset, "AA4")
+       add(reset0.ac97_rst_n, "D6")
+       add(reset0.videoin_rst_n, "W17")
+       add(reset0.flash_rst_n, "P22", extra="SLEW = FAST | DRIVE = 8")
+       
        add_vec(norflash0.adr, ["L22", "L20", "K22", "K21", "J19", "H20", "F22",
                "F21", "K17", "J17", "E22", "E20", "H18", "H19", "F20",
                "G19", "C22", "C20", "D22", "D21", "F19", "F18", "D20", "D19"],
@@ -18,7 +23,6 @@ def get(ns, norflash0, uart0):
        add(norflash0.oe_n, "M22", extra="SLEW = FAST | DRIVE = 8")
        add(norflash0.we_n, "N20", extra="SLEW = FAST | DRIVE = 8")
        add(norflash0.ce_n, "M21", extra="SLEW = FAST | DRIVE = 8")
-       add(norflash0.rst_n, "P22", extra="SLEW = FAST | DRIVE = 8")
        
        add(uart0.tx, "L17", extra="SLEW = SLOW")
        add(uart0.rx, "K18", extra="PULLUP")
@@ -38,8 +42,6 @@ def get(ns, norflash0, uart0):
 NET "sys_clk" LOC = AB11 | IOSTANDARD = LVCMOS33;
 NET "sys_clk" TNM_NET = "GRPclk50";
 TIMESPEC "TSclk50" = PERIOD "GRPclk50" 20 ns HIGH 50%;
-
-NET "sys_rst" LOC = AA4 | IOSTANDARD = LVCMOS33;
        """
        
        return r
diff --git a/milkymist/m1reset/__init__.py b/milkymist/m1reset/__init__.py
new file mode 100644 (file)
index 0000000..bfc3421
--- /dev/null
@@ -0,0 +1,23 @@
+from functools import partial
+
+from migen.fhdl.structure import *
+
+class Inst:
+       def __init__(self):
+               d = partial(declare_signal, self)
+               d("trigger_reset")
+               d("sys_rst")
+               d("ac97_rst_n")
+               d("videoin_rst_n")
+               d("flash_rst_n")
+               self._inst = Instance("m1reset",
+                       [("sys_rst", self.sys_rst),
+                       ("ac97_rst_n", self.ac97_rst_n),
+                       ("videoin_rst_n", self.videoin_rst_n),
+                       ("flash_rst_n", self.flash_rst_n)],
+                       [("trigger_reset", self.trigger_reset)],
+                       clkport="sys_clk")
+
+       def get_fragment(self):
+               return Fragment(instances=[self._inst],
+                       pads={self.ac97_rst_n, self.videoin_rst_n, self.flash_rst_n})
index 55ffa6ea55cfb6769144979188dcad0427339afe..99b6c12df11161f21350bad4017068ac52a86d82 100644 (file)
@@ -13,7 +13,6 @@ class Inst:
                d("oe_n")
                d("we_n")
                d("ce_n")
-               d("rst_n")
                self.timeline = timeline.Inst(self.bus.cyc_i & self.bus.stb_i,
                        [(0, [self.adr.eq(Cat(0, self.bus.adr_i[2:adr_width]))]),
                        (rd_timing, [
@@ -27,6 +26,6 @@ class Inst:
        
        def get_fragment(self):
                comb = [self.oe_n.eq(0), self.we_n.eq(1),
-                       self.ce_n.eq(0), self.rst_n.eq(1)]
-               return Fragment(comb, pads={self.adr, self.d, self.oe_n, self.we_n, self.ce_n, self.rst_n}) \
+                       self.ce_n.eq(0)]
+               return Fragment(comb, pads={self.adr, self.d, self.oe_n, self.we_n, self.ce_n}) \
                        + self.timeline.get_fragment()
diff --git a/top.py b/top.py
index f91cb75d59856fdbce7581f0c148516db5adfe9c..75e8f70de929684252eb0617856bd53534d282c0 100644 (file)
--- a/top.py
+++ b/top.py
@@ -1,10 +1,13 @@
+from migen.fhdl.structure import *
 from migen.fhdl import convtools, verilog, autofragment
 from migen.bus import wishbone, csr, wishbone2csr
 
-from milkymist import lm32, norflash, uart
+from milkymist import m1reset, lm32, norflash, uart
 import constraints
 
 def get():
+       reset0 = m1reset.Inst()
+       
        cpu0 = lm32.Inst()
        norflash0 = norflash.Inst(25, 12)
        wishbone2csr0 = wishbone2csr.Inst()
@@ -16,8 +19,10 @@ def get():
        uart0 = uart.Inst(0, 50*1000*1000, baud=115200)
        csrcon0 = csr.Interconnect(wishbone2csr0.csr, [uart0.bus])
        
-       frag = autofragment.from_local()
+       frag = autofragment.from_local() + Fragment(pads={reset0.trigger_reset})
        vns = convtools.Namespace()
-       src_verilog = verilog.Convert(frag, name="soc", ns=vns)
-       src_ucf = constraints.get(vns, norflash0, uart0)
+       src_verilog = verilog.Convert(frag, name="soc",
+               rst_signal=reset0.sys_rst,
+               ns=vns)
+       src_ucf = constraints.get(vns, reset0, norflash0, uart0)
        return (src_verilog, src_ucf)
diff --git a/verilog/m1reset/m1reset.v b/verilog/m1reset/m1reset.v
new file mode 100644 (file)
index 0000000..4095e46
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Milkymist-NG SoC
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+module m1reset(
+       input sys_clk,
+       input trigger_reset,
+       
+       output reg sys_rst,
+       output ac97_rst_n,
+       output videoin_rst_n,
+       output flash_rst_n
+);
+
+reg [19:0] rst_debounce;
+initial rst_debounce <= 20'hFFFFF;
+initial sys_rst <= 1'b1;
+always @(posedge sys_clk) begin
+       if(trigger_reset)
+               rst_debounce <= 20'hFFFFF;
+       else if(rst_debounce != 20'd0)
+               rst_debounce <= rst_debounce - 20'd1;
+       sys_rst <= rst_debounce != 20'd0;
+end
+
+assign ac97_rst_n = ~sys_rst;
+assign videoin_rst_n = ~sys_rst;
+
+/*
+ * We must release the Flash reset before the system reset
+ * because the Flash needs some time to come out of reset
+ * and the CPU begins fetching instructions from it
+ * as soon as the system reset is released.
+ * From datasheet, minimum reset pulse width is 100ns
+ * and reset-to-read time is 150ns.
+ */
+
+reg [7:0] flash_rstcounter;
+initial flash_rstcounter <= 8'd0;
+always @(posedge sys_clk) begin
+       if(trigger_reset)
+               flash_rstcounter <= 8'd0;
+       else if(~flash_rstcounter[7])
+               flash_rstcounter <= flash_rstcounter + 8'd1;
+end
+
+assign flash_rst_n = flash_rstcounter[7];
+
+endmodule