/*!
* Module:status_router2
* @file status_router2.v
* @date 2015-01-13
* @author Andrey Filippov
*
* @brief 2:1 status data router/mux
*
* @copyright Copyright (c) 2015 Elphel, Inc.
*
* License:
*
* status_router2.v 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, either version 3 of the License, or
* (at your option) any later version.
*
* status_router2.v 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 .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*/
//TODO: make a 4-input mux too?
`timescale 1ns/1ps
`include "system_defines.vh"
//`define DEBUG_FIFO 1
module status_router2 #(
parameter FIFO_TYPE = "ONE_CYCLE" // "TWO_CYCLE"
)(
input rst,
input clk,
input srst, // sync reset
// 2 input channels
input [7:0] db_in0,
input rq_in0,
output start_in0, // only for the first cycle, combinatorial
input [7:0] db_in1,
input rq_in1,
output start_in1, // only for the first cycle, combinatorial
// output (multiplexed) channel
output [7:0] db_out,
output rq_out,
input start_out // only for the first cycle, combinatorial
);
wire [1:0] rq_in={rq_in1,rq_in0};
wire [1:0] start_rcv;
reg [1:0] rcv_rest_r; // receiving remaining (after first) bytes
wire [1:0] fifo_half_full;
assign start_in0=start_rcv[0];
assign start_in1=start_rcv[1];
assign start_rcv=~fifo_half_full & ~rcv_rest_r & rq_in;
wire [7:0] fifo0_out;
wire [7:0] fifo1_out;
wire [1:0] fifo_last_byte;
wire [1:0] fifo_nempty_pre; // pure fifo output
wire [1:0] fifo_nempty; // safe version, zeroed for last byte
wire [1:0] fifo_re;
reg next_chn;
reg current_chn_r;
reg snd_rest_r;
wire snd_pre_start;
wire snd_last_byte;
wire chn_sel_w;
wire early_chn;
wire set_other_only_w; // window to initiate other channel only, same channel must wait
assign chn_sel_w=(&fifo_nempty)?next_chn : fifo_nempty[1];
assign fifo_re=start_out?{chn_sel_w,~chn_sel_w}:(snd_rest_r?{current_chn_r,~current_chn_r}:2'b0);
// assign snd_last_byte=current_chn_r?fifo_last_byte[1]:fifo_last_byte[0];
assign snd_last_byte=current_chn_r?(fifo_nempty_pre[1] && fifo_last_byte[1]):(fifo_nempty_pre[0] && fifo_last_byte[0]);
assign set_other_only_w=snd_last_byte && (current_chn_r? fifo_nempty[0]:fifo_nempty[1]);
assign snd_pre_start=|fifo_nempty && (!snd_rest_r || snd_last_byte);
/// assign snd_pre_start=|fifo_nempty && !snd_rest_r && !start_out; // no channel change after
// assign rq_out=(snd_rest_r && !snd_last_byte) || |fifo_nempty;
assign rq_out=(snd_rest_r || |fifo_nempty) && !snd_last_byte ;
// assign early_chn= (snd_rest_r & ~snd_last_byte)?current_chn_r:chn_sel_w;
assign early_chn= snd_rest_r? current_chn_r: chn_sel_w;
assign db_out=early_chn?fifo1_out:fifo0_out;
assign fifo_nempty=fifo_nempty_pre & ~fifo_last_byte;
always @ (posedge rst or posedge clk) begin
if (rst) rcv_rest_r<= 0;
else if (srst) rcv_rest_r<= 0;
else rcv_rest_r <= (rcv_rest_r & rq_in) | start_rcv;
if (rst) next_chn<= 0;
else if (srst) next_chn<= 0;
else if (|fifo_re) next_chn <= fifo_re[0]; // just to be fair
if (rst) current_chn_r <= 0;
else if (srst) current_chn_r <= 0;
else if (set_other_only_w) current_chn_r <= ~current_chn_r;
else if (snd_pre_start) current_chn_r <= chn_sel_w;
/// else if (|fifo_nempty && !snd_rest_r) current_chn_r <= chn_sel_w;
//|fifo_nempty && (!snd_rest_r
if (rst) snd_rest_r<= 0;
else if (srst) snd_rest_r<= 0;
else snd_rest_r <= (snd_rest_r & ~snd_last_byte) | start_out;
end
/* fifo_same_clock has currently latency of 2 cycles, use smth. faster here? - fifo_1cycle (but it has unregistered data output) */
generate
if (FIFO_TYPE == "ONE_CYCLE") begin
fifo_1cycle #(
.DATA_WIDTH(9),
.DATA_DEPTH(4) // 16
) fifo_in0_i (
.rst (1'b0), // rst), // input
.clk (clk), // input
.sync_rst (srst), // input
.we (start_rcv[0] || rcv_rest_r[0]), // input
.re (fifo_re[0]), // input
.data_in ({rcv_rest_r[0] & ~rq_in[0], db_in0}), // input[8:0] MSB marks last byte
.data_out ({fifo_last_byte[0],fifo0_out}), // output[8:0]
.nempty (fifo_nempty_pre[0]), // output reg
.half_full (fifo_half_full[0]) // output reg
`ifdef DEBUG_FIFO
,.under(), // output reg
.over(), // output reg
.wcount(), // output[3:0] reg
.rcount(), // output[3:0] reg
.num_in_fifo() // output[3:0]
`endif
);
fifo_1cycle #(
.DATA_WIDTH(9),
.DATA_DEPTH(4) // 16
) fifo_in1_i (
.rst (1'b0), // rst), // input
.clk (clk), // input
.sync_rst (srst), // input
.we (start_rcv[1] || rcv_rest_r[1]), // input
.re (fifo_re[1]), // input
.data_in ({rcv_rest_r[1] & ~rq_in[1], db_in1}), // input[8:0] MSB marks last byte
.data_out ({fifo_last_byte[1],fifo1_out}), // output[8:0]
.nempty (fifo_nempty_pre[1]), // output reg
.half_full (fifo_half_full[1]) // output reg
`ifdef DEBUG_FIFO
,.under(), // output reg
.over(), // output reg
.wcount(), // output[3:0] reg
.rcount(), // output[3:0] reg
.num_in_fifo() // output[3:0]
`endif
);
end else begin
fifo_same_clock #(
.DATA_WIDTH(9),
.DATA_DEPTH(4) // 16
) fifo_in0_i (
.rst (1'b0), // rst), // input
.clk (clk), // input
.sync_rst (srst), // input
.we (start_rcv[0] || rcv_rest_r[0]), // input
.re (fifo_re[0]), // input
.data_in ({rcv_rest_r[0] & ~rq_in[0], db_in0}), // input[8:0] MSB marks last byte
.data_out ({fifo_last_byte[0],fifo0_out}), // output[8:0]
.nempty (fifo_nempty_pre[0]), // output reg
.half_full (fifo_half_full[0]) // output reg
`ifdef DEBUG_FIFO
,.under(), // output reg
.over(), // output reg
.wcount(), // output[3:0] reg
.rcount(), // output[3:0] reg
.num_in_fifo() // output[3:0]
`endif
);
fifo_same_clock #(
.DATA_WIDTH(9),
.DATA_DEPTH(4) // 16
) fifo_in1_i (
.rst (1'b0), // rst), // input
.clk (clk), // input
.sync_rst (srst), // input
.we (start_rcv[1] || rcv_rest_r[1]), // input
.re (fifo_re[1]), // input
.data_in ({rcv_rest_r[1] & ~rq_in[1], db_in1}), // input[8:0] MSB marks last byte
.data_out ({fifo_last_byte[1],fifo1_out}), // output[8:0]
.nempty (fifo_nempty_pre[1]), // output reg
.half_full (fifo_half_full[1]) // output reg
`ifdef DEBUG_FIFO
,.under(), // output reg
.over(), // output reg
.wcount(), // output[3:0] reg
.rcount(), // output[3:0] reg
.num_in_fifo() // output[3:0]
`endif
);
end
endgenerate
// one car per green (round robin priority)
// start sending out with with one cycle latency - now 2 cycles because of the FIFO
endmodule