ossc/ip/pll_reconfig/pll_reconfig_top.sv

196 lines
6.4 KiB
Systemverilog

//
// Copyright (C) 2019 Markus Hiienkari <mhiienka@niksula.hut.fi>
//
// This file is part of Open Source Scan Converter project.
//
// This program 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.
//
// 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 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 <http://www.gnu.org/licenses/>.
//
module pll_reconfig_top (
// common
input clk_i,
input rst_i,
// avalon slave
input [31:0] avalon_s_writedata,
output [31:0] avalon_s_readdata,
input [2:0] avalon_s_address,
input [3:0] avalon_s_byteenable,
input avalon_s_write,
input avalon_s_read,
input avalon_s_chipselect,
output avalon_s_waitrequest_n,
// reconfig interface
output areset,
output scanclk,
output reg scanclkena,
output reg configupdate,
output scandata,
input scandone
);
localparam PLL_CONFIG_DATA_BITS = 8'd144;
localparam PLL_CONFIG_DATA_REGS = 5;
localparam PLL_CONFIG_STATUS_REGNUM = 3'h0;
localparam PLL_CONFIG_DATA_STARTREG = 3'h1;
localparam STATE_IDLE = 2'h0;
localparam STATE_SHIFT = 2'h1;
localparam STATE_WAITRESP = 2'h2;
reg [31:0] pll_config_status;
reg [31:0] config_data[0:(PLL_CONFIG_DATA_REGS-1)] /* synthesis ramstyle = "logic" */;
reg areset_strobe;
reg [1:0] state;
reg scan_shift;
reg scandone_prev;
reg configupdate_pre;
reg [7:0] shift_ctr;
wire pll_reset = pll_config_status[0];
wire start_update = pll_config_status[1];
wire [3:0] t_config_id = pll_config_status[5:2];
wire [3:0] c_config_id = pll_config_status[30:27];
wire config_busy = pll_config_status[31];
assign areset = pll_reset | areset_strobe;
assign scanclk = clk_i;
assign scandata = config_data[0][16];
assign avalon_s_waitrequest_n = 1'b1;
// Avalon register interface
always @(posedge clk_i or posedge rst_i) begin
if (rst_i) begin
pll_config_status[7:0] <= 8'h0;
end else begin
if (avalon_s_chipselect && avalon_s_write && (avalon_s_address==PLL_CONFIG_STATUS_REGNUM)) begin
/*if (avalon_s_byteenable[3])
pll_config_status[31:24] <= avalon_s_writedata[31:24];
if (avalon_s_byteenable[2])
pll_config_status[23:16] <= avalon_s_writedata[23:16];
if (avalon_s_byteenable[1])
pll_config_status[15:8] <= avalon_s_writedata[15:8];*/
if (avalon_s_byteenable[0])
pll_config_status[7:0] <= avalon_s_writedata[7:0];
end else begin
pll_config_status[1] <= 1'b0; // reset start_update bit
end
end
end
genvar i;
generate
for (i = 0; i < PLL_CONFIG_DATA_REGS; i = i + 1) begin : genreg
always @(posedge clk_i or posedge rst_i) begin
if (rst_i) begin
config_data[i] <= 32'h0;
end else begin
if (!scan_shift) begin
if (avalon_s_chipselect && avalon_s_write && (avalon_s_address==(PLL_CONFIG_DATA_STARTREG+PLL_CONFIG_DATA_REGS-1-i))) begin
if (avalon_s_byteenable[3])
config_data[i][31:24] <= avalon_s_writedata[31:24];
if (avalon_s_byteenable[2])
config_data[i][23:16] <= avalon_s_writedata[23:16];
if (avalon_s_byteenable[1])
config_data[i][15:8] <= avalon_s_writedata[15:8];
if (avalon_s_byteenable[0])
config_data[i][7:0] <= avalon_s_writedata[7:0];
end
end else begin
if (i==(PLL_CONFIG_DATA_REGS-1)) begin
config_data[i] <= {1'b0, config_data[i][31:1]};
end else begin
config_data[i] <= {config_data[i+1][0], config_data[i][31:1]};
end
end
end
end
end
endgenerate
// Main FSM
always @(posedge clk_i or posedge rst_i)
begin
if (rst_i) begin
state <= STATE_IDLE;
scanclkena <= 1'b0;
configupdate_pre <= 1'b0;
configupdate <= 1'b0;
areset_strobe <= 1'b0;
scan_shift <= 1'b0;
scandone_prev <= 1'b0;
pll_config_status[31] <= 1'b0;
end else begin
case (state)
STATE_IDLE:
begin
areset_strobe <= 1'b0;
if (start_update) begin
pll_config_status[31] <= 1'b1;
scanclkena <= 1'b1;
shift_ctr <= PLL_CONFIG_DATA_BITS;
state <= STATE_SHIFT;
end else begin
pll_config_status[31] <= 1'b0;
end
end
STATE_SHIFT:
begin
scan_shift <= 1'b1;
if (shift_ctr > 0) begin
shift_ctr <= shift_ctr - 1'b1;
end else begin
scan_shift <= 1'b0;
scanclkena <= 1'b0;
configupdate_pre <= 1'b1;
state <= STATE_WAITRESP;
end
end
STATE_WAITRESP:
begin
configupdate_pre <= 1'b0;
if (pll_reset) begin
state <= STATE_IDLE;
end else if (scandone_prev) begin
areset_strobe <= 1'b1;
pll_config_status[30:27] <= t_config_id;
state <= STATE_IDLE;
end
end
default:
state <= STATE_IDLE;
endcase
scandone_prev <= scandone;
configupdate <= configupdate_pre;
end
end
always @(*) begin
if (avalon_s_chipselect && avalon_s_read) begin
case (avalon_s_address)
PLL_CONFIG_STATUS_REGNUM: avalon_s_readdata = pll_config_status;
default: avalon_s_readdata = 32'h00000000;
endcase
end else begin
avalon_s_readdata = 32'h00000000;
end
end
endmodule