OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

[/] [eco32/] [trunk/] [sim/] [serial.c] - Blame information for rev 248

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 8 hellwig
/*
2 246 hellwig
 * serial.c -- serial line simulation
3 8 hellwig
 */
4
 
5
 
6
#ifdef __linux__
7
#define _XOPEN_SOURCE
8
#endif
9
 
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#include <setjmp.h>
14
#include <signal.h>
15
#include <sys/types.h>
16
#include <sys/wait.h>
17
#include <unistd.h>
18
#include <fcntl.h>
19
#include <termios.h>
20
 
21
#include "common.h"
22
#include "console.h"
23
#include "error.h"
24
#include "except.h"
25
#include "cpu.h"
26
#include "timer.h"
27 246 hellwig
#include "serial.h"
28 8 hellwig
 
29
 
30
/**************************************************************/
31
 
32
 
33
static Bool debug = false;
34
 
35
 
36
typedef struct {
37
  pid_t pid;
38
  FILE *in;
39
  FILE *out;
40
  Word rcvrCtrl;
41
  Word rcvrData;
42
  int rcvrIRQ;
43
  Word xmtrCtrl;
44
  Word xmtrData;
45
  int xmtrIRQ;
46 246 hellwig
} Serial;
47 8 hellwig
 
48
 
49 246 hellwig
static Serial serials[MAX_NSERIALS];
50
static int nSerials;
51 8 hellwig
 
52
 
53
/**************************************************************/
54
 
55
 
56
static void rcvrCallback(int dev) {
57
  int c;
58
 
59
  if (debug) {
60 246 hellwig
    cPrintf("\n**** SERIAL RCVR CALLBACK ****\n");
61 8 hellwig
  }
62 246 hellwig
  timerStart(SERIAL_RCVR_USEC, rcvrCallback, dev);
63
  c = fgetc(serials[dev].in);
64 8 hellwig
  if (c == EOF) {
65
    /* no character typed */
66
    return;
67
  }
68
  /* any character typed */
69 246 hellwig
  serials[dev].rcvrData = c & 0xFF;
70
  serials[dev].rcvrCtrl |= SERIAL_RCVR_RDY;
71
  if (serials[dev].rcvrCtrl & SERIAL_RCVR_IEN) {
72
    /* raise serial line rcvr interrupt */
73
    cpuSetInterrupt(serials[dev].rcvrIRQ);
74 8 hellwig
  }
75
}
76
 
77
 
78
static void xmtrCallback(int dev) {
79
  if (debug) {
80 246 hellwig
    cPrintf("\n**** SERIAL XMTR CALLBACK ****\n");
81 8 hellwig
  }
82 246 hellwig
  fputc(serials[dev].xmtrData & 0xFF, serials[dev].out);
83
  serials[dev].xmtrCtrl |= SERIAL_XMTR_RDY;
84
  if (serials[dev].xmtrCtrl & SERIAL_XMTR_IEN) {
85
    /* raise serial line xmtr interrupt */
86
    cpuSetInterrupt(serials[dev].xmtrIRQ);
87 8 hellwig
  }
88
}
89
 
90
 
91
/**************************************************************/
92
 
93
 
94 246 hellwig
Word serialRead(Word addr) {
95 8 hellwig
  int dev, reg;
96
  Word data;
97
 
98
  if (debug) {
99 246 hellwig
    cPrintf("\n**** SERIAL READ from 0x%08X", addr);
100 8 hellwig
  }
101 25 hellwig
  dev = addr >> 12;
102 246 hellwig
  if (dev >= nSerials) {
103 8 hellwig
    /* illegal device */
104
    throwException(EXC_BUS_TIMEOUT);
105
  }
106 25 hellwig
  reg = addr & 0x0FFF;
107 246 hellwig
  if (reg == SERIAL_RCVR_CTRL) {
108
    data = serials[dev].rcvrCtrl;
109 8 hellwig
  } else
110 246 hellwig
  if (reg == SERIAL_RCVR_DATA) {
111
    serials[dev].rcvrCtrl &= ~SERIAL_RCVR_RDY;
112
    if (serials[dev].rcvrCtrl & SERIAL_RCVR_IEN) {
113
      /* lower serial line rcvr interrupt */
114
      cpuResetInterrupt(serials[dev].rcvrIRQ);
115 8 hellwig
    }
116 246 hellwig
    data = serials[dev].rcvrData;
117 8 hellwig
  } else
118 246 hellwig
  if (reg == SERIAL_XMTR_CTRL) {
119
    data = serials[dev].xmtrCtrl;
120 8 hellwig
  } else
121 246 hellwig
  if (reg == SERIAL_XMTR_DATA) {
122 8 hellwig
    /* this register is write-only */
123
    throwException(EXC_BUS_TIMEOUT);
124
  } else {
125
    /* illegal register */
126
    throwException(EXC_BUS_TIMEOUT);
127
  }
128
  if (debug) {
129
    cPrintf(", data = 0x%08X ****\n", data);
130
  }
131
  return data;
132
}
133
 
134
 
135 246 hellwig
void serialWrite(Word addr, Word data) {
136 8 hellwig
  int dev, reg;
137
 
138
  if (debug) {
139 246 hellwig
    cPrintf("\n**** SERIAL WRITE to 0x%08X, data = 0x%08X ****\n",
140 8 hellwig
            addr, data);
141
  }
142 25 hellwig
  dev = addr >> 12;
143 246 hellwig
  if (dev >= nSerials) {
144 8 hellwig
    /* illegal device */
145
    throwException(EXC_BUS_TIMEOUT);
146
  }
147 25 hellwig
  reg = addr & 0x0FFF;
148 246 hellwig
  if (reg == SERIAL_RCVR_CTRL) {
149
    if (data & SERIAL_RCVR_IEN) {
150
      serials[dev].rcvrCtrl |= SERIAL_RCVR_IEN;
151 8 hellwig
    } else {
152 246 hellwig
      serials[dev].rcvrCtrl &= ~SERIAL_RCVR_IEN;
153 8 hellwig
    }
154 246 hellwig
    if (data & SERIAL_RCVR_RDY) {
155
      serials[dev].rcvrCtrl |= SERIAL_RCVR_RDY;
156 8 hellwig
    } else {
157 246 hellwig
      serials[dev].rcvrCtrl &= ~SERIAL_RCVR_RDY;
158 8 hellwig
    }
159 246 hellwig
    if ((serials[dev].rcvrCtrl & SERIAL_RCVR_IEN) != 0 &&
160
        (serials[dev].rcvrCtrl & SERIAL_RCVR_RDY) != 0) {
161
      /* raise serial line rcvr interrupt */
162
      cpuSetInterrupt(serials[dev].rcvrIRQ);
163 8 hellwig
    } else {
164 246 hellwig
      /* lower serial line rcvr interrupt */
165
      cpuResetInterrupt(serials[dev].rcvrIRQ);
166 8 hellwig
    }
167
  } else
168 246 hellwig
  if (reg == SERIAL_RCVR_DATA) {
169 8 hellwig
    /* this register is read-only */
170
    throwException(EXC_BUS_TIMEOUT);
171
  } else
172 246 hellwig
  if (reg == SERIAL_XMTR_CTRL) {
173
    if (data & SERIAL_XMTR_IEN) {
174
      serials[dev].xmtrCtrl |= SERIAL_XMTR_IEN;
175 8 hellwig
    } else {
176 246 hellwig
      serials[dev].xmtrCtrl &= ~SERIAL_XMTR_IEN;
177 8 hellwig
    }
178 246 hellwig
    if (data & SERIAL_XMTR_RDY) {
179
      serials[dev].xmtrCtrl |= SERIAL_XMTR_RDY;
180 8 hellwig
    } else {
181 246 hellwig
      serials[dev].xmtrCtrl &= ~SERIAL_XMTR_RDY;
182 8 hellwig
    }
183 246 hellwig
    if ((serials[dev].xmtrCtrl & SERIAL_XMTR_IEN) != 0 &&
184
        (serials[dev].xmtrCtrl & SERIAL_XMTR_RDY) != 0) {
185
      /* raise serial line xmtr interrupt */
186
      cpuSetInterrupt(serials[dev].xmtrIRQ);
187 8 hellwig
    } else {
188 246 hellwig
      /* lower serial line xmtr interrupt */
189
      cpuResetInterrupt(serials[dev].xmtrIRQ);
190 8 hellwig
    }
191
  } else
192 246 hellwig
  if (reg == SERIAL_XMTR_DATA) {
193
    serials[dev].xmtrData = data & 0xFF;
194
    serials[dev].xmtrCtrl &= ~SERIAL_XMTR_RDY;
195
    if (serials[dev].xmtrCtrl & SERIAL_XMTR_IEN) {
196
      /* lower serial line xmtr interrupt */
197
      cpuResetInterrupt(serials[dev].xmtrIRQ);
198 8 hellwig
    }
199 246 hellwig
    timerStart(SERIAL_XMTR_USEC, xmtrCallback, dev);
200 8 hellwig
  } else {
201
    /* illegal register */
202
    throwException(EXC_BUS_TIMEOUT);
203
  }
204
}
205
 
206
 
207
/**************************************************************/
208
 
209
 
210 246 hellwig
void serialReset(void) {
211 8 hellwig
  int i;
212
 
213 246 hellwig
  cPrintf("Resetting Serial Lines...\n");
214
  for (i = 0; i < nSerials; i++) {
215
    serials[i].rcvrCtrl = 0;
216
    serials[i].rcvrData = 0;
217
    serials[i].rcvrIRQ = IRQ_SERIAL_0_RCVR + 2 * i;
218
    timerStart(SERIAL_RCVR_USEC, rcvrCallback, i);
219
    serials[i].xmtrCtrl = SERIAL_XMTR_RDY;
220
    serials[i].xmtrData = 0;
221
    serials[i].xmtrIRQ = IRQ_SERIAL_0_XMTR + 2 * i;
222 8 hellwig
  }
223
}
224
 
225
 
226 243 hellwig
static void makeRaw(int fd) {
227
  struct termios t;
228 8 hellwig
 
229 243 hellwig
  tcgetattr(fd, &t);
230
  t.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
231
  t.c_oflag &= ~OPOST;
232
  t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
233
  t.c_cflag &= ~(CSIZE|PARENB);
234
  t.c_cflag |= CS8;
235
  tcsetattr(fd, TCSANOW, &t);
236 8 hellwig
}
237
 
238
 
239 246 hellwig
void serialInit(int numSerials, Bool connectTerminals[]) {
240 8 hellwig
  int i;
241 243 hellwig
  int master;
242
  char slavePath[100];
243
  int slave;
244
  char termTitle[100];
245
  char termSlave[100];
246 8 hellwig
 
247 246 hellwig
  nSerials = numSerials;
248
  for (i = 0; i < nSerials; i++) {
249 8 hellwig
    /* open pseudo terminal */
250 243 hellwig
    master = open("/dev/ptmx", O_RDWR | O_NONBLOCK);
251
    if (master < 0) {
252
      error("cannot open pseudo terminal master for serial line %d", i);
253 8 hellwig
    }
254 243 hellwig
    grantpt(master);
255
    unlockpt(master);
256
    strcpy(slavePath, ptsname(master));
257 8 hellwig
    if (debug) {
258 243 hellwig
      cPrintf("pseudo terminal %d: master fd = %d, slave path = '%s'\n",
259
              i, master, slavePath);
260 8 hellwig
    }
261 246 hellwig
    if (connectTerminals[i]) {
262 243 hellwig
      /* connect a terminal to the serial line */
263
      /* i.e., fork and exec a new xterm process */
264 246 hellwig
      serials[i].pid = fork();
265
      if (serials[i].pid < 0) {
266 243 hellwig
        error("cannot fork xterm process for serial line %d", i);
267
      }
268 246 hellwig
      if (serials[i].pid == 0) {
269 243 hellwig
        /* terminal process */
270
        setpgid(0, 0);
271
        close(master);
272
        /* open and configure pseudo terminal slave */
273
        slave = open(slavePath, O_RDWR | O_NONBLOCK);
274
        if (slave < 0) {
275
          error("cannot open pseudo terminal slave '%s'\n", slavePath);
276
        }
277
        makeRaw(slave);
278
        /* exec xterm */
279
        sprintf(termTitle, "ECO32 Terminal %d", i);
280
        sprintf(termSlave, "-Sab%d", slave);
281
        execlp("xterm", "xterm", "-title", termTitle, termSlave, NULL);
282
        error("cannot exec xterm process for serial line %d", i);
283
      }
284
    } else {
285
      /* leave serial line unconnected */
286 246 hellwig
      serials[i].pid = 0;
287 243 hellwig
      cPrintf("Serial line %d can be accessed by opening device '%s'.\n",
288
              i, slavePath);
289 8 hellwig
    }
290
    fcntl(master, F_SETFL, O_NONBLOCK);
291 246 hellwig
    serials[i].in = fdopen(master, "r");
292
    setvbuf(serials[i].in, NULL, _IONBF, 0);
293
    serials[i].out = fdopen(master, "w");
294
    setvbuf(serials[i].out, NULL, _IONBF, 0);
295
    if (connectTerminals[i]) {
296 243 hellwig
      /* skip the window id written by xterm */
297 246 hellwig
      while (fgetc(serials[i].in) != '\n') ;
298 243 hellwig
    }
299 8 hellwig
  }
300 246 hellwig
  serialReset();
301 8 hellwig
}
302
 
303
 
304 246 hellwig
void serialExit(void) {
305 8 hellwig
  int i;
306
 
307
  /* kill and wait for all xterm processes */
308 246 hellwig
  for (i = 0; i < nSerials; i++) {
309
    if (serials[i].pid > 0) {
310
      kill(serials[i].pid, SIGKILL);
311
      waitpid(serials[i].pid, NULL, 0);
312 8 hellwig
    }
313
  }
314
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.