1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00
corundum/fpga/common/rtl/rb_drp.v

264 lines
7.3 KiB
Coq
Raw Permalink Normal View History

// SPDX-License-Identifier: BSD-2-Clause-Views
2022-02-21 23:20:54 -08:00
/*
* Copyright (c) 2022-2023 The Regents of the University of California
*/
2022-02-21 23:20:54 -08:00
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DRP register block
*/
module rb_drp #
(
parameter DRP_ADDR_WIDTH = 10,
parameter DRP_DATA_WIDTH = 15,
parameter DRP_INFO = 32'd0,
parameter REG_ADDR_WIDTH = 16,
parameter REG_DATA_WIDTH = 32,
parameter REG_STRB_WIDTH = (REG_DATA_WIDTH/8),
parameter RB_TYPE = 32'h0000C150,
parameter RB_BASE_ADDR = 0,
parameter RB_NEXT_PTR = 0
)
(
input wire clk,
input wire rst,
/*
* Register interface
*/
input wire [REG_ADDR_WIDTH-1:0] reg_wr_addr,
input wire [REG_DATA_WIDTH-1:0] reg_wr_data,
input wire [REG_STRB_WIDTH-1:0] reg_wr_strb,
input wire reg_wr_en,
output wire reg_wr_wait,
output wire reg_wr_ack,
input wire [REG_ADDR_WIDTH-1:0] reg_rd_addr,
input wire reg_rd_en,
output wire [REG_DATA_WIDTH-1:0] reg_rd_data,
output wire reg_rd_wait,
output wire reg_rd_ack,
/*
* DRP
*/
input wire drp_clk,
input wire drp_rst,
output wire [DRP_ADDR_WIDTH-1:0] drp_addr,
output wire [DRP_DATA_WIDTH-1:0] drp_di,
output wire drp_en,
output wire drp_we,
input wire [DRP_DATA_WIDTH-1:0] drp_do,
input wire drp_rdy
);
localparam RBB = RB_BASE_ADDR & {REG_ADDR_WIDTH{1'b1}};
// check configuration
initial begin
if (REG_DATA_WIDTH != 32) begin
$error("Error: Register interface width must be 32 (instance %m)");
$finish;
end
if (REG_STRB_WIDTH * 8 != REG_DATA_WIDTH) begin
$error("Error: Register interface requires byte (8-bit) granularity (instance %m)");
$finish;
end
if (REG_ADDR_WIDTH < 7) begin
$error("Error: Register address width too narrow (instance %m)");
$finish;
end
if (RB_NEXT_PTR >= RB_BASE_ADDR && RB_NEXT_PTR < RB_BASE_ADDR + 7'h20) begin
$error("Error: RB_NEXT_PTR overlaps block (instance %m)");
$finish;
end
end
// control registers
reg reg_wr_ack_reg = 1'b0;
reg [REG_DATA_WIDTH-1:0] reg_rd_data_reg = 0;
reg reg_rd_ack_reg = 1'b0;
reg [1:0] rb_state_reg = 2'd0;
reg rb_flag_reg = 1'b0;
(* srl_style = "register" *)
reg rb_flag_sync_reg_1 = 1'b0;
(* srl_style = "register" *)
reg rb_flag_sync_reg_2 = 1'b0;
reg [1:0] drp_state_reg = 2'd0;
reg drp_flag_reg = 1'b0;
(* srl_style = "register" *)
reg drp_flag_sync_reg_1 = 1'b0;
(* srl_style = "register" *)
reg drp_flag_sync_reg_2 = 1'b0;
reg [DRP_ADDR_WIDTH-1:0] rb_ctrl_addr_reg = 0;
reg [DRP_DATA_WIDTH-1:0] rb_ctrl_di_reg = 0;
reg rb_ctrl_we_reg = 1'b0;
reg rb_ctrl_en_reg = 1'b0;
reg [DRP_ADDR_WIDTH-1:0] rb_addr_reg = 0;
reg [DRP_DATA_WIDTH-1:0] rb_di_reg = 0;
reg [DRP_DATA_WIDTH-1:0] rb_do_reg = 0;
reg rb_we_reg = 1'b0;
reg [DRP_ADDR_WIDTH-1:0] drp_addr_reg = 0;
reg [DRP_DATA_WIDTH-1:0] drp_di_reg = 0;
reg [DRP_DATA_WIDTH-1:0] drp_do_reg = 0;
reg drp_en_reg = 1'b0;
reg drp_we_reg = 1'b0;
reg drp_do_valid_reg = 1'b0;
assign reg_wr_wait = 1'b0;
assign reg_wr_ack = reg_wr_ack_reg;
assign reg_rd_data = reg_rd_data_reg;
assign reg_rd_wait = 1'b0;
assign reg_rd_ack = reg_rd_ack_reg;
assign drp_addr = drp_addr_reg;
assign drp_di = drp_di_reg;
assign drp_en = drp_en_reg;
assign drp_we = drp_we_reg;
always @(posedge drp_clk) begin
drp_en_reg <= 1'b0;
drp_we_reg <= 1'b0;
if (drp_rdy) begin
drp_do_reg <= drp_do;
drp_do_valid_reg <= 1'b1;
end
case (drp_state_reg)
2'd0: begin
if (rb_flag_sync_reg_2) begin
drp_state_reg <= 2'd1;
drp_addr_reg <= rb_addr_reg;
drp_di_reg <= rb_di_reg;
drp_en_reg <= 1'b1;
drp_we_reg <= rb_we_reg;
drp_do_valid_reg <= 1'b0;
end
end
2'd1: begin
if (drp_do_valid_reg) begin
drp_state_reg <= 2'd2;
drp_flag_reg <= 1'b1;
end
end
2'd2: begin
if (!rb_flag_sync_reg_2) begin
drp_state_reg <= 2'd0;
drp_flag_reg <= 1'b0;
end
end
endcase
if (drp_rst) begin
drp_state_reg <= 2'd0;
drp_flag_reg <= 1'b0;
drp_en_reg <= 1'b0;
drp_we_reg <= 1'b0;
drp_do_valid_reg <= 1'b0;
end
end
// synchronization
always @(posedge clk) begin
drp_flag_sync_reg_1 <= drp_flag_reg;
drp_flag_sync_reg_2 <= drp_flag_sync_reg_1;
end
always @(posedge drp_clk) begin
rb_flag_sync_reg_1 <= rb_flag_reg;
rb_flag_sync_reg_2 <= rb_flag_sync_reg_1;
end
always @(posedge clk) begin
reg_wr_ack_reg <= 1'b0;
reg_rd_data_reg <= 0;
reg_rd_ack_reg <= 1'b0;
case (rb_state_reg)
2'd0: begin
if (rb_ctrl_en_reg) begin
rb_state_reg <= 2'd1;
rb_flag_reg <= 1'b1;
rb_addr_reg <= rb_ctrl_addr_reg;
rb_di_reg <= rb_ctrl_di_reg;
rb_we_reg <= rb_ctrl_we_reg;
end
end
2'd1: begin
if (drp_flag_sync_reg_2) begin
rb_state_reg <= 2'd2;
rb_flag_reg <= 1'b0;
rb_do_reg <= drp_do_reg;
end
end
2'd2: begin
if (!drp_flag_sync_reg_2) begin
rb_state_reg <= 2'd0;
rb_ctrl_en_reg <= 1'b0;
end
end
endcase
if (reg_wr_en && !reg_wr_ack_reg) begin
// write operation
reg_wr_ack_reg <= 1'b1;
case ({reg_wr_addr >> 2, 2'b00})
RBB+7'h10: begin
// DRP: control
rb_ctrl_en_reg <= reg_wr_data[0];
rb_ctrl_we_reg <= reg_wr_data[1];
end
RBB+7'h14: rb_ctrl_addr_reg <= reg_wr_data; // DRP: address
RBB+7'h18: rb_ctrl_di_reg <= reg_wr_data; // DRP: data in
default: reg_wr_ack_reg <= 1'b0;
endcase
end
if (reg_rd_en && !reg_rd_ack_reg) begin
// read operation
reg_rd_ack_reg <= 1'b1;
case ({reg_rd_addr >> 2, 2'b00})
RBB+7'h00: reg_rd_data_reg <= RB_TYPE; // DRP: Type
RBB+7'h04: reg_rd_data_reg <= 32'h00000100; // DRP: Version
RBB+7'h08: reg_rd_data_reg <= RB_NEXT_PTR; // DRP: Next header
RBB+7'h0C: reg_rd_data_reg <= DRP_INFO; // DRP: info
RBB+7'h10: begin
// DRP: control
reg_rd_data_reg[0] <= rb_ctrl_en_reg;
reg_rd_data_reg[1] <= rb_ctrl_we_reg;
reg_rd_data_reg[8] <= (rb_state_reg != 2'd0);
end
RBB+7'h14: reg_rd_data_reg <= rb_ctrl_addr_reg; // DRP: address
RBB+7'h18: reg_rd_data_reg <= rb_ctrl_di_reg; // DRP: data in
RBB+7'h1C: reg_rd_data_reg <= rb_do_reg; // DRP: data out
default: reg_rd_ack_reg <= 1'b0;
endcase
end
if (rst) begin
reg_wr_ack_reg <= 1'b0;
reg_rd_ack_reg <= 1'b0;
rb_state_reg <= 2'd0;
rb_ctrl_en_reg <= 1'b0;
end
end
endmodule
`resetall