mirror of
https://github.com/marqs85/ossc.git
synced 2024-11-16 15:10:55 +00:00
196 lines
6.4 KiB
Systemverilog
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
|