Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add Ethernet MAC

  • Loading branch information...
commit 4e18e456864a0a37b684e088bd33876ccfbf89c8 1 parent 7d18736
Sébastien Bourdeauducq authored May 20, 2012
2  build.py
@@ -12,6 +12,7 @@ def add_core_dir(d):
12 12
 def add_core_files(d, files):
13 13
 	for f in files:
14 14
 		verilog_sources.append(os.path.join("verilog", d, f))
  15
+add_core_dir("generic")
15 16
 add_core_dir("m1crg")
16 17
 add_core_dir("s6ddrphy")
17 18
 add_core_files("lm32", ["lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
@@ -20,6 +21,7 @@ def add_core_files(d, files):
20 21
 	"lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v",
21 22
 	"lm32_dcache.v", "lm32_top.v", "lm32_debug.v", "lm32_jtag.v", "jtag_cores.v",
22 23
 	"jtag_tap_spartan6.v"])
  24
+add_core_dir("minimac3")
23 25
 
24 26
 os.chdir("build")
25 27
 
1  common/csrbase.h
@@ -4,5 +4,6 @@
4 4
 #define UART_BASE	0xe0000000
5 5
 #define DFII_BASE	0xe0000800
6 6
 #define ID_BASE		0xe0001000
  7
+#define MINIMAC_BASE	0xe0001800
7 8
 
8 9
 #endif /* __CSRBASE_H */
27  constraints.py
... ...
@@ -1,5 +1,5 @@
1 1
 class Constraints:
2  
-	def __init__(self, crg0, norflash0, uart0, ddrphy0):
  2
+	def __init__(self, crg0, norflash0, uart0, ddrphy0, minimac0):
3 3
 		self.constraints = []
4 4
 		def add(signal, pin, vec=-1, iostandard="LVCMOS33", extra=""):
5 5
 			self.constraints.append((signal, vec, pin, iostandard, extra))
@@ -15,6 +15,7 @@ def add_vec(signal, pins, iostandard="LVCMOS33", extra=""):
15 15
 		add(crg0.videoin_rst_n, "W17")
16 16
 		add(crg0.flash_rst_n, "P22", extra="SLEW = FAST | DRIVE = 8")
17 17
 		add(crg0.trigger_reset, "AA4")
  18
+		add(crg0.phy_clk, "M20")
18 19
 		
19 20
 		add_vec(norflash0.adr, ["L22", "L20", "K22", "K21", "J19", "H20", "F22",
20 21
 			"F21", "K17", "J17", "E22", "E20", "H18", "H19", "F20",
@@ -47,6 +48,21 @@ def add_vec(signal, pins, iostandard="LVCMOS33", extra=""):
47 48
 			extra=ddrsettings)
48 49
 		add_vec(ddrphy0.sd_dm, ["E1", "E3", "F3", "G4"], extra=ddrsettings)
49 50
 		add_vec(ddrphy0.sd_dqs, ["F1", "F2", "H5", "H6"], extra=ddrsettings)
  51
+		
  52
+		add(minimac0.phy_rst_n, "R22")
  53
+		add(minimac0.phy_dv, "V21")
  54
+		add(minimac0.phy_rx_clk, "H22")
  55
+		add(minimac0.phy_rx_er, "V22")
  56
+		add_vec(minimac0.phy_rx_data, ["U22", "U20", "T22", "T21"])
  57
+		add(minimac0.phy_tx_en, "N19")
  58
+		add(minimac0.phy_tx_clk, "H21")
  59
+		add(minimac0.phy_tx_er, "M19")
  60
+		add_vec(minimac0.phy_tx_data, ["M16", "L15", "P19", "P20"])
  61
+		add(minimac0.phy_col, "W20")
  62
+		add(minimac0.phy_crs, "W22")
  63
+		
  64
+		self._phy_rx_clk = minimac0.phy_rx_clk
  65
+		self._phy_tx_clk = minimac0.phy_tx_clk
50 66
 
51 67
 	def get_ios(self):
52 68
 		return set([c[0] for c in self.constraints])
@@ -69,6 +85,13 @@ def get_ucf(self, ns):
69 85
 INST "m1crg/rd_bufpll" LOC = "BUFPLL_X0Y3";
70 86
 
71 87
 PIN "m1crg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE;
72  
-"""
  88
+
  89
+NET "{phy_rx_clk}" TNM_NET = "GRPphy_rx_clk";
  90
+NET "{phy_tx_clk}" TNM_NET = "GRPphy_tx_clk";
  91
+TIMESPEC "TSphy_rx_clk" = PERIOD "GRPphy_rx_clk" 40 ns HIGH 50%;
  92
+TIMESPEC "TSphy_tx_clk" = PERIOD "GRPphy_tx_clk" 40 ns HIGH 50%;
  93
+TIMESPEC "TSphy_tx_clk_io" = FROM "GRPphy_tx_clk" TO "PADS" 10 ns;
  94
+TIMESPEC "TSphy_rx_clk_io" = FROM "PADS" TO "GRPphy_rx_clk" 10 ns;
  95
+""".format(phy_rx_clk=ns.get_name(self._phy_rx_clk), phy_tx_clk=ns.get_name(self._phy_tx_clk))
73 96
 	
74 97
 		return r
3  milkymist/m1crg/__init__.py
@@ -18,7 +18,8 @@ def __init__(self, infreq, outfreq1x):
18 18
 			"clk4x_wr",
19 19
 			"clk4x_wr_strb",
20 20
 			"clk4x_rd",
21  
-			"clk4x_rd_strb"
  21
+			"clk4x_rd_strb",
  22
+			"phy_clk"
22 23
 		]:
23 24
 			s = Signal(name=name)
24 25
 			setattr(self, name, s)
105  milkymist/minimac3/__init__.py
... ...
@@ -0,0 +1,105 @@
  1
+from migen.fhdl.structure import *
  2
+from migen.bank.description import *
  3
+from migen.bank.eventmanager import *
  4
+from migen.bank import csrgen
  5
+from migen.bus import wishbone
  6
+
  7
+_count_width = 11
  8
+
  9
+class MiniMAC:
  10
+	def __init__(self, address):
  11
+		# PHY signals
  12
+		self.phy_tx_clk = Signal()
  13
+		self.phy_tx_data = Signal(BV(4))
  14
+		self.phy_tx_en = Signal()
  15
+		self.phy_tx_er = Signal()
  16
+		self.phy_rx_clk = Signal()
  17
+		self.phy_rx_data = Signal(BV(4))
  18
+		self.phy_dv = Signal()
  19
+		self.phy_rx_er = Signal()
  20
+		self.phy_col = Signal()
  21
+		self.phy_crs = Signal()
  22
+		self.phy_rst_n = Signal()
  23
+		
  24
+		# CPU interface
  25
+		self._phy_reset = RegisterField("phy_reset", reset=1)
  26
+		self._rx_count_0 = RegisterField("rx_count_0", _count_width, access_bus=READ_ONLY, access_dev=WRITE_ONLY)
  27
+		self._rx_count_1 = RegisterField("rx_count_1", _count_width, access_bus=READ_ONLY, access_dev=WRITE_ONLY)
  28
+		self._tx_count = RegisterField("tx_count", _count_width, access_dev=READ_WRITE)
  29
+		regs = [self._phy_reset, self._rx_count_0, self._rx_count_1, self._tx_count]
  30
+		
  31
+		self._rx_event_0 = EventSourcePulse()
  32
+		self._rx_event_1 = EventSourcePulse()
  33
+		self._tx_event = EventSourcePulse()
  34
+		self.events = EventManager(self._rx_event_0, self._rx_event_1, self._tx_event)
  35
+		
  36
+		self.bank = csrgen.Bank(regs + self.events.get_registers(), address=address)
  37
+		self.membus = wishbone.Interface()
  38
+		
  39
+	def get_fragment(self):
  40
+		init = Signal(reset=1)
  41
+		rx_ready_0 = Signal()
  42
+		rx_ready_1 = Signal()
  43
+		rx_pending_0 = self._rx_event_0.pending
  44
+		rx_pending_1 = self._rx_event_1.pending
  45
+		rx_pending_0_r = Signal()
  46
+		rx_pending_1_r = Signal()
  47
+		comb = [
  48
+			self.phy_rst_n.eq(~self._phy_reset.field.r),
  49
+			
  50
+			rx_ready_0.eq(init | (rx_pending_0_r & ~rx_pending_0)),
  51
+			rx_ready_1.eq(init | (rx_pending_1_r & ~rx_pending_1)),
  52
+			
  53
+			self._tx_count.field.w.eq(0),
  54
+			self._tx_count.field.we.eq(self._tx_event.trigger)
  55
+		]
  56
+		sync = [
  57
+			init.eq(0),
  58
+			rx_pending_0_r.eq(rx_pending_0),
  59
+			rx_pending_1_r.eq(rx_pending_1)
  60
+		]
  61
+		inst = [
  62
+			Instance("minimac3",
  63
+				[
  64
+					("rx_done_0", self._rx_event_0.trigger),
  65
+					("rx_count_0", self._rx_count_0.field.w),
  66
+					("rx_done_1", self._rx_event_1.trigger),
  67
+					("rx_count_1", self._rx_count_1.field.w),
  68
+					
  69
+					("tx_done", self._tx_event.trigger),
  70
+					
  71
+					("wb_dat_o", self.membus.dat_r),
  72
+					("wb_ack_o", self.membus.ack),
  73
+					
  74
+					("phy_tx_data", self.phy_tx_data),
  75
+					("phy_tx_en", self.phy_tx_en),
  76
+					("phy_tx_er", self.phy_tx_er),
  77
+				], [
  78
+					("rx_ready_0", rx_ready_0),
  79
+					("rx_ready_1", rx_ready_1),
  80
+					
  81
+					("tx_start", self._tx_count.re),
  82
+					("tx_count", self._tx_count.field.r),
  83
+					
  84
+					("wb_adr_i", self.membus.adr),
  85
+					("wb_dat_i", self.membus.dat_w),
  86
+					("wb_sel_i", self.membus.sel),
  87
+					("wb_stb_i", self.membus.stb),
  88
+					("wb_cyc_i", self.membus.cyc),
  89
+					("wb_we_i", self.membus.we),
  90
+					
  91
+					("phy_tx_clk", self.phy_tx_clk),
  92
+					("phy_rx_clk", self.phy_rx_clk),
  93
+					("phy_rx_data", self.phy_rx_data),
  94
+					("phy_dv", self.phy_dv),
  95
+					("phy_rx_er", self.phy_rx_er),
  96
+					("phy_col", self.phy_col),
  97
+					("phy_crs", self.phy_crs)
  98
+				],
  99
+				clkport="sys_clk",
  100
+				rstport="sys_rst"
  101
+			)
  102
+		]
  103
+		return Fragment(comb, sync, instances=inst) \
  104
+			+ self.events.get_fragment() \
  105
+			+ self.bank.get_fragment()
9  top.py
@@ -5,7 +5,7 @@
5 5
 from migen.fhdl import verilog, autofragment
6 6
 from migen.bus import wishbone, wishbone2asmi, csr, wishbone2csr, dfi
7 7
 
8  
-from milkymist import m1crg, lm32, norflash, uart, sram, s6ddrphy, dfii, asmicon, identifier
  8
+from milkymist import m1crg, lm32, norflash, uart, sram, s6ddrphy, dfii, asmicon, identifier, minimac3
9 9
 from cmacros import get_macros
10 10
 from constraints import Constraints
11 11
 
@@ -88,6 +88,7 @@ def get():
88 88
 	cpu0 = lm32.LM32()
89 89
 	norflash0 = norflash.NorFlash(25, 12)
90 90
 	sram0 = sram.SRAM(sram_size//4)
  91
+	minimac0 = minimac3.MiniMAC(csr_offset("MINIMAC"))
91 92
 	wishbone2asmi0 = wishbone2asmi.WB2ASMI(l2_size//4, asmiport_wb)
92 93
 	wishbone2csr0 = wishbone2csr.WB2CSR()
93 94
 	
@@ -104,6 +105,7 @@ def get():
104 105
 		], [
105 106
 			(binc("000"), norflash0.bus),
106 107
 			(binc("001"), sram0.bus),
  108
+			(binc("011"), minimac0.membus),
107 109
 			(binc("10"), wishbone2asmi0.wishbone),
108 110
 			(binc("11"), wishbone2csr0.wishbone)
109 111
 		],
@@ -118,7 +120,8 @@ def get():
118 120
 	csrcon0 = csr.Interconnect(wishbone2csr0.csr, [
119 121
 		uart0.bank.interface,
120 122
 		dfii0.bank.interface,
121  
-		identifier0.bank.interface
  123
+		identifier0.bank.interface,
  124
+		minimac0.bank.interface
122 125
 	])
123 126
 	
124 127
 	#
@@ -134,7 +137,7 @@ def get():
134 137
 	crg0 = m1crg.M1CRG(50*MHz, clk_freq)
135 138
 	
136 139
 	frag = autofragment.from_local() + interrupts + ddrphy_clocking(crg0, ddrphy0)
137  
-	cst = Constraints(crg0, norflash0, uart0, ddrphy0)
  140
+	cst = Constraints(crg0, norflash0, uart0, ddrphy0, minimac0)
138 141
 	src_verilog, vns = verilog.convert(frag,
139 142
 		cst.get_ios(),
140 143
 		name="soc",
48  verilog/generic/psync.v
... ...
@@ -0,0 +1,48 @@
  1
+/*
  2
+ * Milkymist SoC
  3
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
  18
+module psync(
  19
+	input clk1,
  20
+	input i,
  21
+	input clk2,
  22
+	output o
  23
+);
  24
+
  25
+reg level;
  26
+always @(posedge clk1)
  27
+	if(i)
  28
+		level <= ~level;
  29
+
  30
+reg level1;
  31
+reg level2;
  32
+reg level3;
  33
+always @(posedge clk2) begin
  34
+	level1 <= level;
  35
+	level2 <= level1;
  36
+	level3 <= level2;
  37
+end
  38
+
  39
+assign o = level2 ^ level3;
  40
+
  41
+initial begin
  42
+	level <= 1'b0;
  43
+	level1 <= 1'b0;
  44
+	level2 <= 1'b0;
  45
+	level3 <= 1'b0;
  46
+end
  47
+
  48
+endmodule
14  verilog/m1crg/m1crg.v
@@ -37,7 +37,10 @@ module m1crg #(
37 37
 	output clk4x_wr,
38 38
 	output clk4x_wr_strb,
39 39
 	output clk4x_rd,
40  
-	output clk4x_rd_strb
  40
+	output clk4x_rd_strb,
  41
+	
  42
+	/* Ethernet PHY clock */
  43
+	output reg phy_clk
41 44
 );
42 45
 
43 46
 /*
@@ -107,6 +110,7 @@ wire pllout0;
107 110
 wire pllout1;
108 111
 wire pllout2;
109 112
 wire pllout3;
  113
+wire pllout4;
110 114
 
111 115
 PLL_ADV #(
112 116
 	.BANDWIDTH("OPTIMIZED"),
@@ -126,7 +130,7 @@ PLL_ADV #(
126 130
 	.CLKOUT3_DIVIDE(4*f_div),
127 131
 	.CLKOUT3_DUTY_CYCLE(0.5),
128 132
 	.CLKOUT3_PHASE(0.0),
129  
-	.CLKOUT4_DIVIDE(7),
  133
+	.CLKOUT4_DIVIDE(4*f_mult),
130 134
 	.CLKOUT4_DUTY_CYCLE(0.5),
131 135
 	.CLKOUT4_PHASE(0),
132 136
 	.CLKOUT5_DIVIDE(7),
@@ -144,7 +148,7 @@ PLL_ADV #(
144 148
 	.CLKOUT1(pllout1), /* < x4 clock for reads */
145 149
 	.CLKOUT2(pllout2), /* < x2 90 clock to generate memory clock, clock DQS and memory address and control signals. */
146 150
 	.CLKOUT3(pllout3), /* < x1 clock for system and memory controller */
147  
-	.CLKOUT4(),
  151
+	.CLKOUT4(pllout4), /* < buffered clkin */
148 152
 	.CLKOUT5(),
149 153
 	.CLKOUTDCM0(),
150 154
 	.CLKOUTDCM1(),
@@ -199,5 +203,9 @@ BUFG bufg_x1(
199 203
 	.I(pllout3),
200 204
 	.O(sys_clk)
201 205
 );
  206
+
  207
+/* Ethernet PHY */
  208
+always @(posedge pllout4)
  209
+	phy_clk <= ~phy_clk;
202 210
  
203 211
 endmodule
155  verilog/minimac3/minimac3.v
... ...
@@ -0,0 +1,155 @@
  1
+/*
  2
+ * Milkymist SoC
  3
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
  18
+module minimac3(
  19
+	input sys_clk,
  20
+	input sys_rst,
  21
+
  22
+	/* Control */
  23
+	input rx_ready_0,
  24
+	output rx_done_0,
  25
+	output [10:0] rx_count_0,
  26
+	input rx_ready_1,
  27
+	output rx_done_1,
  28
+	output [10:0] rx_count_1,
  29
+	
  30
+	input tx_start,
  31
+	output tx_done,
  32
+	input [10:0] tx_count,
  33
+
  34
+	/* WISHBONE to access RAM */
  35
+	input [29:0] wb_adr_i,
  36
+	output [31:0] wb_dat_o,
  37
+	input [31:0] wb_dat_i,
  38
+	input [3:0] wb_sel_i,
  39
+	input wb_stb_i,
  40
+	input wb_cyc_i,
  41
+	output wb_ack_o,
  42
+	input wb_we_i,
  43
+
  44
+	/* To PHY */
  45
+	input phy_tx_clk,
  46
+	output [3:0] phy_tx_data,
  47
+	output phy_tx_en,
  48
+	output phy_tx_er,
  49
+	input phy_rx_clk,
  50
+	input [3:0] phy_rx_data,
  51
+	input phy_dv,
  52
+	input phy_rx_er,
  53
+	input phy_col,
  54
+	input phy_crs
  55
+);
  56
+
  57
+wire [1:0] phy_rx_ready;
  58
+wire [1:0] phy_rx_done;
  59
+wire [10:0] phy_rx_count_0;
  60
+wire [10:0] phy_rx_count_1;
  61
+wire phy_tx_start;
  62
+wire phy_tx_done;
  63
+wire [10:0] phy_tx_count;
  64
+
  65
+minimac3_sync sync(
  66
+	.sys_clk(sys_clk),
  67
+	.phy_rx_clk(phy_rx_clk),
  68
+	.phy_tx_clk(phy_tx_clk),
  69
+	
  70
+	.sys_rx_ready({rx_ready_1, rx_ready_0}),
  71
+	.sys_rx_done({rx_done_1, rx_done_0}),
  72
+	.sys_rx_count_0(rx_count_0),
  73
+	.sys_rx_count_1(rx_count_1),
  74
+	.sys_tx_start(tx_start),
  75
+	.sys_tx_done(tx_done),
  76
+	.sys_tx_count(tx_count),
  77
+	
  78
+	.phy_rx_ready(phy_rx_ready),
  79
+	.phy_rx_done(phy_rx_done),
  80
+	.phy_rx_count_0(phy_rx_count_0),
  81
+	.phy_rx_count_1(phy_rx_count_1),
  82
+	.phy_tx_start(phy_tx_start),
  83
+	.phy_tx_done(phy_tx_done),
  84
+	.phy_tx_count(phy_tx_count)
  85
+);
  86
+
  87
+wire [7:0] rxb0_dat;
  88
+wire [10:0] rxb0_adr;
  89
+wire rxb0_we;
  90
+wire [7:0] rxb1_dat;
  91
+wire [10:0] rxb1_adr;
  92
+wire rxb1_we;
  93
+wire [7:0] txb_dat;
  94
+wire [10:0] txb_adr;
  95
+minimac3_memory memory(
  96
+	.sys_clk(sys_clk),
  97
+	.sys_rst(sys_rst),
  98
+	.phy_rx_clk(phy_rx_clk),
  99
+	.phy_tx_clk(phy_tx_clk),
  100
+
  101
+	.wb_adr_i(wb_adr_i),
  102
+	.wb_dat_o(wb_dat_o),
  103
+	.wb_dat_i(wb_dat_i),
  104
+	.wb_sel_i(wb_sel_i),
  105
+	.wb_stb_i(wb_stb_i),
  106
+	.wb_cyc_i(wb_cyc_i),
  107
+	.wb_ack_o(wb_ack_o),
  108
+	.wb_we_i(wb_we_i),
  109
+	
  110
+	.rxb0_dat(rxb0_dat),
  111
+	.rxb0_adr(rxb0_adr),
  112
+	.rxb0_we(rxb0_we),
  113
+	.rxb1_dat(rxb1_dat),
  114
+	.rxb1_adr(rxb1_adr),
  115
+	.rxb1_we(rxb1_we),
  116
+	
  117
+	.txb_dat(txb_dat),
  118
+	.txb_adr(txb_adr)
  119
+);
  120
+
  121
+minimac3_tx tx(
  122
+	.phy_tx_clk(phy_tx_clk),
  123
+	
  124
+	.tx_start(phy_tx_start),
  125
+	.tx_done(phy_tx_done),
  126
+	.tx_count(phy_tx_count),
  127
+	.txb_dat(txb_dat),
  128
+	.txb_adr(txb_adr),
  129
+	
  130
+	.phy_tx_en(phy_tx_en),
  131
+	.phy_tx_data(phy_tx_data)
  132
+);
  133
+assign phy_tx_er = 1'b0;
  134
+
  135
+minimac3_rx rx(
  136
+	.phy_rx_clk(phy_rx_clk),
  137
+	
  138
+	.rx_ready(phy_rx_ready),
  139
+	.rx_done(phy_rx_done),
  140
+	.rx_count_0(phy_rx_count_0),
  141
+	.rx_count_1(phy_rx_count_1),
  142
+	
  143
+	.rxb0_dat(rxb0_dat),
  144
+	.rxb0_adr(rxb0_adr),
  145
+	.rxb0_we(rxb0_we),
  146
+	.rxb1_dat(rxb1_dat),
  147
+	.rxb1_adr(rxb1_adr),
  148
+	.rxb1_we(rxb1_we),
  149
+	
  150
+	.phy_dv(phy_dv),
  151
+	.phy_rx_data(phy_rx_data),
  152
+	.phy_rx_er(phy_rx_er)
  153
+);
  154
+
  155
+endmodule
169  verilog/minimac3/minimac3_memory.v
... ...
@@ -0,0 +1,169 @@
  1
+/*
  2
+ * Milkymist SoC
  3
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+ 
  18
+/* TODO: use behavioral BRAM models (Xst can extract byte WE) */
  19
+
  20
+module minimac3_memory(
  21
+	input sys_clk,
  22
+	input sys_rst,
  23
+	input phy_rx_clk,
  24
+	input phy_tx_clk,
  25
+	
  26
+	input [29:0] wb_adr_i,
  27
+	output [31:0] wb_dat_o,
  28
+	input [31:0] wb_dat_i,
  29
+	input [3:0] wb_sel_i,
  30
+	input wb_stb_i,
  31
+	input wb_cyc_i,
  32
+	output reg wb_ack_o,
  33
+	input wb_we_i,
  34
+	
  35
+	input [7:0] rxb0_dat,
  36
+	input [10:0] rxb0_adr,
  37
+	input rxb0_we,
  38
+	input [7:0] rxb1_dat,
  39
+	input [10:0] rxb1_adr,
  40
+	input rxb1_we,
  41
+	
  42
+	output [7:0] txb_dat,
  43
+	input [10:0] txb_adr
  44
+
  45
+);
  46
+
  47
+wire wb_en = wb_cyc_i & wb_stb_i;
  48
+wire [1:0] wb_buf = wb_adr_i[10:9];
  49
+wire [31:0] wb_dat_i_le = {wb_dat_i[7:0], wb_dat_i[15:8], wb_dat_i[23:16], wb_dat_i[31:24]};
  50
+wire [3:0] wb_sel_i_le = {wb_sel_i[0], wb_sel_i[1], wb_sel_i[2], wb_sel_i[3]};
  51
+
  52
+wire [31:0] rxb0_wbdat;
  53
+RAMB16BWER #(
  54
+	.DATA_WIDTH_A(36),
  55
+	.DATA_WIDTH_B(9),
  56
+	.DOA_REG(0),
  57
+	.DOB_REG(0),
  58
+	.EN_RSTRAM_A("FALSE"),
  59
+	.EN_RSTRAM_B("FALSE"),
  60
+	.SIM_DEVICE("SPARTAN6"),
  61
+	.WRITE_MODE_A("WRITE_FIRST"),
  62
+	.WRITE_MODE_B("WRITE_FIRST")
  63
+) rxb0 (
  64
+	.DIA(wb_dat_i_le),
  65
+	.DIPA(4'd0),
  66
+	.DOA(rxb0_wbdat),
  67
+	.ADDRA({wb_adr_i[8:0], 5'd0}),
  68
+	.WEA({4{wb_en & wb_we_i & (wb_buf == 2'b00)}} & wb_sel_i_le),
  69
+	.ENA(1'b1),
  70
+	.RSTA(1'b0),
  71
+	.CLKA(sys_clk),
  72
+
  73
+	.DIB(rxb0_dat),
  74
+	.DIPB(1'd0),
  75
+	.DOB(),
  76
+	.ADDRB({rxb0_adr, 3'd0}),
  77
+	.WEB({4{rxb0_we}}),
  78
+	.ENB(1'b1),
  79
+	.RSTB(1'b0),
  80
+	.CLKB(phy_rx_clk)
  81
+);
  82
+
  83
+wire [31:0] rxb1_wbdat;
  84
+RAMB16BWER #(
  85
+	.DATA_WIDTH_A(36),
  86
+	.DATA_WIDTH_B(9),
  87
+	.DOA_REG(0),
  88
+	.DOB_REG(0),
  89
+	.EN_RSTRAM_A("FALSE"),
  90
+	.EN_RSTRAM_B("FALSE"),
  91
+	.SIM_DEVICE("SPARTAN6"),
  92
+	.WRITE_MODE_A("WRITE_FIRST"),
  93
+	.WRITE_MODE_B("WRITE_FIRST")
  94
+) rxb1 (
  95
+	.DIA(wb_dat_i_le),
  96
+	.DIPA(4'd0),
  97
+	.DOA(rxb1_wbdat),
  98
+	.ADDRA({wb_adr_i[8:0], 5'd0}),
  99
+	.WEA({4{wb_en & wb_we_i & (wb_buf == 2'b01)}} & wb_sel_i_le),
  100
+	.ENA(1'b1),
  101
+	.RSTA(1'b0),
  102
+	.CLKA(sys_clk),
  103
+
  104
+	.DIB(rxb1_dat),
  105
+	.DIPB(1'd0),
  106
+	.DOB(),
  107
+	.ADDRB({rxb1_adr, 3'd0}),
  108
+	.WEB({4{rxb1_we}}),
  109
+	.ENB(1'b1),
  110
+	.RSTB(1'b0),
  111
+	.CLKB(phy_rx_clk)
  112
+);
  113
+
  114
+wire [31:0] txb_wbdat;
  115
+RAMB16BWER #(
  116
+	.DATA_WIDTH_A(36),
  117
+	.DATA_WIDTH_B(9),
  118
+	.DOA_REG(0),
  119
+	.DOB_REG(0),
  120
+	.EN_RSTRAM_A("FALSE"),
  121
+	.EN_RSTRAM_B("FALSE"),
  122
+	.SIM_DEVICE("SPARTAN6"),
  123
+	.WRITE_MODE_A("WRITE_FIRST"),
  124
+	.WRITE_MODE_B("WRITE_FIRST")
  125
+) txb (
  126
+	.DIA(wb_dat_i_le),
  127
+	.DIPA(4'd0),
  128
+	.DOA(txb_wbdat),
  129
+	.ADDRA({wb_adr_i[8:0], 5'd0}),
  130
+	.WEA({4{wb_en & wb_we_i & (wb_buf == 2'b10)}} & wb_sel_i_le),
  131
+	.ENA(1'b1),
  132
+	.RSTA(1'b0),
  133
+	.CLKA(sys_clk),
  134
+
  135
+	.DIB(8'd0),
  136
+	.DIPB(1'd0),
  137
+	.DOB(txb_dat),
  138
+	.ADDRB({txb_adr, 3'd0}),
  139
+	.WEB(4'd0),
  140
+	.ENB(1'b1),
  141
+	.RSTB(1'b0),
  142
+	.CLKB(phy_tx_clk)
  143
+);
  144
+
  145
+always @(posedge sys_clk) begin
  146
+	if(sys_rst)
  147
+		wb_ack_o <= 1'b0;
  148
+	else begin
  149
+		wb_ack_o <= 1'b0;
  150
+		if(wb_en & ~wb_ack_o)
  151
+			wb_ack_o <= 1'b1;
  152
+	end
  153
+end
  154
+
  155
+reg [1:0] wb_buf_r;
  156
+always @(posedge sys_clk)
  157
+	wb_buf_r <= wb_buf;
  158
+
  159
+reg [31:0] wb_dat_o_le;
  160
+always @(*) begin
  161
+	case(wb_buf_r)
  162
+		2'b00: wb_dat_o_le = rxb0_wbdat;
  163
+		2'b01: wb_dat_o_le = rxb1_wbdat;
  164
+		default: wb_dat_o_le = txb_wbdat;
  165
+	endcase
  166
+end
  167
+assign wb_dat_o = {wb_dat_o_le[7:0], wb_dat_o_le[15:8], wb_dat_o_le[23:16], wb_dat_o_le[31:24]};
  168
+
  169
+endmodule
146  verilog/minimac3/minimac3_rx.v
... ...
@@ -0,0 +1,146 @@
  1
+/*
  2
+ * Milkymist SoC
  3
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
  18
+module minimac3_rx(
  19
+	input phy_rx_clk,
  20
+	
  21
+	input [1:0] rx_ready,
  22
+	output [1:0] rx_done,
  23
+	output reg [10:0] rx_count_0,
  24
+	output reg [10:0] rx_count_1,
  25
+	
  26
+	output [7:0] rxb0_dat,
  27
+	output [10:0] rxb0_adr,
  28
+	output rxb0_we,
  29
+	output [7:0] rxb1_dat,
  30
+	output [10:0] rxb1_adr,
  31
+	output rxb1_we,
  32
+	
  33
+	input phy_dv,
  34
+	input [3:0] phy_rx_data,
  35
+	input phy_rx_er
  36
+);
  37
+
  38
+reg [1:0] available_slots;
  39
+always @(posedge phy_rx_clk)
  40
+	available_slots <= (available_slots & ~rx_done) | rx_ready;
  41
+initial available_slots <= 2'd0;
  42
+
  43
+reg [1:0] used_slot;
  44
+reg used_slot_update;
  45
+always @(posedge phy_rx_clk) begin
  46
+	if(used_slot_update) begin
  47
+		used_slot[0] <= available_slots[0];
  48
+		used_slot[1] <= available_slots[1] & ~available_slots[0];
  49
+	end
  50
+end
  51
+
  52
+reg rx_done_ctl;
  53
+assign rx_done = {2{rx_done_ctl}} & used_slot;
  54
+
  55
+reg rx_count_reset_ctl;
  56
+reg rx_count_inc_ctl;
  57
+wire [1:0] rx_count_reset = {2{rx_count_reset_ctl}} & used_slot;
  58
+wire [1:0] rx_count_inc = {2{rx_count_inc_ctl}} & used_slot;
  59
+always @(posedge phy_rx_clk) begin
  60
+	if(rx_count_reset[0])
  61
+		rx_count_0 <= 11'd0;
  62
+	else if(rx_count_inc[0])
  63
+		rx_count_0 <= rx_count_0 + 11'd1;
  64
+	if(rx_count_reset[1])
  65
+		rx_count_1 <= 11'd0;
  66
+	else if(rx_count_inc[1])
  67
+		rx_count_1 <= rx_count_1 + 11'd1;
  68
+end
  69
+
  70
+assign rxb0_adr = rx_count_0;
  71
+assign rxb1_adr = rx_count_1;
  72
+reg rxb_we_ctl;
  73
+assign rxb0_we = rxb_we_ctl & used_slot[0];
  74
+assign rxb1_we = rxb_we_ctl & used_slot[1];
  75
+
  76
+reg [3:0] lo;
  77
+reg [3:0] hi;
  78
+reg [1:0] load_nibble;
  79
+always @(posedge phy_rx_clk) begin
  80
+	if(load_nibble[0])
  81
+		lo <= phy_rx_data;
  82
+	if(load_nibble[1])
  83
+		hi <= phy_rx_data;
  84
+end
  85
+assign rxb0_dat = {hi, lo};
  86
+assign rxb1_dat = {hi, lo};
  87
+
  88
+reg [1:0] state;
  89
+reg [1:0] next_state;
  90
+
  91
+parameter IDLE		= 2'd0;
  92
+parameter LOAD_LO	= 2'd1;
  93
+parameter LOAD_HI	= 2'd2;
  94
+parameter TERMINATE	= 2'd3;
  95
+
  96
+initial state <= IDLE;
  97
+always @(posedge phy_rx_clk)
  98
+	state <= next_state;
  99
+
  100
+always @(*) begin
  101
+	used_slot_update = 1'b0;
  102
+	rx_done_ctl = 1'b0;
  103
+	rx_count_reset_ctl = 1'b0;
  104
+	rx_count_inc_ctl = 1'b0;
  105
+	rxb_we_ctl = 1'b0;
  106
+	load_nibble = 2'b00;
  107
+	
  108
+	next_state = state;
  109
+	case(state)
  110
+		IDLE: begin
  111
+			used_slot_update = 1'b1;
  112
+			if(phy_dv) begin
  113
+				rx_count_reset_ctl = 1'b1;
  114
+				used_slot_update = 1'b0;
  115
+				load_nibble = 2'b01;
  116
+				next_state = LOAD_HI;
  117
+			end
  118
+		end
  119
+		LOAD_LO: begin
  120
+			rxb_we_ctl = 1'b1;
  121
+			rx_count_inc_ctl = 1'b1;
  122
+			if(phy_dv) begin
  123
+				load_nibble = 2'b01;
  124
+				next_state = LOAD_HI;
  125
+			end else begin
  126
+				rx_done_ctl = 1'b1;
  127
+				next_state = TERMINATE;
  128
+			end
  129
+		end
  130
+		LOAD_HI: begin
  131
+			if(phy_dv) begin
  132
+				load_nibble = 2'b10;
  133
+				next_state = LOAD_LO;
  134
+			end else begin
  135
+				rx_done_ctl = 1'b1;
  136
+				next_state = TERMINATE;
  137
+			end
  138
+		end
  139
+		TERMINATE: begin
  140
+			used_slot_update = 1'b1;
  141
+			next_state = IDLE;
  142
+		end
  143
+	endcase
  144
+end
  145
+
  146
+endmodule
93  verilog/minimac3/minimac3_sync.v
... ...
@@ -0,0 +1,93 @@
  1
+/*
  2
+ * Milkymist SoC
  3
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
  18
+module minimac3_sync(
  19
+	input sys_clk,
  20
+	input phy_rx_clk,
  21
+	input phy_tx_clk,
  22
+	
  23
+	input [1:0] sys_rx_ready,
  24
+	output [1:0] sys_rx_done,
  25
+	output reg [10:0] sys_rx_count_0,
  26
+	output reg [10:0] sys_rx_count_1,
  27
+	
  28
+	input sys_tx_start,
  29
+	output sys_tx_done,
  30
+	input [10:0] sys_tx_count,
  31
+	
  32
+	output [1:0] phy_rx_ready,
  33
+	input [1:0] phy_rx_done,
  34
+	input [10:0] phy_rx_count_0,
  35
+	input [10:0] phy_rx_count_1,
  36
+	
  37
+	output phy_tx_start,
  38
+	input phy_tx_done,
  39
+	output reg [10:0] phy_tx_count
  40
+);
  41
+
  42
+psync rx_ready_0(
  43
+	.clk1(sys_clk),
  44
+	.i(sys_rx_ready[0]),
  45
+	.clk2(phy_rx_clk),
  46
+	.o(phy_rx_ready[0])
  47
+);
  48
+psync rx_ready_1(
  49
+	.clk1(sys_clk),
  50
+	.i(sys_rx_ready[1]),
  51
+	.clk2(phy_rx_clk),
  52
+	.o(phy_rx_ready[1])
  53
+);
  54
+psync rx_done_0(
  55
+	.clk1(phy_rx_clk),
  56
+	.i(phy_rx_done[0]),
  57
+	.clk2(sys_clk),
  58
+	.o(sys_rx_done[0])
  59
+);
  60
+psync rx_done_1(
  61
+	.clk1(phy_rx_clk),
  62
+	.i(phy_rx_done[1]),
  63
+	.clk2(sys_clk),
  64
+	.o(sys_rx_done[1])
  65
+);
  66
+reg [10:0] sys_rx_count_0_r;
  67
+reg [10:0] sys_rx_count_1_r;
  68
+always @(posedge sys_clk) begin
  69
+	sys_rx_count_0_r <= phy_rx_count_0;
  70
+	sys_rx_count_0 <= sys_rx_count_0_r;
  71
+	sys_rx_count_1_r <= phy_rx_count_1;
  72
+	sys_rx_count_1 <= sys_rx_count_1_r;
  73
+end
  74
+
  75
+psync tx_start(
  76
+	.clk1(sys_clk),
  77
+	.i(sys_tx_start),
  78
+	.clk2(phy_tx_clk),
  79
+	.o(phy_tx_start)
  80
+);
  81
+psync tx_done(
  82
+	.clk1(phy_tx_clk),
  83
+	.i(phy_tx_done),
  84
+	.clk2(sys_clk),
  85
+	.o(sys_tx_done)
  86
+);
  87
+reg [10:0] phy_tx_count_r;
  88
+always @(posedge phy_tx_clk) begin
  89
+	phy_tx_count_r <= sys_tx_count;
  90
+	phy_tx_count <= phy_tx_count_r;
  91
+end
  92
+
  93
+endmodule
100  verilog/minimac3/minimac3_tx.v
... ...
@@ -0,0 +1,100 @@
  1
+/*
  2
+ * Milkymist SoC
  3
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
  18
+module minimac3_tx(
  19
+	input phy_tx_clk,
  20
+
  21
+	input tx_start,
  22
+	output reg tx_done,
  23
+	input [10:0] tx_count,
  24
+	input [7:0] txb_dat,
  25
+	output [10:0] txb_adr,
  26
+	
  27
+	output reg phy_tx_en,
  28
+	output reg [3:0] phy_tx_data
  29
+);
  30
+
  31
+reg phy_tx_en_r;
  32
+reg phy_tx_data_sel;
  33
+wire [3:0] phy_tx_data_r = phy_tx_data_sel ? txb_dat[7:4] : txb_dat[3:0];
  34
+always @(posedge phy_tx_clk) begin
  35
+	phy_tx_en <= phy_tx_en_r;
  36
+	phy_tx_data <= phy_tx_data_r;
  37
+end
  38
+
  39
+reg [10:0] byte_count;
  40
+reg byte_count_reset;
  41
+reg byte_count_inc;
  42
+always @(posedge phy_tx_clk) begin
  43
+	if(byte_count_reset)
  44
+		byte_count <= 11'd0;
  45
+	else if(byte_count_inc)
  46
+		byte_count <= byte_count + 11'd1;
  47
+end
  48
+assign txb_adr = byte_count;
  49
+wire byte_count_max = byte_count == tx_count;
  50
+
  51
+parameter IDLE		= 2'd0;
  52
+parameter SEND_LO	= 2'd1;
  53
+parameter SEND_HI	= 2'd2;
  54
+parameter TERMINATE	= 2'd3;
  55
+
  56
+reg [1:0] state;
  57
+reg [1:0] next_state;
  58
+
  59
+initial state <= IDLE;
  60
+always @(posedge phy_tx_clk)
  61
+	state <= next_state;
  62
+
  63
+always @(*) begin
  64
+	phy_tx_en_r = 1'b0;
  65
+	phy_tx_data_sel = 1'b0;
  66
+	byte_count_reset = 1'b0;
  67
+	byte_count_inc = 1'b0;
  68
+	tx_done = 1'b0;
  69
+	
  70
+	next_state = state;
  71
+	
  72
+	case(state)
  73
+		IDLE: begin
  74
+			byte_count_reset = 1'b1;
  75
+			if(tx_start)
  76
+				next_state = SEND_LO;
  77
+		end
  78
+		SEND_LO: begin
  79
+			byte_count_inc = 1'b1;
  80
+			phy_tx_en_r = 1'b1;
  81
+			phy_tx_data_sel = 1'b0;
  82
+			next_state = SEND_HI;
  83
+		end
  84
+		SEND_HI: begin
  85
+			phy_tx_en_r = 1'b1;
  86
+			phy_tx_data_sel = 1'b1;
  87
+			if(byte_count_max)
  88
+				next_state = TERMINATE;
  89
+			else
  90
+				next_state = SEND_LO;
  91
+		end
  92
+		TERMINATE: begin
  93
+			byte_count_reset = 1'b1;
  94
+			tx_done = 1'b1;
  95
+			next_state = IDLE;
  96
+		end
  97
+	endcase
  98
+end
  99
+
  100
+endmodule

0 notes on commit 4e18e45

Please sign in to comment.
Something went wrong with that request. Please try again.