Skip to content

Commit 703623d

Browse files
authored
Merge pull request #740 from elbeno/add-id-irqs
✨ Add `id_irq` type
2 parents dbf7b1e + 469bad0 commit 703623d

File tree

4 files changed

+124
-25
lines changed

4 files changed

+124
-25
lines changed

include/interrupt/config.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ template <irq_num_t Number, priority_t Priority> struct super_config {
3939
constexpr static auto irq_number = Number;
4040
};
4141

42+
namespace fields {
43+
template <bool V> struct field_t {};
44+
template <bool V> struct op_t {};
45+
46+
template <bool V> constexpr auto read(field_t<V>) -> op_t<V> { return {}; }
47+
template <bool V> constexpr auto clear(field_t<V>) -> op_t<V> { return {}; }
48+
template <bool V> constexpr auto apply(op_t<V>) { return V; }
49+
} // namespace fields
50+
4251
template <typename EnableField, typename StatusField> struct sub_config {
4352
template <bool Enable> constexpr static auto enable() -> void {}
4453
constexpr static auto enable_field = EnableField{};
@@ -72,6 +81,9 @@ template <typename... Flows> class flow_config {
7281
};
7382
} // namespace detail
7483

84+
template <bool V = true> using enable_t = detail::fields::field_t<V>;
85+
template <bool V = true> using status_t = detail::fields::field_t<V>;
86+
7587
template <base_irq_config... Cfgs>
7688
struct root : detail::parent_config<Cfgs...> {
7789
template <typename T> using dynamic_controller_t = dynamic_controller<T>;
@@ -95,6 +107,14 @@ struct sub_irq : detail::policy_config<Policies>,
95107
template <typename... Nexi> using built_t = sub_irq_impl<sub_irq, Nexi...>;
96108
};
97109

110+
template <typename EnableField, typename Policies>
111+
struct id_irq : detail::policy_config<Policies>,
112+
detail::parent_config<>,
113+
detail::sub_config<EnableField, status_t<>> {
114+
template <typename...> using built_t = id_irq_impl<id_irq>;
115+
template <typename> constexpr static bool triggers_flow = false;
116+
};
117+
98118
template <irq_num_t Number, priority_t Priority, typename Policies,
99119
sub_irq_config... Cfgs>
100120
struct shared_irq : detail::policy_config<Policies>,

include/interrupt/impl.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ struct sub_irq_impl : Config {
5757
}
5858
};
5959

60+
template <typename Config> struct id_irq_impl : Config {
61+
constexpr static bool active = true;
62+
63+
using Config::enable_field;
64+
using Config::status_field;
65+
66+
[[nodiscard]] static auto get_interrupt_enables() {
67+
return stdx::make_tuple(enable_field);
68+
}
69+
70+
static auto run() -> void {}
71+
};
72+
6073
template <typename Config, sub_irq_interface... Subs>
6174
struct shared_irq_impl : Config {
6275
constexpr static bool active = (Subs::active or ...);

test/interrupt/dynamic_controller.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,20 @@ template <typename F> constexpr auto write(field_value_t<F> v) {
5757
struct test_flow_1_t : public flow::service<"1"> {};
5858
struct test_flow_2_t : public flow::service<"2"> {};
5959

60-
using en_field_1_t = mock_field_t<1, mock_register_t, 0, 0>;
61-
using sts_field_t = mock_field_t<2, mock_register_t, 1, 1>;
62-
using en_field_2_t = mock_field_t<3, mock_register_t, 2, 2>;
60+
using en_field_0_t = mock_field_t<1, mock_register_t, 0, 0>;
61+
using en_field_1_t = mock_field_t<1, mock_register_t, 1, 1>;
62+
using sts_field_t = mock_field_t<2, mock_register_t, 2, 2>;
63+
using en_field_2_t = mock_field_t<3, mock_register_t, 3, 3>;
6364

65+
struct test_resource_0;
6466
struct test_resource_1;
6567
struct test_resource_2;
6668

6769
using config_t = interrupt::root<interrupt::shared_irq<
6870
0_irq, 0, interrupt::policies<>,
71+
interrupt::id_irq<
72+
en_field_0_t,
73+
interrupt::policies<interrupt::required_resources<test_resource_0>>>,
6974
interrupt::sub_irq<
7075
en_field_1_t, sts_field_t,
7176
interrupt::policies<interrupt::required_resources<test_resource_1>>,
@@ -79,59 +84,74 @@ using dynamic_t = interrupt::dynamic_controller<config_t>;
7984

8085
auto reset_dynamic_state() -> void {
8186
register_value = 0;
87+
8288
dynamic_t::disable<test_flow_1_t, test_flow_2_t>();
89+
dynamic_t::turn_on_resource<test_resource_0>();
8390
dynamic_t::turn_on_resource<test_resource_1>();
8491
dynamic_t::turn_on_resource<test_resource_2>();
92+
93+
dynamic_t::enable_by_field<true, en_field_0_t>();
94+
CHECK(register_value == 0b1);
8595
}
8696
} // namespace
8797

8898
TEST_CASE("enable one irq", "[dynamic controller]") {
8999
reset_dynamic_state();
90100
dynamic_t::enable<test_flow_1_t>();
91-
CHECK(register_value == 0b1);
101+
CHECK(register_value == 0b11);
92102
}
93103

94104
TEST_CASE("enable multiple irqs", "[dynamic controller]") {
95105
reset_dynamic_state();
96106
dynamic_t::enable<test_flow_1_t, test_flow_2_t>();
97-
CHECK(register_value == 0b101);
107+
CHECK(register_value == 0b1011);
98108
}
99109

100-
TEST_CASE("disabling resource disables irq that requires it",
110+
TEST_CASE("disabling resource disables sub_irq that requires it",
101111
"[dynamic controller]") {
102112
reset_dynamic_state();
103113

104114
dynamic_t::enable<test_flow_2_t>();
105-
CHECK(register_value == 0b100);
115+
CHECK(register_value == 0b1001);
106116

107117
dynamic_t::turn_off_resource<test_resource_2>();
108-
CHECK(register_value == 0);
118+
CHECK(register_value == 0b1);
109119
dynamic_t::turn_on_resource<test_resource_2>();
110-
CHECK(register_value == 0b100);
120+
CHECK(register_value == 0b1001);
121+
}
122+
123+
TEST_CASE("disabling resource disables id_irq that requires it",
124+
"[dynamic controller]") {
125+
reset_dynamic_state();
126+
127+
dynamic_t::turn_off_resource<test_resource_0>();
128+
CHECK(register_value == 0);
129+
dynamic_t::turn_on_resource<test_resource_0>();
130+
CHECK(register_value == 0b1);
111131
}
112132

113133
TEST_CASE("disabling resource disables only irqs that require it",
114134
"[dynamic controller]") {
115135
reset_dynamic_state();
116136

117137
dynamic_t::enable<test_flow_1_t, test_flow_2_t>();
118-
CHECK(register_value == 0b101);
138+
CHECK(register_value == 0b1011);
119139

120140
dynamic_t::turn_off_resource<test_resource_2>();
121-
CHECK(register_value == 0b1);
141+
CHECK(register_value == 0b11);
122142
dynamic_t::turn_on_resource<test_resource_2>();
123-
CHECK(register_value == 0b101);
143+
CHECK(register_value == 0b1011);
124144
}
125145

126146
TEST_CASE("disable resource that multiple irqs require",
127147
"[dynamic controller]") {
128148
reset_dynamic_state();
129149

130150
dynamic_t::enable<test_flow_1_t, test_flow_2_t>();
131-
CHECK(register_value == 0b101);
151+
CHECK(register_value == 0b1011);
132152

133153
dynamic_t::turn_off_resource<test_resource_1>();
134-
CHECK(register_value == 0);
154+
CHECK(register_value == 0b1);
135155
dynamic_t::turn_on_resource<test_resource_1>();
136-
CHECK(register_value == 0b101);
156+
CHECK(register_value == 0b1011);
137157
}

test/interrupt/manager.cpp

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ using config_b = interrupt::root<
1717
interrupt::irq<17_irq, 42, interrupt::policies<>, flow_1, flow_2>>;
1818
} // namespace
1919

20-
TEST_CASE("init enables interrupts", "[flow]") {
20+
TEST_CASE("init enables interrupts", "[manager]") {
2121
auto m = interrupt::manager<config_a, test_nexus>{};
2222
inited = false;
2323
enabled<17_irq> = false;
@@ -30,7 +30,7 @@ TEST_CASE("init enables interrupts", "[flow]") {
3030
CHECK(priority<17_irq> == 42);
3131
}
3232

33-
TEST_CASE("run single flow", "[flow]") {
33+
TEST_CASE("run single flow", "[manager]") {
3434
auto m = interrupt::manager<config_a, test_nexus>{};
3535
flow_run<flow_1> = false;
3636

@@ -39,7 +39,7 @@ TEST_CASE("run single flow", "[flow]") {
3939
CHECK(flow_run<flow_1>);
4040
}
4141

42-
TEST_CASE("run multiple flows", "[flow]") {
42+
TEST_CASE("run multiple flows", "[manager]") {
4343
auto m = interrupt::manager<config_b, test_nexus>{};
4444
flow_run<flow_1> = false;
4545
flow_run<flow_2> = false;
@@ -58,7 +58,7 @@ struct alt_nexus {
5858
};
5959
} // namespace
6060

61-
TEST_CASE("run flow across multiple nexi", "[flow]") {
61+
TEST_CASE("run flow across multiple nexi", "[manager]") {
6262
auto m = interrupt::manager<config_a, test_nexus, alt_nexus>{};
6363
flow_run<flow_1> = false;
6464
flow_run<alt_flow<flow_1>> = false;
@@ -93,7 +93,7 @@ using config_shared =
9393
interrupt::irq<38_irq, 39, interrupt::policies<>, flow_38>>;
9494
} // namespace
9595

96-
TEST_CASE("init enables mcu interrupts", "[flow]") {
96+
TEST_CASE("init enables mcu interrupts", "[manager]") {
9797
auto m = interrupt::manager<config_shared, test_nexus>{};
9898
inited = false;
9999
enabled<33_irq> = false;
@@ -111,7 +111,7 @@ TEST_CASE("init enables mcu interrupts", "[flow]") {
111111
CHECK(priority<38_irq> == 39);
112112
}
113113

114-
TEST_CASE("init enables dynamic interrupts", "[flow]") {
114+
TEST_CASE("init enables dynamic interrupts", "[manager]") {
115115
auto m = interrupt::manager<config_shared, test_nexus>{};
116116
enable_field_t<33'1>::value = false;
117117
enable_field_t<33'2>::value = false;
@@ -122,7 +122,7 @@ TEST_CASE("init enables dynamic interrupts", "[flow]") {
122122
CHECK(enable_field_t<33'2>::value);
123123
}
124124

125-
TEST_CASE("run flows if sub_irq is enabled", "[flow]") {
125+
TEST_CASE("run flows if sub_irq is enabled", "[manager]") {
126126
auto m = interrupt::manager<config_shared, test_nexus>{};
127127
enable_field_t<33'1>::value = true;
128128
status_field_t<33'1>::value = true;
@@ -137,7 +137,7 @@ TEST_CASE("run flows if sub_irq is enabled", "[flow]") {
137137
CHECK(not flow_run<flow_33_2>);
138138
}
139139

140-
TEST_CASE("init enables mcu interrupt if any flow is active", "[flow]") {
140+
TEST_CASE("init enables mcu interrupt if any flow is active", "[manager]") {
141141
using config_t = root<interrupt::shared_irq<
142142
33_irq, 34, interrupt::policies<>,
143143
interrupt::sub_irq<enable_field_t<33'0>, status_field_t<33'0>,
@@ -158,7 +158,7 @@ TEST_CASE("init enables mcu interrupt if any flow is active", "[flow]") {
158158
}
159159

160160
TEST_CASE("init does not enable mcu interrupt if all flows are inactive",
161-
"[flow]") {
161+
"[manager]") {
162162
using config_t = root<interrupt::shared_irq<
163163
33_irq, 34, interrupt::policies<>,
164164
interrupt::sub_irq<enable_field_t<33'0>, status_field_t<33'0>,
@@ -191,7 +191,7 @@ using config_shared_sub = root<interrupt::shared_irq<
191191
interrupt::policies<>, flow_33_2_2>>>>;
192192
} // namespace
193193

194-
TEST_CASE("run flows for shared sub irqs if enabled", "[flow]") {
194+
TEST_CASE("run flows for shared sub irqs if enabled", "[manager]") {
195195
auto m = interrupt::manager<config_shared_sub, test_nexus>{};
196196
enable_field_t<33'1>::value = false;
197197

@@ -213,3 +213,49 @@ TEST_CASE("run flows for shared sub irqs if enabled", "[flow]") {
213213
CHECK(flow_run<flow_33_2_1>);
214214
CHECK(not flow_run<flow_33_2_2>);
215215
}
216+
217+
namespace {
218+
using config_shared_no_enable = root<interrupt::shared_irq<
219+
33_irq, 34, interrupt::policies<>,
220+
interrupt::sub_irq<interrupt::enable_t<>, status_field_t<33'1>,
221+
interrupt::policies<>, flow_33_1>>>;
222+
using config_shared_no_status = root<interrupt::shared_irq<
223+
33_irq, 34, interrupt::policies<>,
224+
interrupt::sub_irq<enable_field_t<33'1>, interrupt::status_t<>,
225+
interrupt::policies<>, flow_33_1>>>;
226+
} // namespace
227+
228+
TEST_CASE("run flows with no enable field", "[manager]") {
229+
auto m = interrupt::manager<config_shared_no_enable, test_nexus>{};
230+
status_field_t<33'1>::value = true;
231+
flow_run<flow_33_1> = false;
232+
233+
m.run<33_irq>();
234+
235+
CHECK(not status_field_t<33'2'1>::value);
236+
CHECK(flow_run<flow_33_1>);
237+
}
238+
239+
TEST_CASE("run flows with no status field", "[manager]") {
240+
auto m = interrupt::manager<config_shared_no_status, test_nexus>{};
241+
enable_field_t<33'1>::value = true;
242+
flow_run<flow_33_1> = false;
243+
244+
m.run<33_irq>();
245+
246+
CHECK(flow_run<flow_33_1>);
247+
}
248+
249+
namespace {
250+
using config_shared_id = root<interrupt::shared_irq<
251+
33_irq, 34, interrupt::policies<>,
252+
interrupt::id_irq<enable_field_t<33'0>, interrupt::policies<>>>>;
253+
} // namespace
254+
255+
TEST_CASE("init enables id interrupts", "[manager]") {
256+
auto m = interrupt::manager<config_shared_id, test_nexus>{};
257+
258+
enable_field_t<33'0>::value = false;
259+
m.init();
260+
CHECK(enable_field_t<33'0>::value);
261+
}

0 commit comments

Comments
 (0)