OpenCores
URL https://opencores.org/ocsvn/freeahb/freeahb/trunk

Subversion Repositories freeahb

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/freeahb/trunk/LICENSE
1,7 → 1,3
MIT License
 
Copyright (C) 2017 Revanth Kamaraj
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
9,9 → 5,6
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19,3 → 12,4
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
 
/freeahb/trunk/README.md
1,5 → 1,5
## AHB Master
 
Author: Revanth Kamaraj (revanth91kamaraj@gmail.com)
Author : Revanth Kamaraj (revanth91kamaraj@gmail.com)
Description : This repository provides a fully compliant AHB 2.0 Master.
 
This repository provides a fully compliant AHB 2.0 Master with SPLIT/RETRY support. Bursts are done using a combination of INCR16/INCR8/INCR4 and INCR.
/freeahb/trunk/ahb_master.v
1,16 → 1,5
//////////////////////////////////////////////////////////////////////////////*
//
// This RTL describes a generic AHB master with support for single and
// burst transfers. Split/retry pipeline rollback is also supported.
// The entire design is driven by a single clock i.e., AHB clock. A global
// asynchronous active low reset is provided.
//
//////////////////////////////////////////////////////////////////////////////
//
// MIT License
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Revanth Kamaraj
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
18,9 → 7,6
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29,13 → 15,14
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
/////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
 
module ahb_master #(parameter DATA_WDT = 32, parameter BEAT_WDT = 32) (
 
////////////////////////
///////////////////////////////////////////////////////////////////////
// AHB interface.
////////////////////////
///////////////////////////////////////////////////////////////////////
 
input i_hclk,
input i_hreset_n,
output reg [31:0] o_haddr,
53,43 → 40,19
///////////////////////////////////////////////////////////////////////
// User interface.
///////////////////////////////////////////////////////////////////////
//
// NOTE: You can change UI signals at any time if the unit is IDLING.
//
// NOTE: o_next is a combinational signal.
//
// NOTE: When reset is released, the signals on the UI should represent an
// IDLING state. From there onwards, you can change the UI at any time but once
// you change it, further changes can be made only if o_next = 1. You could
// perhaps connect o_next to read_enable of a FIFO.
//
// To go to IDLE, you must follow this...
// To set the unit to IDLE mode, make
// i_sof = 1, i_rd = 0 and [ i_wr = 0 (or)
// i_wr = 1 and i_dav = 0 ]
// on o_next = 1. As mentioned above, you change UI signals without having
// o_next = 1 but once changed you must change them again only when o_next = 1.
//
// NOTE: The first UI request of a burst must have valid data provided in case
// of a write. You CANNOT start a burst with the first UI request having
// wr = 1 and dav = 0.
//
///////////////////////////////////////////////////////////////////////
// Limitations of the UI
///////////////////////////////////////////////////////////////////////
//
// 1. Start address should be aligned with i_size.
//
///////////////////////////////////////////////////////////////////////
// Required UI must change only if this is 1. You can also
// change UI signals when the unit idling (SOF=0, RD=0, WR=0).
 
// UI must change only if this is 1.
output reg o_next, // External FIFO pop.
 
// Data to write onto AHB. No need to shift.
 
input [DATA_WDT-1:0] i_data, // Data to write. Can change during burst if o_next = 1.
input i_dav, // Data to write valid. Can change during burst if o_next = 1.
 
// Burst properties. Address should be aligned to i_size.
 
input [31:0] i_addr, // Base address of burst. Hold constant throughout the burst.
input [2:0] i_size, // 2**n bytes/beat. Hold constant throughout the burst.
input i_wr, // Write to AHB bus. Hold constant throughout the burst.
96,22 → 59,22
input i_rd, // Read from AHB bus. Hold constant throughout the burst.
input i_wrap, // Enable wrap transfer. i_min_len should be 2**.
input [BEAT_WDT-1:0] i_min_len, // Minimum guaranteed length of burst (number of beats).
// Hold constant throughout the burst.
// Keep i_sof=0 to extend the burst beyond.
// For wrap, this should be 2**.
// Hold constant throughout the burst.Keep i_sof=0 to extend the
// burst beyond i_min_len.For wrap, this should be striclty 2**.
 
// SOF
input i_sof, // 1 = Start of burst. Always
// 1 for disjoint transfers.
// When i_sof=1, new burst
// parameters should be
// provided. For wrap
// transfers, should go to
// 1 once transfer is
// done. No INCR extension.
 
input i_sof, // 1 = Start of burst. Always 1 for disjoint transfers.
// When i_sof=1, new burst parameters should be
// provided. For wrap transfers, should go to
// 1 once transfer is done (or) dav ==0 i.e.,
// no INCR extension is available for wrap, as expected.
// For a burst, this should be a pulse on the first
// beat. For a write transfer, i_dav == 1 when i_sof == 1.
 
// Data read from AHB. No need to shift.
output reg[DATA_WDT-1:0] o_data, // Data got from AHB is presented here.
 
output reg[DATA_WDT-1:0] o_data, // Data got from AHB is presented here (read).
output reg[31:0] o_addr, // Corresponding address is presented here.
output reg o_dav // Used as o_data valid indicator.
);
153,18 → 116,18
// Flip-flops.
//////////////////
 
reg [4:0] burst_ctr; // Small counter to keep track of current burst count.
reg [B:0] beat_ctr; // Counter to keep track of word/beat count.
reg [4:0] burst_ctr;
reg [B:0] beat_ctr;
 
// Pipeline flip-flops.
reg [1:0] gnt;
reg [2:0] hburst; // Only for stage 1.
reg [2:0] hburst;
reg [D:0] hwdata [1:0];
reg [31:0] haddr [1:0];
reg [1:0] htrans [1:0];
reg [1:0] hwrite;
reg [2:0] hsize [1:0];
reg [B:0] beat; // Only for stage 2.
reg [B:0] beat;
 
// Tracks if we are in a pending state.
reg pend_split;
182,6 → 145,12
// Inputs are valid only if there is a read or if there is a write with valid data.
wire rd_wr = i_rd || (i_wr && i_dav);
 
// 1 = Continues previous burst. Invert SOF. 0 - New transfer.
wire cont = ~i_sof;
 
// Calculate address mask
wire [31:0] addr_mask = get_address_mask (i_wrap, i_min_len, i_size);
 
// Detects that 1k boundary condition will be crossed on next address
always @*
begin:blk4
190,22 → 159,18
 
comp_addr = haddr[0];
 
// Address mask.
for(i=0;i<32;i++)
if ( addr_mask[i] )
comp_addr[i] = ((haddr[0] + (1 << i_size)) >> 10) >> i;
 
if ( comp_addr != haddr[0][31:10] )
// Check for 1K crossing.
if ( comp_addr[31:10] != haddr[0][31:10] )
b1k_spec = 1'd1;
else
b1k_spec = 1'd0;
end
 
// 1 = Continues previous burst. Invert SOF.
wire cont = ~i_sof;
 
// Calculate address mask
wire [31:0] addr_mask = get_address_mask (i_wrap, i_min_len, i_size);
 
////////////////////
// Misc. logic.
/////////////////////
275,9 → 240,9
 
hwdata[0] <= unshift(hwdata[1], haddr[1]);
haddr[0] <= haddr[1];
hburst <= compute_hburst (beat, haddr[1], hsize[1]);
hburst <= compute_hburst(beat, haddr[1], hsize[1], addr_mask, haddr[1], i_wrap);
htrans[0] <= NONSEQ;
burst_ctr <= compute_burst_ctr(beat, haddr[1], hsize[1]);
burst_ctr <= compute_burst_ctr(beat, haddr[1], hsize[1], addr_mask, haddr[1]);
beat_ctr <= beat;
end
else
288,7 → 253,8
begin
htrans[0] <= IDLE;
end
else if ( (!cont && rd_wr) || !gnt[0] || (burst_ctr == 1 && o_hburst != INCR)
else if ( (!cont && rd_wr) || !gnt[0] ||
(burst_ctr == 1 && o_hburst != INCR)
|| htrans[0] == IDLE || b1k_spec )
begin:blk1
// We need to recompute the burst type here
299,15 → 265,22
if ( !cont )
haddr[0] <= i_addr;
else if ( addr_mask[i] )
haddr[0][i] <= (haddr[0] + (rd_wr << i_size)) >> i;
haddr[0][i] <=
(haddr[0] + (rd_wr << i_size)) >> i;
end
 
hburst <= compute_hburst (!cont ? i_min_len : beat_ctr,
!cont ? i_addr : haddr[0] + (rd_wr << i_size) , i_size);
!cont ? i_addr :
haddr[0] + (rd_wr << i_size) ,
i_size, addr_mask, haddr[0],
i_wrap);
 
htrans[0] <= rd_wr ? NONSEQ : IDLE;
 
burst_ctr <= compute_burst_ctr(!cont ? i_min_len : beat_ctr - rd_wr,
!cont ? i_addr : haddr[0] + (rd_wr << i_size) , i_size);
!cont ? i_addr :
haddr[0] + (rd_wr << i_size) ,
i_size, addr_mask, haddr[0]);
 
beat_ctr <= !cont ? i_min_len : ((hburst == INCR) ? beat_ctr : beat_ctr - rd_wr);
end
319,7 → 292,8
 
for(i=0;i<32;i++)
if ( addr_mask[i] )
haddr[0][i] <= (haddr[0] + ((htrans[0] != BUSY) << i_size)) >> i;
haddr[0][i] <=
(haddr[0] + ((htrans[0] != BUSY) << i_size)) >> i;
 
htrans[0] <= rd_wr ? SEQ : BUSY;
burst_ctr <= o_hburst == INCR ? burst_ctr : (burst_ctr - rd_wr);
369,7 → 343,7
function [31:0] get_address_mask ( input wrap, input [BEAT_WDT-1:0] len,
input [2:0] hsize );
begin
get_address_mask = 32'hFFFF_FFFF;
get_address_mask = {32{1'dx}}; // Synthesis optimize on no match.
 
if ( wrap == 0 )
begin
379,15 → 353,11
begin:blk3
integer i;
 
// If the bit of addr mask is set, propagate the calculation else
// keep previous value.
// If the bit of addr mask is set, propagate the calculation
// else keep previous value. Works only for 1-hot values.
for(i=0;i<BEAT_WDT;i++)
begin
if ( len[i] )
begin
get_address_mask = (1 << (hsize + i)) - 1;
end
end
if ( len == 1 << i )
get_address_mask = (1 << ({29'd0, hsize} + i)) - 1;
end
end
endfunction
408,14 → 378,26
end
endfunction
 
function [2:0] compute_hburst (input [B:0] val, input [31:0] addr, input [2:0] sz);
begin
compute_hburst = (val >= 16 && no_cross(addr, 15, sz)) ? INCR16 :
(val >= 8 && no_cross(addr, 7, sz)) ? INCR8 :
(val >= 4 && no_cross(addr, 3, sz)) ? INCR4 : INCR;
function [2:0] compute_hburst (input [B:0] val, input [31:0] addr,
input [2:0] sz, input [31:0] mask,
input [31:0] prev_addr,
input wrap);
begin:blk5
integer i;
 
// Wrap transfer active.
if ( addr_mask != 32'hFFFF_FFFF )
// Mask address.
for(i=0;i<32;i++)
if ( mask[i] == 1'd0 )
addr[i] = prev_addr[i];
 
// Decide type of burst, assume no wrap.
compute_hburst = (val >= 16 && no_cross(addr, 15, sz, addr_mask)) ? INCR16:
(val >= 8 && no_cross(addr, 7, sz, addr_mask)) ? INCR8 :
(val >= 4 && no_cross(addr, 3, sz, addr_mask)) ? INCR4 :
INCR;
 
// Now, if wrap transfer active, furthe refine the results.
if ( wrap == 1'd1 )
begin
if ( compute_hburst == INCR )
compute_hburst = SINGLE;
431,19 → 413,40
end
endfunction
 
function [4:0] compute_burst_ctr(input [B:0] val, input [31:0] addr, input [2:0] sz);
begin
compute_burst_ctr = (val >= 16 && no_cross(addr, 15, sz)) ? 5'd16 :
(val >= 8 && no_cross(addr, 7, sz)) ? 5'd8 :
(val >= 4 && no_cross(addr, 3, sz)) ? 5'd4 : 5'd0;
function [4:0] compute_burst_ctr(input [B:0] val, input [31:0] addr,
input [2:0] sz, input [31:0] mask,
input [31:0] prev_addr);
begin:blk6
integer i;
 
// Mask address.
for(i=0;i<32;i++)
if ( mask[i] == 1'd0 )
addr[i] = prev_addr[i];
 
compute_burst_ctr = (val >= 16 && no_cross(addr, 15, sz, addr_mask)) ? 5'd16 :
(val >= 8 && no_cross(addr, 7, sz, addr_mask)) ? 5'd8 :
(val >= 4 && no_cross(addr, 3, sz, addr_mask)) ? 5'd4 :
5'd0;
end
endfunction
 
function no_cross(input [31:0] addr, input [31:0] val, input [2:0] sz);
if ( addr + (val << (1 << sz )) >> 10 != addr[31:10] )
no_cross = 1'd0; // Crossed!
function no_cross(input [31:0] addr, input [31:0] val, input [2:0] sz, input [31:0] mask);
reg [31:0] comp_addr;
integer i;
begin
comp_addr = addr;
 
// Override those with mask.
for(i=0;i<32;i++)
if ( mask[i] )
comp_addr = addr + (val << (1 << sz));
 
if ( comp_addr[31:10] != addr[31:10] )
no_cross = 1'd0;
else
no_cross = 1'd1; // Not crossed
no_cross = 1'd1;
end
endfunction
 
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.