Skip to content

Commit

Permalink
desc64: Rewrite desc64 frontend
Browse files Browse the repository at this point in the history
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 c9714ae
Show file tree
Hide file tree
Showing 11 changed files with 812 additions and 580 deletions.
7 changes: 7 additions & 0 deletions scripts/frontend/run-no-chain.tcl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 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>

# run frontend tests without chaining
source scripts/compile_vsim.tcl
vsim tb_idma_desc64_top -t 1ps \
-GNumberOfTests=20 \
Expand Down
12 changes: 11 additions & 1 deletion scripts/frontend/run-one.tcl
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# 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>

# run frontend tests with one transfer
source scripts/compile_vsim.tcl
vsim tb_idma_desc64_top -t 1ps -GNumberOfTests=1 -GSimulationTimeoutCycles=200 -voptargs=+acc
vsim tb_idma_desc64_top -t 1ps -GNumberOfTests=1 \
-GSimulationTimeoutCycles=200 \
-GMaxChainedDescriptors=1 \
-voptargs=+acc
#-voptargs=-pedantic

set StdArithNoWarnings 1
Expand Down
7 changes: 7 additions & 0 deletions scripts/frontend/run-only-chain.tcl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 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>

# run tests with only chaining
source scripts/compile_vsim.tcl
vsim tb_idma_desc64_top -t 1ps \
-GMaxChainedDescriptors=100 \
Expand Down
7 changes: 7 additions & 0 deletions scripts/frontend/run.tcl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 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>

# run frontend tests with default settings
source scripts/compile_vsim.tcl

vsim tb_idma_desc64_top -t 1ps -voptargs=+acc
Expand Down
133 changes: 133 additions & 0 deletions src/frontends/desc64/idma_desc64_ar_gen.sv
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
191 changes: 191 additions & 0 deletions src/frontends/desc64/idma_desc64_reader.sv
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
Loading

0 comments on commit c9714ae

Please sign in to comment.