Skip to content

Commit

Permalink
Add Ethernet MAC
Browse files Browse the repository at this point in the history
Sebastien Bourdeauducq committed May 19, 2012

Verified

This commit was signed with the committer’s verified signature.
skmcgrail Sean McGrail
1 parent 7d18736 commit 4e18e45
Showing 13 changed files with 863 additions and 9 deletions.
2 changes: 2 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -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")

1 change: 1 addition & 0 deletions common/csrbase.h
Original file line number Diff line number Diff line change
@@ -4,5 +4,6 @@
#define UART_BASE 0xe0000000
#define DFII_BASE 0xe0000800
#define ID_BASE 0xe0001000
#define MINIMAC_BASE 0xe0001800

#endif /* __CSRBASE_H */
27 changes: 25 additions & 2 deletions constraints.py
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion milkymist/m1crg/__init__.py
Original file line number Diff line number Diff line change
@@ -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)
105 changes: 105 additions & 0 deletions milkymist/minimac3/__init__.py
Original file line number Diff line number Diff line change
@@ -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()
9 changes: 6 additions & 3 deletions top.py
Original file line number Diff line number Diff line change
@@ -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",
48 changes: 48 additions & 0 deletions verilog/generic/psync.v
Original file line number Diff line number Diff line change
@@ -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
14 changes: 11 additions & 3 deletions verilog/m1crg/m1crg.v
Original file line number Diff line number Diff line change
@@ -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
155 changes: 155 additions & 0 deletions verilog/minimac3/minimac3.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* Milkymist SoC
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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 minimac3(
input sys_clk,
input sys_rst,

/* Control */
input rx_ready_0,
output rx_done_0,
output [10:0] rx_count_0,
input rx_ready_1,
output rx_done_1,
output [10:0] rx_count_1,

input tx_start,
output tx_done,
input [10:0] tx_count,

/* WISHBONE to access RAM */
input [29:0] wb_adr_i,
output [31:0] wb_dat_o,
input [31:0] wb_dat_i,
input [3:0] wb_sel_i,
input wb_stb_i,
input wb_cyc_i,
output wb_ack_o,
input wb_we_i,

/* To PHY */
input phy_tx_clk,
output [3:0] phy_tx_data,
output phy_tx_en,
output phy_tx_er,
input phy_rx_clk,
input [3:0] phy_rx_data,
input phy_dv,
input phy_rx_er,
input phy_col,
input phy_crs
);

wire [1:0] phy_rx_ready;
wire [1:0] phy_rx_done;
wire [10:0] phy_rx_count_0;
wire [10:0] phy_rx_count_1;
wire phy_tx_start;
wire phy_tx_done;
wire [10:0] phy_tx_count;

minimac3_sync sync(
.sys_clk(sys_clk),
.phy_rx_clk(phy_rx_clk),
.phy_tx_clk(phy_tx_clk),

.sys_rx_ready({rx_ready_1, rx_ready_0}),
.sys_rx_done({rx_done_1, rx_done_0}),
.sys_rx_count_0(rx_count_0),
.sys_rx_count_1(rx_count_1),
.sys_tx_start(tx_start),
.sys_tx_done(tx_done),
.sys_tx_count(tx_count),

.phy_rx_ready(phy_rx_ready),
.phy_rx_done(phy_rx_done),
.phy_rx_count_0(phy_rx_count_0),
.phy_rx_count_1(phy_rx_count_1),
.phy_tx_start(phy_tx_start),
.phy_tx_done(phy_tx_done),
.phy_tx_count(phy_tx_count)
);

wire [7:0] rxb0_dat;
wire [10:0] rxb0_adr;
wire rxb0_we;
wire [7:0] rxb1_dat;
wire [10:0] rxb1_adr;
wire rxb1_we;
wire [7:0] txb_dat;
wire [10:0] txb_adr;
minimac3_memory memory(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.phy_rx_clk(phy_rx_clk),
.phy_tx_clk(phy_tx_clk),

.wb_adr_i(wb_adr_i),
.wb_dat_o(wb_dat_o),
.wb_dat_i(wb_dat_i),
.wb_sel_i(wb_sel_i),
.wb_stb_i(wb_stb_i),
.wb_cyc_i(wb_cyc_i),
.wb_ack_o(wb_ack_o),
.wb_we_i(wb_we_i),

.rxb0_dat(rxb0_dat),
.rxb0_adr(rxb0_adr),
.rxb0_we(rxb0_we),
.rxb1_dat(rxb1_dat),
.rxb1_adr(rxb1_adr),
.rxb1_we(rxb1_we),

.txb_dat(txb_dat),
.txb_adr(txb_adr)
);

minimac3_tx tx(
.phy_tx_clk(phy_tx_clk),

.tx_start(phy_tx_start),
.tx_done(phy_tx_done),
.tx_count(phy_tx_count),
.txb_dat(txb_dat),
.txb_adr(txb_adr),

.phy_tx_en(phy_tx_en),
.phy_tx_data(phy_tx_data)
);
assign phy_tx_er = 1'b0;

minimac3_rx rx(
.phy_rx_clk(phy_rx_clk),

.rx_ready(phy_rx_ready),
.rx_done(phy_rx_done),
.rx_count_0(phy_rx_count_0),
.rx_count_1(phy_rx_count_1),

.rxb0_dat(rxb0_dat),
.rxb0_adr(rxb0_adr),
.rxb0_we(rxb0_we),
.rxb1_dat(rxb1_dat),
.rxb1_adr(rxb1_adr),
.rxb1_we(rxb1_we),

.phy_dv(phy_dv),
.phy_rx_data(phy_rx_data),
.phy_rx_er(phy_rx_er)
);

endmodule
169 changes: 169 additions & 0 deletions verilog/minimac3/minimac3_memory.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Milkymist SoC
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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/>.
*/

/* TODO: use behavioral BRAM models (Xst can extract byte WE) */

module minimac3_memory(
input sys_clk,
input sys_rst,
input phy_rx_clk,
input phy_tx_clk,

input [29:0] wb_adr_i,
output [31:0] wb_dat_o,
input [31:0] wb_dat_i,
input [3:0] wb_sel_i,
input wb_stb_i,
input wb_cyc_i,
output reg wb_ack_o,
input wb_we_i,

input [7:0] rxb0_dat,
input [10:0] rxb0_adr,
input rxb0_we,
input [7:0] rxb1_dat,
input [10:0] rxb1_adr,
input rxb1_we,

output [7:0] txb_dat,
input [10:0] txb_adr

);

wire wb_en = wb_cyc_i & wb_stb_i;
wire [1:0] wb_buf = wb_adr_i[10:9];
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]};
wire [3:0] wb_sel_i_le = {wb_sel_i[0], wb_sel_i[1], wb_sel_i[2], wb_sel_i[3]};

wire [31:0] rxb0_wbdat;
RAMB16BWER #(
.DATA_WIDTH_A(36),
.DATA_WIDTH_B(9),
.DOA_REG(0),
.DOB_REG(0),
.EN_RSTRAM_A("FALSE"),
.EN_RSTRAM_B("FALSE"),
.SIM_DEVICE("SPARTAN6"),
.WRITE_MODE_A("WRITE_FIRST"),
.WRITE_MODE_B("WRITE_FIRST")
) rxb0 (
.DIA(wb_dat_i_le),
.DIPA(4'd0),
.DOA(rxb0_wbdat),
.ADDRA({wb_adr_i[8:0], 5'd0}),
.WEA({4{wb_en & wb_we_i & (wb_buf == 2'b00)}} & wb_sel_i_le),
.ENA(1'b1),
.RSTA(1'b0),
.CLKA(sys_clk),

.DIB(rxb0_dat),
.DIPB(1'd0),
.DOB(),
.ADDRB({rxb0_adr, 3'd0}),
.WEB({4{rxb0_we}}),
.ENB(1'b1),
.RSTB(1'b0),
.CLKB(phy_rx_clk)
);

wire [31:0] rxb1_wbdat;
RAMB16BWER #(
.DATA_WIDTH_A(36),
.DATA_WIDTH_B(9),
.DOA_REG(0),
.DOB_REG(0),
.EN_RSTRAM_A("FALSE"),
.EN_RSTRAM_B("FALSE"),
.SIM_DEVICE("SPARTAN6"),
.WRITE_MODE_A("WRITE_FIRST"),
.WRITE_MODE_B("WRITE_FIRST")
) rxb1 (
.DIA(wb_dat_i_le),
.DIPA(4'd0),
.DOA(rxb1_wbdat),
.ADDRA({wb_adr_i[8:0], 5'd0}),
.WEA({4{wb_en & wb_we_i & (wb_buf == 2'b01)}} & wb_sel_i_le),
.ENA(1'b1),
.RSTA(1'b0),
.CLKA(sys_clk),

.DIB(rxb1_dat),
.DIPB(1'd0),
.DOB(),
.ADDRB({rxb1_adr, 3'd0}),
.WEB({4{rxb1_we}}),
.ENB(1'b1),
.RSTB(1'b0),
.CLKB(phy_rx_clk)
);

wire [31:0] txb_wbdat;
RAMB16BWER #(
.DATA_WIDTH_A(36),
.DATA_WIDTH_B(9),
.DOA_REG(0),
.DOB_REG(0),
.EN_RSTRAM_A("FALSE"),
.EN_RSTRAM_B("FALSE"),
.SIM_DEVICE("SPARTAN6"),
.WRITE_MODE_A("WRITE_FIRST"),
.WRITE_MODE_B("WRITE_FIRST")
) txb (
.DIA(wb_dat_i_le),
.DIPA(4'd0),
.DOA(txb_wbdat),
.ADDRA({wb_adr_i[8:0], 5'd0}),
.WEA({4{wb_en & wb_we_i & (wb_buf == 2'b10)}} & wb_sel_i_le),
.ENA(1'b1),
.RSTA(1'b0),
.CLKA(sys_clk),

.DIB(8'd0),
.DIPB(1'd0),
.DOB(txb_dat),
.ADDRB({txb_adr, 3'd0}),
.WEB(4'd0),
.ENB(1'b1),
.RSTB(1'b0),
.CLKB(phy_tx_clk)
);

always @(posedge sys_clk) begin
if(sys_rst)
wb_ack_o <= 1'b0;
else begin
wb_ack_o <= 1'b0;
if(wb_en & ~wb_ack_o)
wb_ack_o <= 1'b1;
end
end

reg [1:0] wb_buf_r;
always @(posedge sys_clk)
wb_buf_r <= wb_buf;

reg [31:0] wb_dat_o_le;
always @(*) begin
case(wb_buf_r)
2'b00: wb_dat_o_le = rxb0_wbdat;
2'b01: wb_dat_o_le = rxb1_wbdat;
default: wb_dat_o_le = txb_wbdat;
endcase
end
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]};

endmodule
146 changes: 146 additions & 0 deletions verilog/minimac3/minimac3_rx.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* Milkymist SoC
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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 minimac3_rx(
input phy_rx_clk,

input [1:0] rx_ready,
output [1:0] rx_done,
output reg [10:0] rx_count_0,
output reg [10:0] rx_count_1,

output [7:0] rxb0_dat,
output [10:0] rxb0_adr,
output rxb0_we,
output [7:0] rxb1_dat,
output [10:0] rxb1_adr,
output rxb1_we,

input phy_dv,
input [3:0] phy_rx_data,
input phy_rx_er
);

reg [1:0] available_slots;
always @(posedge phy_rx_clk)
available_slots <= (available_slots & ~rx_done) | rx_ready;
initial available_slots <= 2'd0;

reg [1:0] used_slot;
reg used_slot_update;
always @(posedge phy_rx_clk) begin
if(used_slot_update) begin
used_slot[0] <= available_slots[0];
used_slot[1] <= available_slots[1] & ~available_slots[0];
end
end

reg rx_done_ctl;
assign rx_done = {2{rx_done_ctl}} & used_slot;

reg rx_count_reset_ctl;
reg rx_count_inc_ctl;
wire [1:0] rx_count_reset = {2{rx_count_reset_ctl}} & used_slot;
wire [1:0] rx_count_inc = {2{rx_count_inc_ctl}} & used_slot;
always @(posedge phy_rx_clk) begin
if(rx_count_reset[0])
rx_count_0 <= 11'd0;
else if(rx_count_inc[0])
rx_count_0 <= rx_count_0 + 11'd1;
if(rx_count_reset[1])
rx_count_1 <= 11'd0;
else if(rx_count_inc[1])
rx_count_1 <= rx_count_1 + 11'd1;
end

assign rxb0_adr = rx_count_0;
assign rxb1_adr = rx_count_1;
reg rxb_we_ctl;
assign rxb0_we = rxb_we_ctl & used_slot[0];
assign rxb1_we = rxb_we_ctl & used_slot[1];

reg [3:0] lo;
reg [3:0] hi;
reg [1:0] load_nibble;
always @(posedge phy_rx_clk) begin
if(load_nibble[0])
lo <= phy_rx_data;
if(load_nibble[1])
hi <= phy_rx_data;
end
assign rxb0_dat = {hi, lo};
assign rxb1_dat = {hi, lo};

reg [1:0] state;
reg [1:0] next_state;

parameter IDLE = 2'd0;
parameter LOAD_LO = 2'd1;
parameter LOAD_HI = 2'd2;
parameter TERMINATE = 2'd3;

initial state <= IDLE;
always @(posedge phy_rx_clk)
state <= next_state;

always @(*) begin
used_slot_update = 1'b0;
rx_done_ctl = 1'b0;
rx_count_reset_ctl = 1'b0;
rx_count_inc_ctl = 1'b0;
rxb_we_ctl = 1'b0;
load_nibble = 2'b00;

next_state = state;
case(state)
IDLE: begin
used_slot_update = 1'b1;
if(phy_dv) begin
rx_count_reset_ctl = 1'b1;
used_slot_update = 1'b0;
load_nibble = 2'b01;
next_state = LOAD_HI;
end
end
LOAD_LO: begin
rxb_we_ctl = 1'b1;
rx_count_inc_ctl = 1'b1;
if(phy_dv) begin
load_nibble = 2'b01;
next_state = LOAD_HI;
end else begin
rx_done_ctl = 1'b1;
next_state = TERMINATE;
end
end
LOAD_HI: begin
if(phy_dv) begin
load_nibble = 2'b10;
next_state = LOAD_LO;
end else begin
rx_done_ctl = 1'b1;
next_state = TERMINATE;
end
end
TERMINATE: begin
used_slot_update = 1'b1;
next_state = IDLE;
end
endcase
end

endmodule
93 changes: 93 additions & 0 deletions verilog/minimac3/minimac3_sync.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Milkymist SoC
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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 minimac3_sync(
input sys_clk,
input phy_rx_clk,
input phy_tx_clk,

input [1:0] sys_rx_ready,
output [1:0] sys_rx_done,
output reg [10:0] sys_rx_count_0,
output reg [10:0] sys_rx_count_1,

input sys_tx_start,
output sys_tx_done,
input [10:0] sys_tx_count,

output [1:0] phy_rx_ready,
input [1:0] phy_rx_done,
input [10:0] phy_rx_count_0,
input [10:0] phy_rx_count_1,

output phy_tx_start,
input phy_tx_done,
output reg [10:0] phy_tx_count
);

psync rx_ready_0(
.clk1(sys_clk),
.i(sys_rx_ready[0]),
.clk2(phy_rx_clk),
.o(phy_rx_ready[0])
);
psync rx_ready_1(
.clk1(sys_clk),
.i(sys_rx_ready[1]),
.clk2(phy_rx_clk),
.o(phy_rx_ready[1])
);
psync rx_done_0(
.clk1(phy_rx_clk),
.i(phy_rx_done[0]),
.clk2(sys_clk),
.o(sys_rx_done[0])
);
psync rx_done_1(
.clk1(phy_rx_clk),
.i(phy_rx_done[1]),
.clk2(sys_clk),
.o(sys_rx_done[1])
);
reg [10:0] sys_rx_count_0_r;
reg [10:0] sys_rx_count_1_r;
always @(posedge sys_clk) begin
sys_rx_count_0_r <= phy_rx_count_0;
sys_rx_count_0 <= sys_rx_count_0_r;
sys_rx_count_1_r <= phy_rx_count_1;
sys_rx_count_1 <= sys_rx_count_1_r;
end

psync tx_start(
.clk1(sys_clk),
.i(sys_tx_start),
.clk2(phy_tx_clk),
.o(phy_tx_start)
);
psync tx_done(
.clk1(phy_tx_clk),
.i(phy_tx_done),
.clk2(sys_clk),
.o(sys_tx_done)
);
reg [10:0] phy_tx_count_r;
always @(posedge phy_tx_clk) begin
phy_tx_count_r <= sys_tx_count;
phy_tx_count <= phy_tx_count_r;
end

endmodule
100 changes: 100 additions & 0 deletions verilog/minimac3/minimac3_tx.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Milkymist SoC
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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 minimac3_tx(
input phy_tx_clk,

input tx_start,
output reg tx_done,
input [10:0] tx_count,
input [7:0] txb_dat,
output [10:0] txb_adr,

output reg phy_tx_en,
output reg [3:0] phy_tx_data
);

reg phy_tx_en_r;
reg phy_tx_data_sel;
wire [3:0] phy_tx_data_r = phy_tx_data_sel ? txb_dat[7:4] : txb_dat[3:0];
always @(posedge phy_tx_clk) begin
phy_tx_en <= phy_tx_en_r;
phy_tx_data <= phy_tx_data_r;
end

reg [10:0] byte_count;
reg byte_count_reset;
reg byte_count_inc;
always @(posedge phy_tx_clk) begin
if(byte_count_reset)
byte_count <= 11'd0;
else if(byte_count_inc)
byte_count <= byte_count + 11'd1;
end
assign txb_adr = byte_count;
wire byte_count_max = byte_count == tx_count;

parameter IDLE = 2'd0;
parameter SEND_LO = 2'd1;
parameter SEND_HI = 2'd2;
parameter TERMINATE = 2'd3;

reg [1:0] state;
reg [1:0] next_state;

initial state <= IDLE;
always @(posedge phy_tx_clk)
state <= next_state;

always @(*) begin
phy_tx_en_r = 1'b0;
phy_tx_data_sel = 1'b0;
byte_count_reset = 1'b0;
byte_count_inc = 1'b0;
tx_done = 1'b0;

next_state = state;

case(state)
IDLE: begin
byte_count_reset = 1'b1;
if(tx_start)
next_state = SEND_LO;
end
SEND_LO: begin
byte_count_inc = 1'b1;
phy_tx_en_r = 1'b1;
phy_tx_data_sel = 1'b0;
next_state = SEND_HI;
end
SEND_HI: begin
phy_tx_en_r = 1'b1;
phy_tx_data_sel = 1'b1;
if(byte_count_max)
next_state = TERMINATE;
else
next_state = SEND_LO;
end
TERMINATE: begin
byte_count_reset = 1'b1;
tx_done = 1'b1;
next_state = IDLE;
end
endcase
end

endmodule

0 comments on commit 4e18e45

Please sign in to comment.