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 7 to Rev 8
- ↔ Reverse comparison
Rev 7 → Rev 8
/trunk/ahb_master.v
21,131 → 21,171
// SOFTWARE. |
// |
/////////////////////////////////////////////////////////////////////////////// |
// |
// 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. |
// |
// Icarus Verilog: |
// iverilog -g2001 -Wall ahb_master.v |
// <No Errors/Warnings> |
// |
// Verilator: |
// vlator --lint-only ahb_master.v |
// <No Errors/Warnings> |
// |
/////////////////////////////////////////////////////////////////////////////// |
|
module ahb_master #(parameter DATA_WDT = 32, parameter BEAT_WDT = 32) ( |
module ahb_master ( |
i_hclk, |
i_hreset_n, |
o_haddr, |
o_hburst, |
o_htrans, |
o_hwdata, |
o_hwrite, |
o_hsize, |
i_hrdata, |
i_hready, |
i_hresp, |
i_hgrant, |
o_hbusreq, |
o_next, |
i_data, |
i_dav, |
i_addr, |
i_size, |
i_wr, |
i_rd, |
i_wrap, |
i_min_len, |
i_sof, |
o_data, |
o_addr, |
o_dav |
); |
|
/////////////////////////////////////////////////////////////////////// |
// AHB interface. |
/////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////// |
// Parameters |
//////////////////////////////////////////////////////////////////////// |
|
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, |
parameter DATA_WDT = 32; |
parameter BEAT_WDT = 32; |
|
/////////////////////////////////////////////////////////////////////// |
// User interface. |
/////////////////////////////////////////////////////////////////////// |
|
// 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). |
/////////////////////////////////////////////////////////////////////// |
// AHB interface. |
/////////////////////////////////////////////////////////////////////// |
|
output reg o_next, // External FIFO pop. |
input i_hclk; |
input i_hreset_n; |
output [31:0] o_haddr; |
output [2:0] o_hburst; |
output [1:0] o_htrans; |
output [DATA_WDT-1:0] o_hwdata; |
output o_hwrite; |
output [2:0] o_hsize; |
input [DATA_WDT-1:0] i_hrdata; |
input i_hready; |
input [1:0] i_hresp; |
input i_hgrant; |
output o_hbusreq; |
|
// Data to write onto AHB. No need to shift. |
/////////////////////////////////////////////////////////////////////// |
// User interface. |
/////////////////////////////////////////////////////////////////////// |
|
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. |
// 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). |
|
// Burst properties. Address should be aligned to i_size. |
output o_next; // External FIFO pop. |
|
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 i_min_len.For wrap, this should be striclty 2**. |
// Data to write onto AHB. No need to shift. |
|
// SOF |
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. |
|
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. |
// Burst properties. Address should be aligned to i_size. |
|
// Data read from AHB. No need to shift. |
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 i_min_len.For wrap, this should be striclty 2**. |
|
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. |
); |
// SOF |
|
//////////////////// |
// Localparams |
//////////////////// |
input i_sof; // 1 = Start of burst. Always 1 for disjoint transfers. |
// When i_sof=1, new burst parameters should be |
// provided. |
|
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; |
// Data read from AHB. No need to shift. |
|
// Abbreviations. |
localparam D = DATA_WDT-1; |
localparam B = BEAT_WDT-1; |
output [DATA_WDT-1:0] o_data; // Data got from AHB is presented here (read). |
output [31:0] o_addr; // Corresponding address is presented here. |
output o_dav; // Used as o_data valid indicator. |
|
////////////////// |
//////////////////////////// |
// Local Constants |
//////////////////////////// |
|
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 [4:0] burst_ctr; |
reg [B:0] beat_ctr; |
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 [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; |
reg [31:0] addr_mask [1:-1]; |
reg [1:0] wrap; |
reg [1:0] gnt; |
reg [2:0] hburst; |
reg [DATA_WDT-1: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 [BEAT_WDT-1:0] min_len [1:0]; |
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; |
reg pend_split; |
|
//////////////////////// |
// Signal aliases. |
///////////////////////// |
// Assigns |
///////////////////////// |
|
// Wire to check 1K crossing. |
reg b1k_spec; |
// Beat counter. |
wire [BEAT_WDT-1:0] beat_ctr_val = hburst == INCR ? beat_ctr : (beat_ctr - {{(BEAT_WDT-1){1'd0}}, rd_wr}); |
|
// 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); |
|
155,41 → 195,29
// 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); |
|
// Detects that 1k boundary condition will be crossed on next address |
always @* |
begin:blk4 |
logic [31:0] comp_addr; |
integer i; |
addr_mask[-1] = get_address_mask (i_wrap, i_min_len, i_size); |
|
comp_addr = haddr[0]; |
// 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]}; |
|
// Address mask. |
for(i=0;i<32;i++) |
if ( addr_mask[i] ) |
comp_addr[i] = ((haddr[0] + (1 << i_size)) >> 10) >> i; |
// UI must change only if this is 1. |
assign o_next = (i_hready && i_hgrant && !pend_split); |
|
// Check for 1K crossing. |
if ( comp_addr[31:10] != haddr[0][31:10] ) |
b1k_spec = 1'd1; |
else |
b1k_spec = 1'd0; |
end |
// hbus request |
assign o_hbusreq = hbusreq; |
|
//////////////////// |
// Misc. logic. |
///////////////////// |
// Output ports. |
assign o_data = odata; |
assign o_addr = oaddr; |
assign o_dav = odav; |
|
// 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. |
///////////////////////// |
|
212,9 → 240,9
begin |
// Request bus when doing reads/writes else do not request bus |
if ( !i_hreset_n ) |
o_hbusreq <= 1'd0; |
hbusreq <= 1'd0; |
else |
o_hbusreq <= i_rd | i_wr; |
hbusreq <= i_rd | i_wr; |
end |
|
////////////////////////////// |
226,12 → 254,20
if ( !i_hreset_n ) |
begin |
// Signal IDLE on reset. |
htrans[0] <= IDLE; |
pend_split <= 1'd0; |
htrans[0] <= IDLE; |
pend_split <= 1'd0; |
hwdata[0] <= {DATA_WDT{1'd0}}; |
hwrite[0] <= 1'd0; |
addr_mask[0] <= 32'd0; |
hsize[0] <= 3'd0; |
wrap[0] <= 1'd0; |
burst_ctr <= 5'd0; |
beat_ctr <= {(BEAT_WDT){1'd0}}; |
min_len[0] <= {(BEAT_WDT){1'd0}}; |
end |
else if ( spl_ret_cyc_1 ) // Split retry cycle I |
begin |
htrans[0] <= IDLE; |
htrans[0] <= IDLE; |
pend_split <= 1'd1; |
end |
else if ( i_hready && i_hgrant ) |
242,70 → 278,67
begin |
// If there's a pending split, perform a pipeline rollback |
|
{hwrite[0], hsize[0], addr_mask[0], wrap[0]} <= |
{hwrite[1], hsize[1], addr_mask[1], wrap[1]}; |
{hwrite[0], hsize[0], addr_mask[0], wrap[0], min_len[0]} <= |
{hwrite[1], hsize[1], addr_mask[1], wrap[1], min_len[1]}; |
|
hwdata[0] <= unshift(hwdata[1], haddr[1]); |
haddr[0] <= haddr[1]; |
hburst <= compute_hburst(beat, haddr[1], hsize[1], addr_mask[1], haddr[1], wrap[1]); |
{burst_ctr, hburst} <= compute_hburst ( |
beat, |
1'd1, |
1'd0, |
hsize[1], |
addr_mask[1], |
haddr[1], |
wrap[1], |
{{(32-BEAT_WDT){1'd0}}, min_len[1]} |
); |
htrans[0] <= NONSEQ; |
burst_ctr <= compute_burst_ctr(beat, haddr[1], hsize[1], addr_mask[1], haddr[1]); |
beat_ctr <= beat; |
end |
else |
begin |
{hwdata[0], hwrite[0], hsize[0], addr_mask[0] , wrap[0]} <= |
{i_data, i_wr, i_size , addr_mask[-1] , i_wrap }; |
{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. |
begin |
begin:blk0 |
htrans[0] <= IDLE; |
end |
else if ( (!cont && rd_wr) || !gnt[0] || |
(burst_ctr == 1 && o_hburst != INCR) |
|| htrans[0] == IDLE || b1k_spec ) |
else if |
( |
(!cont && rd_wr) || |
!gnt[0] || |
(burst_ctr == 1 && o_hburst != INCR) || |
(htrans[0] == IDLE) || |
b1k_spec(haddr[0], i_size, addr_mask[0]) |
) |
begin:blk1 |
// We need to recompute the burst type here |
integer i; |
haddr[0] <= gen_addr ( haddr[0], {31'd0, rd_wr}, {29'd0, i_size}, cont, addr_mask[-1] ); |
|
for(i=0;i<32;i++) |
begin |
if ( !cont ) |
haddr[0] <= i_addr; |
else if ( addr_mask[-1][i] ) |
haddr[0][i] <= |
(haddr[0] + (rd_wr << i_size)) >> i; |
end |
{burst_ctr, hburst} <= compute_hburst ( |
beat_ctr, |
cont, |
rd_wr, |
i_size, |
addr_mask[-1], |
haddr[0], |
i_wrap, |
{{(32-BEAT_WDT){1'd0}}, i_min_len} |
); |
|
hburst <= compute_hburst (!cont ? i_min_len : beat_ctr, |
!cont ? i_addr : |
haddr[0] + (rd_wr << i_size) , |
i_size, addr_mask[-1], 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, addr_mask[-1], haddr[0]); |
|
beat_ctr <= !cont ? i_min_len : ((hburst == INCR) ? beat_ctr : beat_ctr - rd_wr); |
htrans[0] <= rd_wr == 1'd1 ? NONSEQ : IDLE; |
beat_ctr <= cont == 1'd0 ? i_min_len : beat_ctr_val; |
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[-1][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); |
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; |
beat_ctr <= beat_ctr_val; |
end |
end |
end |
315,9 → 348,19
// HWDATA phase. Stage II. |
////////////////////////////// |
|
always @ (posedge i_hclk) |
always @ (posedge i_hclk or negedge i_hreset_n) |
begin |
if ( i_hready && gnt[0] ) |
if ( !i_hreset_n ) |
begin |
hwdata[1] <= {DATA_WDT{1'd0}}; |
haddr[1] <= 32'd0; |
hwrite[1] <= 1'd0; |
htrans[1] <= IDLE; |
addr_mask[1] <= 32'd0; |
hsize[1] <= 3'd0; |
beat <= {(BEAT_WDT){1'd0}}; |
end |
else if ( i_hready && gnt[0] ) |
begin |
hwdata[1] <= shift(hwdata[0], haddr[0]); |
|
333,22 → 376,29
always @ (posedge i_hclk or negedge i_hreset_n) |
begin |
if ( !i_hreset_n ) |
o_dav <= 1'd0; |
begin |
odav <= 1'd0; |
odata <= {DATA_WDT{1'd0}}; |
oaddr <= 32'd0; |
end |
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]; |
odav <= ~hwrite[1]; |
odata <= unshift(i_hrdata, haddr[1]); |
oaddr <= haddr[1]; |
end |
else |
o_dav <= 1'd0; |
begin |
odav <= 1'd0; |
end |
end |
|
////////////////////////////// |
// Functions. |
// Functions (Pure). |
/////////////////////////////// |
|
function [31:0] get_address_mask ( input wrap, input [BEAT_WDT-1:0] len, |
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. |
386,75 → 436,99
end |
endfunction |
|
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); |
function [7:0] compute_hburst |
( |
input [BEAT_WDT-1:0] beat, |
input cont, |
input rd_wr, |
input [2:0] sz, |
input [31:0] mask, |
input [31:0] prev_addr, |
input wrap, |
input [31:0] min_len |
); |
reg [31:0] addr; |
reg [BEAT_WDT-1:0] val; |
begin:blk5 |
integer i; |
|
// Mask address. |
for(i=0;i<32;i++) |
if ( mask[i] == 1'd0 ) |
addr[i] = prev_addr[i]; |
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, 15, sz, mask)) ? INCR16 : |
(val >= 8 && no_cross(addr, 7, sz, mask)) ? INCR8 : |
(val >= 4 && no_cross(addr, 3, sz, mask)) ? INCR4 : |
INCR ; |
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 == 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; |
if ( compute_hburst[2:0] == INCR ) |
compute_hburst[2:0] = SINGLE; |
else |
begin |
case ( min_len ) |
32'd4 : compute_hburst[2:0] = WRAP4; |
32'd8 : compute_hburst[2:0] = WRAP8; |
32'd16 : compute_hburst[2:0] = WRAP16; |
default : compute_hburst[2:0] = SINGLE; |
endcase |
end |
end |
end |
endfunction |
|
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; |
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 = gen_addr(addr, val, 32'd1 << sz, 1'd1, mask ); |
|
// 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, mask)) ? 5'd16 : |
(val >= 8 && no_cross(addr, 7, sz, mask)) ? 5'd8 : |
(val >= 4 && no_cross(addr, 3, sz, mask)) ? 5'd4 : |
5'd0; |
if ( comp_addr[31:10] != addr[31:10] ) |
no_cross = 1'd0; |
else |
no_cross = 1'd1; |
end |
endfunction |
|
function no_cross (input [31:0] addr, input [31:0] val, |
input [2:0] sz, input [31:0] mask); |
reg [31:0] comp_addr; |
function get_bit ( input [31:0] data, integer sel ); |
get_bit = data[sel]; |
endfunction |
|
function [31:0] gen_addr ( input [31:0] addr, input [31:0] rd_wr, |
input [31:0] sz, input cont, |
input [31:0] mask ); |
integer i; |
begin |
comp_addr = addr; |
|
// Override those with mask. |
for(i=0;i<32;i++) |
begin |
if ( mask[i] ) |
comp_addr = addr + (val << (1 << sz)); |
gen_addr[i] = cont == 1'd0 ? addr[i] : |
get_bit(addr + (rd_wr << sz), i); |
else |
gen_addr[i] = addr[i]; |
end |
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] ) |
no_cross = 1'd0; |
b1k_spec = 1'd1; |
else |
no_cross = 1'd1; |
b1k_spec = 1'd0; |
end |
endfunction |
|