blob: f333d1dafab93dff5e30d0554bc76a7030cc646a [file] [log] [blame]
// SPDX-FileCopyrightText: 2022 Piotr Wegrzyn
//
// 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
`include "config.v"
module wb_compressor (
`ifdef USE_POWER_PINS
inout vccd1,
inout vssd1,
`endif
input i_clk,
input i_rst,
input wb_cyc,
input wb_stb,
input [`WB_ADDR_W-1:0] wb_adr,
input [`RW-1:0] wb_o_dat,
output reg [`RW-1:0] wb_i_dat,
input wb_we,
input [1:0] wb_sel,
input wb_8_burst, wb_4_burst,
output reg wb_ack,
output reg wb_err,
output reg [`RW-1:0] cw_io_o,
input [`RW-1:0] cw_io_i,
output reg cw_req,
output reg cw_dir,
input cw_ack,
input cw_err
);
`define SW 4
`define S_IDLE `SW'b0
`define S_HDR_1 `SW'b1
`define S_WACK `SW'b10
`define S_DATA_R `SW'b11
`define S_DATA_W `SW'b101
`define S_DATA_WT `SW'b111
`define S_WC `SW'b100
reg [`SW-1:0] state;
wire [3:0] cyc_type = (wb_8_burst ? 4'b001 : (wb_4_burst ? 4'b010 : 4'b000));
wire [`RW-1:0] header_0 = {wb_adr[`WB_ADDR_W-1:`RW], cyc_type, wb_we, wb_sel, 1'b1};
reg [`WB_ADDR_W-1:0] l_wb_adr;
wire [`WB_ADDR_W-1:0] wb_exp_adr = l_wb_adr + {20'b0, burst_cnt};
reg [`WB_ADDR_W-1:0] ack_exp_adr;
reg l_we;
`define MAX_BRST_LOG 3
reg [`MAX_BRST_LOG-1:0] burst_end, burst_cnt;
wire xfer_ack = ((cw_ack | cw_err) && wb_cyc && wb_stb);
wire ignored_addr = wb_adr < `WB_ADDR_W'h002000;
always @(posedge i_clk) begin
if (i_rst) begin
state <= `S_IDLE;
wb_ack <= 1'b0;
wb_err <= 1'b0;
cw_req <= 1'b0;
cw_dir <= 1'b0;
cw_io_o <= 'b0;
end else begin
case (state)
default: begin
if (wb_cyc & wb_stb & ~ignored_addr) begin
state <= `S_HDR_1;
cw_io_o <= header_0;
cw_dir <= 1'b0;
cw_req <= 1'b1;
l_we <= wb_we;
burst_end <= (wb_8_burst ? 3'd7 : (wb_4_burst ? 3'd3 : 3'b0));
burst_cnt <= `MAX_BRST_LOG'b0;
end
end
`S_HDR_1: begin
state <= `S_WACK;
cw_req <= 1'b0;
cw_io_o <= wb_adr[`RW-1:0];
end
`S_WACK: begin
if (cw_ack)
state <= (l_we ? `S_DATA_W : `S_DATA_R);
cw_io_o <= wb_o_dat;
end
`S_DATA_R: begin
cw_dir <= 1'b1;
cw_io_o <= wb_o_dat;
wb_ack <= 1'b0;
wb_err <= 1'b0;
if (xfer_ack && burst_cnt != burst_end) begin
burst_cnt <= burst_cnt + 1'b1;
wb_ack <= cw_ack; // It is good idea to break combinational path at end of IC
wb_err <= cw_err;
wb_i_dat <= cw_io_i;
ack_exp_adr <= wb_exp_adr;
end else if (xfer_ack && burst_cnt == burst_end) begin
burst_cnt <= `MAX_BRST_LOG'b0;
wb_ack <= cw_ack;
wb_err <= cw_err;
wb_i_dat <= cw_io_i;
state <= `S_WC;
cw_dir <= ~cw_dir;
ack_exp_adr <= wb_exp_adr;
end
end
`S_DATA_W: begin
cw_dir <= 1'b0;
wb_ack <= 1'b0;
wb_err <= 1'b0;
cw_req <= 1'b0;
if (xfer_ack && burst_cnt != burst_end) begin
burst_cnt <= burst_cnt + 1'b1;
wb_ack <= cw_ack;
wb_err <= cw_err;
wb_i_dat <= cw_io_i;
ack_exp_adr <= wb_exp_adr;
state <= `S_DATA_WT;
end else if (xfer_ack && burst_cnt == burst_end) begin
burst_cnt <= `MAX_BRST_LOG'b0;
wb_ack <= cw_ack;
wb_err <= cw_err;
wb_i_dat <= cw_io_i;
state <= `S_WC;
cw_dir <= ~cw_dir;
ack_exp_adr <= wb_exp_adr;
end
end
`S_DATA_WT: begin
cw_req <= 1'b0;
wb_ack <= 1'b0;
wb_err <= 1'b0;
// wait for new data and send sync signal
// continous data delivery with clock sychronizers is not possible, due to ACK delay
// it causes no problem with read burst, beacause wishbone communication is unidirectional then
if (wb_cyc & wb_stb & ~wb_ack) begin // wait for stb reassert when new burst data is delivered
cw_req <= 1'b1;
cw_io_o <= wb_o_dat;
state <= `S_DATA_W;
end
end
`S_WC: begin
cw_dir <= 1'b0;
cw_req <= 1'b0;
wb_ack <= 1'b0;
wb_err <= 1'b0;
state <= `S_IDLE;
end
endcase
end
end
`undef S_DATA_R
`undef S_DATA_W
endmodule