123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- /*
- * e1_tx_framer.v
- *
- * vim: ts=4 sw=4
- *
- * E1 Frame generation as described G.704
- *
- *
- * Copyright (C) 2019 Sylvain Munaut <tnt@246tNt.com>
- * All rights reserved.
- *
- * LGPL v3+, see LICENSE.lgpl3
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- `default_nettype none
- module e1_tx_framer (
- // Fetch interface
- input wire [7:0] in_data,
- input wire [1:0] in_crc_e, // CRC error bits to use in this multiframe
- output wire [3:0] in_frame,
- output wire [4:0] in_ts,
- output reg in_mf_first, // First request for this multiframe
- output reg in_mf_last, // Last request for this multiframe
- output reg in_req,
- input wire in_rdy,
- // Output
- output reg out_bit,
- output reg out_valid,
- // Loopback Input
- input wire lb_bit,
- input wire lb_valid,
- // Control
- input wire ctrl_time_src, // 0=internal, 1=external
- input wire ctrl_do_framing,
- input wire ctrl_do_crc4,
- input wire ctrl_loopback,
- input wire alarm,
- // Timing sources
- input wire ext_tick,
- output wire int_tick,
- // Common
- input wire clk,
- input wire rst
- );
- // Signals
- // -------
- // Tick source
- reg [5:0] tick_cnt;
- reg strobe;
- // Fetch unit
- reg [3:0] fetch_frame;
- reg [4:0] fetch_ts;
- reg fetch_ts_is0;
- reg fetch_ts_is31;
- reg fetch_first;
- reg fetch_last;
- reg fetch_done;
- wire [7:0] fetch_data;
- wire [1:0] fetch_crc_e;
- wire fetch_valid;
- wire fetch_ack;
- // TS0 generation
- reg [7:0] shift_data_nxt;
- wire [7:0] odd_bit0;
- // Shift register
- reg [7:0] shift_data;
- reg shift_at_first;
- reg shift_at_last;
- reg shift_at_crc;
- // CRC4
- wire crc_in_bit;
- wire crc_in_first;
- wire crc_in_valid;
- reg crc_capture;
- wire [3:0] crc_out;
- reg [3:0] crc_smf;
- // Tick source
- // -----------
- always @(posedge clk or posedge rst)
- if (rst)
- tick_cnt <= 5'b00000;
- else
- tick_cnt <= strobe ? 5'b01100 : (tick_cnt - 1);
- always @(posedge clk)
- strobe <= (ctrl_time_src ? ext_tick : tick_cnt[4]) & ~strobe;
- assign int_tick = strobe;
- // Fetch control
- // -------------
- // Frame
- always @(posedge clk or posedge rst)
- if (rst)
- fetch_frame <= 4'hf;
- else if (fetch_ack)
- fetch_frame <= fetch_frame + fetch_ts_is31;
- // Time Slot
- always @(posedge clk or posedge rst)
- if (rst) begin
- fetch_ts <= 5'h1f;
- fetch_ts_is0 <= 1'b0;
- fetch_ts_is31 <= 1'b1;
- end else if (fetch_ack) begin
- fetch_ts <= fetch_ts + 1;
- fetch_ts_is0 <= fetch_ts_is31;
- fetch_ts_is31 <= (fetch_ts == 5'h1e);
- end
- // External request
- assign in_frame = fetch_frame;
- assign in_ts = fetch_ts;
- always @(posedge clk or posedge rst)
- if (rst) begin
- in_mf_first <= 1'b0;
- in_mf_last <= 1'b1;
- end else if (fetch_ack) begin
- in_mf_first <= in_mf_last;
- in_mf_last <= (fetch_frame == 4'hf) && (fetch_ts == 5'h1e) ;
- end
- always @(posedge clk)
- in_req <= fetch_ack;
- // Track the first ever request (hence first valid data ...)
- always @(posedge clk or posedge rst)
- if (rst)
- fetch_done <= 1'b0;
- else if (in_req)
- fetch_done <= 1'b1;
- // Data output to next stage
- assign fetch_data = in_data;
- assign fetch_crc_e = in_crc_e;
- assign fetch_valid = in_rdy & fetch_done;
- // TS0 generation
- // --------------
- // After fetch_ack we have plenty of time to generate the next data
- // from the response
- assign odd_bit0 = { fetch_crc_e[1:0], 6'b110100 };
- always @(posedge clk)
- if (fetch_ts_is0 & ctrl_do_framing) begin
- // TS0 with auto-framing
- if (fetch_frame[0])
- // Odd frame number
- shift_data_nxt <= { odd_bit0[fetch_frame[3:1]], 1'b1, alarm, 5'b11111 };
- else
- // Even frame number
- shift_data_nxt <= 8'h1b; // CRC bits are set later
- end else begin
- // Either auto-frame is disabled, or this is not TS0
- // If there is no valid data available, fill with 0xff
- shift_data_nxt <= fetch_valid ? fetch_data : 8'hff;
- end
- // Shift register
- // --------------
- reg [3:0] bit_cnt;
- reg bit_first;
- // Bit counter
- always @(posedge clk or posedge rst)
- if (rst)
- bit_cnt <= 4'b1000;
- else if (strobe)
- bit_cnt <= bit_cnt[3] ? 4'b0110 : (bit_cnt - 1);
- // Shift register
- always @(posedge clk or posedge rst)
- if (rst)
- shift_data <= 8'hff;
- else if (strobe)
- shift_data <= bit_cnt[3] ? shift_data_nxt : { shift_data[6:0], 1'b1 };
- // Ack to upstream
- assign fetch_ack = strobe & bit_cnt[3];
- // Track special positions
- always @(posedge clk or posedge rst)
- if (rst) begin
- shift_at_first <= 1'b1;
- shift_at_last <= 1'b0;
- shift_at_crc <= 1'b0;
- end else if (strobe) begin
- shift_at_first <= (fetch_frame[2:0] == 3'b000) & fetch_ts_is0 & bit_cnt[3];
- shift_at_last <= (fetch_frame[2:0] == 3'b000) & fetch_ts_is0 & (bit_cnt[2:0] == 3'b000);
- shift_at_crc <= ~fetch_frame[0] & fetch_ts_is0 & bit_cnt[3];
- end
- // CRC4
- // ----
- // CRC4 computation
- assign crc_in_bit = shift_at_crc ? 1'b0 : shift_data[7];
- assign crc_in_first = shift_at_first;
- assign crc_in_valid = strobe;
- always @(posedge clk)
- crc_capture <= shift_at_last;
- e1_crc4 crc_I (
- .in_bit(crc_in_bit),
- .in_first(crc_in_first),
- .in_valid(crc_in_valid),
- .out_crc4(crc_out),
- .clk(clk),
- .rst(rst)
- );
- always @(posedge clk or posedge rst)
- if (rst)
- crc_smf <= 4'b1111;
- else if (crc_capture)
- crc_smf <= crc_out;
- else if (shift_at_crc & strobe)
- crc_smf <= { crc_smf[2:0], 1'b1 };
- // Output
- // ------
- always @(posedge clk or posedge rst)
- if (rst) begin
- out_bit <= 1'b1;
- out_valid <= 1'b0;
- end else begin
- out_bit <= ctrl_loopback ? lb_bit : ((ctrl_do_crc4 & shift_at_crc) ? crc_smf[3] : shift_data[7]);
- out_valid <= ctrl_loopback ? lb_valid : strobe;
- end
- endmodule // e1_tx_framer
|