1
- -- This Source Code Form is subject to the terms of the Mozilla Public
2
- -- License, v. 2.0. If a copy of the MPL was not distributed with this
3
- -- file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- --
5
- -- Copyright 2024 Oxide Computer Company
6
-
7
- -- Note: Documentation can be rendered in VSCode using the TerosHDL
8
- -- plugin: https://terostechnology.github.io/terosHDLdoc/
9
- -- ! A simple request arbiter that can do priority or round-robbin arbitration
10
- -- ! Built generically using unconstrained arrays.
11
- -- ! In Priority mode, the LSB (0) gets the highest priority.
12
- -- ! In round-robbin mode, the LSB gets the priority only when there was not a grant in the previous
13
- -- ! cycle and two requests occur simultaneously.
14
- -- ! A goal is to do this in a single cycle, without having to scan the request bits so that
15
- -- ! this scales well with increasing vectors.
16
- -- ! This arbiter uses the fact that <number> AND <two's complement of number> gives
17
- -- ! you a vector with the lowest (right-most) bit of <number> set
18
- library ieee;
19
- use ieee.std_logic_1164.all ;
20
- use ieee.numeric_std.all ;
21
-
22
- use work.arbiter_pkg.arbiter_mode;
23
-
24
- entity arbiter is
25
- generic
26
- (
27
- -- ! Using arbiter_pkg.arbiter_mode enum, choose
28
- -- ! arbiter type
29
- MODE : arbiter_mode
30
- );
31
- port
32
- (
33
- clk : in std_logic ;
34
- reset : in std_logic ;
35
- -- ! Request vector blocks requesting arbitration must
36
- -- ! assert their request until grant has been asserted
37
- -- ! grant remains until request is de-asserted.
38
- requests : in std_logic_vector ;
39
- -- ! This block asserts grant signals, and holds them
40
- -- ! until the the associated request signal drops.
41
- grants : out std_logic_vector
42
- );
43
- end entity ;
44
- architecture rtl of arbiter is
45
- constant ZEROS : unsigned (requests'range ) := (others => '0' );
46
- signal requests_int : unsigned (requests'range );
47
- signal requests_masked_twos : unsigned (requests'range );
48
- signal requests_masked : unsigned (requests'range );
49
- signal requests_last : unsigned (requests'range );
50
- signal grants_int : unsigned (requests'range );
51
- signal grants_last : unsigned (requests'range );
52
- signal grants_mask : unsigned (requests'range );
53
- signal req_vec_f_edge : unsigned (requests'range );
54
- signal req_f_edge : std_logic ;
55
- begin
56
- requests_int <= unsigned (requests);
57
- round_robin_mode : if MODE = ROUND_ROBIN generate
58
- -- This uses a grant-masking scheme to generate round-robin grant behavior.
59
- -- We want to mask off the previous granted channel and any lower bits
60
- -- so the upper bits get a round-robin chance.
61
- grants_mask <= not (grants_last or (grants_last - 1 ));
62
-
63
- -- Mask the requests based on the current grant mask, unless we have no active requests or grants, in
64
- -- which case, pass the unmasked vector through
65
- requests_masked <= requests_int and grants_mask when (requests_int and grants_mask) /= 0 else
66
- requests_int;
67
- else generate
68
- -- In priority mode, we needn't mask grants since the priority encoder takes over
69
- -- and we will allow multiple grants to the same requester to the exclusion of others
70
- -- given the desired priority.
71
- grants_mask <= (others => '0' );
72
- requests_masked <= requests_int;
73
- end generate ;
74
-
75
- -- Build two's complement, remember basic boolean math? 2's complement = (not <dat>) + 1
76
- requests_masked_twos <= (not requests_masked) + 1 ;
77
-
78
- fedge_detects : for i in requests_int'range generate
79
- req_vec_f_edge(i) <= '1' when requests_int(i) = '0' and requests_last(i) = '1' else
80
- '0' ;
81
- end generate ;
82
- -- Unary OR reduction, active when any bit is active
83
- req_f_edge <= or req_vec_f_edge;
84
-
85
- the_arbiter : process (clk)
86
- begin
87
- if reset then
88
- grants_int <= ZEROS;
89
- grants_last <= (others => '0' );
90
- requests_last <= (others => '0' );
91
- elsif rising_edge (clk) then
92
- -- Store history for edge detector
93
- requests_last <= requests_int;
94
- -- To determine a grant, we take the currently active requests vector,
95
- -- which is masked by the allowable requests in round-robbin mode, and then
96
- -- bitwise AND that with it's two's complement
97
- -- to get 1 bit active as our active grant.
98
- grants_int <= requests_masked and requests_masked_twos;
99
- if req_f_edge then
100
- -- Note: we expect requesters of this to hold request high until they both have the grant,
101
- -- and are finished with their current transaction. This means that falling edges of
102
- -- requests cause arbitration updates and we save the current grant for use in round-robin
103
- -- arbitration next time.
104
- grants_last <= grants_int;
105
- end if ;
106
- end if ;
107
- end process ;
108
-
109
- grants <= std_logic_vector (grants_int);
110
-
111
- end architecture ;
1
+ -- This Source Code Form is subject to the terms of the Mozilla Public
2
+ -- License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ -- file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ --
5
+ -- Copyright 2024 Oxide Computer Company
6
+
7
+ -- Note: Documentation can be rendered in VSCode using the TerosHDL
8
+ -- plugin: https://terostechnology.github.io/terosHDLdoc/
9
+ -- ! A simple request arbiter that can do priority or round-robbin arbitration
10
+ -- ! Built generically using unconstrained arrays.
11
+ -- ! In Priority mode, the LSB (0) gets the highest priority.
12
+ -- ! In round-robbin mode, the LSB gets the priority only when there was not a grant in the previous
13
+ -- ! cycle and two requests occur simultaneously.
14
+ -- ! A goal is to do this in a single cycle, without having to scan the request bits so that
15
+ -- ! this scales well with increasing vectors.
16
+ -- ! This arbiter uses the fact that <number> AND <two's complement of number> gives
17
+ -- ! you a vector with the lowest (right-most) bit of <number> set
18
+
19
+ library ieee;
20
+ use ieee.std_logic_1164.all ;
21
+ use ieee.numeric_std.all ;
22
+ use work.arbiter_pkg.arbiter_mode;
23
+
24
+ entity arbiter is
25
+ generic (
26
+ -- ! Using arbiter_pkg.arbiter_mode enum, choose
27
+ -- ! arbiter type
28
+ mode : arbiter_mode
29
+ );
30
+ port (
31
+ clk : in std_logic ;
32
+ reset : in std_logic ;
33
+ -- ! Request vector blocks requesting arbitration must
34
+ -- ! assert their request until grant has been asserted
35
+ -- ! grant remains until request is de-asserted.
36
+ requests : in std_logic_vector ;
37
+ -- ! This block asserts grant signals, and holds them
38
+ -- ! until the the associated request signal drops.
39
+ grants : out std_logic_vector
40
+ );
41
+ end entity ;
42
+
43
+ architecture rtl of arbiter is
44
+
45
+ constant zeros : unsigned (requests'range ) := (others => '0' );
46
+ signal requests_int : unsigned (requests'range );
47
+ signal requests_masked_twos : unsigned (requests'range );
48
+ signal requests_masked : unsigned (requests'range );
49
+ signal requests_last : unsigned (requests'range );
50
+ signal grants_int : unsigned (requests'range );
51
+ signal grants_last : unsigned (requests'range );
52
+ signal grants_mask : unsigned (requests'range );
53
+ signal req_vec_f_edge : unsigned (requests'range );
54
+ signal req_f_edge : std_logic ;
55
+
56
+ begin
57
+
58
+ requests_int <= unsigned (requests);
59
+
60
+ round_robin_mode : if mode = ROUND_ROBIN generate
61
+ -- This uses a grant-masking scheme to generate round-robin grant behavior.
62
+ -- We want to mask off the previous granted channel and any lower bits
63
+ -- so the upper bits get a round-robin chance.
64
+ grants_mask <= not (grants_last or (grants_last - 1 ));
65
+
66
+ -- Mask the requests based on the current grant mask, unless we have no active requests or grants, in
67
+ -- which case, pass the unmasked vector through
68
+ requests_masked <= requests_int and grants_mask when (requests_int and grants_mask) /= 0 else
69
+ requests_int;
70
+ else generate
71
+ -- In priority mode, we needn't mask grants since the priority encoder takes over
72
+ -- and we will allow multiple grants to the same requester to the exclusion of others
73
+ -- given the desired priority.
74
+ grants_mask <= (others => '0' );
75
+ requests_masked <= requests_int;
76
+ end generate ;
77
+
78
+ -- Build two's complement, remember basic boolean math? 2's complement = (not <dat>) + 1
79
+ requests_masked_twos <= (not requests_masked) + 1 ;
80
+
81
+ fedge_detects : for i in requests_int'range generate
82
+ req_vec_f_edge(i) <= '1' when requests_int(i) = '0' and requests_last(i) = '1' else
83
+ '0' ;
84
+ end generate ;
85
+
86
+ -- Unary OR reduction, active when any bit is active
87
+ req_f_edge <= or req_vec_f_edge;
88
+
89
+ the_arbiter : process (clk)
90
+ begin
91
+ if reset then
92
+ grants_int <= zeros;
93
+ grants_last <= (others => '0' );
94
+ requests_last <= (others => '0' );
95
+ elsif rising_edge (clk) then
96
+ -- Store history for edge detector
97
+ requests_last <= requests_int;
98
+ -- To determine a grant, we take the currently active requests vector,
99
+ -- which is masked by the allowable requests in round-robbin mode, and then
100
+ -- bitwise AND that with it's two's complement
101
+ -- to get 1 bit active as our active grant.
102
+ grants_int <= requests_masked and requests_masked_twos;
103
+ if req_f_edge then
104
+ -- Note: we expect requesters of this to hold request high until they both have the grant,
105
+ -- and are finished with their current transaction. This means that falling edges of
106
+ -- requests cause arbitration updates and we save the current grant for use in round-robin
107
+ -- arbitration next time.
108
+ grants_last <= grants_int;
109
+ end if ;
110
+ end if ;
111
+ end process ;
112
+
113
+ grants <= std_logic_vector (grants_int);
114
+
115
+ end rtl ;
0 commit comments