7
mirror of https://github.com/parallella/parallella-hw.git synced 2024-11-24 11:35:00 +00:00
parallella-hw/archive/fpga/old/hdl/elink-gold/fpgacfg.v
Andreas Olofsson 046706db8a Reorg
2016-02-03 00:43:14 -05:00

638 lines
21 KiB
Verilog

/*
File: fpgacfg.v
This file is part of the Parallella FPGA Reference Design.
Copyright (C) 2013 Adapteva, Inc.
Contributed by Roman Trogan <support@adapteva.com>
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 (see the file COPYING). If not, see
<http://www.gnu.org/licenses/>.
*/
//#######################################################
//# The following fpga config registers are supported:
//# - SYS_CONFIG `REG_SYSCFG (system configuration)
//# - CHIP_RESET `REG_RESET (reset to the chip/fpga)
//# - VERSION `REG_VERSION (firmware version)
//# - FILTER_L `REG_FILTERL (filter range low)
//# - FILTER_H `REG_FILTERH (filter range high)
//# - FILTER_C `REG_FILTERC (filter capture)
//# - TIMEOUT `REG_TIMEOUT (read timeout)
//########################################################
`include "fpga_constants.v"
module fpgacfg (/*AUTOARG*/
// Outputs
reset_chip, reset_fpga, elink_access_out, elink_write_out,
elink_datamode_out, elink_ctrlmode_out, elink_dstaddr_out,
elink_srcaddr_out, elink_data_out, elink_wr_wait_out,
elink_rd_wait_out, elink_disable, elink_cclk_enb, elink_clk_div,
axi_access_out, axi_write_out, axi_datamode_out, axi_ctrlmode_out,
axi_dstaddr_out, axi_srcaddr_out, axi_data_out, axi_wr_wait_out,
axi_rd_wait_out,
// Inputs
eclk, aclk, reset, elink_access_in, elink_write_in,
elink_datamode_in, elink_ctrlmode_in, elink_dstaddr_in,
elink_srcaddr_in, elink_data_in, elink_wr_wait_in,
elink_rd_wait_in, axi_access_in, axi_write_in, axi_datamode_in,
axi_ctrlmode_in, axi_dstaddr_in, axi_srcaddr_in, axi_data_in,
axi_wr_wait_in, axi_rd_wait_in
);
//#########
//# Inputs
//#########
input eclk;
input aclk;
input reset;
//##############################
//# From elink
//##############################
input elink_access_in;
input elink_write_in;
input [1:0] elink_datamode_in;
input [3:0] elink_ctrlmode_in;
input [31:0] elink_dstaddr_in;
input [31:0] elink_srcaddr_in;
input [31:0] elink_data_in;
input elink_wr_wait_in;
input elink_rd_wait_in;
//##############################
//# From axi
//##############################
input axi_access_in;
input axi_write_in;
input [1:0] axi_datamode_in;
input [3:0] axi_ctrlmode_in;
input [31:0] axi_dstaddr_in;
input [31:0] axi_srcaddr_in;
input [31:0] axi_data_in;
input axi_wr_wait_in;
input axi_rd_wait_in;
//##########
//# Outputs
//##########
output reset_chip;
output reset_fpga;
//##############################
//# To elink
//##############################
output elink_access_out;
output elink_write_out;
output [1:0] elink_datamode_out;
output [3:0] elink_ctrlmode_out;
output [31:0] elink_dstaddr_out;
output [31:0] elink_srcaddr_out;
output [31:0] elink_data_out;
output elink_wr_wait_out;
output elink_rd_wait_out;
// controls
output elink_disable;
output elink_cclk_enb;
output [1:0] elink_clk_div;
//##############################
//# To axi
//##############################
output axi_access_out;
output axi_write_out;
output [1:0] axi_datamode_out;
output [3:0] axi_ctrlmode_out;
output [31:0] axi_dstaddr_out;
output [31:0] axi_srcaddr_out;
output [31:0] axi_data_out;
output axi_wr_wait_out;
output axi_rd_wait_out;
/*AUTOINPUT*/
/*AUTOWIRE*/
//#########
//# Regs
//#########
reg [31:0] syscfg_reg;
wire [31:0] version_reg = `VERSION_VALUE;
reg [31:0] filterl_reg;
reg [31:0] filterh_reg;
reg [31:0] filterc_reg;
reg [31:0] timeout_reg;
reg wb_access_reg;
reg [1:0] wb_datamode_reg;
reg [3:0] wb_ctrlmode_reg;
reg [31:0] wb_dstaddr_reg;
reg [31:0] wb_data_reg;
reg [6:0] rd_tran_cnt;
reg [31:0] timeout_cnt;
reg [31:0] to_dstaddr_reg;
reg [11:0] to_data_reg;
reg second_wb_from_one_or_two;
//#########
//# Wires
//#########
wire fpgacfg_addr_match;
wire fpgacfg_access;
wire fpgacfg_write_access;
wire fpgacfg_read_access;
wire reset_reg_access;
wire reset_reg_write;
wire reset_reg_write_sync;
wire version_reg_access;
wire version_reg_read;
wire [31:0] wb_data;
wire syscfg_reg_access;
wire syscfg_reg_write;
wire syscfg_reg_read;
wire filterl_reg_access;
wire filterl_reg_write;
wire filterl_reg_read;
wire filterh_reg_access;
wire filterh_reg_write;
wire filterh_reg_read;
wire filterc_reg_access;
wire filterc_reg_write;
wire filterc_reg_read;
wire timeout_reg_access;
wire timeout_reg_write;
wire timeout_reg_read;
wire [30:0] orange_low_diff;
wire [30:0] orange_high_diff;
wire orange_inc;
wire orange_exc;
wire otran_en;
wire wb_axi_slave;
wire otran_to_axi_slave;
wire [1:0] filterc_reg_status;
wire filterc_reg_capture;
wire [3:0] sys_ctrlmode;
wire [1:0] sys_filtere;
wire sys_timeoute;
wire rd_tran_start;
wire rd_tran_end;
wire rd_tran_inc;
wire rd_tran_dec;
wire rd_tran_upd;
wire [6:0] rd_tran_cnt_inc;
wire [6:0] rd_tran_cnt_dec;
wire [6:0] rd_tran_cnt_next;
wire rd_tran_active;
wire [31:0] timeout_cnt_dec;
wire timeout_cnt_upd;
wire to_access;
wire [31:0] to_dstaddr;
wire [31:0] to_data;
wire read_row_one_or_two;
wire wb_from_one_or_two;
wire write_row2;
wire sys_dwb_prev_dis;
wire sys_tran_modif_row2;
wire [3:0] sys_ctrlmode_row2;
wire [11:0] sys_srcaddr_row2;
`ifdef TARGET_E64
assign sys_dwb_prev_dis = syscfg_reg[27];
assign sys_tran_modif_row2 = syscfg_reg[26];
assign sys_ctrlmode_row2[3:0] = syscfg_reg[23:20];
assign sys_srcaddr_row2[11:0] = syscfg_reg[19:8];
`elsif TARGET_E16
assign sys_dwb_prev_dis = 1'b1;
assign sys_tran_modif_row2 = 1'b0;
assign sys_ctrlmode_row2[3:0] = 4'b0000;
assign sys_srcaddr_row2[11:0] = 12'd0;
`endif
//##########################################
//# Configuration registers write detection
//##########################################
assign fpgacfg_addr_match =
(axi_dstaddr_in[31:8] == {`CHIP_CORE0_ID,`MM_MMR, 4'b0000,`MM_FPGA});
assign fpgacfg_access = axi_access_in & fpgacfg_addr_match;
assign fpgacfg_write_access = fpgacfg_access & axi_write_in;
assign fpgacfg_read_access = fpgacfg_access & ~axi_write_in;
//########################################################################
//# System Configuration Register
//# ----------------------------------------------------------------------
//# bits meaning
//# ----------------------------------------------------------------------
//# [31:28] "Control Mode"
//# [27:6] Reserved:
//# [27] - disable "double read" prevention logic
//# [26] - enable tran modification for row 2
//# [23:20] - control mode for write tran to row 2
//# [19:8] - src address for write tran to row 2
//# [5:4] "Epiphany Clock Divider"
//# 00 - No division, full speed
//# 01 - Divide by 2
//# 10 - Divide by 4
//# 11 - Divide by 8
//# [3] "Elink Disable"
//# 0 - Normal operation
//# 1 - Disable TX drivers (except lclk & frame)
//# CCLK continues to run, LCLK is held low
//# [2:1] "Filter Enable"
//# 00 - filter disable
//# 01 - inclusive range (enable transactions
//# within the range)
//# 10 - exclusive range (enable transactions outside
//# the range)
//# 11 - reserved
//#
//# [0] "Time Out Enable"
//# 1 - enable
//# 0 - disable
//########################################################################
assign syscfg_reg_access = fpgacfg_access &
(axi_dstaddr_in[7:2] == `REG_SYSCFG);
assign syscfg_reg_write = syscfg_reg_access & axi_write_in;
assign syscfg_reg_read = syscfg_reg_access & ~axi_write_in;
always @ (posedge eclk or posedge reset)
if(reset)
syscfg_reg[31:0] <= 32'd0;
else if(syscfg_reg_write)
syscfg_reg[31:0] <= axi_data_in[31:0];
assign sys_ctrlmode[3:0] = syscfg_reg[31:28];
assign elink_clk_div[1:0] = syscfg_reg[5:4];
assign elink_disable = syscfg_reg[3];
assign sys_filtere[1:0] = syscfg_reg[2:1];
assign sys_timeoute = syscfg_reg[0];
//###########################
//# Reset Register
//###########################
assign reset_reg_access = fpgacfg_access &
(axi_dstaddr_in[7:2] == `REG_RESET);
assign reset_reg_write = reset_reg_access & axi_write_in & ~axi_wr_wait_out;
pulse2pulse pulse2pulse (.out (reset_reg_write_sync),
.outclk (aclk),
.in (reset_reg_write),
.inclk (eclk),
.reset (1'b0));
reg [6:0] reset_counter;
reg reset_go;
reg reset_reg;
reg elink_cclk_enb;
always @ (posedge aclk) begin
if(reset_reg_write_sync) begin
reset_go <= 1'b1;
reset_counter <= 7'd0;
end else if(reset_go) begin
reset_counter <= reset_counter + 7'd1;
if(reset_counter[6:5] == 2'b11)
reset_go <= 1'b0;
end
if(reset_go) begin
case(reset_counter[6:5])
2'b00: begin // assert reset, keep clock going
reset_reg <= 1'b1;
elink_cclk_enb <= 1'b1;
end
2'b01: begin // keep asserting reset, stop clock
reset_reg <= 1'b1;
elink_cclk_enb <= 1'b0;
end
2'b10: begin // de-assert reset, clock still stopped
reset_reg <= 1'b0;
elink_cclk_enb <= 1'b0;
end
default: begin // restart clock, done
reset_reg <= 1'b0;
elink_cclk_enb <= 1'b1;
end
endcase
end else begin // normal operation
reset_reg <= 1'b0;
elink_cclk_enb <= 1'b1; //~elink_disable;
end
end // always @ (posedge aclk)
// reset chip & fpga at the same time
assign reset_chip = reset_reg;
assign reset_fpga = reset_reg;
//#############################
//# Version Control Register
//#############################
assign version_reg_access = fpgacfg_access &
(axi_dstaddr_in[7:2] == `REG_VERSION);
assign version_reg_read = version_reg_access & ~axi_write_in;
//###################################################################
//# Filter Low Register
//# -----------------------------------------------------------------
//# bits meaning
//# [31:2] low address of the filter range
//# [1:0] don't care
//#####################################################################
assign filterl_reg_access = fpgacfg_access &
(axi_dstaddr_in[7:2] == `REG_FILTERL);
assign filterl_reg_write = filterl_reg_access & axi_write_in;
assign filterl_reg_read = filterl_reg_access & ~axi_write_in;
always @ (posedge eclk or posedge reset)
if(reset)
filterl_reg[31:0] <= {(32){1'b0}};
else if(filterl_reg_write)
filterl_reg[31:0] <= axi_data_in[31:0];
//###################################################################
//# Filter High Register
//# -----------------------------------------------------------------
//# bits meaning
//# [31:2] high address of the filter range
//# [1:0] don't care
//#####################################################################
assign filterh_reg_access = fpgacfg_access &
(axi_dstaddr_in[7:2] == `REG_FILTERH);
assign filterh_reg_write = filterh_reg_access & axi_write_in;
assign filterh_reg_read = filterh_reg_access & ~axi_write_in;
always @ (posedge eclk or posedge reset)
if(reset)
filterh_reg[31:0] <= {(32){1'b0}};
else if(filterh_reg_write)
filterh_reg[31:0] <= axi_data_in[31:0];
//###################################################################
//# Filter Capture Register
//# -----------------------------------------------------------------
//# bits meaning
//# [31:2] captured address of the filter-out violating transaction
//# [1:0] status
//# 00 - not a valid value
//# 01 - first violating transaction
//# 10 - second violating transaction
//# 11 - there are more than 3 violating transactions
//#
//# * Every write to this register clears its value
//#
//#####################################################################
assign filterc_reg_access = fpgacfg_access &
(axi_dstaddr_in[7:2] == `REG_FILTERC);
assign filterc_reg_write = filterc_reg_access & axi_write_in;
assign filterc_reg_read = filterc_reg_access & ~axi_write_in;
always @ (posedge eclk or posedge reset)
if(reset)
filterc_reg[31:0] <= {(32){1'b0}};
else if(filterc_reg_write)
filterc_reg[31:0] <= {(32){1'b0}};
else if(filterc_reg_capture)
filterc_reg[31:0] <= {elink_dstaddr_in[31:2],filterc_reg_status[1:0]};
assign filterc_reg_status[1:0] = (filterc_reg[1:0] == 2'b11) ? 2'b11 :
filterc_reg[1:0] + 2'b01;
assign filterc_reg_capture = elink_access_in & ~otran_en;
//###################################################################
//# Read Timeout Register
//#####################################################################
assign timeout_reg_access = fpgacfg_access &
(axi_dstaddr_in[7:2] == `REG_TIMEOUT);
assign timeout_reg_write = timeout_reg_access & axi_write_in;
assign timeout_reg_read = timeout_reg_access & ~axi_write_in;
always @ (posedge eclk or posedge reset)
if(reset)
timeout_reg[31:0] <= `TIMEOUT_DEFAULT;
else if(timeout_reg_write)
timeout_reg[31:0] <= axi_data_in[31:0];
//###############################
//# FpgaCfg Read Transactions
//###############################
assign wb_data[31:0] = syscfg_reg_read ? syscfg_reg[31:0] :
version_reg_read ? version_reg[31:0] :
filterl_reg_read ? filterl_reg[31:0] :
filterh_reg_read ? filterh_reg[31:0] :
filterc_reg_read ? filterc_reg[31:0] :
timeout_reg_read ? timeout_reg[31:0] :
{(32){1'b0}};
always @ (posedge eclk or posedge reset)
if(reset)
wb_access_reg <= 1'b0;
else
wb_access_reg <= fpgacfg_read_access | (wb_access_reg & axi_wr_wait_in);
always @ (posedge eclk)
if(fpgacfg_read_access & ~wb_access_reg)
begin
wb_datamode_reg[1:0] <= axi_datamode_in[1:0];
wb_ctrlmode_reg[3:0] <= axi_ctrlmode_in[3:0];
wb_dstaddr_reg[31:0] <= axi_srcaddr_in[31:0];
wb_data_reg[31:0] <= wb_data[31:0];
end
//###########################
//# Time Out Logic
//###########################
assign rd_tran_start = elink_access_out & ~elink_write_out;
assign rd_tran_end = ~(wb_access_reg | axi_wr_wait_in) &
(elink_access_in & otran_to_axi_slave | to_access);
assign rd_tran_inc = rd_tran_start & ~(&(rd_tran_cnt[6:0]));
assign rd_tran_dec = rd_tran_end & (|(rd_tran_cnt[6:0]));
assign rd_tran_upd = rd_tran_inc ^ rd_tran_dec;
assign rd_tran_cnt_inc[6:0] = rd_tran_cnt[6:0] + {{(6){1'b0}},1'b1};
assign rd_tran_cnt_dec[6:0] = rd_tran_cnt[6:0] - {{(6){1'b0}},1'b1};
assign rd_tran_cnt_next[6:0] = rd_tran_inc ? rd_tran_cnt_inc[6:0] :
rd_tran_cnt_dec[6:0];
always @ (posedge eclk or posedge reset)
if(reset)
rd_tran_cnt[6:0] <= {(7){1'b0}};
else if(rd_tran_upd)
rd_tran_cnt[6:0] <= rd_tran_cnt_next[6:0];
assign rd_tran_active = |(rd_tran_cnt[6:0]);
always @ (posedge eclk or posedge reset)
if(reset)
timeout_cnt[31:0] <= {(32){1'b1}};
else if(rd_tran_start | rd_tran_end)
timeout_cnt[31:0] <= timeout_reg[31:0];
else if(timeout_cnt_upd)
timeout_cnt[31:0] <= timeout_cnt_dec[31:0];
assign timeout_cnt_upd = sys_timeoute & rd_tran_active &
|(timeout_cnt[31:0]);
assign timeout_cnt_dec[31:0] = timeout_cnt[31:0] - {{(31){1'b0}},1'b1};
//# Timeout Response Transaction
always @ (posedge eclk)
if(rd_tran_start)
begin
to_dstaddr_reg[31:0] <= elink_srcaddr_out[31:0];
to_data_reg[11:0] <= elink_dstaddr_out[31:20];
end
assign to_dstaddr[31:0] = to_dstaddr_reg[31:0];
assign to_data[31:0] = {to_data_reg[11:0],20'h0dead};
assign to_access = sys_timeoute & ~(|(timeout_cnt[31:0]));
//###########################
//# Filter Range Check
//###########################
//# from the chip (output)
assign orange_low_diff[30:0] = {1'b0,elink_dstaddr_in[31:2]} -
{1'b0,filterl_reg[31:2]};
assign orange_high_diff[30:0] = {1'b0,elink_dstaddr_in[31:2]} -
{1'b0,filterh_reg[31:2]};
assign orange_inc = ~orange_low_diff[30] & orange_high_diff[30];
assign orange_exc = orange_low_diff[30] | ~orange_high_diff[30];
assign otran_en = otran_to_axi_slave | ~wb_axi_slave &
(orange_inc & (sys_filtere[1:0] == 2'b01) |
orange_exc & (sys_filtere[1:0] == 2'b10) |
(sys_filtere[1:0] == 2'b00));
//# write back transaction to AXI Slave port is always enabled
assign wb_axi_slave = elink_write_in &
(elink_dstaddr_in[31:20] == `AXI_COORD);
assign otran_to_axi_slave = wb_axi_slave & wb_axi_slave_en;
//###########################
//# Transactions to ELink
//###########################
assign elink_access_out = axi_access_in & ~fpgacfg_addr_match;
assign elink_write_out = axi_write_in;
assign elink_datamode_out[1:0] = axi_datamode_in[1:0];
assign elink_dstaddr_out[31:0] = axi_dstaddr_in[31:0];
assign elink_data_out[31:0] = axi_data_in[31:0];
assign elink_ctrlmode_out[3:0] = axi_ctrlmode_in[3:0] | sys_ctrlmode[3:0] |
{(4){write_row2}} & sys_ctrlmode_row2[3:0];
assign elink_srcaddr_out[31:0] = write_row2 ?
{sys_srcaddr_row2[11:0],axi_srcaddr_in[19:0]} :
axi_srcaddr_in[31:0];
assign elink_wr_wait_out = axi_wr_wait_in | wb_access_reg;
assign elink_rd_wait_out = axi_rd_wait_in | wb_access_reg;
assign write_row2 = axi_write_in & sys_tran_modif_row2 &
~(axi_datamode_in[1:0] == 2'b11) &
(axi_dstaddr_in[28:26] == 3'b010);
//############################
//# Transactions to AXI
//############################
assign axi_access_out = wb_access_reg |
to_access |
elink_access_in & otran_en;
assign axi_write_out = wb_access_reg |
to_access |
elink_write_in;
assign axi_srcaddr_out[31:0] = elink_srcaddr_in[31:0];
assign axi_datamode_out[1:0] = wb_access_reg ? wb_datamode_reg[1:0] :
elink_datamode_in[1:0];
assign axi_ctrlmode_out[3:0] = wb_access_reg ? wb_ctrlmode_reg[3:0] :
elink_ctrlmode_in[3:0];
assign axi_dstaddr_out[31:0] = wb_access_reg ? wb_dstaddr_reg[31:0] :
to_access ? to_dstaddr[31:0] :
elink_dstaddr_in[31:0];
assign axi_data_out[31:0] = wb_access_reg ? wb_data_reg[31:0] :
to_access ? to_data[31:0] :
elink_data_in[31:0];
assign axi_wr_wait_out = elink_wr_wait_in & ~fpgacfg_write_access;
assign axi_rd_wait_out = elink_rd_wait_in & ~fpgacfg_read_access;
//#####################################
//# Workaround for a double write back
//# data coming from row 1 and row 2
//# of the chip
//#####################################
assign read_row_one_or_two = (to_data_reg[8:6] == 3'b001) |
(to_data_reg[8:6] == 3'b010);
assign wb_from_one_or_two = read_row_one_or_two &
elink_access_in & wb_axi_slave &
~elink_wr_wait_out;
always @ (posedge eclk or posedge reset)
if(reset)
second_wb_from_one_or_two <= 1'b0;
else if(wb_from_one_or_two)
second_wb_from_one_or_two <= ~second_wb_from_one_or_two;
assign wb_axi_slave_en = ~read_row_one_or_two | second_wb_from_one_or_two |
sys_dwb_prev_dis;
endmodule // fpgacfg