1 /*
2 * Copyright (c) 2017 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * Reduced set of HW models sufficient to run some of the sample apps
9 * and regression tests
10 */
11
12 #include <stdint.h>
13 #include <signal.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <pthread.h>
17 #include "hw_models_top.h"
18 #include "timer_model.h"
19 #include "irq_ctrl.h"
20 #include "posix_board_if.h"
21 #include "hw_counter.h"
22 #include <zephyr/arch/posix/posix_soc_if.h>
23 #include "posix_arch_internal.h"
24 #include <zephyr/sys/util.h>
25
26
27 static uint64_t simu_time; /* The actual time as known by the HW models */
28 static uint64_t end_of_time = NEVER; /* When will this device stop */
29
30 /* List of HW model timers: */
31 extern uint64_t hw_timer_timer; /* When should this timer_model be called */
32 extern uint64_t irq_ctrl_timer;
33 extern uint64_t hw_counter_timer;
34
35 static enum {
36 HWTIMER = 0,
37 IRQCNT,
38 HW_COUNTER,
39 NUMBER_OF_TIMERS,
40 NONE
41 } next_timer_index = NONE;
42
43 static uint64_t *Timer_list[NUMBER_OF_TIMERS] = {
44 &hw_timer_timer,
45 &irq_ctrl_timer,
46 &hw_counter_timer,
47 };
48
49 static uint64_t next_timer_time;
50
51 /* Have we received a SIGTERM or SIGINT */
52 static volatile sig_atomic_t signaled_end;
53
54 /**
55 * Handler for SIGTERM and SIGINT
56 */
hwm_signal_end_handler(int sig)57 void hwm_signal_end_handler(int sig)
58 {
59 signaled_end = 1;
60 }
61
62 /**
63 * Set the handler for SIGTERM and SIGINT which will cause the
64 * program to exit gracefully when they are received the 1st time
65 *
66 * Note that our handler only sets a variable indicating the signal was
67 * received, and in each iteration of the hw main loop this variable is
68 * evaluated.
69 * If for some reason (the program is stuck) we never evaluate it, the program
70 * would never exit.
71 * Therefore we set SA_RESETHAND: This way, the 2nd time the signal is received
72 * the default handler would be called to terminate the program no matter what.
73 *
74 * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809 or
75 * _XOPEN_SOURCE>=500
76 */
hwm_set_sig_handler(void)77 void hwm_set_sig_handler(void)
78 {
79 struct sigaction act;
80
81 act.sa_handler = hwm_signal_end_handler;
82 PC_SAFE_CALL(sigemptyset(&act.sa_mask));
83
84 act.sa_flags = SA_RESETHAND;
85
86 PC_SAFE_CALL(sigaction(SIGTERM, &act, NULL));
87 PC_SAFE_CALL(sigaction(SIGINT, &act, NULL));
88 }
89
90
hwm_sleep_until_next_timer(void)91 static void hwm_sleep_until_next_timer(void)
92 {
93 if (next_timer_time >= simu_time) { /* LCOV_EXCL_BR_LINE */
94 simu_time = next_timer_time;
95 } else {
96 /* LCOV_EXCL_START */
97 posix_print_warning("next_timer_time corrupted (%"PRIu64"<= %"
98 PRIu64", timer idx=%i)\n",
99 (uint64_t)next_timer_time,
100 (uint64_t)simu_time,
101 next_timer_index);
102 /* LCOV_EXCL_STOP */
103 }
104
105 if (signaled_end || (simu_time > end_of_time)) {
106 posix_print_trace("\nStopped at %.3Lfs\n",
107 ((long double)simu_time)/1.0e6L);
108 posix_exit(0);
109 }
110 }
111
112
113 /**
114 * Find in between all timers which is the next one
115 * and update next_timer_* accordingly
116 */
hwm_find_next_timer(void)117 void hwm_find_next_timer(void)
118 {
119 next_timer_index = 0;
120 next_timer_time = *Timer_list[0];
121
122 for (unsigned int i = 1; i < NUMBER_OF_TIMERS ; i++) {
123 if (next_timer_time > *Timer_list[i]) {
124 next_timer_index = i;
125 next_timer_time = *Timer_list[i];
126 }
127 }
128 }
129
130 /**
131 * Execute the next scheduled HW event/timer
132 */
hwm_one_event(void)133 void hwm_one_event(void)
134 {
135 hwm_sleep_until_next_timer();
136
137 switch (next_timer_index) { /* LCOV_EXCL_BR_LINE */
138 case HWTIMER:
139 hwtimer_timer_reached();
140 break;
141 case IRQCNT:
142 hw_irq_ctrl_timer_triggered();
143 break;
144 case HW_COUNTER:
145 hw_counter_triggered();
146 break;
147 default:
148 /* LCOV_EXCL_START */
149 posix_print_error_and_exit(
150 "next_timer_index corrupted\n");
151 break;
152 /* LCOV_EXCL_STOP */
153 }
154
155 hwm_find_next_timer();
156 }
157
158 /**
159 * Set the simulated time when the process will stop
160 */
hwm_set_end_of_time(uint64_t new_end_of_time)161 void hwm_set_end_of_time(uint64_t new_end_of_time)
162 {
163 end_of_time = new_end_of_time;
164 }
165
166 /**
167 * Return the current time as known by the device
168 */
hwm_get_time(void)169 uint64_t hwm_get_time(void)
170 {
171 return simu_time;
172 }
173
posix_get_hw_cycle(void)174 uint64_t posix_get_hw_cycle(void)
175 {
176 return hwm_get_time();
177 }
178
179 /**
180 * Function to initialize the HW models
181 */
hwm_init(void)182 void hwm_init(void)
183 {
184 hwm_set_sig_handler();
185 hwtimer_init();
186 hw_counter_init();
187 hw_irq_ctrl_init();
188
189 hwm_find_next_timer();
190 }
191
192 /**
193 * Function to free any resources allocated by the HW models
194 * Note that this function needs to be designed so it is possible
195 * to call it more than once during cleanup
196 */
hwm_cleanup(void)197 void hwm_cleanup(void)
198 {
199 hwtimer_cleanup();
200 hw_irq_ctrl_cleanup();
201 }
202