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