blob: 179d9e7be4d8fd21f212ccc3fb808a5440b3898d [file] [log] [blame]
// Copyright 2023 Google LLC
// Copyright lowRISC contributors
//
// 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.
/**
* DMA Engine
*
* The this module acts as a gasket for Antmicro's fastVDMA, modified to
* support TLUL as a front-end.
*/
module dma
(
input logic clk_i,
input logic rst_ni,
// Reader Interface
output tlul_pkg::tl_h2d_t reader_tl_h_o,
input tlul_pkg::tl_d2h_t reader_tl_h_i,
// Writer Interface
output tlul_pkg::tl_h2d_t writer_tl_h_o,
input tlul_pkg::tl_d2h_t writer_tl_h_i,
// Control Interface
input tlul_pkg::tl_h2d_t tl_d_i,
output tlul_pkg::tl_d2h_t tl_d_o,
// Interrupt Outputs
output logic intr_reader_done_o,
output logic intr_writer_done_o
);
import top_pkg::*;
import tlul_pkg::*;
logic [2:0] dma_control_d_opcode;
logic [2:0] dma_read_a_opcode;
logic [2:0] dma_write_a_opcode;
logic a_ack;
logic wr_req;
logic addr_align_err;
logic meta_data_err;
logic tl_err;
logic error, error_int;
assign a_ack = tl_d_i.a_valid & tl_d_o.a_ready;
assign wr_req = a_ack & ((tl_d_i.a_opcode == PutFullData) | (tl_d_i.a_opcode == PutPartialData));
assign reader_tl_h_o_pre.a_opcode = tlul_pkg::tl_a_op_e'(dma_read_a_opcode);
assign writer_tl_h_o_pre.a_opcode = tlul_pkg::tl_a_op_e'(dma_write_a_opcode);
// Controller integrity checks
logic ctl_intg_err;
tlul_cmd_intg_chk ctl_chk(
.tl_i(tl_d_i),
.err_o(ctl_intg_err)
);
assign error_int = ctl_intg_err || addr_align_err || meta_data_err || tl_err;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
error <= 1'b0;
end else if (a_ack) begin
error <= error_int;
end
end
tlul_pkg::tl_d2h_t tl_d_o_pre;
assign tl_d_o_pre.d_opcode = tlul_pkg::tl_d_op_e'(dma_control_d_opcode);
assign tl_d_o_pre.d_user = '{default: '0};
assign tl_d_o_pre.d_error = error;
tlul_rsp_intg_gen #(
) u_ctl_rsp_intg_gen (
.tl_i(tl_d_o_pre),
.tl_o(tl_d_o)
);
// Reader integrity checks
logic reader_intg_err;
tlul_rsp_intg_chk reader_chk(
.tl_i(reader_tl_h_i),
.err_o(reader_intg_err)
);
tlul_pkg::tl_h2d_t reader_tl_h_o_pre;
tlul_cmd_intg_gen #(
) u_reader_cmd_intg_gen (
.tl_i(reader_tl_h_o_pre),
.tl_o(reader_tl_h_o)
);
// Writer integrity checks
logic writer_intg_err;
tlul_rsp_intg_chk writer_chk(
.tl_i(writer_tl_h_i),
.err_o(writer_intg_err)
);
tlul_pkg::tl_h2d_t writer_tl_h_o_pre;
tlul_cmd_intg_gen #(
) u_writer_cmd_intg_gen (
.tl_i(writer_tl_h_o_pre),
.tl_o(writer_tl_h_o)
);
// Reader will never write any data
assign reader_tl_h_o_pre.a_user = '{
default: '0,
instr_type: prim_mubi_pkg::MuBi4False,
data_intg: prim_secded_pkg::prim_secded_inv_39_32_enc('0)
};
assign writer_tl_h_o_pre.a_user = '{
default: '0,
instr_type: prim_mubi_pkg::MuBi4False,
data_intg: '0
};
DMATop u_fastvdma (
.clock ( clk_i ),
.reset ( ~rst_ni ),
// Control inputs
.io_control_a_opcode ( tl_d_i.a_opcode ),
.io_control_a_param ( tl_d_i.a_param ),
.io_control_a_size ( tl_d_i.a_size ),
.io_control_a_source ( tl_d_i.a_source ),
.io_control_a_address ( tl_d_i.a_address ),
.io_control_a_mask ( tl_d_i.a_mask ),
.io_control_a_data ( tl_d_i.a_data ),
.io_control_a_corrupt ( ),
.io_control_a_valid ( tl_d_i.a_valid ),
.io_control_a_ready ( tl_d_o_pre.a_ready ),
// Control outputs
.io_control_d_opcode ( dma_control_d_opcode ),
.io_control_d_param ( tl_d_o_pre.d_param ),
.io_control_d_size ( tl_d_o_pre.d_size ),
.io_control_d_source ( tl_d_o_pre.d_source ),
.io_control_d_sink ( tl_d_o_pre.d_sink ),
.io_control_d_denied ( ),
.io_control_d_data ( tl_d_o_pre.d_data ),
.io_control_d_corrupt ( ),
.io_control_d_valid ( tl_d_o_pre.d_valid ),
.io_control_d_ready ( tl_d_i.d_ready ),
// Reader outputs
.io_read_a_opcode ( dma_read_a_opcode ),
.io_read_a_param ( reader_tl_h_o_pre.a_param ),
.io_read_a_size ( reader_tl_h_o_pre.a_size ),
.io_read_a_source ( reader_tl_h_o_pre.a_source ),
.io_read_a_address ( reader_tl_h_o_pre.a_address ),
.io_read_a_mask ( reader_tl_h_o_pre.a_mask ),
.io_read_a_data ( reader_tl_h_o_pre.a_data ),
.io_read_a_corrupt ( ),
.io_read_a_valid ( reader_tl_h_o_pre.a_valid ),
.io_read_a_ready ( reader_tl_h_i.a_ready ),
// Reader inputs
.io_read_d_opcode ( reader_tl_h_i.d_opcode ),
.io_read_d_param ( reader_tl_h_i.d_param ),
.io_read_d_size ( reader_tl_h_i.d_size ),
.io_read_d_source ( reader_tl_h_i.d_source ),
.io_read_d_sink ( reader_tl_h_i.d_sink ),
.io_read_d_denied ( ),
.io_read_d_data ( reader_tl_h_i.d_data ),
.io_read_d_corrupt ( ),
.io_read_d_valid ( reader_tl_h_i.d_valid ),
.io_read_d_ready ( reader_tl_h_o_pre.d_ready ),
//// Writer outputs
.io_write_a_opcode ( dma_write_a_opcode ),
.io_write_a_param ( writer_tl_h_o_pre.a_param ),
.io_write_a_size ( writer_tl_h_o_pre.a_size ),
.io_write_a_source ( writer_tl_h_o_pre.a_source ),
.io_write_a_address ( writer_tl_h_o_pre.a_address ),
.io_write_a_mask ( writer_tl_h_o_pre.a_mask ),
.io_write_a_data ( writer_tl_h_o_pre.a_data ),
.io_write_a_corrupt ( ),
.io_write_a_valid ( writer_tl_h_o_pre.a_valid ),
.io_write_a_ready ( writer_tl_h_i.a_ready ),
// Writer inputs
.io_write_d_opcode ( writer_tl_h_i.d_opcode ),
.io_write_d_param ( writer_tl_h_i.d_param ),
.io_write_d_size ( writer_tl_h_i.d_size ),
.io_write_d_source ( writer_tl_h_i.d_source ),
.io_write_d_sink ( writer_tl_h_i.d_sink ),
.io_write_d_denied ( ),
.io_write_d_data ( writer_tl_h_i.d_data ),
.io_write_d_corrupt ( ),
.io_write_d_valid ( writer_tl_h_i.d_valid ),
.io_write_d_ready ( writer_tl_h_o_pre.d_ready ),
// Other signals
.io_irq_readerDone ( intr_reader_done_o ),
.io_irq_writerDone ( intr_writer_done_o ),
.io_sync_readerSync ( 1'b0 ),
.io_sync_writerSync ( 1'b0 )
);
// Explicitly throw controller error for comportability spec
// if writes aren't addr aligned. The DMA IP truncates the
// bottom two bits regardless.
always_comb begin
if (wr_req) begin
addr_align_err = |tl_d_i.a_address[1:0];
end else begin
addr_align_err = 1'b0;
end
end
assign meta_data_err = tl_a_user_chk(tl_d_i.a_user);
tlul_err u_ctrl_err (
.clk_i,
.rst_ni,
.tl_i (tl_d_i),
.err_o (tl_err)
);
endmodule