mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			620 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Verilog
		
	
	
	
	
	
			
		
		
	
	
			620 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Verilog
		
	
	
	
	
	
| // Copyright 2020-2022 F4PGA Authors
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //     http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| //
 | |
| // SPDX-License-Identifier: Apache-2.0
 | |
| 
 | |
| `default_nettype wire
 | |
| module fifo_ctl (
 | |
| 	raddr,
 | |
| 	waddr,
 | |
| 	fflags,
 | |
| 	ren_o,
 | |
| 	sync,
 | |
| 	rmode,
 | |
| 	wmode,
 | |
| 	rclk,
 | |
| 	rst_R_n,
 | |
| 	wclk,
 | |
| 	rst_W_n,
 | |
| 	ren,
 | |
| 	wen,
 | |
| 	upaf,
 | |
| 	upae
 | |
| );
 | |
| 	parameter ADDR_WIDTH = 11;
 | |
| 	parameter FIFO_WIDTH = 3'd2;
 | |
| 	parameter DEPTH = 6;
 | |
| 	output wire [ADDR_WIDTH - 1:0] raddr;
 | |
| 	output wire [ADDR_WIDTH - 1:0] waddr;
 | |
| 	output wire [7:0] fflags;
 | |
| 	output wire ren_o;
 | |
| 	input wire sync;
 | |
| 	input wire [1:0] rmode;
 | |
| 	input wire [1:0] wmode;
 | |
| 	(* clkbuf_sink *)
 | |
| 	input wire rclk;
 | |
| 	input wire rst_R_n;
 | |
| 	(* clkbuf_sink *)
 | |
| 	input wire wclk;
 | |
| 	input wire rst_W_n;
 | |
| 	input wire ren;
 | |
| 	input wire wen;
 | |
| 	input wire [ADDR_WIDTH - 1:0] upaf;
 | |
| 	input wire [ADDR_WIDTH - 1:0] upae;
 | |
| 	localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1;
 | |
| 	reg [ADDR_WIDTH:0] pushtopop1;
 | |
| 	reg [ADDR_WIDTH:0] pushtopop2;
 | |
| 	reg [ADDR_WIDTH:0] poptopush1;
 | |
| 	reg [ADDR_WIDTH:0] poptopush2;
 | |
| 	wire [ADDR_WIDTH:0] pushtopop0;
 | |
| 	wire [ADDR_WIDTH:0] poptopush0;
 | |
| 	wire [ADDR_WIDTH:0] smux_poptopush;
 | |
| 	wire [ADDR_WIDTH:0] smux_pushtopop;
 | |
| 	assign smux_poptopush = (sync ? poptopush0 : poptopush2);
 | |
| 	assign smux_pushtopop = (sync ? pushtopop0 : pushtopop2);
 | |
| 	always @(posedge rclk or negedge rst_R_n)
 | |
| 		if (~rst_R_n) begin
 | |
| 			pushtopop1 <= 'h0;
 | |
| 			pushtopop2 <= 'h0;
 | |
| 		end
 | |
| 		else begin
 | |
| 			pushtopop1 = pushtopop0;
 | |
| 			pushtopop2 = pushtopop1;
 | |
| 		end
 | |
| 	always @(posedge wclk or negedge rst_W_n)
 | |
| 		if (~rst_W_n) begin
 | |
| 			poptopush1 <= 'h0;
 | |
| 			poptopush2 <= 'h0;
 | |
| 		end
 | |
| 		else begin
 | |
| 			poptopush1 <= poptopush0;
 | |
| 			poptopush2 <= poptopush1;
 | |
| 		end
 | |
| 	fifo_push #(
 | |
| 		.ADDR_WIDTH(ADDR_WIDTH),
 | |
| 		.DEPTH(DEPTH)
 | |
| 	) u_fifo_push(
 | |
| 		.wclk(wclk),
 | |
| 		.wen(wen),
 | |
| 		.rst_n(rst_W_n),
 | |
| 		.rmode(rmode),
 | |
| 		.wmode(wmode),
 | |
| 		.gcout(pushtopop0),
 | |
| 		.gcin(smux_poptopush),
 | |
| 		.ff_waddr(waddr),
 | |
| 		.pushflags(fflags[7:4]),
 | |
| 		.upaf(upaf)
 | |
| 	);
 | |
| 	fifo_pop #(
 | |
| 		.ADDR_WIDTH(ADDR_WIDTH),
 | |
| 		.FIFO_WIDTH(FIFO_WIDTH),
 | |
| 		.DEPTH(DEPTH)
 | |
| 	) u_fifo_pop(
 | |
| 		.rclk(rclk),
 | |
| 		.ren_in(ren),
 | |
| 		.rst_n(rst_R_n),
 | |
| 		.rmode(rmode),
 | |
| 		.wmode(wmode),
 | |
| 		.ren_o(ren_o),
 | |
| 		.gcout(poptopush0),
 | |
| 		.gcin(smux_pushtopop),
 | |
| 		.out_raddr(raddr),
 | |
| 		.popflags(fflags[3:0]),
 | |
| 		.upae(upae)
 | |
| 	);
 | |
| endmodule
 | |
| module fifo_push (
 | |
| 	pushflags,
 | |
| 	gcout,
 | |
| 	ff_waddr,
 | |
| 	rst_n,
 | |
| 	wclk,
 | |
| 	wen,
 | |
| 	rmode,
 | |
| 	wmode,
 | |
| 	gcin,
 | |
| 	upaf
 | |
| );
 | |
| 	parameter ADDR_WIDTH = 11;
 | |
| 	parameter DEPTH = 6;
 | |
| 	output wire [3:0] pushflags;
 | |
| 	output wire [ADDR_WIDTH:0] gcout;
 | |
| 	output wire [ADDR_WIDTH - 1:0] ff_waddr;
 | |
| 	input rst_n;
 | |
| 	(* clkbuf_sink *)
 | |
| 	input wclk;
 | |
| 	input wen;
 | |
| 	input [1:0] rmode;
 | |
| 	input [1:0] wmode;
 | |
| 	input [ADDR_WIDTH:0] gcin;
 | |
| 	input [ADDR_WIDTH - 1:0] upaf;
 | |
| 	localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1;
 | |
| 	reg full_next;
 | |
| 	reg full;
 | |
| 	reg paf_next;
 | |
| 	reg paf;
 | |
| 	reg fmo;
 | |
| 	reg fmo_next;
 | |
| 	reg overflow;
 | |
| 	reg p1;
 | |
| 	reg p2;
 | |
| 	reg f1;
 | |
| 	reg f2;
 | |
| 	reg q1;
 | |
| 	reg q2;
 | |
| 	reg [1:0] gmode;
 | |
| 	reg [ADDR_WIDTH:0] waddr;
 | |
| 	reg [ADDR_WIDTH:0] raddr;
 | |
| 	reg [ADDR_WIDTH:0] gcout_reg;
 | |
| 	reg [ADDR_WIDTH:0] gcout_next;
 | |
| 	reg [ADDR_WIDTH:0] raddr_next;
 | |
| 	reg [ADDR_WIDTH - 1:0] paf_thresh;
 | |
| 	wire overflow_next;
 | |
| 	wire [ADDR_WIDTH:0] waddr_next;
 | |
| 	wire [ADDR_WIDTH:0] gc8out_next;
 | |
| 	wire [ADDR_WIDTH - 1:0] gc16out_next;
 | |
| 	wire [ADDR_WIDTH - 2:0] gc32out_next;
 | |
| 	wire [ADDR_WIDTH:0] tmp;
 | |
| 	wire [ADDR_WIDTH:0] next_count;
 | |
| 	wire [ADDR_WIDTH:0] count;
 | |
| 	wire [ADDR_WIDTH:0] fbytes;
 | |
| 	genvar i;
 | |
| 	assign next_count = fbytes - (waddr_next >= raddr_next ? waddr_next - raddr_next : (~raddr_next + waddr_next) + 1);
 | |
| 	assign count = fbytes - (waddr >= raddr ? waddr - raddr : (~raddr + waddr) + 1);
 | |
| 	assign fbytes = 1 << (DEPTH + 5);
 | |
| 	always @(*) begin
 | |
| 		paf_thresh = wmode[1] ? upaf : (wmode[0] ? upaf << 1 : upaf << 2);
 | |
| 	end
 | |
| 	always @(*)
 | |
| 		case (wmode)
 | |
| 			2'h0, 2'h1, 2'h2: begin
 | |
| 				full_next = (wen ? f1 : f2);
 | |
| 				fmo_next = (wen ? p1 : p2);
 | |
| 				paf_next = (wen ? q1 : q2);
 | |
| 			end
 | |
| 			default: begin
 | |
| 				full_next = 1'b0;
 | |
| 				fmo_next = 1'b0;
 | |
| 				paf_next = 1'b0;
 | |
| 			end
 | |
| 		endcase
 | |
| 	always @(*) begin : PUSH_FULL_FLAGS
 | |
| 		f1 = 1'b0;
 | |
| 		f2 = 1'b0;
 | |
| 		p1 = 1'b0;
 | |
| 		p2 = 1'b0;
 | |
| 		q1 = next_count < {1'b0, paf_thresh};
 | |
| 		q2 = count < {1'b0, paf_thresh};
 | |
| 		case (wmode)
 | |
| 			2'h0:
 | |
| 				case (DEPTH)
 | |
| 					3'h6: begin
 | |
| 						f1 = {~waddr_next[11], waddr_next[10:2]} == raddr_next[11:2];
 | |
| 						f2 = {~waddr[11], waddr[10:2]} == raddr_next[11:2];
 | |
| 						p1 = ((waddr_next[10:2] + 1) & 9'h1ff) == raddr_next[10:2];
 | |
| 						p2 = ((waddr[10:2] + 1) & 9'h1ff) == raddr_next[10:2];
 | |
| 					end
 | |
| 					3'h5: begin
 | |
| 						f1 = {~waddr_next[10], waddr_next[9:2]} == raddr_next[10:2];
 | |
| 						f2 = {~waddr[10], waddr[9:2]} == raddr_next[10:2];
 | |
| 						p1 = ((waddr_next[9:2] + 1) & 8'hff) == raddr_next[9:2];
 | |
| 						p2 = ((waddr[9:2] + 1) & 8'hff) == raddr_next[9:2];
 | |
| 					end
 | |
| 					3'h4: begin
 | |
| 						f1 = {~waddr_next[9], waddr_next[8:2]} == raddr_next[9:2];
 | |
| 						f2 = {~waddr[9], waddr[8:2]} == raddr_next[9:2];
 | |
| 						p1 = ((waddr_next[8:2] + 1) & 7'h7f) == raddr_next[8:2];
 | |
| 						p2 = ((waddr[8:2] + 1) & 7'h7f) == raddr_next[8:2];
 | |
| 					end
 | |
| 					3'h3: begin
 | |
| 						f1 = {~waddr_next[8], waddr_next[7:2]} == raddr_next[8:2];
 | |
| 						f2 = {~waddr[8], waddr[7:2]} == raddr_next[8:2];
 | |
| 						p1 = ((waddr_next[7:2] + 1) & 6'h3f) == raddr_next[7:2];
 | |
| 						p2 = ((waddr[7:2] + 1) & 6'h3f) == raddr_next[7:2];
 | |
| 					end
 | |
| 					3'h2: begin
 | |
| 						f1 = {~waddr_next[7], waddr_next[6:2]} == raddr_next[7:2];
 | |
| 						f2 = {~waddr[7], waddr[6:2]} == raddr_next[7:2];
 | |
| 						p1 = ((waddr_next[6:2] + 1) & 5'h1f) == raddr_next[6:2];
 | |
| 						p2 = ((waddr[6:2] + 1) & 5'h1f) == raddr_next[6:2];
 | |
| 					end
 | |
| 					3'h1: begin
 | |
| 						f1 = {~waddr_next[6], waddr_next[5:2]} == raddr_next[6:2];
 | |
| 						f2 = {~waddr[6], waddr[5:2]} == raddr_next[6:2];
 | |
| 						p1 = ((waddr_next[5:2] + 1) & 4'hf) == raddr_next[5:2];
 | |
| 						p2 = ((waddr[5:2] + 1) & 4'hf) == raddr_next[5:2];
 | |
| 					end
 | |
| 					3'h0: begin
 | |
| 						f1 = {~waddr_next[5], waddr_next[4:2]} == raddr_next[5:2];
 | |
| 						f2 = {~waddr[5], waddr[4:2]} == raddr_next[5:2];
 | |
| 						p1 = ((waddr_next[4:2] + 1) & 3'h7) == raddr_next[4:2];
 | |
| 						p2 = ((waddr[4:2] + 1) & 3'h7) == raddr_next[4:2];
 | |
| 					end
 | |
| 					3'h7: begin
 | |
| 						f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:2]} == raddr_next[ADDR_WIDTH:2];
 | |
| 						f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:2]} == raddr_next[ADDR_WIDTH:2];
 | |
| 						p1 = ((waddr_next[ADDR_WIDTH - 1:2] + 1) & {ADDR_WIDTH - 2 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:2];
 | |
| 						p2 = ((waddr[ADDR_WIDTH - 1:2] + 1) & {ADDR_WIDTH - 2 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:2];
 | |
| 					end
 | |
| 				endcase
 | |
| 			2'h1:
 | |
| 				case (DEPTH)
 | |
| 					3'h6: begin
 | |
| 						f1 = {~waddr_next[11], waddr_next[10:1]} == raddr_next[11:1];
 | |
| 						f2 = {~waddr[11], waddr[10:1]} == raddr_next[11:1];
 | |
| 						p1 = ((waddr_next[10:1] + 1) & 10'h3ff) == raddr_next[10:1];
 | |
| 						p2 = ((waddr[10:1] + 1) & 10'h3ff) == raddr_next[10:1];
 | |
| 					end
 | |
| 					3'h5: begin
 | |
| 						f1 = {~waddr_next[10], waddr_next[9:1]} == raddr_next[10:1];
 | |
| 						f2 = {~waddr[10], waddr[9:1]} == raddr_next[10:1];
 | |
| 						p1 = ((waddr_next[9:1] + 1) & 9'h1ff) == raddr_next[9:1];
 | |
| 						p2 = ((waddr[9:1] + 1) & 9'h1ff) == raddr_next[9:1];
 | |
| 					end
 | |
| 					3'h4: begin
 | |
| 						f1 = {~waddr_next[9], waddr_next[8:1]} == raddr_next[9:1];
 | |
| 						f2 = {~waddr[9], waddr[8:1]} == raddr_next[9:1];
 | |
| 						p1 = ((waddr_next[8:1] + 1) & 8'hff) == raddr_next[8:1];
 | |
| 						p2 = ((waddr[8:1] + 1) & 8'hff) == raddr_next[8:1];
 | |
| 					end
 | |
| 					3'h3: begin
 | |
| 						f1 = {~waddr_next[8], waddr_next[7:1]} == raddr_next[8:1];
 | |
| 						f2 = {~waddr[8], waddr[7:1]} == raddr_next[8:1];
 | |
| 						p1 = ((waddr_next[7:1] + 1) & 7'h7f) == raddr_next[7:1];
 | |
| 						p2 = ((waddr[7:1] + 1) & 7'h7f) == raddr_next[7:1];
 | |
| 					end
 | |
| 					3'h2: begin
 | |
| 						f1 = {~waddr_next[7], waddr_next[6:1]} == raddr_next[7:1];
 | |
| 						f2 = {~waddr[7], waddr[6:1]} == raddr_next[7:1];
 | |
| 						p1 = ((waddr_next[6:1] + 1) & 6'h3f) == raddr_next[6:1];
 | |
| 						p2 = ((waddr[6:1] + 1) & 6'h3f) == raddr_next[6:1];
 | |
| 					end
 | |
| 					3'h1: begin
 | |
| 						f1 = {~waddr_next[6], waddr_next[5:1]} == raddr_next[6:1];
 | |
| 						f2 = {~waddr[6], waddr[5:1]} == raddr_next[6:1];
 | |
| 						p1 = ((waddr_next[5:1] + 1) & 5'h1f) == raddr_next[5:1];
 | |
| 						p2 = ((waddr[5:1] + 1) & 5'h1f) == raddr_next[5:1];
 | |
| 					end
 | |
| 					3'h0: begin
 | |
| 						f1 = {~waddr_next[5], waddr_next[4:1]} == raddr_next[5:1];
 | |
| 						f2 = {~waddr[5], waddr[4:1]} == raddr_next[5:1];
 | |
| 						p1 = ((waddr_next[4:1] + 1) & 4'hf) == raddr_next[4:1];
 | |
| 						p2 = ((waddr[4:1] + 1) & 4'hf) == raddr_next[4:1];
 | |
| 					end
 | |
| 					3'h7: begin
 | |
| 						f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:1]} == raddr_next[ADDR_WIDTH:1];
 | |
| 						f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:1]} == raddr_next[ADDR_WIDTH:1];
 | |
| 						p1 = ((waddr_next[ADDR_WIDTH - 1:1] + 1) & {ADDR_WIDTH - 1 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:1];
 | |
| 						p2 = ((waddr[ADDR_WIDTH - 1:1] + 1) & {ADDR_WIDTH - 1 {1'b1}}) == raddr_next[ADDR_WIDTH - 1:1];
 | |
| 					end
 | |
| 				endcase
 | |
| 			2'h2:
 | |
| 				case (DEPTH)
 | |
| 					3'h6: begin
 | |
| 						f1 = {~waddr_next[11], waddr_next[10:0]} == raddr_next[11:0];
 | |
| 						f2 = {~waddr[11], waddr[10:0]} == raddr_next[11:0];
 | |
| 						p1 = ((waddr_next[10:0] + 1) & 11'h7ff) == raddr_next[10:0];
 | |
| 						p2 = ((waddr[10:0] + 1) & 11'h7ff) == raddr_next[10:0];
 | |
| 					end
 | |
| 					3'h5: begin
 | |
| 						f1 = {~waddr_next[10], waddr_next[9:0]} == raddr_next[10:0];
 | |
| 						f2 = {~waddr[10], waddr[9:0]} == raddr_next[10:0];
 | |
| 						p1 = ((waddr_next[9:0] + 1) & 10'h3ff) == raddr_next[9:0];
 | |
| 						p2 = ((waddr[9:0] + 1) & 10'h3ff) == raddr_next[9:0];
 | |
| 					end
 | |
| 					3'h4: begin
 | |
| 						f1 = {~waddr_next[9], waddr_next[8:0]} == raddr_next[9:0];
 | |
| 						f2 = {~waddr[9], waddr[8:0]} == raddr_next[9:0];
 | |
| 						p1 = ((waddr_next[8:0] + 1) & 9'h1ff) == raddr_next[8:0];
 | |
| 						p2 = ((waddr[8:0] + 1) & 9'h1ff) == raddr_next[8:0];
 | |
| 					end
 | |
| 					3'h3: begin
 | |
| 						f1 = {~waddr_next[8], waddr_next[7:0]} == raddr_next[8:0];
 | |
| 						f2 = {~waddr[8], waddr[7:0]} == raddr_next[8:0];
 | |
| 						p1 = ((waddr_next[7:0] + 1) & 8'hff) == raddr_next[7:0];
 | |
| 						p2 = ((waddr[7:0] + 1) & 8'hff) == raddr_next[7:0];
 | |
| 					end
 | |
| 					3'h2: begin
 | |
| 						f1 = {~waddr_next[7], waddr_next[6:0]} == raddr_next[7:0];
 | |
| 						f2 = {~waddr[7], waddr[6:0]} == raddr_next[7:0];
 | |
| 						p1 = ((waddr_next[6:0] + 1) & 7'h7f) == raddr_next[6:0];
 | |
| 						p2 = ((waddr[6:0] + 1) & 7'h7f) == raddr_next[6:0];
 | |
| 					end
 | |
| 					3'h1: begin
 | |
| 						f1 = {~waddr_next[6], waddr_next[5:0]} == raddr_next[6:0];
 | |
| 						f2 = {~waddr[6], waddr[5:0]} == raddr_next[6:0];
 | |
| 						p1 = ((waddr_next[5:0] + 1) & 6'h3f) == raddr_next[5:0];
 | |
| 						p2 = ((waddr[5:0] + 1) & 6'h3f) == raddr_next[5:0];
 | |
| 					end
 | |
| 					3'h0: begin
 | |
| 						f1 = {~waddr_next[5], waddr_next[4:0]} == raddr_next[5:0];
 | |
| 						f2 = {~waddr[5], waddr[4:0]} == raddr_next[5:0];
 | |
| 						p1 = ((waddr_next[4:0] + 1) & 5'h1f) == raddr_next[4:0];
 | |
| 						p2 = ((waddr[4:0] + 1) & 5'h1f) == raddr_next[4:0];
 | |
| 					end
 | |
| 					3'h7: begin
 | |
| 						f1 = {~waddr_next[ADDR_WIDTH], waddr_next[ADDR_WIDTH - 1:0]} == raddr_next[ADDR_WIDTH:0];
 | |
| 						f2 = {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH - 1:0]} == raddr_next[ADDR_WIDTH:0];
 | |
| 						p1 = ((waddr_next[ADDR_WIDTH - 1:0] + 1) & {ADDR_WIDTH {1'b1}}) == raddr_next[ADDR_WIDTH - 1:0];
 | |
| 						p2 = ((waddr[ADDR_WIDTH - 1:0] + 1) & {ADDR_WIDTH {1'b1}}) == raddr_next[ADDR_WIDTH - 1:0];
 | |
| 					end
 | |
| 				endcase
 | |
| 			2'h3: begin
 | |
| 				f1 = 1'b0;
 | |
| 				f2 = 1'b0;
 | |
| 				p1 = 1'b0;
 | |
| 				p2 = 1'b0;
 | |
| 			end
 | |
| 		endcase
 | |
| 	end
 | |
| 	always @(*)
 | |
| 		case (wmode)
 | |
| 			2'h0: gmode = 2'h0;
 | |
| 			2'h1: gmode = (rmode == 2'h0 ? 2'h0 : 2'h1);
 | |
| 			2'h2: gmode = (rmode == 2'h2 ? 2'h2 : rmode);
 | |
| 			2'h3: gmode = 2'h3;
 | |
| 		endcase
 | |
| 	assign gc8out_next = (waddr_next >> 1) ^ waddr_next;
 | |
| 	assign gc16out_next = (waddr_next >> 2) ^ (waddr_next >> 1);
 | |
| 	assign gc32out_next = (waddr_next >> 3) ^ (waddr_next >> 2);
 | |
| 	always @(*)
 | |
| 		if (wen)
 | |
| 			case (gmode)
 | |
| 				2'h2: gcout_next = gc8out_next;
 | |
| 				2'h1: gcout_next = {1'b0, gc16out_next};
 | |
| 				2'h0: gcout_next = {2'b00, gc32out_next};
 | |
| 				default: gcout_next = {ADDR_PLUS_ONE {1'b0}};
 | |
| 			endcase
 | |
| 		else
 | |
| 			gcout_next = {ADDR_PLUS_ONE {1'b0}};
 | |
| 	always @(posedge wclk or negedge rst_n)
 | |
| 		if (~rst_n) begin
 | |
| 			full <= 1'b0;
 | |
| 			fmo <= 1'b0;
 | |
| 			paf <= 1'b0;
 | |
| 			raddr <= {ADDR_PLUS_ONE {1'b0}};
 | |
| 		end
 | |
| 		else begin
 | |
| 			full <= full_next;
 | |
| 			fmo <= fmo_next;
 | |
| 			paf <= paf_next;
 | |
| 			case (gmode)
 | |
| 				0: raddr <= raddr_next & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00};
 | |
| 				1: raddr <= raddr_next & {{ADDR_WIDTH {1'b1}}, 1'b0};
 | |
| 				2: raddr <= raddr_next & {ADDR_WIDTH + 1 {1'b1}};
 | |
| 				3: raddr <= 12'h000;
 | |
| 			endcase
 | |
| 		end
 | |
| 	assign overflow_next = full & wen;
 | |
| 	always @(posedge wclk or negedge rst_n)
 | |
| 		if (~rst_n)
 | |
| 			overflow <= 1'b0;
 | |
| 		else if (wen == 1'b1)
 | |
| 			overflow <= overflow_next;
 | |
| 	always @(posedge wclk or negedge rst_n)
 | |
| 		if (~rst_n) begin
 | |
| 			waddr <= {ADDR_WIDTH + 1 {1'b0}};
 | |
| 			gcout_reg <= {ADDR_WIDTH + 1 {1'b0}};
 | |
| 		end
 | |
| 		else if (wen == 1'b1) begin
 | |
| 			waddr <= waddr_next;
 | |
| 			gcout_reg <= gcout_next;
 | |
| 		end
 | |
| 	assign gcout = gcout_reg;
 | |
| 	generate
 | |
| 		for (i = 0; i < (ADDR_WIDTH + 1); i = i + 1) begin : genblk1
 | |
| 			assign tmp[i] = ^(gcin >> i);
 | |
| 		end
 | |
| 	endgenerate
 | |
| 	always @(*)
 | |
| 		case (gmode)
 | |
| 			2'h0: raddr_next = {tmp[ADDR_WIDTH - 2:0], 2'b00} & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00};
 | |
| 			2'h1: raddr_next = {tmp[ADDR_WIDTH - 1:0], 1'b0} & {{ADDR_WIDTH {1'b1}}, 1'b0};
 | |
| 			2'h2: raddr_next = {tmp[ADDR_WIDTH:0]} & {ADDR_WIDTH + 1 {1'b1}};
 | |
| 			default: raddr_next = {ADDR_WIDTH + 1 {1'b0}};
 | |
| 		endcase
 | |
| 	assign ff_waddr = waddr[ADDR_WIDTH - 1:0];
 | |
| 	assign pushflags = {full, fmo, paf, overflow};
 | |
| 	assign waddr_next = waddr + (wmode == 2'h0 ? 'h4 : (wmode == 2'h1 ? 'h2 : 'h1));
 | |
| endmodule
 | |
| module fifo_pop (
 | |
| 	ren_o,
 | |
| 	popflags,
 | |
| 	out_raddr,
 | |
| 	gcout,
 | |
| 	rst_n,
 | |
| 	rclk,
 | |
| 	ren_in,
 | |
| 	rmode,
 | |
| 	wmode,
 | |
| 	gcin,
 | |
| 	upae
 | |
| );
 | |
| 	parameter ADDR_WIDTH = 11;
 | |
| 	parameter FIFO_WIDTH = 3'd2;
 | |
| 	parameter DEPTH = 6;
 | |
| 	output wire ren_o;
 | |
| 	output wire [3:0] popflags;
 | |
| 	output reg [ADDR_WIDTH - 1:0] out_raddr;
 | |
| 	output wire [ADDR_WIDTH:0] gcout;
 | |
| 	input rst_n;
 | |
| 	(* clkbuf_sink *)
 | |
| 	input rclk;
 | |
| 	input ren_in;
 | |
| 	input [1:0] rmode;
 | |
| 	input [1:0] wmode;
 | |
| 	input [ADDR_WIDTH:0] gcin;
 | |
| 	input [ADDR_WIDTH - 1:0] upae;
 | |
| 	localparam ADDR_PLUS_ONE = ADDR_WIDTH + 1;
 | |
| 	reg empty;
 | |
| 	reg epo;
 | |
| 	reg pae;
 | |
| 	reg underflow;
 | |
| 	reg e1;
 | |
| 	reg e2;
 | |
| 	reg o1;
 | |
| 	reg o2;
 | |
| 	reg q1;
 | |
| 	reg q2;
 | |
| 	reg [1:0] bwl_sel;
 | |
| 	reg [1:0] gmode;
 | |
| 	reg [ADDR_WIDTH - 1:0] ff_raddr;
 | |
| 	reg [ADDR_WIDTH:0] waddr;
 | |
| 	reg [ADDR_WIDTH:0] raddr;
 | |
| 	reg [ADDR_WIDTH:0] gcout_reg;
 | |
| 	reg [ADDR_WIDTH:0] gcout_next;
 | |
| 	reg [ADDR_WIDTH:0] waddr_next;
 | |
| 	reg [ADDR_WIDTH - 1:0] pae_thresh;
 | |
| 	wire ren_out;
 | |
| 	wire empty_next;
 | |
| 	wire pae_next;
 | |
| 	wire epo_next;
 | |
| 	wire [ADDR_WIDTH - 2:0] gc32out_next;
 | |
| 	wire [ADDR_WIDTH - 1:0] gc16out_next;
 | |
| 	wire [ADDR_WIDTH:0] gc8out_next;
 | |
| 	wire [ADDR_WIDTH:0] raddr_next;
 | |
| 	wire [ADDR_WIDTH - 1:0] ff_raddr_next;
 | |
| 	wire [ADDR_WIDTH:0] tmp;
 | |
| 	wire [ADDR_PLUS_ONE:0] next_count;
 | |
| 	wire [ADDR_PLUS_ONE:0] count;
 | |
| 	wire [ADDR_PLUS_ONE:0] fbytes;
 | |
| 	genvar i;
 | |
| 	assign next_count = waddr - raddr_next;
 | |
| 	assign count = waddr - raddr;
 | |
| 	assign fbytes = 1 << (DEPTH + 5);
 | |
| 	always @(*) pae_thresh = rmode[1] ? upae : (rmode[0] ? upae << 1 : upae << 2);
 | |
| 	assign ren_out = (empty ? 1'b1 : ren_in);
 | |
| 	always @(*)
 | |
| 		case (rmode)
 | |
| 			2'h0: gmode = 2'h0;
 | |
| 			2'h1: gmode = (wmode == 2'h0 ? 2'h0 : 2'h1);
 | |
| 			2'h2: gmode = (wmode == 2'h2 ? 2'h2 : wmode);
 | |
| 			2'h3: gmode = 2'h3;
 | |
| 		endcase
 | |
| 	always @(*) begin
 | |
| 		e1 = 1'b0;
 | |
| 		e2 = 1'b0;
 | |
| 		o1 = 1'b0;
 | |
| 		o2 = 1'b0;
 | |
| 		q1 = next_count < {1'b0, pae_thresh};
 | |
| 		q2 = count < {1'b0, pae_thresh};
 | |
| 		case (rmode)
 | |
| 			2'h0: begin
 | |
| 				e1 = raddr_next[ADDR_WIDTH:2] == waddr_next[ADDR_WIDTH:2];
 | |
| 				e2 = raddr[ADDR_WIDTH:2] == waddr_next[ADDR_WIDTH:2];
 | |
| 				o1 = (raddr_next[ADDR_WIDTH:2] + 1) == waddr_next[ADDR_WIDTH:2];
 | |
| 				o2 = (raddr[ADDR_WIDTH:2] + 1) == waddr_next[ADDR_WIDTH:2];
 | |
| 			end
 | |
| 			2'h1: begin
 | |
| 				e1 = raddr_next[ADDR_WIDTH:1] == waddr_next[ADDR_WIDTH:1];
 | |
| 				e2 = raddr[ADDR_WIDTH:1] == waddr_next[ADDR_WIDTH:1];
 | |
| 				o1 = (raddr_next[ADDR_WIDTH:1] + 1) == waddr_next[ADDR_WIDTH:1];
 | |
| 				o2 = (raddr[ADDR_WIDTH:1] + 1) == waddr_next[ADDR_WIDTH:1];
 | |
| 			end
 | |
| 			2'h2: begin
 | |
| 				e1 = raddr_next[ADDR_WIDTH:0] == waddr_next[ADDR_WIDTH:0];
 | |
| 				e2 = raddr[ADDR_WIDTH:0] == waddr_next[ADDR_WIDTH:0];
 | |
| 				o1 = (raddr_next[ADDR_WIDTH:0] + 1) == waddr_next[ADDR_WIDTH:0];
 | |
| 				o2 = (raddr[ADDR_WIDTH:0] + 1) == waddr_next[11:0];
 | |
| 			end
 | |
| 			2'h3: begin
 | |
| 				e1 = 1'b0;
 | |
| 				e2 = 1'b0;
 | |
| 				o1 = 1'b0;
 | |
| 				o2 = 1'b0;
 | |
| 			end
 | |
| 		endcase
 | |
| 	end
 | |
| 	assign empty_next = (ren_in & !empty ? e1 : e2);
 | |
| 	assign epo_next = (ren_in & !empty ? o1 : o2);
 | |
| 	assign pae_next = (ren_in & !empty ? q1 : q2);
 | |
| 	always @(posedge rclk or negedge rst_n)
 | |
| 		if (~rst_n) begin
 | |
| 			empty <= 1'b1;
 | |
| 			pae <= 1'b1;
 | |
| 			epo <= 1'b0;
 | |
| 		end
 | |
| 		else begin
 | |
| 			empty <= empty_next;
 | |
| 			pae <= pae_next;
 | |
| 			epo <= epo_next;
 | |
| 		end
 | |
| 	assign gc8out_next = (raddr_next >> 1) ^ raddr_next;
 | |
| 	assign gc16out_next = (raddr_next >> 2) ^ (raddr_next >> 1);
 | |
| 	assign gc32out_next = (raddr_next >> 3) ^ (raddr_next >> 2);
 | |
| 	always @(*)
 | |
| 		if (ren_in)
 | |
| 			case (gmode)
 | |
| 				2'h2: gcout_next = gc8out_next;
 | |
| 				2'h1: gcout_next = {1'b0, gc16out_next};
 | |
| 				2'h0: gcout_next = {2'b00, gc32out_next};
 | |
| 				default: gcout_next = 'h0;
 | |
| 			endcase
 | |
| 		else
 | |
| 			gcout_next = 'h0;
 | |
| 	always @(posedge rclk or negedge rst_n)
 | |
| 		if (~rst_n)
 | |
| 			waddr <= 12'h000;
 | |
| 		else
 | |
| 			waddr <= waddr_next;
 | |
| 	always @(posedge rclk or negedge rst_n)
 | |
| 		if (~rst_n) begin
 | |
| 			underflow <= 1'b0;
 | |
| 			bwl_sel <= 2'h0;
 | |
| 			gcout_reg <= 12'h000;
 | |
| 		end
 | |
| 		else if (ren_in) begin
 | |
| 			underflow <= empty;
 | |
| 			if (!empty) begin
 | |
| 				bwl_sel <= raddr_next[1:0];
 | |
| 				gcout_reg <= gcout_next;
 | |
| 			end
 | |
| 		end
 | |
| 	generate
 | |
| 		for (i = 0; i < (ADDR_WIDTH + 1); i = i + 1) begin : genblk1
 | |
| 			assign tmp[i] = ^(gcin >> i);
 | |
| 		end
 | |
| 	endgenerate
 | |
| 	always @(*)
 | |
| 		case (gmode)
 | |
| 			2'h0: waddr_next = {tmp[ADDR_WIDTH - 2:0], 2'b00} & {{ADDR_WIDTH - 1 {1'b1}}, 2'b00};
 | |
| 			2'h1: waddr_next = {tmp[ADDR_WIDTH - 1:0], 1'b0} & {{ADDR_WIDTH {1'b1}}, 1'b0};
 | |
| 			2'h2: waddr_next = {tmp[ADDR_WIDTH:0]} & {ADDR_PLUS_ONE {1'b1}};
 | |
| 			default: waddr_next = {ADDR_PLUS_ONE {1'b0}};
 | |
| 		endcase
 | |
| 	assign ff_raddr_next = ff_raddr + (rmode == 2'h0 ? 'h4 : (rmode == 2'h1 ? 'h2 : 'h1));
 | |
| 	assign raddr_next = raddr + (rmode == 2'h0 ? 'h4 : (rmode == 2'h1 ? 'h2 : 'h1));
 | |
| 	always @(posedge rclk or negedge rst_n)
 | |
| 		if (~rst_n)
 | |
| 			ff_raddr <= 1'sb0;
 | |
| 		else if (empty & ~empty_next)
 | |
| 			ff_raddr <= raddr_next[ADDR_WIDTH - 1:0];
 | |
| 		else if ((ren_in & !empty) & ~empty_next)
 | |
| 			ff_raddr <= ff_raddr_next;
 | |
| 	always @(posedge rclk or negedge rst_n)
 | |
| 		if (~rst_n)
 | |
| 			raddr <= 12'h000;
 | |
| 		else if (ren_in & !empty)
 | |
| 			raddr <= raddr_next;
 | |
| 	always @(*)
 | |
| 		case (FIFO_WIDTH)
 | |
| 			3'h2: out_raddr = {ff_raddr[ADDR_WIDTH - 1:1], bwl_sel[0]};
 | |
| 			3'h4: out_raddr = {ff_raddr[ADDR_WIDTH - 1:2], bwl_sel};
 | |
| 			default: out_raddr = ff_raddr[ADDR_WIDTH - 1:0];
 | |
| 		endcase
 | |
| 	assign ren_o = ren_out;
 | |
| 	assign gcout = gcout_reg;
 | |
| 	assign popflags = {empty, epo, pae, underflow};
 | |
| endmodule
 | |
| `default_nettype none
 |