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

Subversion Repositories wbuart32

[/] [wbuart32/] [trunk/] [bench/] [cpp/] [speechtest.cpp] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    speechtest.cpp
4
//
5
// Project:     wbuart32, a full featured UART with simulator
6
//
7
// Purpose:     To demonstrate a useful Verilog file which could be used as a
8
//              toplevel program later, to demo the transmit UART as it might
9
//      be commanded from a WB bus, and having a FIFO.
10
//
11
//      If all goes well, the program will write out the words of the Gettysburg
12
//      address in interactive mode.  In non-interactive mode, the program will
13
//      read its own output and report on whether or not it worked well.
14
//
15
// Creator:     Dan Gisselquist, Ph.D.
16
//              Gisselquist Technology, LLC
17
//
18
////////////////////////////////////////////////////////////////////////////////
19
//
20 26 dgisselq
// Copyright (C) 2015-2019, Gisselquist Technology, LLC
21 5 dgisselq
//
22
// This program is free software (firmware): you can redistribute it and/or
23
// modify it under the terms of  the GNU General Public License as published
24
// by the Free Software Foundation, either version 3 of the License, or (at
25
// your option) any later version.
26
//
27
// This program is distributed in the hope that it will be useful, but WITHOUT
28
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
29
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
30
// for more details.
31
//
32
// You should have received a copy of the GNU General Public License along
33
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
34
// target there if the PDF file isn't present.)  If not, see
35
// <http://www.gnu.org/licenses/> for a copy.
36
//
37
// License:     GPL, v3, as defined and found on www.gnu.org,
38
//              http://www.gnu.org/licenses/gpl.html
39
//
40
//
41
////////////////////////////////////////////////////////////////////////////////
42
//
43
//
44 18 dgisselq
#include <verilatedos.h>
45 5 dgisselq
#include <stdio.h>
46
#include <fcntl.h>
47
#include <unistd.h>
48
#include <string.h>
49
#include <time.h>
50
#include <sys/types.h>
51
#include <signal.h>
52
#include <ctype.h>
53
#include "verilated.h"
54
#include "Vspeechfifo.h"
55
#include "uartsim.h"
56
#include "verilated_vcd_c.h"
57
 
58
void    usage(void) {
59
        fprintf(stderr, "USAGE: speechtest [-i] [<matchfile>.txt]\n");
60
        fprintf(stderr, "\n"
61
"\tWhere ... \n"
62
"\t-i\tis an optional argument, instructing speechtest to run\n"
63
"\t\tinteractively.  This mode offers no checkin against any possible\n"
64
"\t\ttruth or match file.\n"
65
"\n"
66
"\t<matchfile.txt>\t is the name of a file which will be compared against\n"
67
"\t\tthe output of the simulation.  If the output matches the match\n"
68
"\t\tfile, the simulation will exit with success.  Only the number of\n"
69
"\t\tcharacters in the match file will be tested.\n\n");
70
};
71
 
72
int     main(int argc, char **argv) {
73
        Verilated::commandArgs(argc, argv);
74
        Vspeechfifo     tb;
75
        UARTSIM         *uart;
76
        int             port = 0;
77
        unsigned        setup = 25, testcount = 0, baudclocks;
78
        const char      *matchfile = "speech.txt";
79
        bool            run_interactively = false;
80
 
81
        for(int argn=1; argn<argc; argn++) {
82
                if (argv[argn][0]=='-') for(int j=1; (j<1000)&&(argv[argn][j]); j++)
83
                switch(argv[argn][j]) {
84
                        case 'i': run_interactively = true;
85
                                break;
86
                        default:
87
                                printf("Undefined option, -%c\n", argv[argn][j]);
88
                                usage();
89
                                exit(EXIT_FAILURE);
90
                } else {
91
                        matchfile = argv[argn];
92
                }
93
        }
94
 
95
        tb.i_setup = setup;
96
        baudclocks = setup & 0x0ffffff;
97
 
98
        if (run_interactively) {
99
                //
100
                // The difference between the non-interactive mode and the
101
                // interactive mode is that in the interactive mode we don't
102
                // get to observe the speech being output to stdout.  Thus,
103
                // we blindly run for a period of clocks, and then stop.
104
                //
105
                // The cool part of the interactive mode is that we can
106
                // output internals from the simulation, for the purpose of
107
                // debug by printf.  We can also dump things to a VCD file,
108
                // should you wish to run GTKwave.
109
                //
110
                uart = new UARTSIM(port);
111
                uart->setup(tb.i_setup);
112
 
113
                Verilated::traceEverOn(true);
114
                VerilatedVcdC* tfp = new VerilatedVcdC;
115
                tb.trace(tfp, 99);
116
                tfp->open("speechtrace.vcd");
117
 
118
                testcount = 0;
119 18 dgisselq
                while(testcount < baudclocks * 16 * 4096) {
120 5 dgisselq
                        // Run one tick of the clock.
121
 
122
                        tb.i_clk = 1;   // Positive edge
123
                        tb.eval();
124
                        tfp->dump(5*(2*testcount));
125
                        tb.i_clk = 0;    // Negative edge
126
                        tb.eval();
127
 
128
                        // Now, evaluate the UART, throwing away the received
129
                        // value since the SpeechTest doesnt use it.
130
                        (*uart)(tb.o_uart_tx);
131
 
132
                        tfp->dump(5*(2*testcount+1));
133
                        testcount++;
134
 
135
// #define      DEBUG
136
#ifdef  DEBUG
137
                //
138
                // Here are my notes from my last attempt at debug by printf.
139
                printf("%08x ",
140
                        tb.v__DOT__restart_counter);
141
                printf("%s %s@%d<-%08x[%c/%4d] (%s%s,%08x,%2d,%2d,%2d,%c,%s) %s,%02x >%d\n",
142
                        (tb.v__DOT__restart)?"RST":"   ",
143
                        (tb.v__DOT__wb_stb)?"STB":"   ",
144
                        (tb.v__DOT__wb_addr),
145
                        (tb.v__DOT__wb_data),
146
                                isgraph(tb.v__DOT__wb_data&0x0ff)?
147
                                        (tb.v__DOT__wb_data&0x0ff) : '.',
148
                        (tb.v__DOT__msg_index),
149
                        (tb.v__DOT__wbuarti__DOT____Vcellinp__txfifo____pinNumber2)?"RST":"   ",
150
                        (tb.v__DOT__wbuarti__DOT__txf_wb_write)?"WR":"  ",
151
                        (tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_fill),
152
                        (tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_first),
153
                        (tb.v__DOT__wbuarti__DOT__txfifo__DOT__w_first_plus_one),
154
                        (tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_last),
155
                        isgraph(tb.v__DOT__wbuarti__DOT__tx_data&0x0ff)?
156
                                        (tb.v__DOT__wbuarti__DOT__tx_data&0x0ff) : '.',
157
                        (tb.v__DOT__wbuarti__DOT____Vcellinp__txfifo____pinNumber5)?"RD":"  ",
158
                        (tb.v__DOT__wbuarti__DOT__tx_empty_n)?"TXI":"EMP",
159
                        (tb.v__DOT__wbuarti__DOT__tx_data),
160
                        (tb.o_uart_tx));
161
#endif
162
                }
163
 
164
                tfp->close();
165
 
166
                //
167
                // *IF* we ever get here, then at least explain to the user
168
                // why we stopped.
169
                //
170
                printf("\n\nSimulation complete\n");
171
        } else {
172
                //
173
                // Non-interactive mode is more difficult.  In this case, we
174
                // must figure out how to determine if the test was successful
175
                // or not.  Since uartsim dumps the UART output to standard
176
                // out, we then need to do a bit of work to capture that.
177
                //
178
                // In particular, we are going to fork ourselves and set up our
179
                // child process so that we can read from its standard out
180
                // (and write to its standard in--although we don't).
181
                int     childs_stdin[2], childs_stdout[2];
182
                FILE    *fp = fopen(matchfile, "r");
183
                long    flen = 0;
184
 
185
                //
186
                // Before forking (and getting complicated), let's read the
187
                // file describing the data we are supposed to read.  Our goal
188
                // will basically be to do an strncmp with the data in this
189
                // file, and then to check for zero (equality).
190
                //
191
                if (fp == NULL) {
192
                        fprintf(stderr, "ERR - could not open %s\n", matchfile);
193
                        perror("O/S Err:");
194
                        printf("FAIL\n");
195
                        exit(EXIT_FAILURE);
196
                }
197
 
198
                // Quick, look up how long this file is.
199
                fseek(fp, 0l, SEEK_END);
200
                flen = ftell(fp);
201
                fseek(fp, 0l, SEEK_SET);
202
 
203
                if (flen <= 0) {
204
                        if (flen == 0)
205
                                fprintf(stderr, "ERR - zero length match file!\n");
206
                        else {
207
                                fprintf(stderr, "ERR - getting file length\n");
208
                                perror("O/S Err:");
209
                        }
210
                        printf("FAIL\n");
211
                        exit(EXIT_FAILURE);
212
                }
213
 
214
 
215
                // We are ready to do our forking magic.  So, let's allocate
216
                // pipes for the childs standard input and output streams.
217
                if ((pipe(childs_stdin)!=0)||(pipe(childs_stdout) != 0)) {
218
                        fprintf(stderr, "ERR setting up child pipes\n");
219
                        perror("O/S Err:");
220
                        printf("FAIL\n");
221
                        exit(EXIT_FAILURE);
222
                }
223
 
224
 
225
                //
226
                //      FORK    !!!!!
227
                //
228
                // After this line, there are two threads running--a parent and
229
                // a child.  The childs child_pid will be zero, the parents
230
                // child_pid will be the pid of the child.
231
                pid_t   child_pid = fork();
232
 
233
                // Make sure the fork worked ...
234
                if (child_pid < 0) {
235
                        fprintf(stderr, "ERR setting up child process fork\n");
236
                        perror("O/S Err:");
237
                        printf("FAIL\n");
238
                        exit(EXIT_FAILURE);
239
                }
240
 
241
                if (child_pid) {
242
                        int     nr = -2, rd, fail;
243
 
244
                        // We are the parent
245
                        // Adjust our pipe file descriptors so that they are
246
                        // useful.
247
                        close(childs_stdin[ 0]); // Close the read end
248
                        close(childs_stdout[1]); // Close the write end
249
 
250
                        // Let's allocate some buffers to contain both our
251
                        // match file (string), and what we read from the 
252
                        // UART.  Nominally, we would only need flen+1
253
                        // characters, but this number doesn't quite work--since
254
                        // mkspeech turned all of the the LFs into CR/LF pairs.
255
                        // In the worst case, this would double the number of
256
                        // characters we would need.  Hence, we read allocate
257
                        // enough for the worst case.
258
                        char    *string = (char *)malloc((size_t)(2*flen+2)),
259
                                *rdbuf  = (char *)malloc((size_t)(2*flen+2));
260
 
261
                        // If this doesn't work, admit to a failure
262
                        if ((string == NULL)||(rdbuf == NULL)) {
263
                                fprintf(stderr, "ERR Malloc failure --- cannot allocate space to read match file\n");
264
                                perror("O/S Err:");
265
                                printf("FAIL\n");
266
                                exit(EXIT_FAILURE);
267
                        }
268
 
269
                        // Read the string we are going to match against from
270
                        // the matchfile.  Expand NLs into CR,NL pairs.  Also
271
                        // keep track of the resulting length (in flen), and
272
                        // terminate the string with a null character.
273
                        //
274
                        {
275
                                // Read string, and expand newlines into 
276
                                // CR LF pairs
277
                                char    *dp = string;
278
                                int     ch;
279
                                while((ch =fgetc(fp))!=EOF) {
280
                                        if (ch == '\n')
281
                                                *dp++ = '\r';
282
                                        *dp++ = ch;
283
                                }
284
                                *dp++ = '\0';
285
                                flen = strlen(string);
286
                        }
287
 
288
                        //
289
                        // Enough setup, let's do our work: Read a character
290
                        // from the pipe and compare it against what we are
291
                        // expecting.  Break out on any comparison failure.
292
                        //
293
                        nr = 0;
294
                        rd = 0;
295
                        fail = -1;
296
                        while((nr<flen)
297
                                &&((rd = read(childs_stdout[0],
298
                                        &rdbuf[nr], 1))>0)) {
299
                                for(int i=0; i<rd; i++)
300
                                        if (rdbuf[nr+i] != string[nr+i]) {
301
                                                fail = nr+i;
302
                                                break;
303
                                        }
304
                                if (fail>=0)
305
                                        break;
306
                                rdbuf[rd+nr] = 0;
307
                                nr += rd;
308
                        }
309
 
310
                        // Tell the user how many (of how many) characters we
311
                        // compared (that matched), for debugging purposes.
312
                        //
313
                        printf("MATCH COMPLETE, nr = %d (/ %ld)\n", nr, flen);
314
                                fflush(stdout);
315
 
316
                        kill(child_pid, SIGKILL);
317
 
318
                        free(string);
319
                        free(rdbuf);
320
 
321
                        // Report on the results, either PASS or FAIL
322
                        if (nr == flen) {
323
                                printf("PASS\n");
324
                                exit(EXIT_SUCCESS);
325
                        } else {
326
                                printf("%s\n\nDoes not match.  MISMATCH: ch[%d]=%c != %c (%02x)\nFAIL\n", rdbuf, fail, rdbuf[fail], string[fail], string[fail]);
327
                                exit(EXIT_FAILURE);
328
                        }
329
                        //
330
                        // At this point, the parent is complete, and can
331
                        // exit.
332
                } else {
333
                        //
334
                        // If childs_pid == 0, then we are the child
335
                        //
336
                        // The child reports the uart result via stdout, so
337
                        // let's make certain it points to STDOUT_FILENO.
338
                        //
339
                        close(childs_stdin[ 1]); // Close the write end
340
                        close(childs_stdout[0]); // Close the read end
341
 
342
                        // Now, adjust our stdin/stdout file numbers
343
                        // Stdin first.  (Yes, I know we arent use stdin, this
344
                        // is more for form than anything else.)
345
                        close(STDIN_FILENO);
346
                        if (dup(childs_stdin[0]) != STDIN_FILENO) {
347
                                fprintf(stderr, "Could not create childs stdin\n");
348
                                perror("O/S ERR");
349
                                exit(EXIT_FAILURE);
350
                        }
351
 
352
                        // Set up the standard out file descriptor so that it
353
                        // points to our pipe
354
                        close(STDOUT_FILENO);
355
                        if (dup(childs_stdout[1]) != STDOUT_FILENO) {
356
                                fprintf(stderr, "Could not create childs stdout\n");
357
                                perror("O/S ERR");
358
                                exit(EXIT_FAILURE);
359
                        }
360
 
361
                        // Set the UARTSIM up to producing an output to the
362
                        // STDOUT, rather than a TCP/IP port
363
                        uart = new UARTSIM(0);
364
                        // Set up our baud rate, stop bits, parity, etc.
365
                        // properly
366
                        uart->setup(tb.i_setup);
367
 
368
                        //
369
                        // Now ... we're finally ready to run our simulation.
370
                        //
371
                        // while(testcount < baudclocks * 16 * 2048)
372
                        while(testcount++ < 0x7f000000) {
373
                                // Rising edge of the clock
374
                                tb.i_clk = 1;
375
                                tb.eval();
376
                                // Negative edge of the clock
377
                                tb.i_clk = 0;
378
                                tb.eval();
379
 
380
                                // Advance the UART based upon the output
381
                                // o_uart_tx value
382
                                (*uart)(tb.o_uart_tx);
383
                        }
384
 
385
                        // We will never get here.  If all goes well, we will be
386
                        // killed as soon as we produce the speech.txt file
387
                        // output--many clocks before this.
388
 
389
                        //
390
                        // If we do get here, something is terribly wrong.
391
                        //
392
                        fprintf(stderr, "Child was never killed, did it produce any output?\n");
393
                        fprintf(stderr, "FAIL\n");
394
                        exit(EXIT_FAILURE);
395
                }
396
        }
397
}
398
 

powered by: WebSVN 2.1.0

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