Skip to content

Commit 4e18e45

Browse files
author
Sebastien Bourdeauducq
committedMay 19, 2012
Add Ethernet MAC
1 parent 7d18736 commit 4e18e45

File tree

13 files changed

+863
-9
lines changed

13 files changed

+863
-9
lines changed
 

‎build.py

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def add_core_dir(d):
1212
def add_core_files(d, files):
1313
for f in files:
1414
verilog_sources.append(os.path.join("verilog", d, f))
15+
add_core_dir("generic")
1516
add_core_dir("m1crg")
1617
add_core_dir("s6ddrphy")
1718
add_core_files("lm32", ["lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
@@ -20,6 +21,7 @@ def add_core_files(d, files):
2021
"lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v",
2122
"lm32_dcache.v", "lm32_top.v", "lm32_debug.v", "lm32_jtag.v", "jtag_cores.v",
2223
"jtag_tap_spartan6.v"])
24+
add_core_dir("minimac3")
2325

2426
os.chdir("build")
2527

‎common/csrbase.h

+1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
#define UART_BASE 0xe0000000
55
#define DFII_BASE 0xe0000800
66
#define ID_BASE 0xe0001000
7+
#define MINIMAC_BASE 0xe0001800
78

89
#endif /* __CSRBASE_H */

‎constraints.py

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class Constraints:
2-
def __init__(self, crg0, norflash0, uart0, ddrphy0):
2+
def __init__(self, crg0, norflash0, uart0, ddrphy0, minimac0):
33
self.constraints = []
44
def add(signal, pin, vec=-1, iostandard="LVCMOS33", extra=""):
55
self.constraints.append((signal, vec, pin, iostandard, extra))
@@ -15,6 +15,7 @@ def add_vec(signal, pins, iostandard="LVCMOS33", extra=""):
1515
add(crg0.videoin_rst_n, "W17")
1616
add(crg0.flash_rst_n, "P22", extra="SLEW = FAST | DRIVE = 8")
1717
add(crg0.trigger_reset, "AA4")
18+
add(crg0.phy_clk, "M20")
1819

1920
add_vec(norflash0.adr, ["L22", "L20", "K22", "K21", "J19", "H20", "F22",
2021
"F21", "K17", "J17", "E22", "E20", "H18", "H19", "F20",
@@ -47,6 +48,21 @@ def add_vec(signal, pins, iostandard="LVCMOS33", extra=""):
4748
extra=ddrsettings)
4849
add_vec(ddrphy0.sd_dm, ["E1", "E3", "F3", "G4"], extra=ddrsettings)
4950
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
5066

5167
def get_ios(self):
5268
return set([c[0] for c in self.constraints])
@@ -69,6 +85,13 @@ def get_ucf(self, ns):
6985
INST "m1crg/rd_bufpll" LOC = "BUFPLL_X0Y3";
7086
7187
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))
7396

7497
return r

‎milkymist/m1crg/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ def __init__(self, infreq, outfreq1x):
1818
"clk4x_wr",
1919
"clk4x_wr_strb",
2020
"clk4x_rd",
21-
"clk4x_rd_strb"
21+
"clk4x_rd_strb",
22+
"phy_clk"
2223
]:
2324
s = Signal(name=name)
2425
setattr(self, name, s)

‎milkymist/minimac3/__init__.py

+105
Original file line numberDiff line numberDiff line change
@@ -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()

‎top.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from migen.fhdl import verilog, autofragment
66
from migen.bus import wishbone, wishbone2asmi, csr, wishbone2csr, dfi
77

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
99
from cmacros import get_macros
1010
from constraints import Constraints
1111

@@ -88,6 +88,7 @@ def get():
8888
cpu0 = lm32.LM32()
8989
norflash0 = norflash.NorFlash(25, 12)
9090
sram0 = sram.SRAM(sram_size//4)
91+
minimac0 = minimac3.MiniMAC(csr_offset("MINIMAC"))
9192
wishbone2asmi0 = wishbone2asmi.WB2ASMI(l2_size//4, asmiport_wb)
9293
wishbone2csr0 = wishbone2csr.WB2CSR()
9394

@@ -104,6 +105,7 @@ def get():
104105
], [
105106
(binc("000"), norflash0.bus),
106107
(binc("001"), sram0.bus),
108+
(binc("011"), minimac0.membus),
107109
(binc("10"), wishbone2asmi0.wishbone),
108110
(binc("11"), wishbone2csr0.wishbone)
109111
],
@@ -118,7 +120,8 @@ def get():
118120
csrcon0 = csr.Interconnect(wishbone2csr0.csr, [
119121
uart0.bank.interface,
120122
dfii0.bank.interface,
121-
identifier0.bank.interface
123+
identifier0.bank.interface,
124+
minimac0.bank.interface
122125
])
123126

124127
#
@@ -134,7 +137,7 @@ def get():
134137
crg0 = m1crg.M1CRG(50*MHz, clk_freq)
135138

136139
frag = autofragment.from_local() + interrupts + ddrphy_clocking(crg0, ddrphy0)
137-
cst = Constraints(crg0, norflash0, uart0, ddrphy0)
140+
cst = Constraints(crg0, norflash0, uart0, ddrphy0, minimac0)
138141
src_verilog, vns = verilog.convert(frag,
139142
cst.get_ios(),
140143
name="soc",

‎verilog/generic/psync.v

+48
Original file line numberDiff line numberDiff line change
@@ -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

‎verilog/m1crg/m1crg.v

+11-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ module m1crg #(
3737
output clk4x_wr,
3838
output clk4x_wr_strb,
3939
output clk4x_rd,
40-
output clk4x_rd_strb
40+
output clk4x_rd_strb,
41+
42+
/* Ethernet PHY clock */
43+
output reg phy_clk
4144
);
4245

4346
/*
@@ -107,6 +110,7 @@ wire pllout0;
107110
wire pllout1;
108111
wire pllout2;
109112
wire pllout3;
113+
wire pllout4;
110114

111115
PLL_ADV #(
112116
.BANDWIDTH("OPTIMIZED"),
@@ -126,7 +130,7 @@ PLL_ADV #(
126130
.CLKOUT3_DIVIDE(4*f_div),
127131
.CLKOUT3_DUTY_CYCLE(0.5),
128132
.CLKOUT3_PHASE(0.0),
129-
.CLKOUT4_DIVIDE(7),
133+
.CLKOUT4_DIVIDE(4*f_mult),
130134
.CLKOUT4_DUTY_CYCLE(0.5),
131135
.CLKOUT4_PHASE(0),
132136
.CLKOUT5_DIVIDE(7),
@@ -144,7 +148,7 @@ PLL_ADV #(
144148
.CLKOUT1(pllout1), /* < x4 clock for reads */
145149
.CLKOUT2(pllout2), /* < x2 90 clock to generate memory clock, clock DQS and memory address and control signals. */
146150
.CLKOUT3(pllout3), /* < x1 clock for system and memory controller */
147-
.CLKOUT4(),
151+
.CLKOUT4(pllout4), /* < buffered clkin */
148152
.CLKOUT5(),
149153
.CLKOUTDCM0(),
150154
.CLKOUTDCM1(),
@@ -199,5 +203,9 @@ BUFG bufg_x1(
199203
.I(pllout3),
200204
.O(sys_clk)
201205
);
206+
207+
/* Ethernet PHY */
208+
always @(posedge pllout4)
209+
phy_clk <= ~phy_clk;
202210

203211
endmodule

‎verilog/minimac3/minimac3.v

+155
Original file line numberDiff line numberDiff line change
@@ -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

‎verilog/minimac3/minimac3_memory.v

+169
Original file line numberDiff line numberDiff line change
@@ -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

‎verilog/minimac3/minimac3_rx.v

+146
Original file line numberDiff line numberDiff line change
@@ -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

‎verilog/minimac3/minimac3_sync.v

+93
Original file line numberDiff line numberDiff line change
@@ -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

‎verilog/minimac3/minimac3_tx.v

+100
Original file line numberDiff line numberDiff line change
@@ -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 commit comments

Comments
 (0)
Please sign in to comment.