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

Subversion Repositories freeahb

Compare Revisions

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

Rev 1 → Rev 2

/trunk/LICENSE
0,0 → 1,21
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
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
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
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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.
/trunk/README.md
0,0 → 1,5
## AHB Master
 
Author: Revanth Kamaraj (revanth91kamaraj@gmail.com)
 
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.
/trunk/ahb_master.v
0,0 → 1,454
//////////////////////////////////////////////////////////////////////////////*
//
// 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
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// 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
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
 
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,
output reg [2:0] o_hburst,
output reg [1:0] o_htrans,
output reg[DATA_WDT-1:0]o_hwdata,
output reg o_hwrite,
output reg [2:0] o_hsize,
input [DATA_WDT-1:0]i_hrdata,
input i_hready,
input [1:0] i_hresp,
input i_hgrant,
output reg o_hbusreq,
 
///////////////////////////////////////////////////////////////////////
// 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.
//
///////////////////////////////////////////////////////////////////////
 
// 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.
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**.
 
// 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.
 
// 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[31:0] o_addr, // Corresponding address is presented here.
output reg o_dav // Used as o_data valid indicator.
);
 
////////////////////
// Localparams
////////////////////
 
localparam [1:0] IDLE = 0;
localparam [1:0] BUSY = 1;
localparam [1:0] NONSEQ = 2;
localparam [1:0] SEQ = 3;
localparam [1:0] OKAY = 0;
localparam [1:0] ERROR = 1;
localparam [1:0] SPLIT = 2;
localparam [1:0] RETRY = 3;
localparam [2:0] SINGLE = 0;
localparam [2:0] INCR = 1;
localparam [2:0] WRAP4 = 2;
localparam [2:0] INCR4 = 3;
localparam [2:0] WRAP8 = 4;
localparam [2:0] INCR8 = 5;
localparam [2:0] WRAP16 = 6;
localparam [2:0] INCR16 = 7;
localparam [2:0] BYTE = 0;
localparam [2:0] HWORD = 1;
localparam [2:0] WORD = 2; // 32-bit
localparam [2:0] DWORD = 3; // 64-bit
localparam [2:0] BIT128 = 4;
localparam [2:0] BIT256 = 5;
localparam [2:0] BIT512 = 6;
localparam [2:0] BIT1024 = 7;
 
// Abbreviations.
localparam D = DATA_WDT-1;
localparam B = BEAT_WDT-1;
 
//////////////////
// 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.
 
// Pipeline flip-flops.
reg [1:0] gnt;
reg [2:0] hburst; // Only for stage 1.
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.
 
// Tracks if we are in a pending state.
reg pend_split;
 
////////////////////////
// Signal aliases.
/////////////////////////
 
// Wire to check 1K crossing.
reg b1k_spec;
 
// Detects the first cycle of split and retry.
wire spl_ret_cyc_1 = gnt[1] && !i_hready && (i_hresp == RETRY || i_hresp == SPLIT);
 
// 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);
 
// Detects that 1k boundary condition will be crossed on next address
always @*
begin:blk4
logic [31:0] comp_addr;
integer i;
 
comp_addr = haddr[0];
 
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] )
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.
/////////////////////
 
// Output drivers.
always @* {o_haddr, o_hburst, o_htrans, o_hwdata, o_hwrite, o_hsize} =
{haddr[0], hburst, htrans[0], hwdata[1], hwrite[0], hsize[0]};
 
// UI must change only if this is 1.
always @* o_next = (i_hready && i_hgrant && !pend_split);
 
////////////////////////
// Grant tracker.
/////////////////////////
 
// Passes grant throughout the pipeline.
always @ (posedge i_hclk or negedge i_hreset_n)
begin
if ( !i_hreset_n )
gnt <= 2'd0;
else if ( spl_ret_cyc_1 )
gnt <= 2'd0; // A split retry cycle 1 will invalidate the pipeline.
else if ( i_hready )
gnt <= {gnt[0], i_hgrant};
end
 
//////////////////////////
// Bus request
//////////////////////////
 
always @ (posedge i_hclk or negedge i_hreset_n)
begin
// Request bus when doing reads/writes else do not request bus
if ( !i_hreset_n )
o_hbusreq <= 1'd0;
else
o_hbusreq <= i_rd | i_wr;
end
 
//////////////////////////////
// Address phase. Stage I.
//////////////////////////////
 
always @ (posedge i_hclk or negedge i_hreset_n)
begin
if ( !i_hreset_n )
begin
// Signal IDLE on reset.
htrans[0] <= IDLE;
pend_split <= 1'd0;
end
else if ( spl_ret_cyc_1 ) // Split retry cycle I
begin
htrans[0] <= IDLE;
pend_split <= 1'd1;
end
else if ( i_hready && i_hgrant )
begin
pend_split <= 1'd0; // Any pending split will be cleared
 
if ( pend_split )
begin
// If there's a pending split, perform a pipeline rollback
 
{hwrite[0], hsize[0]} <=
{hwrite[1], hsize[1]};
 
hwdata[0] <= unshift(hwdata[1], haddr[1]);
haddr[0] <= haddr[1];
hburst <= compute_hburst (beat, haddr[1], hsize[1]);
htrans[0] <= NONSEQ;
burst_ctr <= compute_burst_ctr(beat, haddr[1], hsize[1]);
beat_ctr <= beat;
end
else
begin
{hwdata[0], hwrite[0], hsize[0]} <= {i_data, i_wr, i_size};
 
if ( !cont && !rd_wr ) // Signal IDLE.
begin
htrans[0] <= IDLE;
end
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
integer i;
 
for(i=0;i<32;i++)
begin
if ( !cont )
haddr[0] <= i_addr;
else if ( addr_mask[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);
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);
 
beat_ctr <= !cont ? i_min_len : ((hburst == INCR) ? beat_ctr : beat_ctr - rd_wr);
end
else
begin:blk2
// We are in a normal burst. No need to change HBURST.
 
integer i;
 
for(i=0;i<32;i++)
if ( addr_mask[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);
beat_ctr <= o_hburst == INCR ? beat_ctr : (beat_ctr - rd_wr);
end
end
end
end
 
//////////////////////////////
// HWDATA phase. Stage II.
//////////////////////////////
 
always @ (posedge i_hclk)
begin
if ( i_hready && gnt[0] )
begin
hwdata[1] <= shift(hwdata[0], haddr[0]);
 
{haddr[1], hwrite[1], hsize[1], htrans[1], beat} <=
{haddr[0], hwrite[0], hsize[0], htrans[0], beat_ctr};
end
end
 
////////////////////////////////
// HRDATA phase. Stage III.
////////////////////////////////
 
always @ (posedge i_hclk or negedge i_hreset_n)
begin
if ( !i_hreset_n )
o_dav <= 1'd0;
else if ( gnt[1] && i_hready && (htrans[1] == SEQ || htrans[1] == NONSEQ) )
begin
o_dav <= !hwrite[1];
o_data <= unshift(i_hrdata, haddr[1]);
o_addr <= haddr[1];
end
else
o_dav <= 1'd0;
end
 
//////////////////////////////
// Functions.
///////////////////////////////
 
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;
 
if ( wrap == 0 )
begin
get_address_mask = 32'hFFFF_FFFF;
end
else
begin:blk3
integer i;
 
// If the bit of addr mask is set, propagate the calculation else
// keep previous value.
for(i=0;i<BEAT_WDT;i++)
begin
if ( len[i] )
begin
get_address_mask = (1 << (hsize + i)) - 1;
end
end
end
end
endfunction
 
function [DATA_WDT-1:0] shift ( input [DATA_WDT-1:0] data, input [31:0] addr );
reg [31:0] shamt;
begin
shamt = addr % (DATA_WDT/8); // Supported since RHS is constant.
shift = data << shamt;
end
endfunction
 
function [DATA_WDT-1:0] unshift ( input [DATA_WDT-1:0] data, input [31:0] addr );
reg [31:0] shamt;
begin
shamt = addr % (DATA_WDT/8); // Supported since RHS is constant
unshift = data >> shamt;
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;
 
// Wrap transfer active.
if ( addr_mask != 32'hFFFF_FFFF )
begin
if ( compute_hburst == INCR )
compute_hburst = SINGLE;
else if ( i_min_len == 4 )
compute_hburst = WRAP4;
else if ( i_min_len == 8 )
compute_hburst = WRAP8;
else if ( i_min_len == 16 )
compute_hburst = WRAP16;
else
compute_hburst = SINGLE;
end
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;
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!
else
no_cross = 1'd1; // Not crossed
endfunction
 
endmodule
 
///////////////////////////////////////////////////////////////////////////////
// EOF
///////////////////////////////////////////////////////////////////////////////
 
/trunk/autocommit.sh
0,0 → 1,21
date=`date`
 
git status
git pull orgin master
git status
git add *
git status
git commit -am "Autosave $date"
git status
git push origin master
git status
 
svn status
svn st | grep ^! | awk '{print " --force "$2}' | xargs svn rm
svn status
svn add --force * --auto-props --parents --depth infinity
svn status
svn commit -m "Autosave $date"
svn status
 
 

powered by: WebSVN 2.1.0

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