-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Now featuring: - Data-Flow design - Lots of bugs, as it's not even compiled once
- Loading branch information
Axel Vanoni
committed
Sep 2, 2022
1 parent
fea88cc
commit d84c804
Showing
12 changed files
with
822 additions
and
580 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// Copyright 2022 ETH Zurich and University of Bologna. | ||
// Solderpad Hardware License, Version 0.51, see LICENSE for details. | ||
// SPDX-License-Identifier: SHL-0.51 | ||
|
||
// Axel Vanoni <axvanoni@student.ethz.ch> | ||
|
||
`include "common_cells/assertions.svh" | ||
`include "common_cells/registers.svh" | ||
|
||
/// This module generates AR packets to fetch descriptors from memory | ||
module idma_desc64_ar_gen #( | ||
/// AXI Data width | ||
parameter int unsigned DataWidth = 64, | ||
/// Descriptor type. `$bits(descriptor_t)` must be a power of two | ||
parameter type descriptor_t = logic, | ||
/// AXI AR channel type | ||
parameter type axi_ar_chan_t = logic, | ||
/// AXI AR id type | ||
parameter type axi_ar_id_t = logic, | ||
/// Type that can hold the usage information of the idma_req fifo | ||
parameter type usage_t = logic, | ||
/// AXI Address type | ||
parameter type addr_t = logic | ||
)( | ||
/// Clock | ||
input logic clk_i, | ||
/// Reset | ||
input logic rst_ni, | ||
/// AXI AR channel | ||
output axi_ar_chan_t axi_ar_chan_o, | ||
/// AXI AR valid | ||
output logic axi_ar_chan_valid_o, | ||
/// AXI AR ready | ||
input logic axi_ar_chan_ready_i, | ||
/// AXI ID to use when requesting | ||
input axi_id_t axi_ar_id_i, | ||
/// queued address to use when we reach the last in a chain | ||
input addr_t queued_address_i, | ||
/// queued address valid | ||
input logic queued_address_valid_i, | ||
/// queued address ready | ||
output logic queued_address_ready_o, | ||
/// next address as read from descriptor | ||
input addr_t next_address_from_descriptor_i, | ||
/// next address valid | ||
input addr_t next_address_from_descriptor_valid_i, | ||
/// number of available slots in the idma request fifo | ||
input usage_t idma_req_available_slots_i, | ||
/// address for feedback for the next request | ||
output addr_t feedback_addr_o, | ||
/// feedback address valid | ||
output logic feedback_addr_valid_o, | ||
/// whether the unit is busy | ||
output logic busy_o | ||
); | ||
|
||
`define MIN(a, b) ((a) < (b) ? a : b) | ||
|
||
localparam int unsigned DataWidthBytes = DataWidth / 8; | ||
localparam int unsigned DescriptorSize = $bits(descriptor_t) / 8; | ||
|
||
localparam logic [2:0] AxiSize = `MIN(`MIN($clog2(DataWidthBytes), | ||
$clog2(DescriptorSize)), 3'b111); | ||
localparam logic [7:0] AxiLength = DescriptorSize / DataWidthBytes; | ||
|
||
logic inflight_q, inflight_d; | ||
logic next_addr_from_desc_valid_q, next_addr_from_desc_valid_d; | ||
logic next_addr_from_desc_valid_this_cycle; | ||
logic take_from_queued; | ||
logic may_send_ar; | ||
addr_t next_addr_q, next_addr_d; | ||
addr_t ar_addr; | ||
usage_t space_in_req_fifo; | ||
|
||
assign next_addr_from_desc_valid_d = next_address_from_descriptor_valid_i; | ||
assign next_addr_from_desc_valid_this_cycle = !next_addr_from_desc_valid_q && | ||
next_address_from_descriptor_valid_i; | ||
|
||
assign next_addr_d = next_addr_from_desc_valid_this_cycle ? | ||
next_address_from_descriptor_i : | ||
next_addr_q; | ||
|
||
assign take_from_queued = next_addr_q == '1 || (next_addr_from_desc_valid_this_cycle && | ||
next_address_from_descriptor_valid_i == 1'b1); | ||
|
||
assign ar_addr = take_from_queued ? queued_address_i : | ||
(next_addr_from_desc_valid_this_cycle ? | ||
next_address_from_descriptor_i : next_addr_q); | ||
|
||
assign space_in_req_fifo = idma_req_available_slots_i - next_address_from_descriptor_valid_i; | ||
|
||
assign may_send_ar = space_in_req_fifo > 0 && (!inflight_q || next_addr_from_desc_valid_this_cycle); | ||
|
||
always_comb begin : proc_inflight | ||
inflight_d = inflight_q; | ||
if (axi_ar_chan_ready_i && axi_ar_chan_valid_o) begin | ||
inflight_d = 1'b1; | ||
end else if (next_addr_from_desc_valid_this_cycle) begin | ||
inflight_d = 1'b0; | ||
end | ||
end | ||
|
||
always_comb begin : proc_ready_valid | ||
axi_ar_chan_valid_o = 1'b0; | ||
queued_address_ready_o = 1'b0; | ||
if (may_send_ar) begin | ||
if (take_from_queued) begin | ||
axi_ar_chan_valid_o = queued_address_valid_i; | ||
queued_address_ready_o = axi_ar_chan_ready_i; | ||
end else begin | ||
axi_ar_chan_valid_o = 1'b1; | ||
end | ||
end | ||
end | ||
|
||
always_comb begin : proc_ar | ||
axi_ar_chan_o = '0; | ||
axi_ar_chan_o.id = axi_ar_id_i; | ||
axi_ar_chan_o.addr = ar_addr; | ||
axi_ar_chan_o.len = AxiLength; | ||
axi_ar_chan_o.size = AxiSize; | ||
axi_ar_chan_o.burst = axi_pkg::BURST_INCR; | ||
end | ||
|
||
`FF(inflight_q, inflight_d, 1'b0); | ||
`FF(next_addr_from_desc_valid_q, next_addr_from_desc_valid_d, 1'b0); | ||
`FF(next_addr_q, next_addr_d, '1); | ||
|
||
assign feedback_addr_o = ar_addr; | ||
assign feedback_addr_valid_o = axi_ar_chan_ready_i && axi_ar_chan_valid_o; | ||
assign busy_o = take_from_queued || inflight_q; | ||
|
||
endmodule : idma_desc64_ar_gen |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
// Copyright 2022 ETH Zurich and University of Bologna. | ||
// Solderpad Hardware License, Version 0.51, see LICENSE for details. | ||
// SPDX-License-Identifier: SHL-0.51 | ||
|
||
// Axel Vanoni <axvanoni@student.ethz.ch> | ||
|
||
`include "common_cells/registers.svh" | ||
|
||
/// This module takes in an AXI R-channel, and reads descriptors from it. | ||
/// Note that an using an address width other than 64 bits will need | ||
/// modifications. | ||
module idma_desc64_reader #( | ||
/// Address width of the AXI bus | ||
parameter int unsigned AddrWidth = 64, | ||
/// Data width of the AXI bus | ||
parameter int unsigned DataWidth = 64, | ||
/// iDMA request type | ||
parameter type idma_req_t = logic, | ||
/// AXI R channel type | ||
parameter type axi_r_chan_t = logic, | ||
/// Configuration descriptor type | ||
parameter type descriptor_t = logic, | ||
/// AXI bus address type, derived from the address width | ||
parameter type addr_t = logic [AddrWidth-1:0] | ||
)( | ||
/// clock | ||
input logic clk_i, | ||
/// reset | ||
input logic rst_ni, | ||
/// whether to drop the next descriptor | ||
/// must be asserted before the first r packet arrives | ||
input logic drop_next_i, | ||
/// axi read channel | ||
input axi_r_chan_t r_chan_i, | ||
/// read channel valid | ||
input logic r_chan_valid_i, | ||
/// read channel ready | ||
output logic r_chan_ready_o, | ||
/// idma request | ||
output idma_req_t idma_req_o, | ||
/// idma request valid | ||
output logic idma_req_valid_o, | ||
/// idma request ready | ||
/// NOTE: we assume that if a read was launched, | ||
/// the connected fifo has still space left, i.e. this signal is always | ||
/// 1 if a request is in-flight. If a request is in-flight and there | ||
/// is not enough space in the fifo, we will either stall the bus or | ||
/// drop the request. | ||
input logic idma_req_ready_i, | ||
/// location of the next descriptor address | ||
output addr_t next_descriptor_addr_o, | ||
/// whether next_descriptor_addr is valid | ||
output addr_t next_descriptor_addr_valid_o, | ||
/// whether this descriptor needs an IRQ raised | ||
output logic do_irq_o, | ||
/// whether do_irq_o is valid | ||
output logic do_irq_valid_o | ||
); | ||
|
||
descriptor_t current_descriptor; | ||
logic ungated_req_valid; | ||
logic ungated_next_descriptor_valid; | ||
logic ungated_do_irq_valid; | ||
logic drop_request_q, drop_request_d; | ||
|
||
always_comb begin : drop_logic | ||
drop_request_d = drop_request_q; | ||
if (drop_next_i) begin | ||
drop_request_d = drop_next_i; | ||
end else if (ungated_req_valid) begin | ||
drop_request_d = 1'b0; | ||
end | ||
end | ||
|
||
if (DataWidth == 256) begin : gen_256_data_path | ||
assign current_descriptor = r_chan_i.data; | ||
assign ungated_req_valid = r_chan_valid_i; | ||
assign ungated_next_descriptor_valid = r_chan_valid_i; | ||
assign ungated_do_irq_valid = r_chan_valid_i; | ||
end else if (DataWidth == 128) begin : gen_128_data_path | ||
logic [127:0] first_half_of_descriptor_q, first_half_of_descriptor_d; | ||
logic [127:0] second_half_of_descriptor; | ||
logic irq_addr_valid_q, irq_addr_valid_d; | ||
|
||
assign ungated_req_valid = r_chan_valid_i && r_chan_i.last; | ||
assign ungated_do_irq_valid = irq_addr_valid_q; | ||
assign ungated_next_descriptor_valid = irq_addr_valid_q; | ||
|
||
assign current_descriptor = descriptor_t'{ | ||
first_half_of_descriptor_q, | ||
second_half_of_descriptor | ||
}; | ||
|
||
always_comb begin | ||
first_half_of_descriptor_d = first_half_of_descriptor_q; | ||
if (r_chan_valid_i && r_chan_ready_o && !r_chan_i.last) begin | ||
first_half_of_descriptor_d = r_chan.data; | ||
end | ||
end | ||
|
||
always_comb begin | ||
// the irq and next address fields are valid | ||
// from receiving the first half until the | ||
// second half was received | ||
irq_addr_valid_d = irq_addr_valid_q; | ||
if (r_chan_valid_i && r_chan_ready_o) begin | ||
irq_addr_valid_d = !r_chan_i.last; | ||
end | ||
end | ||
|
||
`FF(first_half_of_descriptor_q, first_half_of_descriptor_d, 128'b0); | ||
`FF(irq_addr_valid_q, irq_addr_valid_d, 1'b0); | ||
end else if (DataWidth == 64) begin : gen_64_data_path | ||
logic [1:0] fetch_counter_q, fetch_counter_d; | ||
logic [63:0][2:0] descriptor_data_q, descriptor_data_d; | ||
logic [63:0] descriptor_data_last; | ||
|
||
assign ungated_req_valid = r_chan_valid_i && r_chan_i.last; | ||
assign ungated_do_irq_valid = fetch_counter_q > 2'b00; | ||
assign ungated_next_descriptor_valid = fetch_counter_q > 2'b01; | ||
assign descriptor_data_last = r_chan_i.data; | ||
|
||
assign current_descriptor = descriptor_t'{ | ||
descriptor_data_q, | ||
descriptor_data_last | ||
}; | ||
|
||
always_comb begin : proc_fetch_data | ||
descriptor_data_d = descriptor_data_q; | ||
fetch_counter_d = fetch_counter_q; | ||
if (r_chan_valid_i && r_chan_ready_o && !r_chan_i.last) begin | ||
descriptor_data_d[fetch_counter_q] = r_chan_i.data; | ||
fetch_counter_d = fetch_counter_q + 2'b01; | ||
end if (r_chan_valid_i && r_chan_i.last) begin | ||
fetch_counter_d = 2'b00; | ||
end | ||
end | ||
|
||
`FF(descriptor_data_q, descriptor_data_d, 192'b0); | ||
`FF(fetch_counter_q, fetch_counter_d, 2'b0); | ||
end else if (DataWidth == 32) begin : gen_32_data_path | ||
logic [2:0] fetch_counter_q, fetch_counter_d; | ||
logic [31:0][6:0] descriptor_data_q, descriptor_data_d; | ||
logic [31:0] descriptor_data_last; | ||
|
||
assign ungated_req_valid = r_chan_valid_i && r_chan_i.last; | ||
assign ungated_do_irq_valid = fetch_counter_q > 3'd1; | ||
assign ungated_next_descriptor_valid = fetch_counter_q > 3'd3; | ||
assign descriptor_data_last = r_chan_i.data; | ||
|
||
assign current_descriptor = descriptor_t'{ | ||
descriptor_data_q, | ||
descriptor_data_last | ||
}; | ||
|
||
always_comb begin : proc_fetch_data | ||
descriptor_data_d = descriptor_data_q; | ||
fetch_counter_d = fetch_counter_q; | ||
if (r_chan_valid_i && r_chan_ready_o && !r_chan_i.last) begin | ||
descriptor_data_d[fetch_counter_q] = r_chan_i.data; | ||
fetch_counter_d = fetch_counter_q + 3'b001; | ||
end if (r_chan_valid_i && r_chan_i.last) begin | ||
fetch_counter_d = 3'b0; | ||
end | ||
end | ||
end | ||
|
||
idma_desc64_reshaper #( | ||
.idma_req_t, | ||
.addr_t, | ||
.descriptor_t | ||
) i_descriptor_reshaper ( | ||
.descriptor_i (current_descriptor), | ||
.idma_req_o, | ||
.next_addr_o (next_descriptor_addr_o), | ||
.do_irq_o | ||
); | ||
|
||
`FF(drop_request_q, drop_request_d, 1'b0); | ||
|
||
// The user should take care that the connected fifo always has | ||
// enough space to put in the new descriptor. If it does not, | ||
// instead of dropping requests, stall the bus (unless we're | ||
// dropping this descriptor). | ||
assign r_chan_ready_o = idma_req_ready_i || drop_request_q; | ||
|
||
assign idma_req_valid = ungated_req_valid && !drop_request_q; | ||
assign next_descriptor_addr_valid_o = ungated_next_descriptor_valid && !drop_request_q; | ||
assign do_irq_valid_o = ungated_do_irq_valid && !drop_request_q; | ||
|
||
endmodule : idma_desc64_reader |
Oops, something went wrong.