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

Subversion Repositories bitserial

[/] [bitserial/] [trunk/] [bit.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 howe.r.j.8
/* Bit-Serial CPU simulator
2
 * LICENSE: MIT
3
 * AUTHOR:  Richard James Howe
4
 * EMAIL:   howe.r.j.89@gmail.com
5
 * GIT:     https://github.com/howerj/bit-serial */
6
#ifdef __unix__
7
#include <sys/select.h>
8
#include <sys/ioctl.h>
9
#include <termios.h>
10
#include <unistd.h>
11
#define __USE_POSIX199309
12
#define _POSIX_C_SOURCE 199309L
13
#endif
14
#include <assert.h>
15
#include <limits.h>
16
#include <stdarg.h>
17
#include <stdint.h>
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <string.h>
21
#include <time.h>
22
 
23
#define MSIZE       (8192u)
24
#define ESCAPE      (27)
25
 
26
typedef uint16_t mw_t; /* machine word */
27
 
28
typedef struct {
29
        mw_t pc, acc, flg, m[MSIZE];
30
        FILE *in, *out;
31
        mw_t ch, leds, switches;
32
        long done, sleep_ms, sleep_every;
33
#ifdef __unix__
34
        struct termios oldattr; /* ugly, but needed for Unix only */
35
#endif
36
} bcpu_t;
37
 
38
enum { fCy, fZ, fNg, fR, fHLT, };
39
 
40
#ifdef __unix__ /* unix junk... */
41
extern int fileno(FILE *file);
42
 
43
static int os_getch(bcpu_t *b) {
44
        assert(b);
45
        return fgetc(b->in);
46
}
47
 
48
static void sleep_us(const unsigned long microseconds) {
49
        struct timespec ts = {
50
                .tv_sec  = (microseconds / 1000000ul),
51
                .tv_nsec = (microseconds % 1000000ul) * 1000ul,
52
        };
53
        nanosleep(&ts, NULL);
54
}
55
 
56
static void os_sleep_ms(bcpu_t *b, unsigned ms) {
57
        assert(b);
58
        sleep_us(ms * 1000ul);
59
}
60
 
61
static int os_kbhit(bcpu_t *b) {
62
        assert(b);
63
        const int fd = STDIN_FILENO;
64
        if (!isatty(fd))
65
                return 1;
66
        int bytes = 0;
67
        ioctl(fd, FIONREAD, &bytes);
68
        return !!bytes;
69
}
70
 
71
static int os_init(bcpu_t *b) {
72
        assert(b);
73
        const int fd = fileno(b->in);
74
        if (!isatty(fd))
75
                return 0;
76
        if (tcgetattr(fd, &b->oldattr) < 0)
77
                return -1;
78
        struct termios newattr = b->oldattr;
79
        newattr.c_iflag &= ~(ICRNL);
80
        newattr.c_lflag &= ~(ICANON | ECHO);
81
        if (tcsetattr(fd, TCSANOW, &newattr) < 0)
82
                return -2;
83
        return 0;
84
}
85
 
86
static int os_deinit(bcpu_t *b) {
87
        assert(b);
88
        if (!isatty(fileno(b->in)))
89
                return 0;
90
        return tcsetattr(fileno(b->in), TCSANOW, &b->oldattr) < 0 ? -1 : 0;
91
}
92
#else
93
#ifdef _WIN32
94
#include <windows.h>
95
extern int getch(void);
96
extern int kbhit(void);
97
static int os_getch(bcpu_t *b) { assert(b); return b->in == stdin ? getch() : fgetc(b->in); }
98
static int os_kbhit(bcpu_t *b) { assert(b); Sleep(1); return kbhit(); }
99
static void os_sleep_ms(bcpu_t *b, unsigned ms) { assert(b); Sleep(ms); }
100
static int os_init(bcpu_t *b) { assert(b); return 0; }
101
static int os_deinit(bcpu_t *b) { assert(b); return 0; }
102
#else
103
static int os_kbhit(bcpu_t *b) { assert(b); return 1; }
104
static int os_getch(bcpu_t *b) { assert(b); return fgetc(b->in); }
105
static void os_sleep_ms(bcpu_t *b, unsigned ms) { assert(b); (void)ms; }
106
static int os_init(bcpu_t *b) { assert(b); return 0; }
107
static int os_deinit(bcpu_t *b) { assert(b); return 0; }
108
#endif
109
#endif /** __unix__ **/
110
 
111
static int wrap_getch(bcpu_t *b) {
112
        assert(b);
113
        const int ch = os_getch(b);
114
        if ((ch == ESCAPE) || (ch < 0))
115
                b->done = 1;
116
        return ch;
117
}
118
 
119
static int wrap_putch(bcpu_t *b, const int ch) {
120
        assert(b);
121
        const int r = fputc(ch, b->out);
122
        if (fflush(b->out) < 0)
123
                return -1;
124
        return r;
125
}
126
 
127
static inline unsigned bits(unsigned b) {
128
        unsigned r = 0;
129
        do if (b & 1) r++; while (b >>= 1);
130
        return r;
131
}
132
 
133
static inline mw_t add(mw_t a, mw_t b, mw_t *carry) {
134
        assert(carry);
135
        const mw_t r = a + b;
136
        *carry &= ~(1u << fCy);
137
        if (r < a && r < b)
138
                *carry |= (1u << fCy);
139
        return r;
140
}
141
 
142
static inline mw_t bload(bcpu_t *b, mw_t addr) {
143
        assert(b);
144
        if (!(0x4000ul & addr))
145
                return b->m[addr % MSIZE];
146
        switch (addr & 0x7) {
147
        case 0: return b->switches;
148
        case 1: return (!os_kbhit(b) << 8ul) | (b->ch & 0xFF);
149
        }
150
        return 0;
151
}
152
 
153
static inline void bstore(bcpu_t *b, mw_t addr, mw_t val) {
154
        assert(b);
155
        if (!(0x4000ul & addr)) {
156
                if (addr >= MSIZE)
157
                        return;
158
                b->m[addr % MSIZE] = val;
159
                return;
160
        }
161
        switch (addr & 0x7) {
162
        case 0: b->leds = val; break;
163
        case 1:
164
                if (val & (1u << 13)) {
165
                        wrap_putch(b, val & 0xFFu);
166
                        fflush(b->out);
167
                }
168
                if (val & (1u << 10))
169
                        b->ch = wrap_getch(b);
170
                break;
171
        case 2: /* TX control */ break;
172
        case 3: /* RX control */ break;
173
        case 4: /* UART control */ break;
174
        }
175
}
176
 
177
static int bcpu(bcpu_t *b) {
178
        assert(b);
179
        int r = 0;
180
        mw_t * const m = b->m, pc = b->pc, acc = b->acc, flg = b->flg;
181
 
182
        for (unsigned count = 0; b->done == 0; count++) {
183
                if ((b->sleep_every && (count % b->sleep_every) == 0) && b->sleep_ms > 0)
184
                        os_sleep_ms(b, b->sleep_ms);
185
 
186
                const mw_t instr = m[pc % MSIZE];
187
                const mw_t op1   = instr & 0x0FFF;
188
                const mw_t cmd   = (instr >> 12u) & 0xFu;
189
 
190
                if (flg & (1u << fHLT))
191
                        goto halt;
192
                if (flg & (1u << fR)) {
193
                        pc  = 0;
194
                        acc = 0;
195
                        flg = 0;
196
                        continue;
197
                }
198
 
199
                flg &= ~((1u << fZ) | (1u << fNg));
200
                flg |= ((!acc) << fZ);              /* set zero flag     */
201
                flg |= ((!!(acc & 0x8000)) << fNg); /* set negative flag */
202
 
203
                const mw_t lop = (cmd & 0x8) ? op1 : bload(b, op1);
204
 
205
                pc++;
206
                switch (cmd) {
207
                case 0x0: acc |= lop;                                 break; /* OR      */
208
                case 0x1: acc &= lop;                                 break; /* AND     */
209
                case 0x2: acc ^= lop;                                 break; /* XOR     */
210
                case 0x3: acc = add(acc, lop, &flg);                  break; /* ADD     */
211
 
212
                case 0x4: acc <<= bits(lop);                          break; /* LSHIFT  */
213
                case 0x5: acc >>= bits(lop);                          break; /* RSHIFT  */
214
                case 0x6: acc = bload(b, lop);                        break; /* LOAD    */
215
                case 0x7: bstore(b, lop, acc);                        break; /* STORE   */
216
 
217
                case 0x8: acc = bload(b, op1);                        break; /* LOAD-C  */
218
                case 0x9: bstore(b, op1, acc);                        break; /* STORE-C */
219
                case 0xA: acc = op1;                                  break; /* LITERAL */
220
                case 0xB:                                             break; /* UNUSED  */
221
 
222
                case 0xC: pc = op1;                                   break; /* JUMP    */
223
                case 0xD: if (!acc) pc = op1;                         break; /* JUMPZ   */
224
                case 0xE: if (op1 & 1) flg = acc; else pc = acc;      break; /* SET     */
225
                case 0xF: if (op1 & 1) acc = flg; else acc = pc - 1u; break; /* GET     */
226
                default: r = -1; goto halt;
227
                }
228
        }
229
halt:
230
        b->pc  = pc;
231
        b->acc = acc;
232
        b->flg = flg;
233
        return r;
234
}
235
 
236
int main(int argc, char **argv) {
237
        static bcpu_t b = { .flg = 1u << fZ, .sleep_ms = 5, .sleep_every = 64 * 1024 };
238
        if (argc != 2)
239
                return 1;
240
        b.in  = stdin;
241
        b.out = stdout;
242
        FILE *in = fopen(argv[1], "rb");
243
        if (!in)
244
                return 2;
245
        for (size_t i = 0; i < MSIZE; i++) {
246
                unsigned pc = 0;
247
                if (fscanf(in, "%x", &pc) != 1)
248
                        break;
249
                b.m[i] = pc;
250
        }
251
        if (os_init(&b) < 0)
252
                return 3;
253
        setbuf(stdin,  NULL);
254
        setbuf(stdout, NULL);
255
        const int r = bcpu(&b) < 0 ? 4 : 0;
256
        if (os_deinit(&b) < 0)
257
                return 5;
258
        return r;
259
}
260
 

powered by: WebSVN 2.1.0

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