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

Subversion Repositories wbuart32

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

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

powered by: WebSVN 2.1.0

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