Build works on Snow Leopard, using Arduino toolchain
[simavr] / simavr / sim / simavr.c
1 /*
2         simavr.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <getopt.h>
30 #include "simavr.h"
31 #include "sim_elf.h"
32
33 #include "sim_core.h"
34 #include "avr_eeprom.h"
35 #include "avr_uart.h"
36
37 void hdump(const char *w, uint8_t *b, size_t l)
38 {
39         uint32_t i;
40         if (l < 16) {
41                 printf("%s: ",w);
42                 for (i = 0; i < l; i++) printf("%02x",b[i]);
43         } else {
44                 printf("%s:\n",w);
45                 for (i = 0; i < l; i++) {
46                         if (!(i & 0x1f)) printf("    ");
47                         printf("%02x",b[i]);
48                         if ((i & 0x1f) == 0x1f) {
49                                 printf(" ");
50                                 printf("\n");
51                         }
52                 }
53         }
54         printf("\n");
55 }
56
57
58
59 int avr_init(avr_t * avr)
60 {
61         avr->flash = malloc(avr->flashend + 1);
62         memset(avr->flash, 0xff, avr->flashend + 1);
63         avr->data = malloc(avr->ramend + 1);
64         memset(avr->data, 0, avr->ramend + 1);
65
66         // cpu is in limbo before init is finished.
67         avr->state = cpu_Limbo;
68         avr->frequency = 1000000;       // can be overriden via avr_mcu_section
69         if (avr->init)
70                 avr->init(avr);
71         avr->state = cpu_Running;
72         avr_reset(avr); 
73         return 0;
74 }
75
76 void avr_reset(avr_t * avr)
77 {
78         memset(avr->data, 0x0, avr->ramend + 1);
79         _avr_sp_set(avr, avr->ramend);
80         avr->pc = 0;
81         for (int i = 0; i < 8; i++)
82                 avr->sreg[i] = 0;
83         if (avr->reset)
84                 avr->reset(avr);
85
86         avr_io_t * port = avr->io_port;
87         while (port) {
88                 if (port->reset)
89                         port->reset(avr, port);
90                 port = port->next;
91         }
92
93 }
94
95
96 void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
97 {
98         memcpy(avr->flash + address, code, size);
99 }
100
101 void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
102 {
103         if (addr > avr->ramend) {
104                 printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x out of ram\n",
105                                 avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
106                 CRASH();
107         }
108         if (addr < 32) {
109                 printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x low registers\n",
110                                 avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
111                 CRASH();
112         }
113 #if AVR_STACK_WATCH
114         /*
115          * this checks that the current "function" is not doctoring the stack frame that is located
116          * higher on the stack than it should be. It's a sign of code that has overrun it's stack
117          * frame and is munching on it's own return address.
118          */
119         if (avr->stack_frame_index > 1 && addr > avr->stack_frame[avr->stack_frame_index-2].sp) {
120                 printf("\e[31m%04x : munching stack SP %04x, A=%04x <= %02x\e[0m\n", avr->pc, _avr_sp_get(avr), addr, v);
121         }
122 #endif
123         avr->data[addr] = v;
124 }
125
126 uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
127 {
128         if (addr > avr->ramend) {
129                 printf("*** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n",
130                                 avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, avr->ramend);
131                 CRASH();
132         }
133         return avr->data[addr];
134 }
135
136
137 int avr_run(avr_t * avr)
138 {
139         if (avr->state == cpu_Stopped)
140                 return avr->state;
141
142         uint16_t new_pc = avr->pc;
143
144         if (avr->state == cpu_Running) {
145                 new_pc = avr_run_one(avr);
146                 avr_dump_state(avr);
147         } else
148                 avr->cycle ++;
149
150         // re-synth the SREG
151         //SREG();
152         // if we just re-enabled the interrupts...
153         if (avr->sreg[S_I] && !(avr->data[R_SREG] & (1 << S_I))) {
154         //      printf("*** %s: Renabling interrupts\n", __FUNCTION__);
155                 avr->pending_wait++;
156         }
157         avr_io_t * port = avr->io_port;
158         while (port) {
159                 if (port->run)
160                         port->run(avr, port);
161                 port = port->next;
162         }
163
164         avr->pc = new_pc;
165
166         if (avr->state == cpu_Sleeping) {
167                 if (!avr->sreg[S_I]) {
168                         printf("simavr: sleeping with interrupts off, quitting gracefuly\n");
169                         exit(0);
170                 }
171                 usleep(500);
172                 long sleep = (float)avr->frequency * (1.0f / 500.0f);
173                 avr->cycle += sleep;
174         //      avr->state = cpu_Running;
175         }
176         // Interrupt servicing might change the PC too
177         if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {
178                 avr_service_interrupts(avr);
179
180                 avr->data[R_SREG] = 0;
181                 for (int i = 0; i < 8; i++)
182                         if (avr->sreg[i] > 1) {
183                                 printf("** Invalid SREG!!\n");
184                                 CRASH();
185                         } else if (avr->sreg[i])
186                                 avr->data[R_SREG] |= (1 << i);
187         }
188         return avr->state;
189 }
190
191 extern avr_kind_t tiny85;
192 extern avr_kind_t mega48,mega88,mega168;
193 extern avr_kind_t mega644;
194
195 avr_kind_t * avr_kind[] = {
196         &tiny85,
197         &mega48,
198         &mega88,
199         &mega168,
200         &mega644,
201         NULL
202 };
203
204 void display_usage()
205 {
206         printf("usage: simavr [-t] [-m <device>] [-f <frequency>] firmware\n");
207         printf("       -t: run full scale decoder trace\n");
208         exit(1);
209 }
210
211 int main(int argc, char *argv[])
212 {
213         elf_firmware_t f;
214         long f_cpu = 0;
215         int trace = 0;
216         char name[16] = "";
217         int option_count;
218         int option_index = 0;
219
220         struct option long_options[] = {
221                 {"help", no_argument, 0, 'h'},
222                 {"mcu", required_argument, 0, 'm'},
223                 {"freq", required_argument, 0, 'f'},
224                 {"trace", no_argument, 0, 't'},
225                 {0, 0, 0, 0}
226         };
227
228         if (argc == 1)
229                 display_usage();
230
231         while ((option_count = getopt_long(argc, argv, "thm:f:", long_options, &option_index)) != -1) {
232                 switch (option_count) {
233                         case 'h':
234                                 display_usage();
235                                 break;
236                         case 'm':
237                                 strcpy(name, optarg);
238                                 break;
239                         case 'f':
240                                 f_cpu = atoi(optarg);
241                                 break;
242                         case 't':
243                                 trace++;
244                                 break;
245                 }
246         }
247
248         elf_read_firmware(argv[argc-1], &f);
249
250         if (strlen(name))
251                 strcpy(f.mmcu.name, name);
252         if (f_cpu)
253                 f.mmcu.f_cpu = f_cpu;
254
255         printf("firmware %s f=%d mmcu=%s\n", argv[argc-1], f.mmcu.f_cpu, f.mmcu.name);
256
257         avr_kind_t * maker = NULL;
258         for (int i = 0; avr_kind[i] && !maker; i++) {
259                 for (int j = 0; avr_kind[i]->names[j]; j++)
260                         if (!strcmp(avr_kind[i]->names[j], f.mmcu.name)) {
261                                 maker = avr_kind[i];
262                                 break;
263                         }
264         }
265         if (!maker) {
266                 fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name);
267                 exit(1);
268         }
269
270         avr_t * avr = maker->make();
271         printf("Starting %s - flashend %04x ramend %04x e2end %04x\n", avr->mmcu, avr->flashend, avr->ramend, avr->e2end);
272         avr_init(avr);
273         avr->frequency = f.mmcu.f_cpu;
274         avr->codeline = f.codeline;
275         avr_loadcode(avr, f.flash, f.flashsize, 0);
276         avr->codeend = f.flashsize - f.datasize;
277         if (f.eeprom && f.eesize) {
278                 avr_eeprom_desc_t d = { .ee = f.eeprom, .offset = 0, .size = f.eesize };
279                 avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
280         }
281         avr->trace = trace;
282
283         // try to enable "local echo" on the first uart, for testing purposes
284         {
285                 avr_irq_t * src = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUTPUT);
286                 avr_irq_t * dst = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_INPUT);
287                 printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst);
288                 if (src && dst)
289                         avr_connect_irq(avr, src, dst);
290         }
291
292         for (long long i = 0; i < 8000000*10; i++)
293 //      for (long long i = 0; i < 80000; i++)
294                 avr_run(avr);
295         
296 }