OpenCores
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
    /
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/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_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/demo_arbiter.v
0,0 → 1,122
/*
* 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.
*/
 
`define PORT_WIDTH 8
`define ARB_WIDTH 256
`define SELECT_WIDTH 8
 
/*
 
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 XC3S1600E-4FG320:
 
arbiter arbiter_x2
/----------------------------\ /----------------------------\
width MHz slices LUTs registers MHz slices LUTs registers
8 214.961 22 34 35 287.439 34 42 53
16 191.571 47 75 68 284.252 69 87 103
32 148.943 99 163 133 211.730 122 169 188
64 124.285 200 346 262 202.840 245 349 370
128 102.807 434 717 519 165.044 490 739 699
256 100.796 923 1555 1032 163.666 986 1504 1389
512 87.176 1867 3120 2057 148.854 1973 2914 2686
1024 81.974 3628 5976 4106 140.213 3947 5883 5360
2048 69.214 7089 11444 8203 116.050 7966 12164 10513
4096 49.332* 14853 24501 16396 113.404* 15592 23858 21011
 
* at 4096, arbiter and arbiter_x2 exceed device capacity
 
Preliminary results using EP3C25F324C8:
 
arbiter arbiter_x2
/----------------------------\ /----------------------------\
width MHz slices LUTs registers MHz slices LUTs registers
8 384.17 37 33 35 453.31 55 29 53
16 289.60 80 73 68 452.90 108 68 103
32 259.74 165 160 133 357.53 206 152 188
64 187.51 337 320 262 299.94 415 319 370
128 132.12 675 630 519 226.50 853 685 699
256 122.37 1362 1279 1032 217.96 1694 1353 1389
512 99.91 2738 2627 2057 132.29 3303 2642 2686
1024 85.54 5434 5121 4106 130.28 6622 5312 5360
2048 71.77 10861 10128 8203 123.47 13236 10582 10513
4096 61.10 21777 20313 16396 140.86 23208 21177 21011
 
*/
 
module demo_arbiter (
input enable_in,
input enable_out,
input load,
input [`PORT_WIDTH-1:0] port_in,
output [`PORT_WIDTH-1:0] port_out,
output [`SELECT_WIDTH-1:0] select,
output valid,
input clock,
input reset
);
 
wire [`ARB_WIDTH-1:0] req, grant;
 
shifter #(
.count(`ARB_WIDTH/`PORT_WIDTH),
.width(`PORT_WIDTH)
) in_shifter (
.enable(enable_in),
.load(1'b0),
.parallel_in({`ARB_WIDTH{1'bx}}),
.serial_in(port_in),
.parallel_out(req),
.serial_out(),
.clock(clock)
);
 
arbiter #(
.width(`ARB_WIDTH),
.select_width(`SELECT_WIDTH)
) arbiter (
.enable(1'b1),
.req(req),
.grant(grant),
.select(select),
.valid(valid),
.clock(clock),
.reset(reset)
);
 
shifter #(
.count(`ARB_WIDTH/`PORT_WIDTH),
.width(`PORT_WIDTH)
) out_shifter (
.enable(enable_out),
.load(load),
.parallel_in(grant),
.serial_in({`PORT_WIDTH{1'bx}}),
.parallel_out(),
.serial_out(port_out),
.clock(clock)
);
 
endmodule
/trunk/rtl/verilog/demo_filters.v
0,0 → 1,83
/*
* 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
 
`define CLOCK_MHZ 40
`define DEBOUNCE_HIGH_COUNT 3
`define DEBOUNCE_LOW_COUNT 2
`define STRETCH_HIGH_COUNT 10
`define STRETCH_LOW_COUNT 5
 
module demo_filters (
input in,
output out,
output valid_in,
output valid_out,
input clock,
input reset
);
 
wire usec_tick, msec_tick, interconnect;
 
pulser #(
.count(`CLOCK_MHZ)
) usec_pulser (
.enable(1'b1),
.out(usec_tick),
.clock(clock),
.reset(reset)
);
 
pulser #(
.count(1000)
) msec_pulser (
.enable(usec_tick),
.out(msec_tick),
.clock(clock),
.reset(reset)
);
 
debouncer #(
.high_count(`DEBOUNCE_HIGH_COUNT),
.low_count(`DEBOUNCE_LOW_COUNT)
) debouncer (
.enable(msec_tick),
.in(in),
.out(interconnect),
.valid(valid_in),
.clock(clock),
.reset(reset)
);
 
stretcher #(
.high_count(`STRETCH_HIGH_COUNT),
.low_count(`STRETCH_LOW_COUNT)
) stretcher (
.enable(msec_tick),
.in(interconnect),
.out(out),
.valid(valid_out),
.clock(clock),
.reset(reset)
);
 
endmodule
/trunk/rtl/verilog/stretcher.v
0,0 → 1,97
/*
* 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 stretcher #(
parameter count = 0,
parameter high_count = count,
parameter low_count = count
)(
input enable,
input in,
output reg 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
parameter counter_width = max(clog2(high_count), clog2(low_count));
 
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})
'b10:
counter_load = ~(high_count - 1);
'b01:
counter_load = ~(low_count - 1);
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 <= 1'b0;
else if(counter_overflow)
out <= in;
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,56
/*
* 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 shifter #(
parameter count = 0,
parameter width = 0
)(
input enable,
input load,
input [(count*width)-1:0] parallel_in,
input [width-1:0] serial_in,
output [(count*width)-1:0] parallel_out,
output [width-1:0] serial_out,
input clock
);
 
reg [(count*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[(count*width)-1-:width] <= load
? parallel_in[(count*width)-1-:width]
: serial_in;
for(i = count - 1; i > 0; i = i - 1)
internal[(i*width)-1-:width] <= load
? parallel_in[(i*width)-1-:width]
: internal[((i+1)*width)-1-:width];
end
end
 
endmodule
/trunk/rtl/verilog/debouncer.v
0,0 → 1,109
/*
* 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 debouncer #(
parameter count = 0,
parameter high_count = count,
parameter low_count = count
)(
input enable,
input in,
output reg out,
output reg valid,
input clock,
input reset
);
 
`include "functions.v"
 
// register and edge detect the input
reg [1:0] in_reg;
 
always @(posedge clock)
begin
in_reg <= {in_reg[0], in};
end
 
// edge detector
wire rising;
wire falling;
 
assign rising = in_reg[1] & ~in_reg[0];
assign falling = ~in_reg[1] & in_reg[0];
 
// counter
parameter counter_width = max(clog2(high_count), clog2(low_count));
 
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})
'b10:
counter_load = ~(high_count - 1);
'b01:
counter_load = ~(low_count - 1);
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
always @(posedge clock, posedge reset)
begin
if(reset)
out <= 1'b0;
else
begin
if(counter_overflow)
out <= in_reg[1];
end
end
 
always @(posedge clock, posedge reset)
begin
if(reset)
valid <= 1'b0;
else
valid <= counter_overflow;
end
 
endmodule
/trunk/rtl/verilog/arbiter.v
0,0 → 1,388
/*
* 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
 
// 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_narb (
.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/functions.v
0,0 → 1,75
/*
* 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 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/pulser.v
0,0 → 1,66
/*
* 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 = 0,
parameter toggle = 0
) (
input enable,
output reg out,
input clock,
input reset
);
 
`include "functions.v"
 
parameter counter_width = clog2(count);
parameter [counter_width-1:0] counter_load = ~(count - 1);
 
reg [counter_width:0] counter;
wire counter_overflow;
 
assign counter_overflow = counter[counter_width];
 
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.odg Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
trunk/doc/arbiter_diagram.odg Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: trunk/doc/arbiter_diagram.pdf =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: trunk/doc/arbiter_diagram.pdf =================================================================== --- trunk/doc/arbiter_diagram.pdf (nonexistent) +++ trunk/doc/arbiter_diagram.pdf (revision 2)
trunk/doc/arbiter_diagram.pdf Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property

powered by: WebSVN 2.1.0

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