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 8 to Rev 9
    Reverse comparison

Rev 8 → Rev 9

/trunk/ahb_master.v
24,10 → 24,10
//
// This is a Verilog AHB master. It passes lint in Icarus Verilog and Verilog.
// It is strictly compliant with the AHB 2.0 specification. The logic is
// described in Verilog-2001.
// described in Verilog-1995 for max compatibility.
//
// Icarus Verilog:
// iverilog -g2001 -Wall ahb_master.v
// iverilog -g1995 -Wall ahb_master.v
// <No Errors/Warnings>
//
// Verilator:
127,40 → 127,29
output [31:0] o_addr; // Corresponding address is presented here.
output o_dav; // Used as o_data valid indicator.
 
////////////////////////////
// Local Constants
////////////////////////////
wire [1:0] IDLE = 0;
wire [1:0] BUSY = 1;
wire [1:0] NONSEQ = 2;
wire [1:0] SEQ = 3;
wire [1:0] OKAY = 0;
wire [1:0] ERROR = 1;
wire [1:0] SPLIT = 2;
wire [1:0] RETRY = 3;
wire [2:0] SINGLE = 0;
wire [2:0] INCR = 1;
wire [2:0] WRAP4 = 2;
wire [2:0] INCR4 = 3;
wire [2:0] WRAP8 = 4;
wire [2:0] INCR8 = 5;
wire [2:0] WRAP16 = 6;
wire [2:0] INCR16 = 7;
 
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;
 
///////////////////////////
// Flip-flops.
///////////////////////////
 
reg [DATA_WDT-1:0] odata;
reg [31:0] oaddr;
reg odav;
 
reg [4:0] burst_ctr;
reg [BEAT_WDT-1:0] beat_ctr;
reg hbusreq;
 
// Pipeline flip-flops.
reg [1:0] gnt;
reg [2:0] hburst;
reg [DATA_WDT-1:0] hwdata [1:0];
172,73 → 161,38
reg [BEAT_WDT-1:0] beat;
reg [31:0] addr_mask [1:-1];
reg [1:0] wrap;
 
// Tracks if we are in a pending state.
reg pend_split;
 
/////////////////////////
// Assigns
/////////////////////////
 
// Beat counter.
wire [BEAT_WDT-1:0] beat_ctr_val = hburst == INCR ? beat_ctr : (beat_ctr - {{(BEAT_WDT-1){1'd0}}, rd_wr});
wire [4:0] burst_ctr_val = hburst == INCR ? burst_ctr : (burst_ctr - {4'd0, rd_wr});
wire spl_ret_cyc_1 = gnt[1] && !i_hready && (i_hresp == RETRY || i_hresp == SPLIT);
wire rd_wr = i_rd || (i_wr && i_dav);
wire cont = ~i_sof;
wire [31:0] bt = htrans[0] != BUSY ? 32'd1 : 32'd0;
 
// Burst counter.
wire [4:0] burst_ctr_val = hburst == INCR ? burst_ctr : (burst_ctr - {4'd0, rd_wr});
 
// 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);
 
// 1 = Continues previous burst. Invert SOF. 0 - New transfer.
wire cont = ~i_sof;
 
// Busy handling
wire [31:0] bt = htrans[0] != BUSY ? 32'd1 : 32'd0;
 
// Calculate address mask
always @*
addr_mask[-1] = get_address_mask (i_wrap, i_min_len, i_size);
 
// Output drivers.
assign {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.
assign o_next = (i_hready && i_hgrant && !pend_split);
 
// hbus request
assign o_next = (i_hready && i_hgrant && !pend_split);
assign o_hbusreq = hbusreq;
assign o_data = odata;
assign o_addr = oaddr;
assign o_dav = odav;
 
// Output ports.
assign o_data = odata;
assign o_addr = oaddr;
assign o_dav = odav;
always @ (i_wrap, i_min_len, i_size)
addr_mask[-1] = get_address_mask (i_wrap, i_min_len, i_size);
 
/////////////////////////
// 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.
gnt <= 2'd0;
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 )
hbusreq <= 1'd0;
else
245,15 → 199,10
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;
hwdata[0] <= {DATA_WDT{1'd0}};
265,7 → 214,7
beat_ctr <= {(BEAT_WDT){1'd0}};
min_len[0] <= {(BEAT_WDT){1'd0}};
end
else if ( spl_ret_cyc_1 ) // Split retry cycle I
else if ( spl_ret_cyc_1 )
begin
htrans[0] <= IDLE;
pend_split <= 1'd1;
272,17 → 221,16
end
else if ( i_hready && i_hgrant )
begin
pend_split <= 1'd0; // Any pending split will be cleared
pend_split <= 1'd0;
 
if ( pend_split )
begin
// If there's a pending split, perform a pipeline rollback
 
{hwrite[0], hsize[0], addr_mask[0], wrap[0], min_len[0]} <=
{hwrite[1], hsize[1], addr_mask[1], wrap[1], min_len[1]};
{hwrite[0], hsize[0], addr_mask[0], wrap[0], min_len[0], haddr[0]} <=
{hwrite[1], hsize[1], addr_mask[1], wrap[1], min_len[1], haddr[1]};
 
hwdata[0] <= unshift(hwdata[1], haddr[1]);
haddr[0] <= haddr[1];
{burst_ctr, hburst} <= compute_hburst (
beat,
1'd1,
301,7 → 249,7
{hwdata[0], hwrite[0], hsize[0], addr_mask[0] , wrap[0], min_len[0]} <=
{i_data, i_wr, i_size , addr_mask[-1] , i_wrap , i_min_len };
 
if ( !cont && !rd_wr ) // Signal IDLE.
if ( !cont && !rd_wr )
begin:blk0
htrans[0] <= IDLE;
end
314,8 → 262,7
b1k_spec(haddr[0], i_size, addr_mask[0])
)
begin:blk1
// We need to recompute the burst type here
haddr[0] <= gen_addr ( haddr[0], {31'd0, rd_wr}, {29'd0, i_size}, cont, addr_mask[-1] );
haddr[0] <= gen_addr ( (~cont) ? i_addr : haddr[0], {31'd0, rd_wr}, {29'd0, i_size}, cont, addr_mask[-1] );
 
{burst_ctr, hburst} <= compute_hburst (
beat_ctr,
323,7 → 270,7
rd_wr,
i_size,
addr_mask[-1],
haddr[0],
(~cont) ? i_addr : haddr[0],
i_wrap,
{{(32-BEAT_WDT){1'd0}}, i_min_len}
);
333,8 → 280,6
end
else
begin:blk2
// We are in a normal burst. No need to change HBURST.
 
haddr[0] <= gen_addr(haddr[0], bt, {29'd0, i_size}, 1'd1, addr_mask[-1]);
htrans[0] <= rd_wr == 1'd1 ? SEQ : BUSY;
burst_ctr <= burst_ctr_val;
344,10 → 289,6
end
end
 
//////////////////////////////
// HWDATA phase. Stage II.
//////////////////////////////
 
always @ (posedge i_hclk or negedge i_hreset_n)
begin
if ( !i_hreset_n )
369,10 → 310,6
end
end
 
////////////////////////////////
// HRDATA phase. Stage III.
////////////////////////////////
 
always @ (posedge i_hclk or negedge i_hreset_n)
begin
if ( !i_hreset_n )
393,15 → 330,11
end
end
 
//////////////////////////////
// Functions (Pure).
///////////////////////////////
 
function [31:0] get_address_mask ( input wrap,
input [BEAT_WDT-1:0] len,
input [2:0] hsize );
begin
get_address_mask = {32{1'dx}}; // Synthesis optimize on no match.
get_address_mask = {32{1'd0}};
 
if ( wrap == 0 )
begin
411,9 → 344,7
begin:blk3
integer i;
 
// 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++)
for(i=0;i<BEAT_WDT;i=i+1)
if ( len == 1 << i )
get_address_mask = (1 << ({29'd0, hsize} + i)) - 1;
end
423,7 → 354,7
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.
shamt = addr % (DATA_WDT/8);
shift = data << shamt;
end
endfunction
431,7 → 362,7
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
shamt = addr % (DATA_WDT/8);
unshift = data >> shamt;
end
endfunction
455,13 → 386,11
val = cont == 1'd0 ? min_len : beat;
addr = gen_addr(prev_addr, {31'd0, rd_wr}, {29'd0, sz}, cont, mask);
 
// Decide type of burst, assume no wrap.
compute_hburst = (val >= 16 && no_cross(addr, 32'd15, sz, mask)) == 1'd1 ? {5'd16, INCR16} :
(val >= 8 && no_cross(addr, 32'd7, sz, mask)) == 1'd1 ? {5'd8 , INCR8 } :
(val >= 4 && no_cross(addr, 32'd3, sz, mask)) == 1'd1 ? {5'd4 , INCR4 } :
{5'd0 , INCR } ;
 
// Now, if wrap transfer active, furthe refine the results.
if ( wrap == 1'd1 )
begin
if ( compute_hburst[2:0] == INCR )
507,7 → 436,7
input [31:0] mask );
integer i;
begin
for(i=0;i<32;i++)
for(i=0;i<32;i=i+1)
begin
if ( mask[i] )
gen_addr[i] = cont == 1'd0 ? addr[i] :
518,13 → 447,11
end
endfunction
 
// Detects that 1k boundary condition will be crossed on next address.
function b1k_spec ( input [31:0] addr, input [2:0] size, input [31:0] mask );
reg [31:0] comp_addr;
begin:blk4
comp_addr = gen_addr ( addr, 32'd1, {29'd0, size}, 1'd1, mask );
 
// Check for 1K crossing.
if ( comp_addr[31:10] != addr[31:10] )
b1k_spec = 1'd1;
else

powered by: WebSVN 2.1.0

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