- reorganized project directory structure
[z80comp2] / emu / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <signal.h>
6 #include <unistd.h>
7 #include <sched.h>
8 #include <fcntl.h>
9 #include <termios.h>
10 #include <sys/stat.h>
11 #include <sys/select.h>
12 #include <sys/mman.h>
13 #include "emu.h"
14
15 static void sighandler(int s);
16 static int parse_args(int argc, char **argv);
17
18 static const char *rom_fname = "rom";
19 static const char *termdev = "/dev/tty";
20
21 static int ttyfd;
22 static struct termios saved_term;
23 static volatile int quit;
24
25 int main(int argc, char **argv)
26 {
27         void *rom;
28         int res, fd, maxfd;
29         struct stat st;
30         struct termios term;
31         fd_set rdset;
32         struct timeval tv = {0, 0};
33
34         if(parse_args(argc, argv) == -1) {
35                 return 1;
36         }
37
38         if((fd = open(rom_fname, O_RDONLY)) == -1) {
39                 fprintf(stderr, "failed to open ROM image: %s: %s\n", rom_fname, strerror(errno));
40                 return -1;
41         }
42         fstat(fd, &st);
43
44         if((rom = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == (void*)-1) {
45                 fprintf(stderr, "failed to map ROM image\n");
46                 return -1;
47         }
48
49         if((ttyfd = open(termdev, O_RDWR)) == -1) {
50                 fprintf(stderr, "failed to open terminal device: %s: %s\n", termdev, strerror(errno));
51                 return -1;
52         }
53         if(tcgetattr(ttyfd, &term) == -1) {
54                 perror("failed to get terminal attributes");
55                 return -1;
56         }
57         saved_term = term;
58         term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
59         term.c_oflag &= ~OPOST;
60         term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
61         term.c_cflag = (term.c_cflag & ~(CSIZE | PARENB)) | CS8;
62         term.c_cc[VMIN] = 0;
63         term.c_cc[VTIME] = 1;
64         tcsetattr(ttyfd, TCSAFLUSH, &term);
65
66         if(emu_init(rom, st.st_size) == -1) {
67                 return 1;
68         }
69
70         signal(SIGINT, sighandler);
71         signal(SIGQUIT, sighandler);
72         signal(SIGTERM, sighandler);
73         signal(SIGSEGV, sighandler);
74         signal(SIGILL, sighandler);
75
76         while(!quit) {
77                 FD_ZERO(&rdset);
78                 FD_SET(ttyfd, &rdset);
79
80                 maxfd = ttyfd;
81
82                 res = select(maxfd + 1, &rdset, 0, 0, &tv);
83                 if(quit) break;
84
85                 if(res > 0) {
86                         if(FD_ISSET(ttyfd, &rdset)) {
87                                 int i, rd;
88                                 char buf[256];
89
90                                 while((rd = read(ttyfd, buf, sizeof buf)) > 0) {
91                                         for(i=0; i<rd; i++) {
92                                                 emu_serin(0, buf[i]);
93                                         }
94                                 }
95                                 if(!rd) break;  /* EOF */
96                         }
97                 }
98
99                 emu_step();
100                 sched_yield();
101         }
102
103         emu_cleanup();
104
105         tcsetattr(ttyfd, TCSAFLUSH, &saved_term);
106         return 0;
107 }
108
109 void emu_serout(int port, int c)
110 {
111         write(ttyfd, &c, 1);
112 }
113
114 static void sighandler(int s)
115 {
116         quit = 1;
117 }
118
119 static int parse_args(int argc, char **argv)
120 {
121         int i;
122
123         for(i=1; i<argc; i++) {
124                 if(argv[i][0] == '-') {
125                         if(argv[i][2] == 0) {
126                                 switch(argv[i][1]) {
127                                 case 'r':
128                                         if(!argv[++i]) {
129                                                 fprintf(stderr, "-r must be followed by a rom image file\n");
130                                                 return -1;
131                                         }
132                                         rom_fname = argv[i];
133                                         break;
134
135                                 default:
136                                         fprintf(stderr, "invalid option: %s\n", argv[i]);
137                                         return -1;
138                                 }
139                         } else {
140                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
141                                 return -1;
142                         }
143                 } else {
144                         fprintf(stderr, "unexpected argument: %s\n", argv[i]);
145                         return -1;
146                 }
147         }
148         return 0;
149 }