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