Merge pull request #10 from the-real-orca/mingw
[simavr] / tests / tests.c
1 #include "tests.h"
2 #include "sim_avr.h"
3 #include "sim_elf.h"
4 #include "sim_core.h"
5 #include "avr_uart.h"
6 #include <stdio.h>
7 #include <setjmp.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <unistd.h>
12
13 avr_cycle_count_t tests_cycle_count = 0;
14 int tests_disable_stdout = 1;
15
16 static char *test_name = "(uninitialized test)";
17 static int finished = 0;
18
19 #ifdef __MINGW32__
20 #define restore_stderr()        {}
21 #define map_stderr()            {}
22 #else
23 static FILE *orig_stderr = NULL;
24 #define restore_stderr()        { if (orig_stderr) stderr = orig_stderr; }
25 #define map_stderr()            { if (tests_disable_stdout) { \
26                                                                 orig_stderr = stderr;   \
27                                                                 fclose(stdout);                 \
28                                                                 stderr = stdout;                \
29                                                         } }
30 #endif
31                 
32 static void atexit_handler(void) {
33         if (!finished)
34                 _fail(NULL, 0, "Test exit without indicating success.");
35 }
36
37 void tests_success(void) {
38         restore_stderr();
39         fprintf(stderr, "OK: %s\n", test_name);
40         finished = 1;
41 }
42
43 void tests_init(int argc, char **argv) {
44         test_name = strdup(argv[0]);
45         atexit(atexit_handler);
46 }
47
48 static avr_cycle_count_t
49 cycle_timer_longjmp_cb(struct avr_t *avr, avr_cycle_count_t when, void *param) {
50         jmp_buf *jmp = param;
51         longjmp(*jmp, LJR_CYCLE_TIMER);
52         return 0;       // clear warning
53 }
54
55 static jmp_buf *special_deinit_jmpbuf = NULL;
56
57 static void special_deinit_longjmp_cb(struct avr_t *avr) {
58         if (special_deinit_jmpbuf)
59                 longjmp(*special_deinit_jmpbuf, LJR_SPECIAL_DEINIT);
60 }
61
62 static int my_avr_run(avr_t * avr)
63 {
64         if (avr->state == cpu_Stopped)
65                 return avr->state;
66
67         uint16_t new_pc = avr->pc;
68
69         if (avr->state == cpu_Running)
70                 new_pc = avr_run_one(avr);
71
72         // if we just re-enabled the interrupts...
73         // double buffer the I flag, to detect that edge
74         if (avr->sreg[S_I] && !avr->i_shadow)
75                 avr->interrupts.pending_wait++;
76         avr->i_shadow = avr->sreg[S_I];
77
78         // run the cycle timers, get the suggested sleep time
79         // until the next timer is due
80         avr_cycle_count_t sleep = avr_cycle_timer_process(avr);
81
82         avr->pc = new_pc;
83
84         if (avr->state == cpu_Sleeping) {
85                 if (!avr->sreg[S_I]) {
86                         printf("simavr: sleeping with interrupts off, quitting gracefully\n");
87                         avr_terminate(avr);
88                         fail("Test case error: special_deinit() returned?");
89                         exit(0);
90                 }
91                 /*
92                  * try to sleep for as long as we can (?)
93                  */
94                 // uint32_t usec = avr_cycles_to_usec(avr, sleep);
95                 // printf("sleep usec %d cycles %d\n", usec, sleep);
96                 // usleep(usec);
97                 avr->cycle += 1 + sleep;
98         }
99         // Interrupt servicing might change the PC too, during 'sleep'
100         if (avr->state == cpu_Running || avr->state == cpu_Sleeping)
101                 avr_service_interrupts(avr);
102         
103         // if we were stepping, use this state to inform remote gdb
104
105         return avr->state;
106 }
107
108 avr_t *tests_init_avr(const char *elfname) {
109         tests_cycle_count = 0;
110         map_stderr();
111         
112         elf_firmware_t fw;
113         if (elf_read_firmware(elfname, &fw))
114                 fail("Failed to read ELF firmware \"%s\"", elfname);
115         avr_t *avr = avr_make_mcu_by_name(fw.mmcu);
116         if (!avr)
117                 fail("Creating AVR failed.");
118         avr_init(avr);
119         avr_load_firmware(avr, &fw);
120         return avr;
121 }
122
123 int tests_run_test(avr_t *avr, unsigned long run_usec) {
124         if (!avr)
125                 fail("Internal test error: avr == NULL in run_test()");
126         // register a cycle timer to fire after 100 seconds (simulation time);
127         // assert that the simulation has not finished before that.
128         jmp_buf jmp;
129         special_deinit_jmpbuf = &jmp;
130         avr->special_deinit = special_deinit_longjmp_cb;
131         avr_cycle_timer_register_usec(avr, run_usec,
132                                       cycle_timer_longjmp_cb, &jmp);
133         int reason = setjmp(jmp);
134         tests_cycle_count = avr->cycle;
135         if (reason == 0) {
136                 // setjmp() returned directly, run avr
137                 while (1)
138                         my_avr_run(avr);
139         } else if (reason == 1) {
140                 // returned from longjmp(); cycle timer fired
141                 return reason;
142         } else if (reason == 2) {
143                 // returned from special deinit, avr stopped
144                 return reason;
145         }
146         fail("Error in test case: Should never reach this.");
147         return 0;       
148 }
149
150 int tests_init_and_run_test(const char *elfname, unsigned long run_usec) {
151         avr_t *avr = tests_init_avr(elfname);
152         return tests_run_test(avr, run_usec);
153 }
154
155 struct output_buffer {
156         char *str;
157         int currlen;
158         int alloclen;
159         int maxlen;
160 };
161
162 /* static void buf_output_cb(avr_t *avr, avr_io_addr_t addr, uint8_t v, */
163 /*                        void *param) { */
164 static void buf_output_cb(struct avr_irq_t *irq, uint32_t value, void *param) {
165         struct output_buffer *buf = param;
166         if (!buf)
167                 fail("Internal error: buf == NULL in buf_output_cb()");
168         if (buf->currlen > buf->alloclen-1)
169                 fail("Internal error");
170         if (buf->alloclen == 0)
171                 fail("Internal error");
172         if (buf->currlen == buf->alloclen-1) {
173                 buf->alloclen *= 2;
174                 buf->str = realloc(buf->str, buf->alloclen);
175         }
176         buf->str[buf->currlen++] = value;
177         buf->str[buf->currlen] = 0;
178 }
179
180 static void init_output_buffer(struct output_buffer *buf) {
181         buf->str = malloc(128);
182         buf->str[0] = 0;
183         buf->currlen = 0;
184         buf->alloclen = 128;
185         buf->maxlen = 4096;
186 }
187
188 void tests_assert_uart_receive_avr(avr_t *avr,
189                                unsigned long run_usec,
190                                const char *expected,
191                                char uart) {
192         struct output_buffer buf;
193         init_output_buffer(&buf);
194
195         avr_irq_register_notify(avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT),
196                                 buf_output_cb, &buf);
197         enum tests_finish_reason reason = tests_run_test(avr, run_usec);
198         if (reason == LJR_CYCLE_TIMER) {
199                 if (strcmp(buf.str, expected) == 0) {
200                         _fail(NULL, 0, "Simulation did not finish within %lu simulated usec. "
201                              "UART output is correct and complete.", run_usec);
202                 }
203                 _fail(NULL, 0, "Simulation did not finish within %lu simulated usec. "
204                      "UART output so far: \"%s\"", run_usec, buf.str);
205         }
206         if (strcmp(buf.str, expected) != 0)
207                 _fail(NULL, 0, "UART outputs differ: expected \"%s\", got \"%s\"", expected, buf.str);
208 }
209
210 void tests_assert_uart_receive(const char *elfname,
211                                unsigned long run_usec,
212                                const char *expected,
213                                char uart) {
214         avr_t *avr = tests_init_avr(elfname);
215
216         tests_assert_uart_receive_avr(avr,
217                                run_usec,
218                                expected,
219                                uart);
220 }
221
222 void tests_assert_cycles_at_least(unsigned long n) {
223         if (tests_cycle_count < n)
224                 _fail(NULL, 0, "Program ran for too few cycles (%"
225                       PRI_avr_cycle_count " < %lu)", tests_cycle_count, n);
226 }
227
228 void tests_assert_cycles_at_most(unsigned long n) {
229         if (tests_cycle_count > n)
230                 _fail(NULL, 0, "Program ran for too many cycles (%"
231                       PRI_avr_cycle_count " > %lu)", tests_cycle_count, n);
232 }
233
234 void tests_assert_cycles_between(unsigned long min, unsigned long max) {
235         tests_assert_cycles_at_least(min);
236         tests_assert_cycles_at_most(max);
237 }
238
239 void _fail(const char *filename, int linenum, const char *fmt, ...) {
240         restore_stderr();
241
242         if (filename)
243                 fprintf(stderr, "%s:%d: ", filename, linenum);
244
245         fprintf(stderr, "Test ");
246         if (test_name)
247                 fprintf(stderr, "%s ", test_name);
248         fprintf(stderr, "FAILED.\n");
249
250         if (filename)
251                 fprintf(stderr, "%s:%d: ", filename, linenum);
252
253         va_list va;
254         va_start(va, fmt);
255         vfprintf(stderr, fmt, va);
256         putc('\n', stderr);
257
258         finished = 1;
259         _exit(1);
260 }