URL
https://opencores.org/ocsvn/scalable_arbiter/scalable_arbiter/trunk
Subversion Repositories scalable_arbiter
Compare Revisions
- This comparison shows the changes necessary to convert path
/scalable_arbiter
- from Rev 11 to Rev 12
- ↔ Reverse comparison
Rev 11 → Rev 12
/trunk/bench/verilog/tb_arbiter.v
0,0 → 1,166
/* |
* Copyright (c) 2008, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
// This bench simply applies the vectors in the pattern file, |
// and tests that the output matches the expected values. This |
// test is usful to verify basic behavior, but it is difficult |
// to generate vectors for large configurations. |
|
`define WIDTH 8 |
`define SELECT_WIDTH 8 |
`define TURNAROUND 3 |
//`define TURNAROUND 6 for arbiter x2 |
`define TICK 10 |
`define HALF_TICK 5 |
`define TEST_VEC_COUNT 241 |
`define TEST_VEC_MULT 2 |
`define PATTERN_FILE "tb_arbiter.txt" |
|
module tb_arbiter; |
|
reg reset; |
reg clock; |
|
reg [`WIDTH-1:0] req; |
wire [`WIDTH-1:0] grant; |
wire [`SELECT_WIDTH-1:0] select; |
wire valid; |
|
reg [`WIDTH-1:0] pattern[(`TEST_VEC_MULT*`TEST_VEC_COUNT)-1:0]; |
reg [`WIDTH-1:0] grant_expected; |
|
integer test_i; |
integer grant_i; |
integer grant_count; |
integer failures; |
integer monitor_exceptions; |
|
// |
// UUT |
// |
|
arbiter #( |
.width(`WIDTH), |
.select_width(`SELECT_WIDTH) |
) arbiter ( |
.enable(1'b1), |
.req(req), |
.grant(grant), |
.select(select), |
.valid(valid), |
|
.clock(clock), |
.reset(reset) |
); |
|
// |
// clock |
// |
|
always @(clock) |
#`HALF_TICK clock <= !clock; |
|
// |
// test monitors |
// |
|
always @(grant) |
begin |
grant_count = 0; |
for(grant_i = 0; grant_i < `WIDTH; grant_i = grant_i + 1) |
begin |
if(grant[grant_i]) |
begin |
grant_count = grant_count + 1; |
|
if(!req[grant_i]) |
begin |
monitor_exceptions = monitor_exceptions + 1; |
|
$display("EXCEPTION @%e: grant line %d with no req", |
$realtime, grant_i); |
end |
|
if(select != grant_i) |
begin |
monitor_exceptions = monitor_exceptions + 1; |
|
$display("EXCEPTION @%e: select of %d does not match grant of line %d", |
$realtime, select, grant_i); |
end |
end |
end |
|
if(grant_count > 1) |
begin |
monitor_exceptions = monitor_exceptions + 1; |
|
$display("EXCEPTION @%e: grant %h asserts multiple lines", |
$realtime, grant); |
end |
end |
|
// |
// test sequence |
// |
|
initial |
begin |
$readmemb(`PATTERN_FILE, pattern); |
failures = 0; |
monitor_exceptions = 0; |
|
clock = 1; |
req = 0; |
reset = 1; |
#`TICK @(negedge clock) reset = 0; |
|
// apply reqs, and test grants against exepcted values |
for(test_i = 0; test_i < `TEST_VEC_COUNT; test_i = test_i + 1) |
begin |
#`TICK; |
|
req = pattern[test_i*`TEST_VEC_MULT]; |
grant_expected = pattern[test_i*`TEST_VEC_MULT + 1]; |
|
#(`TURNAROUND*`TICK); |
|
if(grant != grant_expected) |
begin |
failures = failures + 1; |
|
$display("FAILED %d: req %h, grant %h (expected %h)", |
test_i, req, grant, grant_expected); |
end |
else |
begin |
$display("ok %d: req %h, grant %h (expected %h)", |
test_i, req, grant, grant_expected); |
end |
end |
|
$display("%d failures", failures); |
$display("%d monitor exceptions", monitor_exceptions); |
|
if(failures == 0 && monitor_exceptions == 0) |
$display("PASS"); |
else |
$display("FAIL"); |
end |
|
endmodule |
/trunk/bench/verilog/tb_arbiter3.v
0,0 → 1,93
/* |
* Copyright (c) 2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
// This bench walks the demo through its sequence, but it does not verify outputs. |
|
`define WIDTH 16 |
`define SELECT_WIDTH 4 |
`define TURNAROUND 3 |
`define TICK 10 |
`define HALF_TICK 5 |
|
module tb_arbiter3; |
|
reg clock; |
reg reset; |
|
reg next_test; |
reg next_step; |
|
wire [`SELECT_WIDTH-1:0] select; |
wire valid; |
|
integer test_i; |
|
`include "functions.v" |
|
// |
// UUT |
// |
|
demo #( |
.width(`WIDTH), |
.select_width(`SELECT_WIDTH) |
) demo ( |
.next_test(next_test), |
.next_step(next_step), |
.select(select), |
.valid(valid), |
.clock(clock), |
.reset(reset) |
); |
|
// |
// clock |
// |
|
always @(clock) |
begin |
#`HALF_TICK clock <= !clock; |
end |
|
// |
// test sequence |
// |
|
initial begin |
clock = 1; |
next_test = 0; |
next_step = 0; |
reset = 1; |
#`TICK @(negedge clock) reset = 0; |
|
// step through the stimulus sequence, 'req_enable' is always high, so |
// reqs will be deasserted as soon as they are granted |
while(1'b1) |
begin |
#`TICK next_test = 1; |
#`TICK next_test = 0; |
|
for(test_i = 0; test_i < `WIDTH; test_i = test_i + 1) |
begin |
#(`TURNAROUND*`TICK) next_step = 1; |
#`TICK next_step = 0; |
end |
end |
end |
|
endmodule |
/trunk/bench/verilog/tb_abrbiter2.v
0,0 → 1,254
/* |
* Copyright (c) 2008, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
// This bench applies req vectors, deasserts req lines as |
// they are granted, and tests that each req is granted |
// only once for each vector. It seems to be a pretty good |
// test because it is similar to the arbiter's intended |
// application, and it focuses on fairness, the most |
// important aspect of the arbiter's behavior. This test |
// also makes it easy to use large arbiter configurations, |
// which tend to find more problems. |
|
`define WIDTH 128 |
`define SELECT_WIDTH 7 |
`define TURNAROUND 3 |
//`define TURNAROUND 6 for arbiter x2 |
`define TICK 10 |
`define HALF_TICK 5 |
`define TEST_VEC_COUNT 8 |
`define PATTERN_FILE "tb_arbiter2.txt" |
`define ROUND_COUNT 3 |
|
module tb_arbiter2; |
|
reg reset; |
reg clock; |
|
reg [`WIDTH-1:0] req; |
wire [`WIDTH-1:0] grant; |
wire [`SELECT_WIDTH-1:0] select; |
wire valid; |
|
reg [`WIDTH-1:0] pattern[`TEST_VEC_COUNT-1:0]; |
|
integer test_i; |
integer grant_i; |
integer grant_count; |
integer req_i; |
integer req_count[`TEST_VEC_COUNT-1:0]; |
integer failures; |
integer monitor_exceptions; |
integer fill_i; |
integer round; |
integer reqs[`WIDTH-1:0]; |
integer grants[`ROUND_COUNT-1:0][`WIDTH-1:0]; |
|
// |
// UUT |
// |
|
arbiter #( |
.width(`WIDTH), |
.select_width(`SELECT_WIDTH) |
) arbiter ( |
.enable(1'b1), |
.req(req), |
.grant(grant), |
.select(select), |
.valid(valid), |
|
.clock(clock), |
.reset(reset) |
); |
|
// |
// clock |
// |
|
always @(clock) |
#`HALF_TICK clock <= !clock; |
|
// |
// test monitors |
// |
|
always @(grant) |
begin |
grant_count = 0; |
for(grant_i = 0; grant_i < `WIDTH; grant_i = grant_i + 1) |
begin |
if(grant[grant_i]) |
begin |
grant_count = grant_count + 1; |
grants[round][grant_i] = grants[round][grant_i] + 1; |
|
if(!req[grant_i]) |
begin |
monitor_exceptions = monitor_exceptions + 1; |
|
$display("EXCEPTION @%e: grant line %d with no req", |
$realtime, grant_i); |
end |
|
if(select != grant_i) |
begin |
monitor_exceptions = monitor_exceptions + 1; |
|
$display("EXCEPTION @%e: select of %d does not match grant of line %d", |
$realtime, select, grant_i); |
end |
end |
end |
|
if(grant_count > 1) |
begin |
monitor_exceptions = monitor_exceptions + 1; |
|
$display("EXCEPTION @%e: grant %h asserts multiple lines", |
$realtime, grant); |
end |
end |
|
// |
// test sequence |
// |
|
initial |
begin |
$readmemh(`PATTERN_FILE, pattern); |
failures = 0; |
monitor_exceptions = 0; |
fill_i = 0; |
round = 0; |
for(req_i = 0; req_i < `WIDTH; req_i = req_i + 1) |
begin |
reqs[req_i] = 0; |
|
grants[0][req_i] = 0; |
grants[1][req_i] = 0; |
grants[2][req_i] = 0; |
end |
// pre-calculate some values used in the test |
for(test_i = 0; test_i < `TEST_VEC_COUNT; test_i = test_i + 1) |
begin |
req_count[test_i] = 0; |
for(req_i = 0; req_i < `WIDTH; req_i = req_i + 1) |
begin |
if(pattern[test_i][req_i]) |
begin |
req_count[test_i] = req_count[test_i] + 1; |
reqs[req_i] = reqs[req_i] + 1; |
end |
end |
end |
|
clock = 1; |
req = 0; |
reset = 1; |
#`TICK @(negedge clock) reset = 0; |
|
// apply reqs, and turn off granted reqs permanently |
for(test_i = 0; test_i < `TEST_VEC_COUNT; test_i = test_i + 1) |
begin |
req = pattern[test_i]; |
|
for(req_i = 0; req_i < req_count[test_i]; req_i = req_i + 1) |
begin |
#(`TURNAROUND*`TICK); |
|
req = req & ~grant; |
end |
|
// one clock to deassert the last req before we apply |
// the next req vector |
#`TICK; |
end |
|
// apply reqs, but only turn off granted reqs temporarily |
round = round + 1; |
for(test_i = 0; test_i < `TEST_VEC_COUNT; test_i = test_i + 1) |
begin |
req = pattern[test_i]; |
|
for(req_i = 0; req_i < req_count[test_i]; req_i = req_i + 1) |
begin |
#(`TURNAROUND*`TICK); |
|
req = pattern[test_i] & ~grant; |
end |
|
// one clock to deassert the reqs before we apply the |
// next req vector |
req = 0; |
#`TICK; |
end |
|
// apply reqs, and fill behind with the next vector as reqs |
// are granted |
round = round + 1; |
req = pattern[0]; |
fill_i = `WIDTH; |
for(test_i = 0; test_i < `TEST_VEC_COUNT; test_i = test_i + 1) |
begin |
for(req_i = 0; req_i < req_count[test_i]; req_i = req_i + 1) |
begin |
#(`TURNAROUND*`TICK); |
|
req = req & ~grant; |
|
for(fill_i = fill_i; ~grant[fill_i%`WIDTH]; fill_i = fill_i + 1) |
begin |
req[fill_i%`WIDTH] = (fill_i/`WIDTH < `TEST_VEC_COUNT) |
? pattern[fill_i/`WIDTH][fill_i%`WIDTH] |
: 1'b0; |
end |
end |
end |
|
// check the results |
for(req_i = 0; req_i < `WIDTH; req_i = req_i + 1) |
begin |
if(reqs[req_i] != grants[0][req_i] |
|| reqs[req_i] != grants[1][req_i] |
|| reqs[req_i] != grants[2][req_i]) |
begin |
failures = failures + 1; |
|
$display("FAILED %d: %d reqs, %d %d %d grants", |
req_i, reqs[req_i], grants[0][req_i], |
grants[1][req_i], grants[2][req_i]); |
end |
else |
begin |
$display("ok %d: %d reqs, %d %d %d grants", |
req_i, reqs[req_i], grants[0][req_i], |
grants[1][req_i], grants[2][req_i]); |
end |
end |
|
$display("%d failures", failures); |
$display("%d monitor exceptions", monitor_exceptions); |
|
if(failures == 0 && monitor_exceptions == 0) |
$display("PASS"); |
else |
$display("FAIL"); |
end |
|
endmodule |
/trunk/bench/verilog/tb_arbiter.txt
0,0 → 1,241
0 0 |
11111111 00000001 |
11111110 00000010 |
11111100 00000100 |
11111000 00001000 |
11110000 00010000 |
11100000 00100000 |
11000000 01000000 |
10000000 10000000 |
0 0 |
11111111 00000001 |
11111110 00000010 |
11111100 00000100 |
11111000 00001000 |
11110000 00010000 |
11100000 00100000 |
11000000 01000000 |
10000000 10000000 |
0 0 |
11111111 00000001 |
01111111 00000001 |
00111111 00000001 |
00011111 00000001 |
00001111 00000001 |
00000111 00000001 |
00000011 00000001 |
00000001 00000001 |
0 0 |
00000001 00000001 |
00000010 00000010 |
00000100 00000100 |
00001000 00001000 |
00010000 00010000 |
00100000 00100000 |
01000000 01000000 |
10000000 10000000 |
0 0 |
10000000 10000000 |
01000000 01000000 |
00100000 00100000 |
00010000 00010000 |
00001000 00001000 |
00000100 00000100 |
00000010 00000010 |
00000001 00000001 |
0 0 |
11111110 00000010 |
11111101 00000100 |
11111011 00001000 |
11110111 00010000 |
11101111 00100000 |
11011111 01000000 |
10111111 10000000 |
01111111 00000001 |
0 0 |
01111111 00000001 |
10111111 00000001 |
11011111 00000001 |
11101111 00000001 |
11110111 00000001 |
11111011 00000001 |
11111101 00000001 |
11111110 00000010 |
0 0 |
00000001 00000001 |
00000000 00000000 |
00000010 00000010 |
00000000 00000000 |
00000100 00000100 |
00000000 00000000 |
00001000 00001000 |
00000000 00000000 |
00010000 00010000 |
00000000 00000000 |
00100000 00100000 |
00000000 00000000 |
01000000 01000000 |
00000000 00000000 |
10000000 10000000 |
0 0 |
10000000 10000000 |
00000000 00000000 |
01000000 01000000 |
00000000 00000000 |
00100000 00100000 |
00000000 00000000 |
00010000 00010000 |
00000000 00000000 |
00001000 00001000 |
00000000 00000000 |
00000100 00000100 |
00000000 00000000 |
00000010 00000010 |
00000000 00000000 |
00000001 00000001 |
0 0 |
11111111 00000001 |
11111110 00000010 |
11111111 00000010 |
11111101 00000100 |
11111111 00000100 |
11111011 00001000 |
11111111 00001000 |
11110111 00010000 |
11111111 00010000 |
11101111 00100000 |
11111111 00100000 |
11011111 01000000 |
11111111 01000000 |
10111111 10000000 |
11111111 10000000 |
01111111 00000001 |
11111111 00000001 |
0 0 |
11111111 00000001 |
01111111 00000001 |
11111111 00000001 |
10111111 00000001 |
11111111 00000001 |
11011111 00000001 |
11111111 00000001 |
11101111 00000001 |
11111111 00000001 |
11110111 00000001 |
11111111 00000001 |
11111011 00000001 |
11111111 00000001 |
11111101 00000001 |
11111111 00000001 |
11111110 00000010 |
11111111 00000010 |
0 0 |
01010101 00000001 |
10000000 10000000 |
01010101 00000001 |
00100000 00100000 |
01010101 01000000 |
00001000 00001000 |
01010101 00010000 |
00000010 00000010 |
01010101 00000100 |
0 0 |
10101010 00000010 |
01000000 01000000 |
10101010 10000000 |
00010000 00010000 |
10101010 00100000 |
00000100 00000100 |
10101010 00001000 |
00000001 00000001 |
10101010 00000010 |
0 0 |
00010000 00010000 |
00100001 00100000 |
01000001 01000000 |
10000001 10000000 |
00010001 00000001 |
00010010 00000010 |
00010100 00000100 |
00011000 00001000 |
00010001 00010000 |
00100001 00100000 |
01000001 01000000 |
10000001 10000000 |
00010001 00000001 |
00010010 00000010 |
00010100 00000100 |
00011000 00001000 |
0 0 |
01010101 00000001 |
01010110 00000010 |
01010101 00000100 |
01011001 00001000 |
01010101 00010000 |
01100101 00100000 |
01010101 01000000 |
10010101 10000000 |
01010101 00000001 |
0 0 |
10101010 00000010 |
10101101 00001000 |
11110111 00100000 |
11011111 10000000 |
01111111 00000001 |
11111110 00000010 |
11111100 00000100 |
11111010 00001000 |
11110010 00010000 |
11101010 00100000 |
11001010 01000000 |
10101010 10000000 |
0 0 |
11001110 00000010 |
01010101 00000100 |
00100001 00000001 |
00101100 00000100 |
01000000 01000000 |
10110110 10000000 |
11100111 10000000 |
01011101 00000100 |
10010110 00000100 |
01010010 00010000 |
00000111 00000010 |
01110110 00000010 |
00010100 00000100 |
10110110 00000100 |
00011110 00000100 |
00110111 00000100 |
10101001 00001000 |
11000100 10000000 |
01001011 00001000 |
11110001 01000000 |
01101110 01000000 |
10011110 10000000 |
01001100 00000100 |
11110111 00000100 |
11010011 01000000 |
01111110 01000000 |
00000011 00000010 |
01001110 00000010 |
10011101 00000100 |
00110000 00010000 |
00110110 00010000 |
01000110 01000000 |
10001101 10000000 |
01110000 00010000 |
00001011 00000001 |
01111100 00001000 |
11010100 00010000 |
01001111 01000000 |
00010001 00000001 |
11101010 00000010 |
01000111 00000010 |
01100001 01000000 |
11111011 01000000 |
00011001 00000001 |
10011111 00000001 |
10010000 00010000 |
00001100 00000100 |
11110011 00010000 |
0 0 |
/trunk/bench/verilog/tb_arbiter2.txt
0,0 → 1,8
8176255410b7cb44a074ee702a9a86db |
8176255410b7cb44a074ee702a9a86db |
49539737fd0c739c556513c608c1228b |
10a60347121e743967d73eb4a2dc629b |
ee6064c875d6fdbda8a95e35102c551e |
0d1361fd41adf235fdafff491b1963e4 |
0d1361fd41adf235fdafff491b1963e4 |
e89c064542709e292edd0abf77b1e89c |
/trunk/rtl/verilog/stretcher.v
0,0 → 1,105
/* |
* Copyright (c) 2008-2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
module stretcher #( |
parameter count = 1, |
parameter high_count = count, |
parameter low_count = count, |
parameter width = 1, |
parameter reset_value = {width{1'b0}} |
)( |
input enable, |
input [width-1:0] in, |
output reg [width-1:0] out, |
output reg valid, |
|
input clock, |
input reset |
); |
|
`include "functions.v" |
|
// edge detector |
wire rising; |
wire falling; |
|
assign rising = |(~out & in); |
assign falling = |(out & ~in); |
|
/// counter width is the maximum size of the loaded value |
parameter counter_width = max(flog2(count - 1) + 1, |
max(flog2(high_count - 1) + 1, flog2(low_count - 1) + 1)); |
|
reg [counter_width:0] counter; |
reg [counter_width-1:0] counter_load; |
wire counter_overflow; |
|
assign counter_overflow = counter[counter_width]; |
|
// select counter value for rising or falling edge |
always @(rising, falling) |
begin |
case({rising, falling}) |
'b11: |
counter_load = -count; |
'b10: |
counter_load = -high_count; |
'b01: |
counter_load = -low_count; |
default: |
counter_load = {counter_width{1'bx}}; |
endcase |
end |
|
// the counter is reset on a rising or falling edge |
// overflow has priority over reset, so input changes |
// will be ignored until the full count is reached |
always @(posedge clock, posedge reset) |
begin |
if(reset) |
counter <= {counter_width{1'b0}}; |
else |
begin |
if(enable & ~counter_overflow) |
counter <= counter + 1; |
else if((rising | falling) & counter_overflow) |
counter <= { 1'b0, counter_load }; |
end |
end |
|
// output is gated by the counter overflow |
always @(posedge clock, posedge reset) |
begin |
if(reset) |
out <= reset_value; |
else |
begin |
if(counter_overflow) |
out <= in; |
end |
end |
|
always @(posedge clock, posedge reset) |
begin |
if(reset) |
valid <= 0; |
else |
valid <= counter_overflow; |
end |
|
endmodule |
/trunk/rtl/verilog/shifter.v
0,0 → 1,58
/* |
* Copyright (c) 2008-2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
module shifter #( |
parameter depth = 0, |
parameter width = 0 |
)( |
input enable, |
input load, |
|
input [(depth*width)-1:0] parallel_in, |
input [width-1:0] serial_in, |
output [(depth*width)-1:0] parallel_out, |
output [width-1:0] serial_out, |
|
input clock |
); |
|
reg [(depth*width)-1:0] internal; |
|
assign parallel_out = internal; |
assign serial_out = internal[width-1:0]; |
|
integer i; |
|
always @(posedge clock) |
begin |
if(enable) |
begin |
internal[(depth*width)-1-:width] <= load |
? parallel_in[(depth*width)-1-:width] |
: serial_in; |
|
for(i = depth - 1; i > 0; i = i - 1) |
begin |
internal[(i*width)-1-:width] <= load |
? parallel_in[(i*width)-1-:width] |
: internal[((i+1)*width)-1-:width]; |
end |
end |
end |
|
endmodule |
/trunk/rtl/verilog/demo.v
0,0 → 1,115
/* |
* Copyright (c) 2008-2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
/* |
These results give a rough idea of how the timing and size scale |
with the arbiter width. It is useful to look at the trends, but |
the individual values should be taken with a grain of salt. |
|
Preliminary results using XC6SLX45-2FGG484: |
|
arbiter arbiter_x2 |
/----------------------------\ /----------------------------\ |
width MHz LEs LUTs FFs MHz LEs LUTs FFs |
8 289.855 42 34 35 399.672 56 36 53 |
16 273.000 83 67 68 397.377 109 70 103 |
32 230.240 188 156 133 289.855 214 143 188 |
64 189.593 391 320 262 289.855 428 288 370 |
128 166.073 796 650 519 261.852 886 618 699 |
256 161.496 1582 1267 1032 261.852 1779 1245 1389 |
512 136.753 3164 2493 2057 196.883 3489 2443 2686 |
1024 122.155 6755 5348 4106 197.280 7015 4928 5360 |
2048 102.198 12538 9485 8203 193.289 13956 9767 10513 |
4096 103.433 27182 20683 16396 190.964 27813 19450 21011 |
|
note: width 4096 arbiter_x2 exceeds device capacity |
|
Preliminary results using EP3C40F484C8: |
|
arbiter arbiter_x2 |
/---------------------------\ /---------------------------\ |
width MHz LEs LUTs FFs MHz LEs LUTs FFs |
8 444.25 50 42 35 457.67 65 46 53 |
16 313.77 92 91 68 396.67 114 92 103 |
32 239.52 195 194 133 338.18 232 194 188 |
64 185.08 388 387 262 311.04 465 393 370 |
128 161.47 769 768 519 283.37 959 822 699 |
256 138.26 1551 1550 1032 249.25 1889 1619 1389 |
512 103.90 3132 3131 2057 155.88 3657 3132 2686 |
1024 88.39 6150 6149 4106 132.93 7328 6282 5360 |
2048 76.24 12283 12282 8203 138.12 14549 12479 10513 |
4096 57.02 24533 24532 16396 128.07 29099 24964 21011 |
*/ |
|
`timescale 1ns / 1ps |
|
module demo #( |
parameter width = 128, |
parameter select_width = 7 |
)( |
input next_test, |
input next_step, |
output [select_width-1:0] select, |
output valid, |
|
input clock, |
input reset |
); |
|
reg [width-1:0] req; |
wire [width-1:0] seq; |
wire [width-1:0] grant; |
|
lfsr #( |
.width(width) |
) lfsr ( |
.enable(next_test), |
.load(1'b0), |
.in(1'bx), |
.out(seq), |
|
.clock(clock), |
.reset(reset) |
); |
|
arbiter #( |
.width(width), |
.select_width(select_width) |
) arbiter ( |
.enable(1'b1), |
.req(req), |
.grant(grant), |
.select(select), |
.valid(valid), |
|
.clock(clock), |
.reset(reset) |
); |
|
always @(posedge clock) |
begin |
if(reset) |
req <= 0; |
else |
begin |
if(next_test) |
req <= seq; |
else if(next_step) |
req <= req & ~grant; |
end |
end |
|
endmodule |
/trunk/rtl/verilog/lfsr.v
0,0 → 1,88
/* |
* Copyright (c) 2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
module lfsr #( |
parameter width = 0, |
parameter reset_value = {width{1'b1}} |
)( |
input enable, |
input load, |
input in, |
output reg [width-1:0] out, |
|
input clock, |
input reset |
); |
|
// it's assumed that the msb is a tap so it need not be in this table, |
// indexes are 0-based, you can add cases for any other widths |
function is_tap ( |
input integer width, index |
); |
begin |
case(width) |
3: is_tap = index == 1; |
4: is_tap = index == 2; |
5: is_tap = index == 2; |
6: is_tap = index == 4; |
7: is_tap = index == 5; |
8: is_tap = index == 5 || index == 4 || index == 3; |
15: is_tap = index == 13; |
16: is_tap = index == 14 || index == 12 || index == 3; |
31: is_tap = index == 27; |
32: is_tap = index == 21 || index == 1 || index == 0; |
63: is_tap = index == 61; |
64: is_tap = index == 62 || index == 60 || index == 59; |
127: is_tap = index == 125; |
128: is_tap = index == 125 || index == 100 || index == 98; |
default: is_tap = 0; |
endcase |
end |
endfunction |
|
// combine the taps to compute the next lsb |
function [0:0] feedback ( |
input [width-1:0] value |
); |
integer i; |
begin |
// always include the msb |
feedback = value[width-1]; |
|
// include the other taps specified by the table |
for(i = 0; i < width - 1; i = i + 1) |
begin |
if(is_tap(width, i)) |
feedback = feedback ^ value[i]; |
end |
end |
endfunction |
|
// the shift register |
always @(posedge clock, posedge reset) |
begin |
if(reset) |
out <= reset_value; |
else |
begin |
if(enable) |
out <= {out[width-2:0], load ? in : feedback(out)}; |
end |
end |
|
endmodule |
/trunk/rtl/verilog/demo_top.v
0,0 → 1,162
/* |
* Copyright (c) 2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
`define MHZ 100 |
`define WIDTH 8 |
`define SELECT_WIDTH 3 |
`define DEBOUNCE_MSEC 250 |
`define STRETCH_MSEC 250 |
|
module demo_top ( |
input [1:0] buttons, |
output [`SELECT_WIDTH:0] indicators, |
|
input refclock |
); |
|
wire reset; |
wire clock; |
wire locked; |
wire usec_tick; |
wire msec_tick; |
wire next_test; |
wire next_step; |
wire [`SELECT_WIDTH-1:0] select; |
wire valid; |
|
reg [1:0] buttons_reg; |
|
// replace the clock generator with the appropriate module for your part |
assign reset = ~locked; |
|
/*clockgen clockgen ( |
.inclk0(refclock), |
.c0(clock), |
.locked(locked) |
);*/ |
clockgen clockgen ( |
.CLKIN_IN(refclock), |
.CLKFX_OUT(clock), |
.CLKIN_IBUFG_OUT(), |
.LOCKED_OUT(locked) |
); |
|
// register inputs |
always @(posedge clock) |
begin |
buttons_reg <= buttons; |
end |
|
// this counter is always enabled, so subtract 1 from the count to account for |
// the extra clock that it takes to reload the counter |
pulser #( |
.count(`MHZ-1) |
) usec_pulser ( |
.enable(1'b1), |
.out(usec_tick), |
|
.clock(clock), |
.reset(1'b0) |
); |
|
// this counter is only enabled every few clocks, so use the full count because |
// the clock that it takes to reload the counter will happen between enables |
pulser #( |
.count(1000) |
) msec_pulser ( |
.enable(usec_tick), |
.out(msec_tick), |
|
.clock(clock), |
.reset(1'b0) |
); |
|
// this assumes that the buttons are normally low, it fires a pulse on the |
// rising edge of a button event, and only accepts one event per DEBOUNCE_MSEC |
debouncer #( |
.low_count(`DEBOUNCE_MSEC) |
) next_test_debouncer ( |
.enable(msec_tick), |
.in(buttons_reg[1]), |
.out(), |
.rising_pulse(next_test), |
.falling_pulse(), |
.valid(), |
|
.clock(clock), |
.reset(1'b0) |
); |
|
debouncer #( |
.low_count(`DEBOUNCE_MSEC) |
) next_step_debouncer ( |
.enable(msec_tick), |
.in(buttons_reg[0]), |
.out(), |
.rising_pulse(next_step), |
.falling_pulse(), |
.valid(), |
|
.clock(clock), |
.reset(1'b0) |
); |
|
// the arbiter demo module |
demo #( |
.width(`WIDTH), |
.select_width(`SELECT_WIDTH) |
) demo ( |
.next_test(next_test), |
.next_step(next_step), |
.select(select), |
.valid(valid), |
|
.clock(clock), |
.reset(reset) |
); |
|
// this stretches brief changes long enough to be visible, specifically, to see |
// select blip when the arbiter wraps around (a wrap around is the transition |
// from granting a higher number req to a lower number, and while select blips, |
// all grants are deasserted) |
stretcher #( |
.count(`STRETCH_MSEC), |
.width(`SELECT_WIDTH) |
) select_stretcher ( |
.enable(msec_tick), |
.in(select), |
.out(indicators[`SELECT_WIDTH:1]), |
.valid(), |
|
.clock(clock), |
.reset(1'b0) |
); |
|
stretcher #( |
.count(`STRETCH_MSEC) |
) valid_stretcher ( |
.enable(msec_tick), |
.in(valid), |
.out(indicators[0]), |
.valid(), |
|
.clock(clock), |
.reset(1'b0) |
); |
|
endmodule |
/trunk/rtl/verilog/debouncer.v
0,0 → 1,132
/* |
* Copyright (c) 2008-2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
module debouncer #( |
parameter count = 1, |
parameter high_count = count, |
parameter low_count = count, |
parameter width = 1, |
parameter reset_value = {width{1'b0}} |
)( |
input enable, |
input [width-1:0] in, |
output [width-1:0] out, |
output reg rising_pulse, |
output reg falling_pulse, |
output reg valid, |
|
input clock, |
input reset |
); |
|
`include "functions.v" |
|
reg [width-1:0] in_reg; |
reg [width-1:0] out_reg; |
|
always @(posedge clock) |
begin |
in_reg <= in; |
end |
|
// edge detector |
wire rising; |
wire falling; |
|
assign rising = |(~in_reg & in); |
assign falling = |(in_reg & ~in); |
|
// counter width is the maximum size of the loaded value |
parameter counter_width = max(flog2(count - 1) + 1, |
max(flog2(high_count - 1) + 1, flog2(low_count - 1) + 1)); |
|
reg [counter_width:0] counter; |
reg [counter_width-1:0] counter_load; |
wire counter_overflow; |
|
assign counter_overflow = counter[counter_width]; |
|
// select counter value for rising or falling edge |
always @(rising, falling) |
begin |
case({rising, falling}) |
'b11: |
counter_load = -count; |
'b10: |
counter_load = -high_count; |
'b01: |
counter_load = -low_count; |
default: |
counter_load = {counter_width{1'bx}}; |
endcase |
end |
|
// the counter is reset on a rising or falling edge |
// reset has priority over overflow, so the counter |
// will not overflow until the input has been stable |
// for a full count |
always @(posedge clock, posedge reset) |
begin |
if(reset) |
counter <= {counter_width{1'b0}}; |
else |
begin |
if(rising | falling) |
counter <= { 1'b0, counter_load }; |
else if(enable & ~counter_overflow) |
counter <= counter + 1; |
end |
end |
|
// output is gated by the counter overflow |
assign out = out_reg; |
|
always @(posedge clock, posedge reset) |
begin |
if(reset) |
out_reg <= reset_value; |
else |
begin |
if(counter_overflow) |
out_reg <= in_reg; |
end |
end |
|
always @(posedge clock, posedge reset) |
begin |
if(reset) |
begin |
rising_pulse <= 1'b0; |
falling_pulse <= 1'b0; |
end |
else |
begin |
rising_pulse <= counter_overflow & ~out_reg & in_reg; |
falling_pulse <= counter_overflow & out_reg & ~in_reg; |
end |
end |
|
always @(posedge clock, posedge reset) |
begin |
if(reset) |
valid <= 1'b0; |
else |
valid <= counter_overflow; |
end |
|
endmodule |
/trunk/rtl/verilog/functions.v
0,0 → 1,92
/* |
* Copyright (c) 2008, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
function integer min ( |
input integer a, b |
); |
begin |
min = a < b ? a : b; |
end |
endfunction |
|
function integer max ( |
input integer a, b |
); |
begin |
max = a > b ? a : b; |
end |
endfunction |
|
// compute the log base 2 of a number, rounded down to the |
// nearest whole number |
function integer flog2 ( |
input integer number |
); |
integer i; |
integer count; |
begin |
flog2 = 0; |
for(i = 0; i < 32; i = i + 1) |
begin |
if(number&(1<<i)) |
flog2 = i; |
end |
end |
endfunction |
|
// compute the log base 2 of a number, rounded up to the |
// nearest whole number |
function integer clog2 ( |
input integer number |
); |
integer i; |
integer count; |
begin |
clog2 = 0; |
count = 0; |
for(i = 0; i < 32; i = i + 1) |
begin |
if(number&(1<<i)) |
begin |
clog2 = i; |
count = count + 1; |
end |
end |
// clog2 holds the largest set bit position and count |
// holds the number of bits set. More than one bit set |
// indicates that the input was not an even power of 2, |
// so round the result up. |
if(count > 1) |
clog2 = clog2 + 1; |
end |
endfunction |
|
// compute the size of the interconnect for the arbiter's |
// 'select' muxes |
function integer mux_sum ( |
input integer width, select_width |
); |
integer i, number; |
begin |
mux_sum = 0; |
number = 1; |
for(i = select_width; i > 0 && number <= width; i = i - 1) |
begin |
mux_sum = mux_sum + i*(number); |
number = number * 2; |
end |
end |
endfunction |
/trunk/rtl/verilog/arbiter.v
0,0 → 1,388
/* |
* Copyright (c) 2008-2009, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
// Two synchronous arbiter implementations are provided: |
// 'arbiter' and 'arbiter_x2'. Both are round-robin arbiters |
// with a configurable number of inputs. The algorithm used is |
// recursive in that you can build a larger arbiter from a |
// tree of smaller arbiters. 'arbiter_x2' is a tree of |
// 'arbiter' modules, 'arbiter' is a tree of 'arbiter_node' |
// modules, and 'arbiter_node' is the primitive of the |
// algorithm, a two input round-robin arbiter. |
// |
// Both 'arbiter' and 'arbiter_x2' can take multiple clocks |
// to grant a request. (Of course, neither arbiter should |
// assert an invalid grant while changing state.) 'arbiter' |
// can take up to three clocks to grant a req, and 'arbiter_x2' |
// can take up to five clocks. 'arbiter_x2' is probably only |
// necessary for configurations over a thousand inputs. |
// Presently, the width of both 'arbiter' and 'arbiter_x2' |
// must be power of two due to the way they instantiate a tree |
// of sub-arbiters. Extra inputs can be assigned to zero, and |
// extra outputs can be left disconnected. |
// |
// Parameters for 'arbiter' and 'arbiter_x2': |
// 'width' is width of the 'req' and 'grant' ports, which |
// must be a power of two. |
// 'select_width' is the width of the 'select' port, which |
// should be the log base two of 'width'. |
// |
// Ports for 'arbiter' and 'arbiter_x2': |
// 'enable' masks the 'grant' outputs. It is used to chain |
// arbiters together, but it might be useful otherwise. |
// It can be left disconnected if not needed. |
// 'req' are the input lines asserted to request access to |
// the arbitrated resource. |
// 'grant' are the output lines asserted to grant each |
// requestor access to the arbitrated resource. |
// 'select' is a binary encoding of the bitwise 'grant' |
// output. It is useful to control a mux that connects |
// requestor outputs to the arbitrated resource. It can |
// be left disconnected if not needed. |
// 'valid' is asserted when any 'req' is asserted. It is |
// used to chain arbiters together, but it might be |
// otherwise useful. It can be left disconnected if not |
// needed. |
|
// 'arbiter_x2' is a two-level tree of arbiters made from |
// registered 'arbiter' modules. It allows a faster clock in |
// large configurations by breaking the arbiter into two |
// registered stages. For most uses, the standard 'arbiter' |
// module is plenty fast. See the 'demo_arbiter' module for |
// some implemntation results. |
|
module arbiter_x2 #( |
parameter width = 0, |
parameter select_width = 1 |
)( |
input enable, |
input [width-1:0] req, |
output reg [width-1:0] grant, |
output reg [select_width-1:0] select, |
output reg valid, |
|
input clock, |
input reset |
); |
|
`include "functions.v" |
|
// 'width1' is the width of the first stage arbiters, which |
// is the square root of 'width' rounded up to the nearest |
// power of 2, calculated as: exp2(ceiling(log2(width)/2)) |
parameter width1 = 1 << ((clog2(width)/2) + (clog2(width)%2)); |
parameter select_width1 = clog2(width1); |
|
// 'width0' is the the width of the second stage arbiter, |
// which is the number of arbiters in the first stage. |
parameter width0 = width/width1; |
parameter select_width0 = clog2(width0); |
|
genvar g; |
|
wire [width-1:0] grant1; |
wire [(width0*select_width1)-1:0] select1; |
wire [width0-1:0] enable1; |
wire [width0-1:0] req0; |
wire [width0-1:0] grant0; |
wire [select_width0-1:0] select0; |
wire valid0; |
wire [select_width1-1:0] select_mux[width0-1:0]; |
|
assign enable1 = grant0 & req0; |
|
// Register the outputs. |
always @(posedge clock, posedge reset) |
begin |
if(reset) |
begin |
valid <= 0; |
grant <= 0; |
select <= 0; |
end |
else |
begin |
valid <= valid0; |
grant <= grant1; |
select <= { select0, select_mux[select0] }; |
end |
end |
|
// Instantiate the first stage of the arbiter tree. |
arbiter #( |
.width(width1), |
.select_width(select_width1) |
) stage1_arbs[width0-1:0] ( |
.enable(enable1), |
.req(req), |
.grant(grant1), |
.select(select1), |
.valid(req0), |
|
.clock(clock), |
.reset(reset) |
); |
|
// Instantiate the second stage of the arbiter tree. |
arbiter #( |
.width(width0), |
.select_width(select_width0) |
) stage0_arb ( |
.enable(enable), |
.req(req0), |
.grant(grant0), |
.select(select0), |
.valid(valid0), |
|
.clock(clock), |
.reset(reset) |
); |
|
// Generate muxes for the select outputs. |
generate |
for(g = 0; g < width0; g = g + 1) |
begin: gen_mux |
assign select_mux[g] = select1[((g+1)*select_width1)-1-:select_width1]; |
end |
endgenerate |
|
endmodule |
|
// 'arbiter' is a tree made from unregistered 'arbiter_node' |
// modules. Unregistered carries between nodes allows |
// the tree to change state on the same clock. The tree |
// contains (width - 1) nodes, so resource usage of the |
// arbiter grows linearly. The number of levels and thus the |
// propogation delay down the tree grows with log2(width). |
// The logarithmic delay scaling makes this arbiter suitable |
// for large configuations. This module can take up to three |
// clocks to grant the next requestor after its inputs change |
// (two clocks for the 'arbiter_node' modules and one clock |
// for the output registers). |
|
module arbiter #( |
parameter width = 0, |
parameter select_width = 1 |
)( |
input enable, |
input [width-1:0] req, |
output reg [width-1:0] grant, |
output reg [select_width-1:0] select, |
output reg valid, |
|
input clock, |
input reset |
); |
|
`include "functions.v" |
|
genvar g; |
|
// These wires interconnect arbiter nodes. |
wire [2*width-2:0] interconnect_req; |
wire [2*width-2:0] interconnect_grant; |
wire [width-2:0] interconnect_select; |
wire [mux_sum(width,clog2(width))-1:0] interconnect_mux; |
|
// Assign inputs to some interconnects. |
assign interconnect_req[2*width-2-:width] = req; |
assign interconnect_grant[0] = enable; |
|
// Assign the select outputs of the first arbiter stage to |
// the first mux stage. |
assign interconnect_mux[mux_sum(width,clog2(width))-1-:width/2] = interconnect_select[width-2-:width/2]; |
|
// Register some interconnects as outputs. |
always @(posedge clock, posedge reset) |
begin |
if(reset) |
begin |
valid <= 0; |
grant <= 0; |
select <= 0; |
end |
else |
begin |
valid <= interconnect_req[0]; |
grant <= interconnect_grant[2*width-2-:width]; |
select <= interconnect_mux[clog2(width)-1:0]; |
end |
end |
|
// Generate the stages of the arbiter tree. Each stage is |
// instantiated as an array of 'abiter_node' modules and |
// is half the width of the previous stage. Some simple |
// arithmetic part-selects the interconnects for each stage. |
// See the "Request/Grant Interconnections" diagram of an |
// arbiter in the documentation. |
generate |
for(g = width; g >= 2; g = g / 2) |
begin: gen_arb |
arbiter_node nodes[(g/2)-1:0] ( |
.enable(interconnect_grant[g-2-:g/2]), |
.req(interconnect_req[2*g-2-:g]), |
.grant(interconnect_grant[2*g-2-:g]), |
.select(interconnect_select[g-2-:g/2]), |
.valid(interconnect_req[g-2-:g/2]), |
|
.clock(clock), |
.reset(reset) |
); |
end |
endgenerate |
|
// Generate the select muxes for each stage of the arbiter |
// tree. The generate begins on the second stage because |
// there are no muxes in the first stage. Each stage is |
// a two dimensional array of muxes, where the dimensions |
// are number of arbiter nodes in the stage times the |
// number of preceeding stages. It takes some tricky |
// arithmetic to part-select the interconnects for each |
// stage. See the "Select Interconnections" diagram of an |
// arbiter in the documentation. |
generate |
for(g = width/2; g >= 2; g = g / 2) |
begin: gen_mux |
mux_array #( |
.width(g/2) |
) mux_array[clog2(width/g)-1:0] ( |
.in(interconnect_mux[mux_sum(g,clog2(width))-1-:clog2(width/g)*g]), |
.select(interconnect_select[g-2-:g/2]), |
.out(interconnect_mux[mux_sum(g/2,clog2(width))-(g/2)-1-:clog2(width/g)*g/2]) |
); |
assign interconnect_mux[mux_sum(g/2,clog2(width))-1-:g/2] = interconnect_select[g-2-:g/2]; |
end |
endgenerate |
|
endmodule |
|
module mux_array #( |
parameter width = 0 |
)( |
input [(2*width)-1:0] in, |
input [width-1:0] select, |
output [width-1:0] out |
); |
|
mux_node nodes[width-1:0] ( |
.in(in), |
.select(select), |
.out(out) |
); |
|
endmodule |
|
module mux_node ( |
input [1:0] in, |
input select, |
output out |
); |
|
assign out = select ? in[1] : in[0]; |
|
endmodule |
|
// This is a two input round-robin arbiter with the |
// addition of the 'valid' and 'enable' signals |
// that allow multiple nodes to be connected to form a |
// larger arbiter. Outputs are not registered to allow |
// interconnected nodes to change state on the same clock. |
|
module arbiter_node ( |
input enable, |
input [1:0] req, |
output [1:0] grant, |
output select, |
output valid, |
|
input clock, |
input reset |
); |
|
// The state determines which 'req' is granted. State '0' |
// grants 'req[0]', state '1' grants 'req[1]'. |
reg grant_state; |
wire next_state; |
|
// The 'grant' of this stage is masked by 'enable', which |
// carries the grants of the subsequent stages back to this |
// stage. The 'grant' is also masked by 'req' to ensure that |
// 'grant' is dropped as soon 'req' goes away. |
assign grant[0] = req[0] & ~grant_state & enable; |
assign grant[1] = req[1] & grant_state & enable; |
|
// Select is a binary value that tracks grant. It could |
// be used to control a mux on the arbitrated resource. |
assign select = grant_state; |
|
// The 'valid' carries reqs to subsequent stages. It is |
// high when the 'req's are high, except during 1-to-0 state |
// transistions when it's dropped for a cycle to allow |
// subsequent arbiter stages to make progress. This causes a |
// two cycle turnaround for 1-to-0 state transistions. |
/* |
always @(grant_state, next_state, req) |
begin |
if(grant_state & ~next_state) |
valid <= 0; |
else if(req[0] | req[1]) |
valid <= 1; |
else |
valid <= 0; |
end |
*/ |
// reduced 'valid' logic |
assign valid = (req[0] & ~grant_state) | req[1]; |
|
// The 'next_state' logic implements round-robin fairness |
// for two inputs. When both reqs are asserted, 'req[0]' is |
// granted first. This state machine along with some output |
// logic can be cascaded to implement round-robin fairness |
// for many inputs. |
/* |
always @(grant_state, req) |
begin |
case(grant_state) |
0: |
if(req[0]) |
next_state <= 0; |
else if(req[1]) |
next_state <= 1; |
else |
next_state <= 0; |
1: |
if(req[1]) |
next_state <= 1; |
else |
next_state <= 0; |
endcase |
end |
*/ |
// reduced next state logic |
assign next_state = (req[1] & ~req[0]) | (req[1] & grant_state); |
|
// state register |
always @(posedge clock, posedge reset) |
begin |
if(reset) |
grant_state <= 0; |
else |
grant_state <= next_state; |
end |
|
endmodule |
/trunk/rtl/verilog/pulser.v
0,0 → 1,68
/* |
* Copyright (c) 2008, Kendall Correll |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
|
`timescale 1ns / 1ps |
|
module pulser #( |
parameter count = 1, |
parameter toggle = 0 |
)( |
input enable, |
output reg out, |
|
input clock, |
input reset |
); |
|
`include "functions.v" |
|
// counter width is the size of the loaded value |
parameter counter_width = flog2(count - 1) + 1; |
|
reg [counter_width:0] counter; |
wire [counter_width-1:0] counter_load; |
wire counter_overflow; |
|
assign counter_overflow = counter[counter_width]; |
assign counter_load = -count; |
|
always @(posedge clock, posedge reset) |
begin |
if(reset) |
out <= 1'b0; |
else |
begin |
if(toggle) |
out <= out ^ counter_overflow; |
else |
out <= counter_overflow; |
end |
end |
|
always @(posedge clock, posedge reset) |
begin |
if(reset) |
counter <= {counter_width{1'b1}}; |
else |
begin |
if(counter_overflow) |
counter <= { 1'b0, counter_load }; |
else if(enable) |
counter <= counter + 1; |
end |
end |
|
endmodule |
/trunk/doc/arbiter_diagram.pdf
)KtaY>X06.2Nk+nZe#6yyrPS Hc_y)$(Ӯ824ʠ̿>\i`W;mE{$VFWөˤcjX⋎T>9ޯkeo`rs=Gɦϗ;uWd>^Oe=߿þeyFϧ3uva{;UpuÒ
+TÕm:]S8ݻ"{ցTn`Va_wvmt6sbgn;='w9Ɲo;='ӓo:='S[˓z\+9^7*9]cRrrLܨ4Mɛ@tcݣڱugTq^w9LfOP۠<'%٦;to̲3;&)7Pэաt+ƈo3_WPeYn1!"t&]i:WPe=ѷYL_*
+*6
+b|
+BOsHj쾡&)Dr
+ %%
+.AtGt`QQC`J2sh|N*Pe5#NMggեzv<ߨt}&+=,n2[⌘:_{7T
+S1!َh6*,VN2!L`q̓AMAgWJ'|CjwK'9hlϞhyc'/ ǖdtH/fOҝ' ry1IbOQC^̶Ч(j]|G)t}
+}
+endstream
+endobj
+
+3 0 obj
+3035
+endobj
+
+5 0 obj
+<>
+stream
+xZKo7ϯs oE1#`ai5C[@-\Kz7gûlc(R`:7я ^\^1fwr y|ׄ;c>,i
+`4=frsjWy0w闪|oaNy̰Ώ~<:C]Gѥ{zO?OYpbjr
+MӌDXcyIoRC8lm}uCjifrHE Q2I#kGkȁ$֎1fѺف!}C(8zAʓ@j٠`v,cH!ǵi@]ɱ!֫@=ŗf#6|ʠD.#CDGa0Q:}Op= &Ar
+Mj*5kTqR=cQq9EXƩm}v~E`A7?j3$s-A䁠b?XPVcՔňz~aN%P=tHF߬RcFU8/=zƄJ&Ŋ(F6=y
+,Y˃9WHS!Eh@Pc(1Tj@c@RIuHF߬RcFUc煸GϘ0uTy 0*/VF4qy 8<mX"]`zt6TpfzaPFK,rRYb"BܣgL:` YHimkbʴ/(2r绚ed%@q(6rR5lbELܫL+mK"ސi͛-m-֨j%Ek|mE:/}a/J%OBvf2+3%g!Hu"tf1;EBܫ&Ȩ&v,;)ʝ#PEsԳ04M@*uK}J8L
+%nLJvM%9]U(rf%ldՔ<^V$H`Cv&HF߬Rحvr.?~?Ɣ b掳": DpCUP4bFBܫ&H.5Vo%PvHF6bꨆ0ś@"0+3F߬g&u&q!!ra-0L$~G֡A-AI"OB>
+stream
+xy|8~ΙνwflFr"*A"$Fe3V\`UڪTZu+mZJ[1sfn}3̙3gy<9C"ڌ8m
+D(Dw
+jTCq)B҄%uREQ8zs,
+$!/CS?=WlWPDF2xӂN)iDaKh$Z } &E~r
+dA~>\gdi!?ڐj Gj |Q"5)3 3P$ 2n77d"YJ~@}F^_Э'؆9\7|/>OO2"_pj9
+|*ga~
+,,^>4M^_㵳s۵Goj;<>m*#6R{ɯȯ:nN%Na2rYyh%qí矅
+aDʠΟsE|{ÝZA.onOf<Ǐ4~oDGH%h싺]3Q\qd&ptZEB ;ݸ_nCx=
+R1Bhj"v܃zW30'8V\ݧ:k{Zyzh;ZQ&nMUN;
+q@Ư-+ԣOz
+A Ŀ'E&Vĝ((qݎmQ+
+O&ׄɉ|E&ȞKOxC]w瀆-CWϡ+>TI&&shND*6D#E?
+>r:6d1DAj#U&Y5|V+s(
+ a 52$M4O\òɗ@QrFsbI.GyreH>9)$s|P`ii\驟$w{ʚIPAabhb̐ vZbx w M&tsѺsUNUu㉵e(tE%̲nn-FnAvJhYMXE,Ukg
+bIJShAbڢT`nV,
+AKl,
+Wu@nĚ.iMwRHҔɔ(Hd}ss)h'Msi~ޚ^
+GDQ@/ҫRBWvr_
+/jsQ'T=[7vKjYϋ7s0 <^NՊ B5(H֊xE89i'Ap^#iAc#2ip=syb1EnE,Yi&f-~
0,0 → 1,372
+Hcful#2ٚdYi0zĒGdwfiLE1Bܷdr=Fdr/&3<$ơӄir\~,&>"dU=.x*bmB,ٱ\7r&6 [_l]E_lyEt]J^t6IU$9Zx|qW- dHr!*b(a=ad5hGAPh4́:u *ءS4;zyDdGuR툸.$q]U;Ā.ԕΡ$AHp5vx\q]\u!Bq%F4KPt+ vyJAa;єAIv\B+1 pT9$(vÕxddǃ5s<q%PDF-1.4 |
%äüöß |
2 0 obj |
<</Length 3 0 R/Filter/FlateDecode>> |
stream |