]> git.sesse.net Git - pistorm/blob - emulator.c
Fix indentation
[pistorm] / emulator.c
1 /*
2 Copyright 2020 Claude Schwartz
3 */
4
5 #include <assert.h>
6 #include <dirent.h>
7 #include <endian.h>
8 #include <fcntl.h>
9 #include <pthread.h>
10 #include <sched.h>
11 #include <signal.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/mman.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 #include "Gayle.h"
22 #include "ide.h"
23 #include "m68k.h"
24 #include "main.h"
25
26 //#define BCM2708_PERI_BASE        0x20000000  //pi0-1
27 //#define BCM2708_PERI_BASE     0xFE000000     //pi4
28 #define BCM2708_PERI_BASE 0x3F000000  // pi3
29 #define BCM2708_PERI_SIZE 0x01000000
30 #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
31 #define GPCLK_BASE (BCM2708_PERI_BASE + 0x101000)
32 #define GPIO_ADDR 0x200000 /* GPIO controller */
33 #define GPCLK_ADDR 0x101000
34 #define CLK_PASSWD 0x5a000000
35 #define CLK_GP0_CTL 0x070
36 #define CLK_GP0_DIV 0x074
37
38 #define SA0 5
39 #define SA1 3
40 #define SA2 2
41
42 #define STATUSREGADDR  \
43   GPIO_CLR = 1 << SA0; \
44   GPIO_CLR = 1 << SA1; \
45   GPIO_SET = 1 << SA2;
46 #define W16            \
47   GPIO_CLR = 1 << SA0; \
48   GPIO_CLR = 1 << SA1; \
49   GPIO_CLR = 1 << SA2;
50 #define R16            \
51   GPIO_SET = 1 << SA0; \
52   GPIO_CLR = 1 << SA1; \
53   GPIO_CLR = 1 << SA2;
54 #define W8             \
55   GPIO_CLR = 1 << SA0; \
56   GPIO_SET = 1 << SA1; \
57   GPIO_CLR = 1 << SA2;
58 #define R8             \
59   GPIO_SET = 1 << SA0; \
60   GPIO_SET = 1 << SA1; \
61   GPIO_CLR = 1 << SA2;
62
63 #define PAGE_SIZE (4 * 1024)
64 #define BLOCK_SIZE (4 * 1024)
65
66 #define GPIOSET(no, ishigh) \
67   do {                      \
68     if (ishigh)             \
69       set |= (1 << (no));   \
70     else                    \
71       reset |= (1 << (no)); \
72   } while (0)
73
74 #define FASTBASE 0x08000000
75 #define FASTSIZE (256 * 1024 * 1024)
76
77 #define GAYLEBASE 0xD80000
78 #define GAYLESIZE (448 * 1024)
79
80 #define KICKBASE 0xF80000
81 #define KICKSIZE (512 * 1024)
82
83 int mem_fd;
84 int mem_fd_gpclk;
85 int gayle_emulation_enabled = 1;
86 void *gpio_map;
87 void *gpclk_map;
88
89 // I/O access
90 volatile unsigned int *gpio;
91 volatile unsigned int *gpclk;
92 volatile unsigned int gpfsel0;
93 volatile unsigned int gpfsel1;
94 volatile unsigned int gpfsel2;
95 volatile unsigned int gpfsel0_o;
96 volatile unsigned int gpfsel1_o;
97 volatile unsigned int gpfsel2_o;
98
99 // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or
100 // SET_GPIO_ALT(x,y)
101 #define INP_GPIO(g) *(gpio + ((g) / 10)) &= ~(7 << (((g) % 10) * 3))
102 #define OUT_GPIO(g) *(gpio + ((g) / 10)) |= (1 << (((g) % 10) * 3))
103 #define SET_GPIO_ALT(g, a)  \
104   *(gpio + (((g) / 10))) |= \
105       (((a) <= 3 ? (a) + 4 : (a) == 4 ? 3 : 2) << (((g) % 10) * 3))
106
107 #define GPIO_SET \
108   *(gpio + 7)  // sets   bits which are 1 ignores bits which are 0
109 #define GPIO_CLR \
110   *(gpio + 10)  // clears bits which are 1 ignores bits which are 0
111
112 #define GET_GPIO(g) (*(gpio + 13) & (1 << g))  // 0 if LOW, (1<<g) if HIGH
113
114 #define GPIO_PULL *(gpio + 37)      // Pull up/pull down
115 #define GPIO_PULLCLK0 *(gpio + 38)  // Pull up/pull down clock
116
117 void setup_io();
118
119 uint32_t read8(uint32_t address);
120 void write8(uint32_t address, uint32_t data);
121
122 uint32_t read16(uint32_t address);
123 void write16(uint32_t address, uint32_t data);
124
125 void write32(uint32_t address, uint32_t data);
126 uint32_t read32(uint32_t address);
127
128 uint16_t read_reg(void);
129 void write_reg(unsigned int value);
130
131 volatile uint16_t srdata;
132 volatile uint32_t srdata2;
133 volatile uint32_t srdata2_old;
134
135 unsigned char g_kick[KICKSIZE];
136 unsigned char g_ram[FASTSIZE]; /* RAM */
137 unsigned char toggle;
138 static volatile unsigned char ovl;
139 static volatile unsigned char maprom;
140
141 void sigint_handler(int sig_num) {
142   printf("\n Exit Ctrl+C %d\n", sig_num);
143   exit(0);
144 }
145
146 void *iplThread(void *args) {
147   printf("IPL thread running/n");
148
149   while (42) {
150     if (GET_GPIO(1) == 0) {
151       toggle = 1;
152       m68k_end_timeslice();
153       //printf("thread!/n");
154     } else {
155       toggle = 0;
156     };
157     usleep(1);
158   }
159 }
160
161 int main(int argc, char *argv[]) {
162   int g;
163   const struct sched_param priority = {99};
164
165   // Some command line switch stuffles
166   for (g = 1; g < argc; g++) {
167     if (strcmp(argv[g], "--disable-gayle") == 0) {
168       gayle_emulation_enabled = 0;
169     }
170   }
171
172   sched_setscheduler(0, SCHED_FIFO, &priority);
173   mlockall(MCL_CURRENT);  // lock in memory to keep us from paging out
174
175   InitGayle();
176
177   signal(SIGINT, sigint_handler);
178   setup_io();
179
180   // Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
181   // on pi model
182   printf("Enable 200MHz GPCLK0 on GPIO4\n");
183
184   *(gpclk + (CLK_GP0_CTL / 4)) = CLK_PASSWD | (1 << 5);
185   usleep(10);
186   while ((*(gpclk + (CLK_GP0_CTL / 4))) & (1 << 7))
187     ;
188   usleep(100);
189   *(gpclk + (CLK_GP0_DIV / 4)) =
190       CLK_PASSWD | (6 << 12);  // divider , 6=200MHz on pi3
191   usleep(10);
192   *(gpclk + (CLK_GP0_CTL / 4)) =
193       CLK_PASSWD | 5 | (1 << 4);  // pll? 6=plld, 5=pllc
194   usleep(10);
195   while (((*(gpclk + (CLK_GP0_CTL / 4))) & (1 << 7)) == 0)
196     ;
197   usleep(100);
198
199   SET_GPIO_ALT(4, 0);  // gpclk0
200
201   // set SA to output
202   INP_GPIO(2);
203   OUT_GPIO(2);
204   INP_GPIO(3);
205   OUT_GPIO(3);
206   INP_GPIO(5);
207   OUT_GPIO(5);
208
209   // set gpio0 (aux0) and gpio1 (aux1) to input
210   INP_GPIO(0);
211   INP_GPIO(1);
212
213   // Set GPIO pins 6,7 and 8-23 to output
214   for (g = 6; g <= 23; g++) {
215     INP_GPIO(g);
216     OUT_GPIO(g);
217   }
218   printf("Precalculate GPIO8-23 as Output\n");
219   gpfsel0_o = *(gpio);  // store gpio ddr
220   printf("gpfsel0: %#x\n", gpfsel0_o);
221   gpfsel1_o = *(gpio + 1);  // store gpio ddr
222   printf("gpfsel1: %#x\n", gpfsel1_o);
223   gpfsel2_o = *(gpio + 2);  // store gpio ddr
224   printf("gpfsel2: %#x\n", gpfsel2_o);
225
226   // Set GPIO pins 8-23 to input
227   for (g = 8; g <= 23; g++) {
228     INP_GPIO(g);
229   }
230   printf("Precalculate GPIO8-23 as Input\n");
231   gpfsel0 = *(gpio);  // store gpio ddr
232   printf("gpfsel0: %#x\n", gpfsel0);
233   gpfsel1 = *(gpio + 1);  // store gpio ddr
234   printf("gpfsel1: %#x\n", gpfsel1);
235   gpfsel2 = *(gpio + 2);  // store gpio ddr
236   printf("gpfsel2: %#x\n", gpfsel2);
237
238   GPIO_CLR = 1 << 2;
239   GPIO_CLR = 1 << 3;
240   GPIO_SET = 1 << 5;
241
242   GPIO_SET = 1 << 6;
243   GPIO_SET = 1 << 7;
244
245   // reset cpld statemachine first
246
247   write_reg(0x01);
248   usleep(100);
249   usleep(1500);
250   write_reg(0x00);
251   usleep(100);
252
253   // load kick.rom if present
254   maprom = 1;
255   int fd = 0;
256   fd = open("kick.rom", O_RDONLY);
257   if (fd < 1) {
258     printf("Failed loading kick.rom, using motherboard kickstart\n");
259     maprom = 0;
260   } else {
261     int size = (int)lseek(fd, 0, SEEK_END);
262     if (size == 0x40000) {
263       lseek(fd, 0, SEEK_SET);
264       read(fd, &g_kick, size);
265       lseek(fd, 0, SEEK_SET);
266       read(fd, &g_kick[0x40000], size);
267     } else {
268       lseek(fd, 0, SEEK_SET);
269       read(fd, &g_kick, size);
270     }
271     printf("Loaded kick.rom with size %d kib\n", size / 1024);
272   }
273
274   // reset amiga and statemachine
275   cpu_pulse_reset();
276   ovl = 1;
277   m68k_write_memory_8(0xbfe201, 0x0001);  // AMIGA OVL
278   m68k_write_memory_8(0xbfe001, 0x0001);  // AMIGA OVL high (ROM@0x0)
279
280   usleep(1500);
281
282   m68k_init();
283   m68k_set_cpu_type(M68K_CPU_TYPE_68020);
284   m68k_pulse_reset();
285
286   if (maprom == 1) {
287     m68k_set_reg(M68K_REG_PC, 0xF80002);
288   } else {
289     m68k_set_reg(M68K_REG_PC, 0x0);
290   }
291
292   /*
293           pthread_t id;
294           int err;
295           err = pthread_create(&id, NULL, &iplThread, NULL);
296           if (err != 0)
297               printf("\ncan't create IPL thread :[%s]", strerror(err));
298           else
299               printf("\n IPL Thread created successfully\n");
300 */
301
302   m68k_pulse_reset();
303   while (42) {
304     m68k_execute(300);
305     /*
306     if (toggle == 1){
307       srdata = read_reg();
308       m68k_set_irq((srdata >> 13) & 0xff);
309     } else {
310          m68k_set_irq(0);
311     };
312     usleep(1);
313 */
314
315     if (GET_GPIO(1) == 0) {
316       srdata = read_reg();
317       m68k_set_irq((srdata >> 13) & 0xff);
318     } else {
319       if (CheckIrq() == 1) {
320         write16(0xdff09c, 0x8008);
321         m68k_set_irq(2);
322       } else
323         m68k_set_irq(0);
324     };
325   }
326
327   return 0;
328 }
329
330 void cpu_pulse_reset(void) {
331   write_reg(0x00);
332   // printf("Status Reg%x\n",read_reg());
333   usleep(100000);
334   write_reg(0x02);
335   // printf("Status Reg%x\n",read_reg());
336 }
337
338 int cpu_irq_ack(int level) {
339   printf("cpu irq ack\n");
340   return level;
341 }
342
343 unsigned int m68k_read_memory_8(unsigned int address) {
344   if (address >= FASTBASE && address < FASTBASE + FASTSIZE) {
345     return g_ram[address - FASTBASE];
346   }
347
348   if (maprom == 1) {
349     if (address >= KICKBASE && address < KICKBASE + KICKSIZE) {
350       return g_kick[address - KICKBASE];
351     }
352   }
353
354   if (gayle_emulation_enabled) {
355     if (address >= GAYLEBASE && address < GAYLEBASE + GAYLESIZE) {
356       return readGayleB(address);
357     }
358   }
359
360   address &= 0xFFFFFF;
361   //  if (address < 0xffffff) {
362   return read8((uint32_t)address);
363   //  }
364
365   //  return 1;
366 }
367
368 unsigned int m68k_read_memory_16(unsigned int address) {
369   if (address >= FASTBASE && address < FASTBASE + FASTSIZE) {
370     return be16toh(*(uint16_t *)&g_ram[address - FASTBASE]);
371   }
372
373   if (maprom == 1) {
374     if (address >= KICKBASE && address < KICKBASE + KICKSIZE) {
375       return be16toh(*(uint16_t *)&g_kick[address - KICKBASE]);
376     }
377   }
378
379   if (gayle_emulation_enabled) {
380     if (address >= GAYLEBASE && address < GAYLEBASE + GAYLESIZE) {
381       return readGayle(address);
382     }
383   }
384
385   //  if (address < 0xffffff) {
386   address &= 0xFFFFFF;
387   return (unsigned int)read16((uint32_t)address);
388   //  }
389
390   //  return 1;
391 }
392
393 unsigned int m68k_read_memory_32(unsigned int address) {
394   if (address >= FASTBASE && address < FASTBASE + FASTSIZE) {
395     return be32toh(*(uint32_t *)&g_ram[address - FASTBASE]);
396   }
397
398   if (maprom == 1) {
399     if (address >= KICKBASE && address < KICKBASE + KICKSIZE) {
400       return be32toh(*(uint32_t *)&g_kick[address - KICKBASE]);
401     }
402   }
403
404   if (gayle_emulation_enabled) {
405     if (address >= GAYLEBASE && address < GAYLEBASE + GAYLESIZE) {
406       return readGayleL(address);
407     }
408   }
409
410   //  if (address < 0xffffff) {
411   address &= 0xFFFFFF;
412   uint16_t a = read16(address);
413   uint16_t b = read16(address + 2);
414   return (a << 16) | b;
415   //  }
416
417   //  return 1;
418 }
419
420 void m68k_write_memory_8(unsigned int address, unsigned int value) {
421   if (address >= FASTBASE && address < FASTBASE + FASTSIZE) {
422     g_ram[address - FASTBASE] = value;
423     return;
424   }
425
426   if (gayle_emulation_enabled) {
427     if (address >= GAYLEBASE && address < GAYLEBASE + GAYLESIZE) {
428       writeGayleB(address, value);
429       return;
430     }
431   }
432   /*
433   if (address == 0xbfe001) {
434     ovl = (value & (1 << 0));
435     printf("OVL:%x\n", ovl);
436   }
437 */
438   //  if (address < 0xffffff) {
439   address &= 0xFFFFFF;
440   write8((uint32_t)address, value);
441   return;
442   //  }
443
444   //  return;
445 }
446
447 void m68k_write_memory_16(unsigned int address, unsigned int value) {
448   if (address >= FASTBASE && address < FASTBASE + FASTSIZE) {
449     *(uint16_t *)&g_ram[address - FASTBASE] = htobe16(value);
450     return;
451   }
452
453   if (gayle_emulation_enabled) {
454     if (address >= GAYLEBASE && address < GAYLEBASE + GAYLESIZE) {
455       writeGayle(address, value);
456       return;
457     }
458   }
459
460   //  if (address < 0xffffff) {
461   address &= 0xFFFFFF;
462   write16((uint32_t)address, value);
463   return;
464   //  }
465   //  return;
466 }
467
468 void m68k_write_memory_32(unsigned int address, unsigned int value) {
469   if (address >= FASTBASE && address < FASTBASE + FASTSIZE) {
470     *(uint32_t *)&g_ram[address - FASTBASE] = htobe32(value);
471     return;
472   }
473
474   if (gayle_emulation_enabled) {
475     if (address >= GAYLEBASE && address < GAYLEBASE + GAYLESIZE) {
476       writeGayleL(address, value);
477     }
478   }
479
480   //  if (address < 0xffffff) {
481   address &= 0xFFFFFF;
482   write16(address, value >> 16);
483   write16(address + 2, value);
484   return;
485   //  }
486
487   //  return;
488 }
489
490 void write16(uint32_t address, uint32_t data) {
491   uint32_t addr_h_s = (address & 0x0000ffff) << 8;
492   uint32_t addr_h_r = (~address & 0x0000ffff) << 8;
493   uint32_t addr_l_s = (address >> 16) << 8;
494   uint32_t addr_l_r = (~address >> 16) << 8;
495   uint32_t data_s = (data & 0x0000ffff) << 8;
496   uint32_t data_r = (~data & 0x0000ffff) << 8;
497
498   //      asm volatile ("dmb" ::: "memory");
499   W16
500       *(gpio) = gpfsel0_o;
501   *(gpio + 1) = gpfsel1_o;
502   *(gpio + 2) = gpfsel2_o;
503
504   *(gpio + 7) = addr_h_s;
505   *(gpio + 10) = addr_h_r;
506   GPIO_CLR = 1 << 7;
507   GPIO_SET = 1 << 7;
508
509   *(gpio + 7) = addr_l_s;
510   *(gpio + 10) = addr_l_r;
511   GPIO_CLR = 1 << 7;
512   GPIO_SET = 1 << 7;
513
514   // write phase
515   *(gpio + 7) = data_s;
516   *(gpio + 10) = data_r;
517   GPIO_CLR = 1 << 7;
518   GPIO_SET = 1 << 7;
519
520   *(gpio) = gpfsel0;
521   *(gpio + 1) = gpfsel1;
522   *(gpio + 2) = gpfsel2;
523   while ((GET_GPIO(0)))
524     ;
525   //     asm volatile ("dmb" ::: "memory");
526 }
527
528 void write8(uint32_t address, uint32_t data) {
529   if ((address & 1) == 0)
530     data = data + (data << 8);  // EVEN, A0=0,UDS
531   else
532     data = data & 0xff;  // ODD , A0=1,LDS
533   uint32_t addr_h_s = (address & 0x0000ffff) << 8;
534   uint32_t addr_h_r = (~address & 0x0000ffff) << 8;
535   uint32_t addr_l_s = (address >> 16) << 8;
536   uint32_t addr_l_r = (~address >> 16) << 8;
537   uint32_t data_s = (data & 0x0000ffff) << 8;
538   uint32_t data_r = (~data & 0x0000ffff) << 8;
539
540   //   asm volatile ("dmb" ::: "memory");
541   W8
542       *(gpio) = gpfsel0_o;
543   *(gpio + 1) = gpfsel1_o;
544   *(gpio + 2) = gpfsel2_o;
545
546   *(gpio + 7) = addr_h_s;
547   *(gpio + 10) = addr_h_r;
548   GPIO_CLR = 1 << 7;
549   GPIO_SET = 1 << 7;
550
551   *(gpio + 7) = addr_l_s;
552   *(gpio + 10) = addr_l_r;
553   GPIO_CLR = 1 << 7;
554   GPIO_SET = 1 << 7;
555
556   // write phase
557   *(gpio + 7) = data_s;
558   *(gpio + 10) = data_r;
559   GPIO_CLR = 1 << 7;
560   GPIO_SET = 1 << 7;
561
562   *(gpio) = gpfsel0;
563   *(gpio + 1) = gpfsel1;
564   *(gpio + 2) = gpfsel2;
565   while ((GET_GPIO(0)))
566     ;
567   //   asm volatile ("dmb" ::: "memory");
568 }
569
570 uint32_t read16(uint32_t address) {
571   volatile int val;
572   uint32_t addr_h_s = (address & 0x0000ffff) << 8;
573   uint32_t addr_h_r = (~address & 0x0000ffff) << 8;
574   uint32_t addr_l_s = (address >> 16) << 8;
575   uint32_t addr_l_r = (~address >> 16) << 8;
576
577   //   asm volatile ("dmb" ::: "memory");
578   R16
579       *(gpio) = gpfsel0_o;
580   *(gpio + 1) = gpfsel1_o;
581   *(gpio + 2) = gpfsel2_o;
582
583   *(gpio + 7) = addr_h_s;
584   *(gpio + 10) = addr_h_r;
585   GPIO_CLR = 1 << 7;
586   GPIO_SET = 1 << 7;
587
588   *(gpio + 7) = addr_l_s;
589   *(gpio + 10) = addr_l_r;
590   GPIO_CLR = 1 << 7;
591   GPIO_SET = 1 << 7;
592
593   // read phase
594   *(gpio) = gpfsel0;
595   *(gpio + 1) = gpfsel1;
596   *(gpio + 2) = gpfsel2;
597   GPIO_CLR = 1 << 6;
598   while (!(GET_GPIO(0)))
599     ;
600   GPIO_CLR = 1 << 6;
601   val = *(gpio + 13);
602   GPIO_SET = 1 << 6;
603   //    asm volatile ("dmb" ::: "memory");
604   return (val >> 8) & 0xffff;
605 }
606
607 uint32_t read8(uint32_t address) {
608   int val;
609   uint32_t addr_h_s = (address & 0x0000ffff) << 8;
610   uint32_t addr_h_r = (~address & 0x0000ffff) << 8;
611   uint32_t addr_l_s = (address >> 16) << 8;
612   uint32_t addr_l_r = (~address >> 16) << 8;
613
614   //    asm volatile ("dmb" ::: "memory");
615   R8
616       *(gpio) = gpfsel0_o;
617   *(gpio + 1) = gpfsel1_o;
618   *(gpio + 2) = gpfsel2_o;
619
620   *(gpio + 7) = addr_h_s;
621   *(gpio + 10) = addr_h_r;
622   GPIO_CLR = 1 << 7;
623   GPIO_SET = 1 << 7;
624
625   *(gpio + 7) = addr_l_s;
626   *(gpio + 10) = addr_l_r;
627   GPIO_CLR = 1 << 7;
628   GPIO_SET = 1 << 7;
629
630   // read phase
631   *(gpio) = gpfsel0;
632   *(gpio + 1) = gpfsel1;
633   *(gpio + 2) = gpfsel2;
634
635   GPIO_CLR = 1 << 6;
636   while (!(GET_GPIO(0)))
637     ;
638   GPIO_CLR = 1 << 6;
639   val = *(gpio + 13);
640   GPIO_SET = 1 << 6;
641   //    asm volatile ("dmb" ::: "memory");
642
643   val = (val >> 8) & 0xffff;
644   if ((address & 1) == 0)
645     return (val >> 8) & 0xff;  // EVEN, A0=0,UDS
646   else
647     return val & 0xff;  // ODD , A0=1,LDS
648 }
649
650 /******************************************************/
651
652 void write_reg(unsigned int value) {
653   STATUSREGADDR
654   *(gpio) = gpfsel0_o;
655   *(gpio + 1) = gpfsel1_o;
656   *(gpio + 2) = gpfsel2_o;
657   *(gpio + 7) = (value & 0xffff) << 8;
658   *(gpio + 10) = (~value & 0xffff) << 8;
659   GPIO_CLR = 1 << 7;
660   GPIO_CLR = 1 << 7;  // delay
661   GPIO_SET = 1 << 7;
662   GPIO_SET = 1 << 7;
663   // Bus HIGH-Z
664   *(gpio) = gpfsel0;
665   *(gpio + 1) = gpfsel1;
666   *(gpio + 2) = gpfsel2;
667 }
668
669 uint16_t read_reg(void) {
670   uint32_t val;
671   STATUSREGADDR
672   // Bus HIGH-Z
673   *(gpio) = gpfsel0;
674   *(gpio + 1) = gpfsel1;
675   *(gpio + 2) = gpfsel2;
676   GPIO_CLR = 1 << 6;
677   GPIO_CLR = 1 << 6;  // delay
678   GPIO_CLR = 1 << 6;
679   GPIO_CLR = 1 << 6;
680   val = *(gpio + 13);
681   GPIO_SET = 1 << 6;
682   return (uint16_t)(val >> 8);
683 }
684
685 //
686 // Set up a memory regions to access GPIO
687 //
688 void setup_io() {
689   /* open /dev/mem */
690   if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
691     printf("can't open /dev/mem \n");
692     exit(-1);
693   }
694
695   /* mmap GPIO */
696   gpio_map = mmap(
697       NULL,                    // Any adddress in our space will do
698       BCM2708_PERI_SIZE,       // Map length
699       PROT_READ | PROT_WRITE,  // Enable reading & writting to mapped memory
700       MAP_SHARED,              // Shared with other processes
701       mem_fd,                  // File to map
702       BCM2708_PERI_BASE        // Offset to GPIO peripheral
703   );
704
705   close(mem_fd);  // No need to keep mem_fd open after mmap
706
707   if (gpio_map == MAP_FAILED) {
708     printf("gpio mmap error %d\n", (int)gpio_map);  // errno also set!
709     exit(-1);
710   }
711
712   gpio = ((volatile unsigned *)gpio_map) + GPIO_ADDR / 4;
713   gpclk = ((volatile unsigned *)gpio_map) + GPCLK_ADDR / 4;
714
715 }  // setup_io