OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/orpsocv2/rtl/verilog/smii
    from Rev 403 to Rev 408
    Reverse comparison

Rev 403 → Rev 408

/smii_sync.v
0,0 → 1,82
/*
* SMII sync generation module
*
* Generate sync to PHY, and for internal statemachines
*
* Julius Baxter, julius.baxter@orsoc.se
*
*/
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2009, 2010 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source 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 Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
module smii_sync
(
// SMII sync
output sync,
// internal
output [10:1] tx_state,
output [10:1] next_tx_state,
output [10:1] rx_state,
 
// clock amd reset
input clk,
input rst
);
reg [10:1] next_tx_state_r;
reg [10:1] tx_state_r;
reg [10:1] rx_state_int;
reg [10:1] rx_state_int2;
reg [10:1] rx_state_int3;
// sync shall go high every 10:th cycle
always @ (posedge clk)
if (rst)
begin
next_tx_state_r <= 10'b0000000010;
tx_state_r <= 0;
end
else
begin
tx_state_r <= next_tx_state_r;
next_tx_state_r <= {next_tx_state_r[9:1],next_tx_state_r[10]};
end
assign tx_state = tx_state_r;
assign next_tx_state = next_tx_state_r;
assign sync = tx_state_r[1];
 
always @(posedge clk)
begin
rx_state_int <= {tx_state_r[9:1],tx_state_r[10]};
rx_state_int2 <= rx_state_int;
rx_state_int3 <= rx_state_int2;
end
// rx_state counter is 2 clocks behind tx state due to flops in and out of
// FPGA
assign rx_state = rx_state_int3;
endmodule // smii_sync
/smii_if.v
0,0 → 1,460
//////////////////////////////////////////////////////////////////////
//// ////
//// SMII ////
//// ////
//// Description ////
//// Low pin count serial MII ethernet interface ////
//// ////
//// To Do: ////
//// - ////
//// ////
//// Author(s): ////
//// - Michael Unneback, unneback@opencores.org ////
//// ORSoC AB michael.unneback@orsoc.se ////
//// - Julius Baxter, julius@orsoc.se ////
//// ORSoC AB ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2009, 2010 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source 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 Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "synthesis-defines.v"
`include "orpsoc-defines.v" // To determine synthesis technology.
module smii_if
(
// SMII
output tx,
input rx,
// MII
// TX
input [3:0] mtxd,
input mtxen,
input mtxerr,
output mtx_clk,
// RX
output [3:0] mrxd,
output mrxdv,
output mrxerr,
output mrx_clk,
output mcoll,
output reg mcrs,
output reg speed,
output reg duplex,
output reg link,
// internal
input [10:1] tx_smii_state,
input [10:1] next_tx_smii_state,
input [10:1] rx_smii_state,
// clock and reset
input eth_clk,
input eth_rst
);
 
reg [7:0] tx_data_reg;
reg tx_data_reg_valid;
reg a0;
reg state_data;
 
reg [3:0] rx_tmp;
 
reg [3:0] rxd_nib;
reg rxdv, rxerr;
reg jabber;
 
reg [10:1] tx_cnt;
reg [10:1] rx_cnt;
/////////////////////////////////////////////////
// Transmit
 
// Tx segment counter when !speed
always @ (posedge eth_clk or posedge eth_rst)
if (eth_rst)
tx_cnt <= 10'b00_0000_0001;
else if (tx_smii_state[10])
tx_cnt <= {tx_cnt[9:1],tx_cnt[10]};
// MII signals registered in eth_clk domain
reg txen_r, txerr_r;
// TX clock generation to the MAC
reg mtx_clk_gen, mtx_clk_gen_reg,
mtx_clk_gen_reg2, mtx_clk_gen_reg3,
mtx_clk_gen_reg4, mtx_clk_gen_reg5,
mtx_clk_gen_reg6, mtx_clk_gen_reg7,
tx_first_clk_gen,
tx_first_clk_reg, tx_first_clk_reg2,
tx_first_clk_reg3, tx_first_clk_reg4,
tx_first_clk_reg5, tx_first_clk_reg6,
tx_first_clk_reg7;
 
// Generate clocks when state is 2, and 7 when transmitting
// We then sample the MII txen signal, to see if we have a valid data frame
// coming up. We can do this 2 or 3 clocks after the MII tx clk. If we do it
// 2 then we allow 2 cycles for our mtxen_r signal to propegate, doubling the
// period contstraint for the path from mtxen_r to the stuff it controls in
// eth_clk domain. If we allow 3 from the eth MAC, then all stuff on the
// eth_clk side of mtxen_r must meet the 125MHz timing.
//
// Once the data is sampled at the right times (plenty after they come from
// the eth MAC, should be no issues there), then it all propegates through
// relatively various levels of registering, configured so that the signals
// appear in the tx_bits[] vector at the right time to be registered once
// more before before having its bits AND-OR selected based on the smii state
// The final SMII TX bit is generated from a sync counter that is one ahead
// of the one we output.
wire tx_first_clk, tx_second_clk;
assign tx_first_clk = (tx_smii_state[2] &
( speed | ( !speed & tx_cnt[10]) ) );
assign tx_second_clk = (tx_smii_state[7] &
txen_r & ( speed | ( !speed & tx_cnt[1]) ) );
always @(posedge eth_clk)
if (eth_rst)
mtx_clk_gen <= 1'b0;
else if (mtx_clk_gen)
mtx_clk_gen <= 1'b0;
// Clock high
else if (tx_first_clk | tx_second_clk)
mtx_clk_gen <= 1'b1;
always @(posedge eth_clk)
mtx_clk_gen_reg <= mtx_clk_gen;
always @(posedge eth_clk)
mtx_clk_gen_reg2 <= mtx_clk_gen_reg;
always @(posedge eth_clk)
mtx_clk_gen_reg3 <= mtx_clk_gen_reg2;
always @(posedge eth_clk)
mtx_clk_gen_reg4 <= mtx_clk_gen_reg3;
 
always @(posedge eth_clk)
mtx_clk_gen_reg5 <= mtx_clk_gen_reg4;
 
always @(posedge eth_clk)
mtx_clk_gen_reg6 <= mtx_clk_gen_reg5;
 
always @(posedge eth_clk)
mtx_clk_gen_reg7 <= mtx_clk_gen_reg6;
 
always @(posedge eth_clk)
tx_first_clk_gen <= tx_first_clk;
always @(posedge eth_clk)
tx_first_clk_reg <= tx_first_clk_gen;
 
always @(posedge eth_clk)
tx_first_clk_reg2 <= tx_first_clk_reg;
 
always @(posedge eth_clk)
tx_first_clk_reg3 <= tx_first_clk_reg2;
 
always @(posedge eth_clk)
tx_first_clk_reg4 <= tx_first_clk_reg3;
always @(posedge eth_clk)
tx_first_clk_reg5 <= tx_first_clk_reg4;
 
always @(posedge eth_clk)
tx_first_clk_reg6 <= tx_first_clk_reg5;
always @(posedge eth_clk)
tx_first_clk_reg7 <= tx_first_clk_reg6;
// Register MII TX enable
always @(posedge eth_clk)
if (eth_rst)
txen_r <= 1'b0;
else if (tx_first_clk_reg3)
txen_r <= mtxen;
 
// Register MII TX error
always @(posedge eth_clk)
if (eth_rst)
txerr_r <= 1'b0;
else if (tx_first_clk_reg3)
txerr_r <= mtxerr;
 
// Register indicating if we're going to sample the second nibble of data
reg tx_nib_second;
always @(posedge eth_clk)
if (eth_rst)
tx_nib_second <= 0;
else if (mtx_clk_gen_reg4)
begin
if (!txen_r)
tx_nib_second <= 0;
else
tx_nib_second <= ~tx_nib_second;
end
// Byte register, appropriately storing nibbles as we recieve them from MAC
reg [7:0] mtxd_r;
always @(posedge eth_clk)
if (txen_r & mtx_clk_gen_reg4 & !tx_nib_second)
mtxd_r[3:0] <= mtxd;
else if (txen_r & mtx_clk_gen_reg4 & tx_nib_second)
mtxd_r[7:4] <= mtxd;
// Sample our registered version of txen_r when we generate our
// "first" of the 2 TX clocks per frame.
reg tx_state_or_data; // 0 = state, 1 = data
always @ (posedge eth_clk)
if (eth_rst)
tx_state_or_data <= 0;
else if (tx_first_clk_reg4)
tx_state_or_data <= txen_r;
 
reg [10:1] tx_bits, tx_bits_reg, tx_bits_reg2;
always @(posedge eth_clk)
begin
tx_bits_reg <= tx_bits;
tx_bits[1] <= txerr_r;
tx_bits[2] <= tx_state_or_data;
tx_bits[3] <= (tx_state_or_data) ? mtxd_r[0] : txerr_r;
tx_bits[4] <= (tx_state_or_data) ? mtxd_r[1] : speed;
tx_bits[5] <= (tx_state_or_data) ? mtxd_r[2] : duplex;
tx_bits[6] <= (tx_state_or_data) ? mtxd_r[3] : link;
tx_bits[7] <= (tx_state_or_data) ? mtxd_r[4] : 0;
tx_bits[8] <= (tx_state_or_data) ? mtxd_r[5] : 1;
tx_bits[9] <= (tx_state_or_data) ? mtxd_r[6] : 1;
tx_bits[10] <= (tx_state_or_data) ? mtxd_r[7] : 1;
end
 
// Generate tx output bit one clock infront, because we register
// in the IOB too.
reg tx_bit;
always @(posedge eth_clk)
tx_bit <= |(tx_bits_reg & next_tx_smii_state);
assign tx = tx_bit;
 
`ifdef ACTEL
 
wire GND;
GND GND_1_net(.Y(GND));
CLKDLY Inst1(.CLK(mtx_clk_gen), .GL(mtx_clk), .DLYGL0(GND), .DLYGL1(GND),
.DLYGL2(GND), .DLYGL3(GND), .DLYGL4(GND)) /* synthesis black_box */;
/*
gbuf mtx_clk_bufg
(
.CLK(mtx_clk_gen),
.GL(mtx_clk)
);
*/
`else
assign mtx_clk = mtx_clk_gen;
`endif
 
/////////////////////////////////////////////////
// Receive
 
`ifndef SYNTHESIS
reg [79:0] rx_statename;
always @* begin
case (1)
rx_smii_state[1] :
rx_statename = "CRS";
rx_smii_state[2] :
rx_statename = "RX_DV";
rx_smii_state[3]:
rx_statename = "RXD0/RXERR";
rx_smii_state[4]:
rx_statename = "RXD1/Fast";
rx_smii_state[5]:
rx_statename = "RXD2/Dupl";
rx_smii_state[6]:
rx_statename = "RXD3/Link";
rx_smii_state[7]:
rx_statename = "RXD4/Jabb";
rx_smii_state[8]:
rx_statename = "RXD5/UNV";
rx_smii_state[9]:
rx_statename = "RXD6/FCD";
rx_smii_state[10] :
rx_statename = "RXD7/AS1";
default:
rx_statename = "XXXXXXX";
endcase // case (1)
end // always @ *
`endif
reg rxdv_thisframe;
wire rxdv_lastframe;
reg rxdv_lastframe_r;
reg [9:0] rxd_thisframe;
reg [9:0] rxd_lastframe;
 
// Logic to detect change in ethernet speed
reg speed_r;
always @(posedge eth_clk)
speed_r <= speed;
wire speed_edge;
assign speed_edge = speed_r != speed;
always @ (posedge eth_clk or posedge eth_rst)
if (eth_rst)
rx_cnt <= 10'd1;
// Data coming in, or we've changed from fast to slow ethernet
else if ((!rxdv_lastframe & rx_smii_state[8] & rxdv_thisframe) | speed_edge)
rx_cnt[10] <= ~speed; // Will be high if not in 100MBit mode
else if (rx_smii_state[10]) // wrap
if (rx_cnt[10])
rx_cnt[10:1] <= {9'b000000000, ~speed}; // Clears bit when fasteth
else
rx_cnt <= {rx_cnt[9:1],1'b0};
always @(posedge eth_clk)
if (rx_smii_state[2])
rxdv_thisframe <= rx;
 
always @(posedge eth_clk)
if (rx_smii_state[1])
mcrs <= rx;
always @(posedge eth_clk) // shift register sampling incoming data
rxd_thisframe <= {rx, rxd_thisframe[9:1]};
always @(posedge eth_clk)
if (rx_smii_state[1])
rxd_lastframe <= rxd_thisframe;
 
assign rxdv_lastframe = rxd_lastframe[1];
// Must remember with rxd_thisframe, data has been registered, so state
// counter is 1 infront of what we have in it
always @(posedge eth_clk)
if (eth_rst)
begin
{rxdv, rxerr, speed, duplex, link, jabber} <= 6'b001110;
end
else
begin
if (rx_smii_state[10]) // Look at sampled shift reg
begin
if ((!rxdv_lastframe)) // !RX DV from last frame
begin
rxerr <= rxd_lastframe[2];
speed <= rxd_lastframe[3];
duplex <= rxd_lastframe[4];
link <= rxd_lastframe[5];
jabber <= rxd_lastframe[6];
// rxd_thisframe[7] should be 1 if
end
end
end // else: !if(eth_rst)
 
// Latch the nibbles at the appropriate moments
always @(posedge eth_clk)
if (rx_smii_state[2])
rxd_nib <= rxd_lastframe[5:2];
else if (rx_smii_state[8])
rxd_nib <= rxd_lastframe[9:6];
 
// Nibble write enables
reg rx_we_nib0, rx_we_nib1;
always @(posedge eth_clk)
if (eth_rst)
rx_we_nib0 <= 0;
else if (rx_smii_state[3] & rxdv_lastframe &
!(!rxdv_thisframe & rx))
// Check in state 3, if DV was high for buffered frame (lastframe), and
// if the incoming frame doesn't negate it with error being signaled
rx_we_nib0 <= 1;
else
rx_we_nib0 <= 0;
 
always @(posedge eth_clk)
if (eth_rst)
rx_we_nib1 <= 0;
else if (rx_smii_state[8] & !(!rxdv_thisframe & (rxd_thisframe[5] | !rx))
& rxdv_lastframe)
// Check in state 8, if DV was high last frame, and this frame isn't a
// status frame indicating either error or not upper nibble valid, in
// which case we do not generate a WE to the FIFO
rx_we_nib1 <= 1;
else
rx_we_nib1 <= 0;
// Pipelining of clocks to MAC, this should run at 125MHz
reg nib_rx_clock;
always @(posedge eth_clk)
nib_rx_clock <= ((rx_smii_state[4] & rx_we_nib0)|(rx_smii_state[9] & rx_we_nib1));
 
// Enable for mrxclk inbetween frame receive
reg inbetween_rx_clock;
always @(posedge eth_clk)
inbetween_rx_clock <= rx_smii_state[4];//(!rxdv_thisframe & !rxdv_lastframe);
// Enable to clock the segment in the 10MBit mode, change rx_cnt[x] to alter
// which of the 10 the segments we use
reg thissegment_rx_clock;
always @(posedge eth_clk)
thissegment_rx_clock <= speed | (rx_cnt[6] & !speed);
reg mrx_clk_gen;
// Receive MII clock generation (very similar to Receive FIFO WE generation)
// This ends up being only about 20MHz when clocking in data
always @(posedge eth_clk)
if (eth_rst)
mrx_clk_gen <= 0;
else if (mrx_clk_gen)
mrx_clk_gen <= 0;
else if ((nib_rx_clock | inbetween_rx_clock) & thissegment_rx_clock )
mrx_clk_gen <= 1;
 
`ifdef ACTEL
 
CLKDLY Inst2(.CLK(mrx_clk_gen), .GL(mrx_clk), .DLYGL0(GND), .DLYGL1(GND),
.DLYGL2(GND), .DLYGL3(GND), .DLYGL4(GND)) /* synthesis black_box */;
 
/*
gbuf mrx_clk_bufg
(
.CLK(mrx_clk_gen),
.GL(mrx_clk)
);
*/
`else
assign mrx_clk = mrx_clk_gen;
`endif
assign mrxd = rxd_nib;
assign mrxdv = rxdv_lastframe;
assign mrxerr = rxerr;
assign mcoll = mcrs & mtxen & !duplex;
endmodule // smii_if
/smii.v
0,0 → 1,142
/*
* SMII <-> MII interface
*
* Julius Baxter, julius.baxter@orsoc.se
*
*/
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2009, 2010 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source 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 Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
 
module smii
(
eth_clk,
eth_rst,
eth_sync_pad_o,
eth_tx_pad_o,
eth_rx_pad_i,
mtxd,
mtxen,
mtxerr,
mtx_clk,
mrxd,
mrxdv,
mrxerr,
mrx_clk,
mcoll,
mcrs,
speed,
duplex,
link
);
input eth_clk;
input eth_rst; // active high reset synchronous to ethernet clock
 
// SMII
output reg eth_sync_pad_o /*synthesis syn_useioff=1 syn_allow_retiming=0 syn_noprune=1*/;
output reg eth_tx_pad_o /*synthesis syn_useioff=1 syn_allow_retiming=0 */;
input eth_rx_pad_i;
// MII
// TX
input [3:0] mtxd;
input mtxen;
input mtxerr;
output mtx_clk;
// RX
output [3:0] mrxd;
output mrxdv;
output mrxerr;
output mrx_clk;
output mcoll;
output mcrs;
output speed;
output duplex;
output link;
 
 
// Wires from pads
wire smii_tx;
reg smii_rx /*synthesis syn_useioff=1 syn_allow_retiming=0 */;
 
// Sync generation
wire [10:1] tx_smii_state;
wire [10:1] next_tx_smii_state;
wire [10:1] rx_smii_state;
wire smii_sync;
smii_sync smii_sync0
(
.sync(smii_sync),
.tx_state(tx_smii_state),
.next_tx_state(next_tx_smii_state),
.rx_state(rx_smii_state),
.clk(eth_clk),
.rst(eth_rst)
);
 
// IOB regs for SMII
always @(posedge eth_clk) eth_sync_pad_o <= smii_sync;
always @(posedge eth_clk) eth_tx_pad_o <= smii_tx;
always @(posedge eth_clk) smii_rx <= eth_rx_pad_i;
smii_if smii_if0
(
// SMII signals
.tx (smii_tx),
.rx (smii_rx),
.tx_smii_state (tx_smii_state[10:1]),
.next_tx_smii_state (next_tx_smii_state[10:1]),
.rx_smii_state (rx_smii_state[10:1]),
// MAC MII receive
.mrxd (mrxd[3:0]),
.mrxdv (mrxdv),
.mrxerr (mrxerr),
.mrx_clk (mrx_clk),
// MAC MII transmit
.mtx_clk (mtx_clk),
.mtxd (mtxd[3:0]),
.mtxen (mtxen),
.mtxerr (mtxerr),
// Collision
.mcoll (mcoll),
// Carrier sense
.mcrs (mcrs),
// Speedy ethernet
.speed (speed),
// Duplex indicator
.duplex (duplex),
// Linke indicator
.link (link),
// Clocks, resets
.eth_clk (eth_clk),
.eth_rst (eth_rst)
);
endmodule // smii
/README
0,0 → 1,5
MII to SMII converter RTL
 
This implements conversion between the 3-pin SMII bus and the higher-pin count MII interface for communication between a 10/100 ethernet MAC and ethernet PHY.
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.