//-----------------------------------------------------------------------------
// The confidential and proprietary information contained in this file may
// only be used by a person authorised under and to the extent permitted
// by a subsisting licensing agreement from ARM Limited.
//
// (C) COPYRIGHT 2006-2007 ARM Limited.
// ALL RIGHTS RESERVED
//
// This entire notice must be reproduced on all copies of this file
// and copies of this file may only be made by a person if such person is
// permitted to do so under the terms of a subsisting license agreement
// from ARM Limited.
//
// File Name : pl230_ahb_ctrl.v
// Checked In : $Date: 2007-03-15 15:17:04 +0530 (Thu, 15 Mar 2007) $
// Revision : $Revision: 10866 $
// State : $state: PL230-DE-98007-r0p0-02rel0 $
//
//-----------------------------------------------------------------------------
// Purpose : AHB master and DMA handshake interface control
//
//-----------------------------------------------------------------------------
`include "pl230_defs.v"
module pl230_ahb_ctrl
(
// Clock and Reset
hclk,
hresetn,
// DMA Control
dma_req,
dma_sreq,
dma_waitonreq,
dma_stall,
dma_active,
dma_done,
// AHB-Lite Master Interface
hready,
hresp,
hrdata,
htrans,
hwrite,
haddr,
hsize,
hburst,
hmastlock,
hprot,
hwdata,
// Memory Mapped Registers
// Controller Configuration Registers
ctrl_base_ptr,
chnl_sw_request,
chnl_useburst_status,
chnl_req_mask_status,
chnl_enable_status,
chnl_pri_alt_status,
chnl_priority_status,
// Integration Registers
dma_done_status,
dma_active_status,
int_test_en,
// Register Control
master_enable,
chnl_ctrl_hprot3to1,
ctrl_state,
clr_useburst,
set_useburst,
toggle_channel,
disable_channel,
data_current_chnl_onehot,
slave_err
);
//----------------------------------------------------------------------------
// Port declarations
//----------------------------------------------------------------------------
// Clock and Reset
input hclk; // AMBA bus clock
input hresetn; // AMBA bus reset
// DMA Control
input [`PL230_CHNLS-1:0] dma_req; // DMA transfer request
input [`PL230_CHNLS-1:0] dma_sreq; // DMA transfer request
input [`PL230_CHNLS-1:0] dma_waitonreq; // DMA request mode
input dma_stall; // DMA transfer stall
output [`PL230_CHNLS-1:0] dma_active; // DMA transfer active
output [`PL230_CHNLS-1:0] dma_done; // DMA transfer done
// AHB-Lite Master Interface
input hready; // AHB slave ready
input hresp; // AHB slave response
input [31:0] hrdata; // AHB read data
output [1:0] htrans; // AHB transfer enable
output hwrite; // AHB transfer direction
output [31:0] haddr; // AHB address
output [2:0] hsize; // AHB transfer size
output [2:0] hburst; // AHB burst length
output hmastlock; // AHB locked access control
output [3:0] hprot; // AHB protection control
output [31:0] hwdata; // AHB write data
// Memory Mapped Registers
// Controller Configuration Registers
input [31-1-`PL230_CHNL_BITS-2-2:0]
ctrl_base_ptr; // control data base pointer
input [`PL230_CHNLS-1:0] chnl_sw_request; // channel manual request
input [`PL230_CHNLS-1:0] chnl_useburst_status; // channel use bursts status
input [`PL230_CHNLS-1:0] chnl_req_mask_status; // channel request mask status
input [`PL230_CHNLS-1:0] chnl_enable_status; // channel enable status
input [`PL230_CHNLS-1:0] chnl_pri_alt_status; // channel primary/alternate
input [`PL230_CHNLS-1:0] chnl_priority_status; // channel priority status
// Integration Registers
input [`PL230_CHNLS-1:0] dma_done_status; // dma_done output status
input [`PL230_CHNLS-1:0] dma_active_status; // dma_active output status
input int_test_en; // Integration test enable
// Register Control
input master_enable; // master enable
input [2:0] chnl_ctrl_hprot3to1; // hprot for chnl ctrl access
output [`PL230_STATE_BITS-1:0]
ctrl_state; // AHB control state
output toggle_channel; // toggle current channel
output disable_channel; // disable current channel
output clr_useburst; // clear chnl_useburst_status
output set_useburst; // set chnl_useburst_status
output [`PL230_CHNLS-1:0] data_current_chnl_onehot;
// current channel (one hot)
output slave_err; // AHB slave response not OK
//----------------------------------------------------------------------------
// Port signal declarations
//----------------------------------------------------------------------------
reg [1:0] htrans; // AHB transfer enable
reg hwrite; // AHB transfer direction
reg [2:0] hsize; // AHB transfer size
reg [31:0] haddr; // AHB address
reg [`PL230_CHNLS-1:0] dma_active; // DMA transfer active
reg [`PL230_CHNLS-1:0] dma_done; // DMA transfer done
`ifdef PL230_ONE_CHNL
wire [`PL230_CHNLS-1:0] data_current_chnl_onehot;
// current channel (one hot)
`else
reg [`PL230_CHNLS-1:0] data_current_chnl_onehot;
// current channel (one hot)
`endif
//----------------------------------------------------------------------------
// Local signal declarations
//----------------------------------------------------------------------------
// Loop index for generating channel specific logic
integer i;
// Control which primary request input can generate a request
reg [`PL230_CHNLS-1:0] request;
// Automatic request
wire auto_request;
// Override R next value
wire override_r_nxt;
// Override the value of R for single requests
reg override_r;
// Pending request next value
reg [`PL230_CHNLS-1:0] pending_reqs_nxt;
// Pending request registers
reg [`PL230_CHNLS-1:0] pending_reqs;
// Current request for edge detection
wire req_delay_nxt;
// Delayed version of the current request for edge detection
reg req_delay;
// Current channel value enable
wire current_chnl_en;
`ifdef PL230_ONE_CHNL
// Current channel - one hot encoded
wire [`PL230_CHNLS-1:0] current_chnl_onehot;
`else
// Select which priority level to priority encode
wire [`PL230_CHNLS-1:0] current_chnl_sel_pri;
// Priority encoder input
reg [31:0] priority_ip;
// Priority encode the pending requests
reg [4:0] priority_enc;
// Current channel next value
wire [`PL230_CHNL_BITS-1:0]
current_chnl_nxt;
// Current channel
reg [`PL230_CHNL_BITS-1:0]
current_chnl;
// Current channel - one hot encoded
reg [`PL230_CHNLS-1:0] current_chnl_onehot;
// Hold the index of the current channel being serviced
reg [`PL230_CHNL_BITS-1:0]
data_current_chnl;
`endif
// Channel index valid next value
wire current_chnl_valid_nxt;
// Channel index valid
reg current_chnl_valid;
// Cycle_ctrl override
wire [2:0] cycle_ctrl_override;
// Current channel control data next value
wire [`PL230_CHANNEL_CFG_BITS-1:0]
channel_cfg_nxt;
// Current channel control data loaded from memory
reg [`PL230_CHANNEL_CFG_BITS-1:0]
channel_cfg;
// Destination address increment
wire [1:0] dst_inc;
// Destination transfer size
wire [1:0] dst_size;
// Source address increment
wire [1:0] src_inc;
// Source transfer size
wire [1:0] src_size;
// Destination AHB protection control
wire [2:0] dst_prot_ctrl;
// Source AHB protection control
wire [2:0] src_prot_ctrl;
// Power of two transactions per request
wire [3:0] r;
// Set chnl_useburst_status
wire next_useburst;
// DMA cycle control
wire [2:0] cycle_ctrl;
// DMA cycle control written back to memory
wire [2:0] cycle_ctrl_writeback;
// Limit the source size to 32bit on the AHB interface
wire [1:0] src_size_limit;
// Limit the destination size to 32bit on the AHB interface
wire [1:0] dst_size_limit;
// Multiplex control, source and destination hprot values
reg [2:0] hprot3to1;
// 2 to the power of R transfers complete
wire twotor_complete;
// R forced to zero when dma_sreq is the request source
wire [3:0] r_override;
// 2 to the power of R
reg [`PL230_N_COUNT_BITS-1:0]
twotor;
// 2 to the power of R counter enable
wire twotor_count_en;
// 2 to the power of R counter next value
wire [`PL230_N_COUNT_BITS-1:0]
twotor_count_nxt;
// 2 to the power of R counter - counts down
reg [`PL230_N_COUNT_BITS-1:0]
twotor_count;
// N transfers complete enable
wire n_complete_en;
// N transfers complete next value
wire n_complete_nxt;
// N transfers complete
reg n_complete;
// N counter eanble
wire n_count_en;
// N counter next value
wire [`PL230_N_COUNT_BITS-1:0]
n_count_nxt;
// N counter - counts down
reg [`PL230_N_COUNT_BITS-1:0]
n_count;
// Channel specific request wait
reg [`PL230_CHNLS-1:0] chnl_req_wait;
// Statemachine request wait
wire req_wait;
// AHB control phase statemachine next value
reg [`PL230_STATE_BITS-1:0]
ctrl_state_nxt;
// AHB control phase statemachine
reg [`PL230_STATE_BITS-1:0]
ctrl_state;
// AHB data phase statemachine enable
wire data_state_en;
// AHB data phase statemachine
reg [`PL230_STATE_BITS-1:0]
data_state;
// Initialise signals at the start of a DMA cycle
wire initialise;
// Load the channnel configuration and the N counter
wire channel_cfg_load;
// Load the two to the power of R counter
reg twotor_count_load;
// Decrement counters after a transfer
wire counter_decrement;
// Data phase statemachine in an AHB transfer state
wire ahb_data_state;
// Active states of data phase staemachine
wire active_states;
// Write channel_cfg back to memory
wire channel_cfg_store;
// Channel stall
wire stall;
// Channel done
wire done;
// Disable channel when the last DMA transfer has completed
wire disable_on_done;
// Disable channel when the channel_cfg data is flagged as invalid
wire disable_on_invalid;
// Disable the current channel when AHB response is not OK
wire disable_on_slave_err;
// Source four byte address delayed from source data read address phase
reg [1:0] src_addr;
// DMA data next value
wire [31:0] dma_data_nxt;
// DMA data update enable
wire dma_data_en;
// Byte adjusted DMA data
reg [31:0] dma_data;
// Hold slave response enable
wire current_slave_err_en;
// Hold slave response next value
wire current_slave_err_nxt;
// Hold slave response when not OK until statemachine is idle
reg current_slave_err;
// Select source or destination transfer size
wire [1:0] mux_size;
// Select source or destination address increment
wire [1:0] mux_inc;
// Control for the address offset
reg [1:0] ctrl_offset;
// Address offset
reg [`PL230_N_COUNT_BITS+1:0]
addr_offset;
// Address offset fixed for scatter/gather primary channel
wire [`PL230_N_COUNT_BITS+1:0]
addr_offset_sg_pri;
// Channel control data word select
reg [1:0] ctrl_dat_sel;
// Current channel control data address
wire [31:0] ctrl_dat_addr;
// Source/Destination end address
reg [31:0] src_dst_end_addr;
// Calcualted source/destination address
wire [31:0] dma_addr;
// AHB interface address next value
wire [31:0] haddr_nxt;
//----------------------------------------------------------------------------
//
// Beginning of main code
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// Hold Pending Requests
//----------------------------------------------------------------------------
// Control which primary request input can generate a request
always @( dma_req or dma_sreq or dma_waitonreq or chnl_useburst_status )
begin : p_request
for ( i = 0; i < `PL230_CHNLS; i=i+1 )
begin
request[i] = dma_req[i] ||
(dma_sreq[i] &&
// Single requests are only used when
dma_waitonreq[i] && !chnl_useburst_status[i]);
end
end // p_request
// Automatic request
assign auto_request = (((cycle_ctrl == 3'b010) &&
(twotor_complete && !n_complete)) ||
((cycle_ctrl[2:1] == 2'b10) &&
(twotor_complete || n_complete))) &&
(ctrl_state == `PL230_ST_WR_DDAT);
// Set the use burst request signal when N transfers are complete for
// Peripheral Scatter/Gather Alternate channel control data
// This signal takes priority over clr_useburst
assign set_useburst = n_complete && channel_cfg_store &&
next_useburst && (cycle_ctrl == 3'b111);
// Clear the use burst request signal when less that 2^R transfers remain
// unless Peripheral Scatter/Gater Primary is completing
assign clr_useburst = (n_count < twotor) && channel_cfg_store &&
(cycle_ctrl != 3'b110);
// Override R next value
assign override_r_nxt = |(current_chnl_onehot &
~dma_req & dma_sreq & ~chnl_useburst_status);
// Override the value of R for single requests
always @( negedge hresetn or posedge hclk )
begin : p_override_r
if ( hresetn == 1'b0 )
override_r <= 1'b0;
else
if ( initialise )
override_r <= override_r_nxt;
end // p_override_r
// Current request for edge detection
assign req_delay_nxt = initialise ? |(current_chnl_onehot & request)
: |(data_current_chnl_onehot & request);
// Delayed version of the current request for edge detection
always @( negedge hresetn or posedge hclk )
begin : p_req_delay
if ( hresetn == 1'b0 )
req_delay <= 1'b0;
else
req_delay <= req_delay_nxt;
end // p_req_delay
// Pending request control
always @( master_enable or chnl_enable_status or
data_current_chnl_onehot or disable_channel or
current_chnl_onehot or initialise or req_delay or request or
chnl_req_mask_status or dma_active or stall or
chnl_sw_request or auto_request or pending_reqs )
begin : p_pending_reqs_nxt
for ( i = 0; i < `PL230_CHNLS; i=i+1 )
begin
pending_reqs_nxt[i] =
// If the channel is enabled
master_enable && chnl_enable_status[i] &&
// and is not about to be disabled
!(data_current_chnl_onehot[i] && disable_channel) &&
// and not cleared by starting a dma cycle
!(current_chnl_onehot[i] && initialise) &&
// then hold request
( // external request which can be masked
( // if request high and not active or stalled
((request[i] && !(dma_active[i] ||
(stall && data_current_chnl_onehot[i]))) ||
// or request low-high transition when active or stalled
(!req_delay && request[i] && (dma_active[i] || stall))) &&
// and the mask is not set
!chnl_req_mask_status[i] ) ||
// internal request via memory mapped registers
chnl_sw_request[i] ||
// automatic request
(auto_request && current_chnl_onehot[i]) ||
// or maintain state
pending_reqs[i]
);
end
end // p_pending_reqs_nxt
// Pending requests register
always @( negedge hresetn or posedge hclk )
begin : p_pending_reqs
if ( hresetn == 1'b0 )
pending_reqs <= {`PL230_CHNLS{1'b0}};
else
pending_reqs <= pending_reqs_nxt;
end // p_pending_reqs
// Channel specific request wait
always @( request or dma_waitonreq or current_chnl_onehot )
begin : p_chnl_req_wait
for ( i = 0; i < `PL230_CHNLS; i=i+1 )
begin
chnl_req_wait[i] = dma_waitonreq[i] && request[i] &&
current_chnl_onehot[i];
end
end // p_chnl_req_wait
// Satemachine request wait
assign req_wait = |chnl_req_wait;
//----------------------------------------------------------------------------
// Priority Encode Pending Requests
//----------------------------------------------------------------------------
`ifdef PL230_ONE_CHNL
// Current channel one-hot select
assign current_chnl_onehot = 1'b1;
// AHB data phase current channel one-hot select
assign data_current_chnl_onehot = 1'b1;
`else
// Select which priority level to priority encode
assign current_chnl_sel_pri = ( |(pending_reqs & chnl_priority_status) )
? pending_reqs & chnl_priority_status
: pending_reqs;
// Priority encode the pending requests
// The priority encoder is fixed width but the connections to it
// depend on the number of channels implemented.
always @( current_chnl_sel_pri )
begin : p_priority_enc
priority_ip = {32{1'b0}};
priority_ip[`PL230_CHNLS-1:0] = current_chnl_sel_pri;
priority_enc =
(priority_ip[0] == 1'b1 ) ? 5'h00:
(priority_ip[1:0] == {1'b1, 1'b0 }) ? 5'h01:
(priority_ip[2:0] == {1'b1, {2{1'b0}}}) ? 5'h02:
(priority_ip[3:0] == {1'b1, {3{1'b0}}}) ? 5'h03:
(priority_ip[4:0] == {1'b1, {4{1'b0}}}) ? 5'h04:
(priority_ip[5:0] == {1'b1, {5{1'b0}}}) ? 5'h05:
(priority_ip[6:0] == {1'b1, {6{1'b0}}}) ? 5'h06:
(priority_ip[7:0] == {1'b1, {7{1'b0}}}) ? 5'h07:
(priority_ip[8:0] == {1'b1, {8{1'b0}}}) ? 5'h08:
(priority_ip[9:0] == {1'b1, {9{1'b0}}}) ? 5'h09:
(priority_ip[10:0] == {1'b1, {10{1'b0}}}) ? 5'h0a:
(priority_ip[11:0] == {1'b1, {11{1'b0}}}) ? 5'h0b:
(priority_ip[12:0] == {1'b1, {12{1'b0}}}) ? 5'h0c:
(priority_ip[13:0] == {1'b1, {13{1'b0}}}) ? 5'h0d:
(priority_ip[14:0] == {1'b1, {14{1'b0}}}) ? 5'h0e:
(priority_ip[15:0] == {1'b1, {15{1'b0}}}) ? 5'h0f:
(priority_ip[16:0] == {1'b1, {16{1'b0}}}) ? 5'h10:
(priority_ip[17:0] == {1'b1, {17{1'b0}}}) ? 5'h11:
(priority_ip[18:0] == {1'b1, {18{1'b0}}}) ? 5'h12:
(priority_ip[19:0] == {1'b1, {19{1'b0}}}) ? 5'h13:
(priority_ip[20:0] == {1'b1, {20{1'b0}}}) ? 5'h14:
(priority_ip[21:0] == {1'b1, {21{1'b0}}}) ? 5'h15:
(priority_ip[22:0] == {1'b1, {22{1'b0}}}) ? 5'h16:
(priority_ip[23:0] == {1'b1, {23{1'b0}}}) ? 5'h17:
(priority_ip[24:0] == {1'b1, {24{1'b0}}}) ? 5'h18:
(priority_ip[25:0] == {1'b1, {25{1'b0}}}) ? 5'h19:
(priority_ip[26:0] == {1'b1, {26{1'b0}}}) ? 5'h1a:
(priority_ip[27:0] == {1'b1, {27{1'b0}}}) ? 5'h1b:
(priority_ip[28:0] == {1'b1, {28{1'b0}}}) ? 5'h1c:
(priority_ip[29:0] == {1'b1, {29{1'b0}}}) ? 5'h1d:
(priority_ip[30:0] == {1'b1, {30{1'b0}}}) ? 5'h1e:
(priority_ip[31:0] == {1'b1, {31{1'b0}}}) ? 5'h1f:
5'h00;
end // p_priority_enc
// Current channel next value
assign current_chnl_nxt = priority_enc[`PL230_CHNL_BITS-1:0];
// Hold the index of the current channel being serviced
always @( negedge hresetn or posedge hclk )
begin : p_current_chnl
if ( hresetn == 1'b0 )
current_chnl <= {`PL230_CHNL_BITS{1'b0}};
else
if ( current_chnl_en )
current_chnl <= current_chnl_nxt;
end // p_current_chnl
// Convert current channel to a one-hot select
always @( current_chnl )
begin : p_current_chnl_onehot
for ( i = 0; i < `PL230_CHNLS; i=i+1 )
begin
current_chnl_onehot[i] = (current_chnl == i);
end
end // p_current_chnl_onehot
// Hold the index of the current channel being serviced
always @( negedge hresetn or posedge hclk )
begin : p_data_current_chnl
if ( hresetn == 1'b0 )
data_current_chnl <= {`PL230_CHNL_BITS{1'b0}};
else
if ( initialise && data_state_en )
data_current_chnl <= current_chnl;
end // p_current_chnl
// Convert the AHB data phase current channel to a one-hot select
always @( data_current_chnl )
begin : p_data_current_chnl_onehot
for ( i = 0; i < `PL230_CHNLS; i=i+1 )
begin
data_current_chnl_onehot[i] = (data_current_chnl == i);
end
end // p_data_current_chnl_onehot
`endif
// Current channel update enable
assign current_chnl_en =
// Update when idle
((ctrl_state == `PL230_ST_IDLE) && !current_chnl_valid) ||
// or when channel_cfg data was invalid or AHB response is not OK
disable_on_invalid || disable_on_slave_err ||
// or when completing 2^R or N transfers
// except for Peripheral Scatter/Gather Primary which transitions
// to Alternate without arbitration
(data_state_en && (cycle_ctrl != 3'b110) &&
((ctrl_state == `PL230_ST_WR_CTRL) ||
(ctrl_state == `PL230_ST_STALL) ||
(ctrl_state == `PL230_ST_DONE))
);
// Channel index valid next value
assign current_chnl_valid_nxt =
// Valid if there is a pending request
|pending_reqs &&
// and the channel is not being disabled
!(disable_on_invalid || disable_on_slave_err);
// Channel index valid
always @( negedge hresetn or posedge hclk )
begin : p_current_chnl_valid
if ( hresetn == 1'b0 )
current_chnl_valid <= 1'b0;
else
if ( current_chnl_en )
current_chnl_valid <= current_chnl_valid_nxt;
end // p_current_chnl_valid
//----------------------------------------------------------------------------
// Channel active and done
//----------------------------------------------------------------------------
// Channel done output
always @( int_test_en or dma_done_status or
master_enable or chnl_enable_status or
data_current_chnl_onehot or done or
request )
begin : p_dma_done
for ( i = 0; i < `PL230_CHNLS; i=i+1 )
begin
dma_done[i] = // If integration test logic is enabled
( int_test_en ) ?
// drive from test logic
dma_done_status[i] :
// or the channel is enabled
( master_enable && chnl_enable_status[i] ) ?
// decode the done state
(data_current_chnl_onehot[i] && done) :
// otherwise bypass
request[i];
end
end // p_dma_done
// Channel active output
always @( int_test_en or dma_active_status or
data_current_chnl_onehot or active_states )
begin : p_dma_active
for ( i = 0; i < `PL230_CHNLS; i=i+1 )
begin
dma_active[i] = // If integration test logic is enabled
( int_test_en ) ?
// drive from test logic
dma_active_status[i] :
// decode the active states
data_current_chnl_onehot[i] && active_states;
end
end // p_dma_active
//----------------------------------------------------------------------------
// Statemachine
//----------------------------------------------------------------------------
// AHB control phase statemachine next value
always @( ctrl_state or master_enable or current_chnl_valid or cycle_ctrl or
twotor_complete or n_complete or disable_on_slave_err or
req_wait or dma_stall )
begin : p_ctrl_state_nxt
ctrl_state_nxt = ctrl_state;
case ( ctrl_state )
`PL230_ST_IDLE: // Idle
begin
if ( master_enable && current_chnl_valid )
ctrl_state_nxt = `PL230_ST_RD_CTRL;
end
`PL230_ST_RD_CTRL: // Read Chnl Control Data
ctrl_state_nxt = `PL230_ST_RD_SPTR;
`PL230_ST_RD_SPTR: // Read Source End Pointer
ctrl_state_nxt = `PL230_ST_RD_DPTR;
`PL230_ST_RD_DPTR: // Read Dest End Pointer
begin
if ( cycle_ctrl == 3'b000 || disable_on_slave_err )
ctrl_state_nxt = `PL230_ST_IDLE;
else
ctrl_state_nxt = `PL230_ST_RD_SDAT;
end
`PL230_ST_RD_SDAT: // Read Source Data
ctrl_state_nxt = `PL230_ST_WR_DDAT;
`PL230_ST_WR_DDAT: // Write Destination Data
begin
if ( twotor_complete || n_complete || disable_on_slave_err )
begin
if ( req_wait && (cycle_ctrl != 3'b110))
ctrl_state_nxt = `PL230_ST_WAIT;
else
ctrl_state_nxt = `PL230_ST_WR_CTRL;
end
else
ctrl_state_nxt = `PL230_ST_RD_SPTR;
end
`PL230_ST_WAIT: // Wait for request
begin
if ( !req_wait )
ctrl_state_nxt = `PL230_ST_WR_CTRL;
end
`PL230_ST_WR_CTRL: // Write Chnl Control Data
begin
if ( cycle_ctrl == 3'b110 )
ctrl_state_nxt = `PL230_ST_PSGP;
else
begin
if ( dma_stall )
ctrl_state_nxt = `PL230_ST_STALL;
else
begin
if ( !n_complete || (cycle_ctrl[2] == 1'b1) )
ctrl_state_nxt = `PL230_ST_IDLE;
else
ctrl_state_nxt = `PL230_ST_DONE;
end
end
end
`PL230_ST_STALL: // Stall
begin
if ( !dma_stall )
begin
if ( !n_complete || (cycle_ctrl[2] == 1'b1) )
ctrl_state_nxt = `PL230_ST_IDLE;
else
ctrl_state_nxt = `PL230_ST_DONE;
end
end
`PL230_ST_DONE: // Done
ctrl_state_nxt = `PL230_ST_IDLE;
`PL230_ST_PSGP: // Periph Scatter/Gather
ctrl_state_nxt = `PL230_ST_RD_CTRL;
`PL230_ST_RESVD_0, // Reserved States
`PL230_ST_RESVD_1,
`PL230_ST_RESVD_2,
`PL230_ST_RESVD_3,
`PL230_ST_RESVD_4:
ctrl_state_nxt = `PL230_ST_IDLE;
default:
ctrl_state_nxt = {`PL230_STATE_BITS{1'bx}};
endcase
end
// AHB control statemachine register
always @( negedge hresetn or posedge hclk )
begin : p_ctrl_state
if ( hresetn == 1'b0 )
ctrl_state <= {`PL230_STATE_BITS{1'b0}};
else
if ( data_state_en )
ctrl_state <= ctrl_state_nxt;
end // p_ctrl_state
// AHB data phase statemachine enable
assign data_state_en = hready || !ahb_data_state;
// AHB data phase statemachine register
always @( negedge hresetn or posedge hclk )
begin : p_data_state
if ( hresetn == 1'b0 )
data_state <= {`PL230_STATE_BITS{1'b0}};
else
if ( data_state_en )
data_state <= ctrl_state;
end // p_data_state
//----------------------------------------------------------------------------
// Control signals derived from the statemachine
//----------------------------------------------------------------------------
// Initialise signals at the start of a DMA cycle
// unless a Peripheral Scatter/Gather Primary transfer has just happened
assign initialise = ( (ctrl_state == `PL230_ST_RD_CTRL) &&
(data_state != `PL230_ST_PSGP) );
// Disable the current channel when done
assign disable_on_invalid = ( ctrl_state == `PL230_ST_RD_DPTR) &&
( cycle_ctrl == 3'b000 );
// Channel stall
assign stall = (ctrl_state == `PL230_ST_STALL);
// Load the channnel configuration and the N counter
// This happens when the control data is valid on hrdata
assign channel_cfg_load = hready && (data_state == `PL230_ST_RD_CTRL);
// Load the two to the power of R counter
// This happens one clock cyle after the channnel configuration is loaded
// as the value of R held in channel_cfg is used
always @( negedge hresetn or posedge hclk )
begin : p_twotor_count_load
if ( hresetn == 1'b0 )
twotor_count_load <= 1'b0;
else
twotor_count_load <= channel_cfg_load;
end // p_twotor_count_load
// Decrement counters after a transfer
assign counter_decrement = hready && (data_state == `PL230_ST_WR_DDAT);
// Data phase statemachine in an AHB transfer state
assign ahb_data_state = !((data_state == `PL230_ST_IDLE) ||
(data_state == `PL230_ST_WAIT) ||
(data_state == `PL230_ST_STALL) ||
(data_state == `PL230_ST_DONE) ||
(data_state == `PL230_ST_PSGP));
// Define states when the dma_active signal is asserted
assign active_states = (data_state != `PL230_ST_IDLE) &&
(data_state != `PL230_ST_STALL) &&
(data_state != `PL230_ST_DONE);
// Write channel_cfg back to memory
assign channel_cfg_store = (data_state == `PL230_ST_WR_CTRL);
// Channel done
assign done = (data_state == `PL230_ST_DONE);
// Disable the current channel when done
assign disable_on_done = done &&
((cycle_ctrl == 3'b001) || (cycle_ctrl == 3'b010));
// Disable the current channel when the last DMA transfer has completed
// or when the channel_cfg data is flagged as invalid (cycle_ctrl = 0)
// or when the slave response is not OK.
assign disable_channel = disable_on_done ||
disable_on_invalid ||
disable_on_slave_err;
// Toggle the chnl_pri_alt_status bit
assign toggle_channel = counter_decrement &&
((((cycle_ctrl == 3'b011) || // Ping-Pong Pri/Alt
(cycle_ctrl == 3'b101) || // S/G Memory Alt
(cycle_ctrl == 3'b111)) // S/G Periph Alt
&& n_complete) || // only after N
(((cycle_ctrl == 3'b100) || // S/G Memory Pri
(cycle_ctrl == 3'b110)) && // S/G Periph Pri
(twotor_complete ||
n_complete))); // after 2^R or N
//----------------------------------------------------------------------------
// AHB data interface
//----------------------------------------------------------------------------
// Write Data
// The write data is either the updated channel control data or the dma date
// to move to the destination address.
// The number of transactions remaining is held in the ncount counter so the
// channel control data is derived from channel_cfg and ncount.
assign hwdata = ( channel_cfg_store ) ?
{
`PL230_CHANNEL_CFG_DST_INC,
`PL230_CHANNEL_CFG_DST_SIZE,
`PL230_CHANNEL_CFG_SRC_INC,
`PL230_CHANNEL_CFG_SRC_SIZE,
`PL230_CHANNEL_CFG_DST_PROT_CTRL,
`PL230_CHANNEL_CFG_SRC_PROT_CTRL,
`PL230_CHANNEL_CFG_R,
n_count,
`PL230_CHANNEL_CFG_NEXT_USEBURST,
cycle_ctrl_writeback
} : // Update channel control data
dma_data; // or write DMA data
// Override the value of cycle_ctrl if the AHB slave response is not OK.
assign cycle_ctrl_override = ( slave_err ) ?
3'b000 : `PL230_HRDATA_CYCLE_CTRL;
// Current channel control data next value
assign channel_cfg_nxt = {
`PL230_HRDATA_DST_INC,
`PL230_HRDATA_SRC_INC,
`PL230_HRDATA_SRC_SIZE,
`PL230_HRDATA_DST_PROT_CTRL,
`PL230_HRDATA_SRC_PROT_CTRL,
`PL230_HRDATA_R,
`PL230_HRDATA_NEXT_USEBURST,
cycle_ctrl_override
};
// Current channel control data loaded from memory
always @( negedge hresetn or posedge hclk )
begin : p_channel_cfg
if ( hresetn == 1'b0 )
channel_cfg <= {`PL230_CHANNEL_CFG_BITS{1'b0}};
else
if ( channel_cfg_load )
channel_cfg <= channel_cfg_nxt;
end // p_channel_cfg
// Source address lower two bits
always @( negedge hresetn or posedge hclk )
begin : p_src_addr
if ( hresetn == 1'b0 )
src_addr <= 2'b00;
else
if ( hready )
src_addr <= haddr[1:0];
end // p_src_addr
// Byte Lane Multiplex
pl230_dma_data upl230_dma_data
(
// DMA Data Control
.src_size (src_size),
.src_addr (src_addr),
// DMA Source Data
.hrdata (hrdata),
// DMA Destination Data
.dma_data_nxt (dma_data_nxt)
);
// DMA data enable
assign dma_data_en = hready && (data_state == `PL230_ST_RD_SDAT);
// DMA data buffer
always @( negedge hresetn or posedge hclk )
begin : p_dma_data
if ( hresetn == 1'b0 )
dma_data <= 32'h0000_0000;
else
if ( dma_data_en )
dma_data <= dma_data_nxt;
end // p_dma_data
// AHB slave response not OK
assign slave_err = ahb_data_state && hready && hresp;
// Hold slave response enable
assign current_slave_err_en = slave_err || (data_state == `PL230_ST_IDLE);
// Hold slave response next value
assign current_slave_err_nxt = slave_err;
// Hold slave response when not OK until statemachine is idle
always @( negedge hresetn or posedge hclk )
begin : p_current_slave_err
if ( hresetn == 1'b0 )
current_slave_err <= 1'b0;
else
if ( current_slave_err_en )
current_slave_err <= current_slave_err_nxt;
end // p_current_slave_err
// Disable the current channel when AHB response is not OK
assign disable_on_slave_err = current_slave_err || slave_err;
//----------------------------------------------------------------------------
// Decode channel control data
//----------------------------------------------------------------------------
// The control data for the current channel being serviced is held in
// channel_cfg.
// Destination address increment
assign dst_inc = `PL230_CHANNEL_CFG_DST_INC;
// Destination transfer size
assign dst_size = `PL230_CHANNEL_CFG_DST_SIZE;
// Source address increment
assign src_inc = `PL230_CHANNEL_CFG_SRC_INC;
// Source transfer size
assign src_size = `PL230_CHANNEL_CFG_SRC_SIZE;
// Destination AHB protection control
assign dst_prot_ctrl = `PL230_CHANNEL_CFG_DST_PROT_CTRL;
// Source AHB protection control
assign src_prot_ctrl = `PL230_CHANNEL_CFG_SRC_PROT_CTRL;
// Power of two transactions per request
assign r = `PL230_CHANNEL_CFG_R;
// Number of transactions remaining
// This is not held in the channel_cfg register as the decremented value is
// written back to memory. So the n_count counter is loaded at the same time
// as channel_cfg is loaded.
// Set chnl_useburst_status
// Used for Peripheral Scatter/Gather Alternate DMA cycles
assign next_useburst = `PL230_CHANNEL_CFG_NEXT_USEBURST;
// DMA cycle control
assign cycle_ctrl = `PL230_CHANNEL_CFG_CYCLE_CTRL;
// DMA cycle control written back to memory
// When N transfers are complete it is set to 0 to indicate that channel_cfg
// is no longer valid.
assign cycle_ctrl_writeback = (n_complete) ? 3'b000 :
`PL230_CHANNEL_CFG_CYCLE_CTRL;
//----------------------------------------------------------------------------
// AHB Control Interface Definitions
//----------------------------------------------------------------------------
// Limit the source size to 32bit on the AHB interface
assign src_size_limit = (src_size == 2'b11) ? 2'b10 : src_size;
// Limit the destination size to 32bit on the AHB interface
assign dst_size_limit = (dst_size == 2'b11) ? 2'b10 : dst_size;
// htrans, hwrite, hsize and hprot3to1 definition
// htrans bit 0 is always assigned to zero
// as only Idle and Non-sequential transfers are supported
always @( ctrl_state or chnl_ctrl_hprot3to1 or
src_size_limit or src_prot_ctrl or
dst_size_limit or dst_prot_ctrl )
begin : p_ahb_ctrl
case (ctrl_state)
`PL230_ST_IDLE,
`PL230_ST_PSGP,
`PL230_ST_WAIT,
`PL230_ST_STALL,
`PL230_ST_DONE:
begin
htrans = `PL230_AHB_TRANS_IDLE;
hwrite = `PL230_AHB_READ;
hsize = `PL230_AHB_SIZE_WORD;
hprot3to1 = chnl_ctrl_hprot3to1;
end
`PL230_ST_RD_CTRL,
`PL230_ST_RD_SPTR,
`PL230_ST_RD_DPTR:
begin
htrans = `PL230_AHB_TRANS_NONSEQ;
hwrite = `PL230_AHB_READ;
hsize = `PL230_AHB_SIZE_WORD;
hprot3to1 = chnl_ctrl_hprot3to1;
end
`PL230_ST_RD_SDAT:
begin
htrans = `PL230_AHB_TRANS_NONSEQ;
hwrite = `PL230_AHB_READ;
hsize = {1'b0, src_size_limit};
hprot3to1 = src_prot_ctrl;
end
`PL230_ST_WR_DDAT:
begin
htrans = `PL230_AHB_TRANS_NONSEQ;
hwrite = `PL230_AHB_WRITE;
This page: |
Created: | Wed Nov 24 14:08:44 2021 |
|
From: |
../../../../../../arm-AAA-ip/DMA-230_MicroDMA_Controller/PL230-BU-00000-r0p0-02rel1/verilog/pl230_ahb_ctrl.v |