Permalink
Browse files

Add Ethernet MAC

  • Loading branch information...
1 parent 7d18736 commit 4e18e456864a0a37b684e088bd33876ccfbf89c8 @sbourdeauducq sbourdeauducq committed May 19, 2012
View
@@ -12,6 +12,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("generic")
add_core_dir("m1crg")
add_core_dir("s6ddrphy")
add_core_files("lm32", ["lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
@@ -20,6 +21,7 @@ def add_core_files(d, files):
"lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v",
"lm32_dcache.v", "lm32_top.v", "lm32_debug.v", "lm32_jtag.v", "jtag_cores.v",
"jtag_tap_spartan6.v"])
+add_core_dir("minimac3")
os.chdir("build")
View
@@ -4,5 +4,6 @@
#define UART_BASE 0xe0000000
#define DFII_BASE 0xe0000800
#define ID_BASE 0xe0001000
+#define MINIMAC_BASE 0xe0001800
#endif /* __CSRBASE_H */
View
@@ -1,5 +1,5 @@
class Constraints:
- def __init__(self, crg0, norflash0, uart0, ddrphy0):
+ def __init__(self, crg0, norflash0, uart0, ddrphy0, minimac0):
self.constraints = []
def add(signal, pin, vec=-1, iostandard="LVCMOS33", extra=""):
self.constraints.append((signal, vec, pin, iostandard, extra))
@@ -15,6 +15,7 @@ def add_vec(signal, pins, iostandard="LVCMOS33", extra=""):
add(crg0.videoin_rst_n, "W17")
add(crg0.flash_rst_n, "P22", extra="SLEW = FAST | DRIVE = 8")
add(crg0.trigger_reset, "AA4")
+ add(crg0.phy_clk, "M20")
add_vec(norflash0.adr, ["L22", "L20", "K22", "K21", "J19", "H20", "F22",
"F21", "K17", "J17", "E22", "E20", "H18", "H19", "F20",
@@ -47,6 +48,21 @@ def add_vec(signal, pins, iostandard="LVCMOS33", extra=""):
extra=ddrsettings)
add_vec(ddrphy0.sd_dm, ["E1", "E3", "F3", "G4"], extra=ddrsettings)
add_vec(ddrphy0.sd_dqs, ["F1", "F2", "H5", "H6"], extra=ddrsettings)
+
+ add(minimac0.phy_rst_n, "R22")
+ add(minimac0.phy_dv, "V21")
+ add(minimac0.phy_rx_clk, "H22")
+ add(minimac0.phy_rx_er, "V22")
+ add_vec(minimac0.phy_rx_data, ["U22", "U20", "T22", "T21"])
+ add(minimac0.phy_tx_en, "N19")
+ add(minimac0.phy_tx_clk, "H21")
+ add(minimac0.phy_tx_er, "M19")
+ add_vec(minimac0.phy_tx_data, ["M16", "L15", "P19", "P20"])
+ add(minimac0.phy_col, "W20")
+ add(minimac0.phy_crs, "W22")
+
+ self._phy_rx_clk = minimac0.phy_rx_clk
+ self._phy_tx_clk = minimac0.phy_tx_clk
def get_ios(self):
return set([c[0] for c in self.constraints])
@@ -69,6 +85,13 @@ def get_ucf(self, ns):
INST "m1crg/rd_bufpll" LOC = "BUFPLL_X0Y3";
PIN "m1crg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE;
-"""
+
+NET "{phy_rx_clk}" TNM_NET = "GRPphy_rx_clk";
+NET "{phy_tx_clk}" TNM_NET = "GRPphy_tx_clk";
+TIMESPEC "TSphy_rx_clk" = PERIOD "GRPphy_rx_clk" 40 ns HIGH 50%;
+TIMESPEC "TSphy_tx_clk" = PERIOD "GRPphy_tx_clk" 40 ns HIGH 50%;
+TIMESPEC "TSphy_tx_clk_io" = FROM "GRPphy_tx_clk" TO "PADS" 10 ns;
+TIMESPEC "TSphy_rx_clk_io" = FROM "PADS" TO "GRPphy_rx_clk" 10 ns;
+""".format(phy_rx_clk=ns.get_name(self._phy_rx_clk), phy_tx_clk=ns.get_name(self._phy_tx_clk))
return r
@@ -18,7 +18,8 @@ def __init__(self, infreq, outfreq1x):
"clk4x_wr",
"clk4x_wr_strb",
"clk4x_rd",
- "clk4x_rd_strb"
+ "clk4x_rd_strb",
+ "phy_clk"
]:
s = Signal(name=name)
setattr(self, name, s)
@@ -0,0 +1,105 @@
+from migen.fhdl.structure import *
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+from migen.bank import csrgen
+from migen.bus import wishbone
+
+_count_width = 11
+
+class MiniMAC:
+ def __init__(self, address):
+ # PHY signals
+ self.phy_tx_clk = Signal()
+ self.phy_tx_data = Signal(BV(4))
+ self.phy_tx_en = Signal()
+ self.phy_tx_er = Signal()
+ self.phy_rx_clk = Signal()
+ self.phy_rx_data = Signal(BV(4))
+ self.phy_dv = Signal()
+ self.phy_rx_er = Signal()
+ self.phy_col = Signal()
+ self.phy_crs = Signal()
+ self.phy_rst_n = Signal()
+
+ # CPU interface
+ self._phy_reset = RegisterField("phy_reset", reset=1)
+ self._rx_count_0 = RegisterField("rx_count_0", _count_width, access_bus=READ_ONLY, access_dev=WRITE_ONLY)
+ self._rx_count_1 = RegisterField("rx_count_1", _count_width, access_bus=READ_ONLY, access_dev=WRITE_ONLY)
+ self._tx_count = RegisterField("tx_count", _count_width, access_dev=READ_WRITE)
+ regs = [self._phy_reset, self._rx_count_0, self._rx_count_1, self._tx_count]
+
+ self._rx_event_0 = EventSourcePulse()
+ self._rx_event_1 = EventSourcePulse()
+ self._tx_event = EventSourcePulse()
+ self.events = EventManager(self._rx_event_0, self._rx_event_1, self._tx_event)
+
+ self.bank = csrgen.Bank(regs + self.events.get_registers(), address=address)
+ self.membus = wishbone.Interface()
+
+ def get_fragment(self):
+ init = Signal(reset=1)
+ rx_ready_0 = Signal()
+ rx_ready_1 = Signal()
+ rx_pending_0 = self._rx_event_0.pending
+ rx_pending_1 = self._rx_event_1.pending
+ rx_pending_0_r = Signal()
+ rx_pending_1_r = Signal()
+ comb = [
+ self.phy_rst_n.eq(~self._phy_reset.field.r),
+
+ rx_ready_0.eq(init | (rx_pending_0_r & ~rx_pending_0)),
+ rx_ready_1.eq(init | (rx_pending_1_r & ~rx_pending_1)),
+
+ self._tx_count.field.w.eq(0),
+ self._tx_count.field.we.eq(self._tx_event.trigger)
+ ]
+ sync = [
+ init.eq(0),
+ rx_pending_0_r.eq(rx_pending_0),
+ rx_pending_1_r.eq(rx_pending_1)
+ ]
+ inst = [
+ Instance("minimac3",
+ [
+ ("rx_done_0", self._rx_event_0.trigger),
+ ("rx_count_0", self._rx_count_0.field.w),
+ ("rx_done_1", self._rx_event_1.trigger),
+ ("rx_count_1", self._rx_count_1.field.w),
+
+ ("tx_done", self._tx_event.trigger),
+
+ ("wb_dat_o", self.membus.dat_r),
+ ("wb_ack_o", self.membus.ack),
+
+ ("phy_tx_data", self.phy_tx_data),
+ ("phy_tx_en", self.phy_tx_en),
+ ("phy_tx_er", self.phy_tx_er),
+ ], [
+ ("rx_ready_0", rx_ready_0),
+ ("rx_ready_1", rx_ready_1),
+
+ ("tx_start", self._tx_count.re),
+ ("tx_count", self._tx_count.field.r),
+
+ ("wb_adr_i", self.membus.adr),
+ ("wb_dat_i", self.membus.dat_w),
+ ("wb_sel_i", self.membus.sel),
+ ("wb_stb_i", self.membus.stb),
+ ("wb_cyc_i", self.membus.cyc),
+ ("wb_we_i", self.membus.we),
+
+ ("phy_tx_clk", self.phy_tx_clk),
+ ("phy_rx_clk", self.phy_rx_clk),
+ ("phy_rx_data", self.phy_rx_data),
+ ("phy_dv", self.phy_dv),
+ ("phy_rx_er", self.phy_rx_er),
+ ("phy_col", self.phy_col),
+ ("phy_crs", self.phy_crs)
+ ],
+ clkport="sys_clk",
+ rstport="sys_rst"
+ )
+ ]
+ return Fragment(comb, sync, instances=inst) \
+ + self.events.get_fragment() \
+ + self.bank.get_fragment()
View
@@ -5,7 +5,7 @@
from migen.fhdl import verilog, autofragment
from migen.bus import wishbone, wishbone2asmi, csr, wishbone2csr, dfi
-from milkymist import m1crg, lm32, norflash, uart, sram, s6ddrphy, dfii, asmicon, identifier
+from milkymist import m1crg, lm32, norflash, uart, sram, s6ddrphy, dfii, asmicon, identifier, minimac3
from cmacros import get_macros
from constraints import Constraints
@@ -88,6 +88,7 @@ def get():
cpu0 = lm32.LM32()
norflash0 = norflash.NorFlash(25, 12)
sram0 = sram.SRAM(sram_size//4)
+ minimac0 = minimac3.MiniMAC(csr_offset("MINIMAC"))
wishbone2asmi0 = wishbone2asmi.WB2ASMI(l2_size//4, asmiport_wb)
wishbone2csr0 = wishbone2csr.WB2CSR()
@@ -104,6 +105,7 @@ def get():
], [
(binc("000"), norflash0.bus),
(binc("001"), sram0.bus),
+ (binc("011"), minimac0.membus),
(binc("10"), wishbone2asmi0.wishbone),
(binc("11"), wishbone2csr0.wishbone)
],
@@ -118,7 +120,8 @@ def get():
csrcon0 = csr.Interconnect(wishbone2csr0.csr, [
uart0.bank.interface,
dfii0.bank.interface,
- identifier0.bank.interface
+ identifier0.bank.interface,
+ minimac0.bank.interface
])
#
@@ -134,7 +137,7 @@ def get():
crg0 = m1crg.M1CRG(50*MHz, clk_freq)
frag = autofragment.from_local() + interrupts + ddrphy_clocking(crg0, ddrphy0)
- cst = Constraints(crg0, norflash0, uart0, ddrphy0)
+ cst = Constraints(crg0, norflash0, uart0, ddrphy0, minimac0)
src_verilog, vns = verilog.convert(frag,
cst.get_ios(),
name="soc",
@@ -0,0 +1,48 @@
+/*
+ * Milkymist 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 psync(
+ input clk1,
+ input i,
+ input clk2,
+ output o
+);
+
+reg level;
+always @(posedge clk1)
+ if(i)
+ level <= ~level;
+
+reg level1;
+reg level2;
+reg level3;
+always @(posedge clk2) begin
+ level1 <= level;
+ level2 <= level1;
+ level3 <= level2;
+end
+
+assign o = level2 ^ level3;
+
+initial begin
+ level <= 1'b0;
+ level1 <= 1'b0;
+ level2 <= 1'b0;
+ level3 <= 1'b0;
+end
+
+endmodule
View
@@ -37,7 +37,10 @@ module m1crg #(
output clk4x_wr,
output clk4x_wr_strb,
output clk4x_rd,
- output clk4x_rd_strb
+ output clk4x_rd_strb,
+
+ /* Ethernet PHY clock */
+ output reg phy_clk
);
/*
@@ -107,6 +110,7 @@ wire pllout0;
wire pllout1;
wire pllout2;
wire pllout3;
+wire pllout4;
PLL_ADV #(
.BANDWIDTH("OPTIMIZED"),
@@ -126,7 +130,7 @@ PLL_ADV #(
.CLKOUT3_DIVIDE(4*f_div),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT3_PHASE(0.0),
- .CLKOUT4_DIVIDE(7),
+ .CLKOUT4_DIVIDE(4*f_mult),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT4_PHASE(0),
.CLKOUT5_DIVIDE(7),
@@ -144,7 +148,7 @@ PLL_ADV #(
.CLKOUT1(pllout1), /* < x4 clock for reads */
.CLKOUT2(pllout2), /* < x2 90 clock to generate memory clock, clock DQS and memory address and control signals. */
.CLKOUT3(pllout3), /* < x1 clock for system and memory controller */
- .CLKOUT4(),
+ .CLKOUT4(pllout4), /* < buffered clkin */
.CLKOUT5(),
.CLKOUTDCM0(),
.CLKOUTDCM1(),
@@ -199,5 +203,9 @@ BUFG bufg_x1(
.I(pllout3),
.O(sys_clk)
);
+
+/* Ethernet PHY */
+always @(posedge pllout4)
+ phy_clk <= ~phy_clk;
endmodule
Oops, something went wrong.

0 comments on commit 4e18e45

Please sign in to comment.