415 lines
13 KiB
Verilog
415 lines
13 KiB
Verilog
// (C) 2001-2019 Intel Corporation. All rights reserved.
|
|
// Your use of Intel Corporation's design tools, logic functions and other
|
|
// software and tools, and its AMPP partner logic functions, and any output
|
|
// files from any of the foregoing (including device programming or simulation
|
|
// files), and any associated documentation or information are expressly subject
|
|
// to the terms and conditions of the Intel Program License Subscription
|
|
// Agreement, Intel FPGA IP License Agreement, or other applicable
|
|
// license agreement, including, without limitation, that your use is for the
|
|
// sole purpose of programming logic devices manufactured by Intel and sold by
|
|
// Intel or its authorized distributors. Please refer to the applicable
|
|
// agreement for further details.
|
|
|
|
|
|
/*
|
|
This block is used to communicate information back and forth between the SGDMA
|
|
and the host. When the response port is not set to streaming then this block
|
|
will be used to generate interrupts for the host. The address span of this block
|
|
differs depending on whether the enhanced features are enabled. The enhanced
|
|
features enables sequence number readback capabilties. The address map is as follows:
|
|
|
|
Enhanced features off:
|
|
|
|
Bytes Access Type Description
|
|
----- ----------- -----------
|
|
0-3 R Status(1)
|
|
4-7 R/W Control(2)
|
|
8-12 R Descriptor Watermark (write watermark[15:0],read watermark [15:0])
|
|
13-15 R Response Watermark
|
|
16-31 N/A <Reserved>
|
|
|
|
|
|
Enhanced features on:
|
|
|
|
Bytes Access Type Description
|
|
----- ----------- -----------
|
|
0-3 R Status(1)
|
|
4-7 R/W Control(2)
|
|
8-12 R Descriptor Watermark (write watermark[15:0],read watermark [15:0])
|
|
13-15 R Response Watermark
|
|
16-20 R Sequence Number (write sequence[15:0],read sequence[15:0])
|
|
21-31 N/A <Reserved>
|
|
|
|
(1) Writing to the interrupt bit of the status register clears the interrupt bit (when applicable)
|
|
(2) Writing to the software reset bit will clear the entire register (as well as all the registers for the entire SGDMA)
|
|
|
|
Status Register:
|
|
|
|
Bits Description
|
|
---- -----------
|
|
0 Busy
|
|
1 Descriptor Buffer Empty
|
|
2 Descriptor Buffer Full
|
|
3 Response Buffer Empty
|
|
4 Response Buffer Full
|
|
5 Stop State
|
|
6 Reset State
|
|
7 Stopped on Error
|
|
8 Stopped on Early Termination
|
|
9 IRQ
|
|
10-31 <Reserved>
|
|
|
|
Control Register:
|
|
|
|
Bits Description
|
|
---- -----------
|
|
0 Stop (will also be set if a stop on error/early termination condition occurs)
|
|
1 Software Reset
|
|
2 Stop on Error
|
|
3 Stop on Early Termination
|
|
4 Global Interrupt Enable Mask
|
|
5 Stop descriptors (stops the dispatcher from issuing more read/write commands)
|
|
6-31 <Reserved>
|
|
|
|
|
|
Author: JCJB
|
|
Date: 08/18/2010
|
|
|
|
1.0 - Initial release
|
|
|
|
1.1 - Removed delayed reset, added set and hold sw_reset
|
|
|
|
1.2 - Updated the sw_reset register to be set when control[1] is set instead of one cycle after.
|
|
This will prevent the read or write masters from starting back up when reset while in the stop state.
|
|
|
|
1.3 - Added the stop dispatcher bit (5) to the control register
|
|
*/
|
|
|
|
|
|
// synthesis translate_off
|
|
`timescale 1ns / 1ps
|
|
// synthesis translate_on
|
|
|
|
// turn off superfluous verilog processor warnings
|
|
// altera message_level Level1
|
|
// altera message_off 10034 10035 10036 10037 10230 10240 10030
|
|
|
|
|
|
|
|
module csr_block (
|
|
clk,
|
|
reset,
|
|
|
|
csr_writedata,
|
|
csr_write,
|
|
csr_byteenable,
|
|
csr_readdata,
|
|
csr_read,
|
|
csr_address,
|
|
csr_irq,
|
|
|
|
done_strobe,
|
|
busy,
|
|
descriptor_buffer_empty,
|
|
descriptor_buffer_full,
|
|
stop_state,
|
|
stopped_on_error,
|
|
stopped_on_early_termination,
|
|
reset_stalled,
|
|
stop,
|
|
sw_reset,
|
|
stop_on_error,
|
|
stop_on_early_termination,
|
|
stop_descriptors,
|
|
sequence_number,
|
|
descriptor_watermark,
|
|
response_watermark,
|
|
response_buffer_empty,
|
|
response_buffer_full,
|
|
transfer_complete_IRQ_mask,
|
|
error_IRQ_mask,
|
|
early_termination_IRQ_mask,
|
|
error,
|
|
early_termination
|
|
);
|
|
|
|
parameter ADDRESS_WIDTH = 3;
|
|
localparam CONTROL_REGISTER_ADDRESS = 3'b001;
|
|
|
|
|
|
input clk;
|
|
input reset;
|
|
|
|
input [31:0] csr_writedata;
|
|
input csr_write;
|
|
input [3:0] csr_byteenable;
|
|
output wire [31:0] csr_readdata;
|
|
input csr_read;
|
|
input [ADDRESS_WIDTH-1:0] csr_address;
|
|
output wire csr_irq;
|
|
|
|
input done_strobe;
|
|
input busy;
|
|
input descriptor_buffer_empty;
|
|
input descriptor_buffer_full;
|
|
input stop_state; // when the DMA runs into some error condition and you have enabled the stop on error (or when the stop control bit is written to)
|
|
input reset_stalled; // the read or write master could be in the middle of a transfer/burst so it might take a while to flush the buffers
|
|
output wire stop;
|
|
output reg stopped_on_error;
|
|
output reg stopped_on_early_termination;
|
|
output reg sw_reset;
|
|
output wire stop_on_error;
|
|
output wire stop_on_early_termination;
|
|
output wire stop_descriptors;
|
|
input [31:0] sequence_number;
|
|
input [31:0] descriptor_watermark;
|
|
input [15:0] response_watermark;
|
|
input response_buffer_empty;
|
|
input response_buffer_full;
|
|
input transfer_complete_IRQ_mask;
|
|
input [7:0] error_IRQ_mask;
|
|
input early_termination_IRQ_mask;
|
|
input [7:0] error;
|
|
input early_termination;
|
|
|
|
/* Internal wires and registers */
|
|
wire [31:0] status;
|
|
reg [31:0] control;
|
|
reg [31:0] readdata;
|
|
reg [31:0] readdata_d1;
|
|
reg irq; // writing to the status register clears the irq bit
|
|
wire set_irq;
|
|
wire clear_irq;
|
|
wire set_stopped_on_error;
|
|
wire set_stopped_on_early_termination;
|
|
wire set_stop;
|
|
wire clear_stop;
|
|
wire global_interrupt_enable;
|
|
wire sw_reset_strobe; // this strobe will be one cycle earlier than sw_reset
|
|
wire set_sw_reset;
|
|
wire clear_sw_reset;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/********************************************** Registers ***************************************************/
|
|
// read latency is 1 cycle
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
readdata_d1 <= 0;
|
|
end
|
|
else if (csr_read == 1)
|
|
begin
|
|
readdata_d1 <= readdata;
|
|
end
|
|
end
|
|
|
|
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
control[31:1] <= 0;
|
|
end
|
|
else
|
|
begin
|
|
if (sw_reset_strobe == 1) // reset strobe is a strobe due to this sync reset
|
|
begin
|
|
control[31:1] <= 0;
|
|
end
|
|
else
|
|
begin
|
|
if ((csr_address == CONTROL_REGISTER_ADDRESS) & (csr_write == 1) & (csr_byteenable[0] == 1))
|
|
begin
|
|
control[7:1] <= csr_writedata[7:1]; // stop bit will be handled seperately since it can be set by the csr slave port access or the SGDMA hitting an error condition
|
|
end
|
|
if ((csr_address == CONTROL_REGISTER_ADDRESS) & (csr_write == 1) & (csr_byteenable[1] == 1))
|
|
begin
|
|
control[15:8] <= csr_writedata[15:8];
|
|
end
|
|
if ((csr_address == CONTROL_REGISTER_ADDRESS) & (csr_write == 1) & (csr_byteenable[2] == 1))
|
|
begin
|
|
control[23:16] <= csr_writedata[23:16];
|
|
end
|
|
if ((csr_address == CONTROL_REGISTER_ADDRESS) & (csr_write == 1) & (csr_byteenable[3] == 1))
|
|
begin
|
|
control[31:24] <= csr_writedata[31:24];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
// control bit 0 (stop) is set by different sources so handling it seperately
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
control[0] <= 0;
|
|
end
|
|
else
|
|
begin
|
|
if (sw_reset_strobe == 1)
|
|
begin
|
|
control[0] <= 0;
|
|
end
|
|
else
|
|
begin
|
|
case ({set_stop, clear_stop})
|
|
2'b00: control[0] <= control[0];
|
|
2'b01: control[0] <= 1'b0;
|
|
2'b10: control[0] <= 1'b1;
|
|
2'b11: control[0] <= 1'b1; // setting will win, this case happens control[0] is being set to 0 (resume) at the same time an error/early termination stop condition occurs
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
sw_reset <= 0;
|
|
end
|
|
else
|
|
begin
|
|
if (set_sw_reset == 1)
|
|
begin
|
|
sw_reset <= 1;
|
|
end
|
|
else if (clear_sw_reset == 1)
|
|
begin
|
|
sw_reset <= 0;
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
stopped_on_error <= 0;
|
|
end
|
|
else
|
|
begin
|
|
case ({set_stopped_on_error, clear_stop})
|
|
2'b00: stopped_on_error <= stopped_on_error;
|
|
2'b01: stopped_on_error <= 1'b0;
|
|
2'b10: stopped_on_error <= 1'b1;
|
|
2'b11: stopped_on_error <= 1'b0;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
stopped_on_early_termination <= 0;
|
|
end
|
|
else
|
|
begin
|
|
case ({set_stopped_on_early_termination, clear_stop})
|
|
2'b00: stopped_on_early_termination <= stopped_on_early_termination;
|
|
2'b01: stopped_on_early_termination <= 1'b0;
|
|
2'b10: stopped_on_early_termination <= 1'b1;
|
|
2'b11: stopped_on_early_termination <= 1'b0;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
irq <= 0;
|
|
end
|
|
else
|
|
begin
|
|
if (sw_reset_strobe == 1)
|
|
begin
|
|
irq <= 0;
|
|
end
|
|
else
|
|
begin
|
|
case ({clear_irq, set_irq})
|
|
2'b00: irq <= irq;
|
|
2'b01: irq <= 1'b1;
|
|
2'b10: irq <= 1'b0;
|
|
2'b11: irq <= 1'b1; // setting will win over a clear
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
/******************************************** End Registers *************************************************/
|
|
|
|
|
|
|
|
/**************************************** Combinational Signals *********************************************/
|
|
generate
|
|
if (ADDRESS_WIDTH == 3)
|
|
begin
|
|
always @ (csr_address or status or control or descriptor_watermark or response_watermark or sequence_number)
|
|
begin
|
|
case (csr_address)
|
|
3'b000: readdata = status;
|
|
3'b001: readdata = control;
|
|
3'b010: readdata = descriptor_watermark;
|
|
3'b011: readdata = response_watermark;
|
|
default: readdata = sequence_number; // all other addresses will decode to the sequence number
|
|
endcase
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
always @ (csr_address or status or control or descriptor_watermark or response_watermark)
|
|
begin
|
|
case (csr_address)
|
|
3'b000: readdata = status;
|
|
3'b001: readdata = control;
|
|
3'b010: readdata = descriptor_watermark;
|
|
default: readdata = response_watermark; // all other addresses will decode to the response watermark
|
|
endcase
|
|
end
|
|
end
|
|
endgenerate
|
|
|
|
|
|
assign clear_irq = (csr_address == 0) & (csr_write == 1) & (csr_byteenable[1] == 1) & (csr_writedata[9] == 1); // this is the IRQ bit
|
|
assign set_irq = (global_interrupt_enable == 1) & (done_strobe == 1) & // transfer ended and interrupts are enabled
|
|
((transfer_complete_IRQ_mask == 1) | // transfer ended and the transfer complete IRQ is enabled
|
|
((error & error_IRQ_mask) != 0) | // transfer ended with an error and this IRQ is enabled
|
|
((early_termination & early_termination_IRQ_mask) == 1)); // transfer ended early due to early termination and this IRQ is enabled
|
|
assign csr_irq = irq;
|
|
|
|
assign clear_stop = (csr_address == CONTROL_REGISTER_ADDRESS) & (csr_write == 1) & (csr_byteenable[0] == 1) & (csr_writedata[0] == 0);
|
|
assign set_stopped_on_error = (done_strobe == 1) & (stop_on_error == 1) & (error != 0); // when clear_stop is set then the stopped_on_error register will be cleared
|
|
assign set_stopped_on_early_termination = (done_strobe == 1) & (stop_on_early_termination == 1) & (early_termination == 1); // when clear_stop is set then the stopped_on_early_termination register will be cleared
|
|
assign set_stop = ((csr_address == CONTROL_REGISTER_ADDRESS) & (csr_write == 1) & (csr_byteenable[0] == 1) & (csr_writedata[0] == 1)) | // host set the stop bit
|
|
(set_stopped_on_error == 1) | // SGDMA setup to stop when an error occurs from the write master
|
|
(set_stopped_on_early_termination == 1) ; // SGDMA setup to stop when the write master overflows
|
|
assign stop = control[0];
|
|
|
|
assign set_sw_reset = (csr_address == CONTROL_REGISTER_ADDRESS) & (csr_write == 1) & (csr_byteenable[0] == 1) & (csr_writedata[1] == 1);
|
|
assign clear_sw_reset = (sw_reset == 1) & (reset_stalled == 0);
|
|
|
|
assign sw_reset_strobe = control[1];
|
|
assign stop_on_error = control[2];
|
|
assign stop_on_early_termination = control[3];
|
|
assign global_interrupt_enable = control[4];
|
|
assign stop_descriptors = control[5];
|
|
|
|
assign csr_readdata = readdata_d1;
|
|
assign status = {{22{1'b0}}, irq, stopped_on_early_termination, stopped_on_error, sw_reset, stop_state, response_buffer_full, response_buffer_empty, descriptor_buffer_full, descriptor_buffer_empty, busy}; // writing to the lower byte of the status register clears the irq bit
|
|
/**************************************** Combinational Signals *********************************************/
|
|
|
|
endmodule
|