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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [sim/] [verilator/] [div_tb.cpp] - Blame information for rev 209

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 209 dgisselq
////////////////////////////////////////////////////////////////////////////////
2 204 dgisselq
//
3
// Filename:    div_tb.cpp
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7
// Purpose:     Bench testing for the divide unit found within the Zip CPU.
8
//
9
//
10
// Creator:     Dan Gisselquist, Ph.D.
11
//              Gisselquist Technology, LLC
12
//
13 209 dgisselq
////////////////////////////////////////////////////////////////////////////////
14 204 dgisselq
//
15
// Copyright (C) 2015, Gisselquist Technology, LLC
16
//
17
// This program is free software (firmware): you can redistribute it and/or
18
// modify it under the terms of  the GNU General Public License as published
19
// by the Free Software Foundation, either version 3 of the License, or (at
20
// your option) any later version.
21
//
22
// This program is distributed in the hope that it will be useful, but WITHOUT
23
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25
// for more details.
26
//
27 209 dgisselq
// You should have received a copy of the GNU General Public License along
28
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
29
// target there if the PDF file isn't present.)  If not, see
30
// <http://www.gnu.org/licenses/> for a copy.
31
//
32 204 dgisselq
// License:     GPL, v3, as defined and found on www.gnu.org,
33
//              http://www.gnu.org/licenses/gpl.html
34
//
35
//
36 209 dgisselq
////////////////////////////////////////////////////////////////////////////////
37 204 dgisselq
//
38
//
39
#include <signal.h>
40
#include <stdint.h>
41
#include <time.h>
42
#include <unistd.h>
43
#include <assert.h>
44
 
45
#include <ctype.h>
46
 
47
#include "verilated.h"
48
#include "Vdiv.h"
49
 
50 209 dgisselq
#ifdef  NEW_VERILATOR
51
#define VVAR(A) div__DOT_ ## A
52
#else
53
#define VVAR(A) v__DOT_ ## A
54
#endif
55
 
56
#define r_busy          VVAR(_r_busy)
57
#define pre_sign        VVAR(_pre_sign)
58
#define r_sign          VVAR(_r_sign)
59
#define r_z             VVAR(_r_z)
60
#define r_bit           VVAR(_r_bit)
61
#define last_bit        VVAR(_last_bit)
62
#define r_dividend      VVAR(_r_dividend)
63
#define r_divisor       VVAR(_r_divisor)
64
#define vdiff           VVAR(_diff)
65
 
66 204 dgisselq
#include "testb.h"
67
// #include "twoc.h"
68
 
69 207 dgisselq
#define DIVASSERT(A) do { if (!(A)) { closetrace(); } assert(A); } while(0)
70
 
71 204 dgisselq
class   DIV_TB : public TESTB<Vdiv> {
72
public:
73
        DIV_TB(void) {
74
        }
75
 
76
        ~DIV_TB(void) {}
77
 
78
        void    reset(void) {
79
                // m_flash.debug(false);
80
                TESTB<Vdiv>::reset();
81
        }
82
 
83
        void    bprint(char *str, int nbits, unsigned long v) {
84
                while(*str)
85
                        str++;
86
                for(int i=0; i<nbits; i++) {
87
                        if ((1l<<(nbits-1-i))&v)
88
                                *str++ = '1';
89
                        else
90
                                *str++ = '0';
91
                        if (((nbits-1-i)&3)==0)
92
                                *str++ = ' ';
93
                } *str = '\0';
94
        }
95
 
96
        void    dbgdump(void) {
97
                char    outstr[2048], *s;
98 209 dgisselq
                sprintf(outstr, "Tick %4lld %s%s%s%s%s%s%s %2d(%s= 0)",
99
                        (unsigned long long)m_tickcount,
100 204 dgisselq
                        (m_core->o_busy)?"B":" ",
101 209 dgisselq
                        (m_core->r_busy)?"R":" ",
102 204 dgisselq
                        (m_core->o_valid)?"V":" ",
103
                        (m_core->i_wr)?"W":" ",
104 209 dgisselq
                        (m_core->pre_sign)?"+":" ",
105
                        (m_core->r_sign)?"-":" ",
106
                        (m_core->r_z)?"Z":" ",
107
                        m_core->r_bit,
108
                        (m_core->last_bit)?"=":"!");
109 204 dgisselq
                s = &outstr[strlen(outstr)];
110
                sprintf(s, "%s\n%10s %40s",s, "Div","");
111
                        s = &s[strlen(s)];
112 209 dgisselq
                bprint( s, 32, m_core->r_dividend);
113 204 dgisselq
                        s=&s[strlen(s)];
114
                sprintf(s, "%s\n%10s ",s, "Div"); s = &s[strlen(s)];
115 209 dgisselq
                bprint( s, 64, m_core->r_divisor);
116 204 dgisselq
                        s=&s[strlen(s)];
117
                sprintf(s, "%s\n%10s %40s",s, "Q",""); s=&s[strlen(s)];
118
                bprint( s, 32, m_core->o_quotient); s = &s[strlen(s)];
119
                sprintf(s, "%s\n%10s %38s",s, "Diff","");
120
                        s=&s[strlen(s)];
121 209 dgisselq
                bprint( s, 33, m_core->vdiff); s = &s[strlen(s)];
122 204 dgisselq
                strcat(s, "\n");
123
                puts(outstr);
124
        }
125
 
126
        void    tick(void) {
127
                bool    debug = false;
128
 
129
                if (debug)
130
                        dbgdump();
131
                TESTB<Vdiv>::tick();
132
        }
133
 
134
        void    divtest(uint32_t n, uint32_t d, uint32_t ans, bool issigned) {
135
                const bool      dbg = false;
136
 
137
                // The test bench is supposed to assert that we are idle when
138
                // we come in here.
139 207 dgisselq
                DIVASSERT(m_core->o_busy == 0);
140 204 dgisselq
 
141
                // Request a divide
142 209 dgisselq
                m_core->i_reset = 0;
143 204 dgisselq
                m_core->i_wr = 1;
144
                m_core->i_signed = (issigned)?1:0;
145
                m_core->i_numerator = n;
146
                m_core->i_denominator = d;
147
 
148
                // Tick once for the request to be registered
149
                tick();
150
 
151
                // Clear the input lines.
152
                m_core->i_wr = 0;
153
                m_core->i_signed = 0;
154
                m_core->i_numerator = 0;
155
                m_core->i_denominator = 0;
156
 
157
                // Make certain busy is immediately true upon the first clock
158
                // after we issue the divide, and that our result is not also
159
                // listed as a valid result.
160
                if (!m_core->o_busy) {
161
                        closetrace();
162 207 dgisselq
                        DIVASSERT(m_core->o_busy);
163 204 dgisselq
                } if (m_core->o_valid != 0) {
164
                        closetrace();
165 207 dgisselq
                        DIVASSERT(m_core->o_valid == 0);
166 204 dgisselq
                }
167
 
168
                // while((!m_core->o_valid)&&(!m_core->o_err))
169
                while(!m_core->o_valid) {
170
                        // If we aren't yet valid, we'd better at least
171
                        // be busy--the CPU requires this.
172
                        if (!m_core->o_busy) {
173
                                // We aren't valid, and we aren't busy.  This
174
                                // is a test failure.
175
                                dbgdump();
176
                                closetrace();
177 207 dgisselq
                                DIVASSERT(m_core->o_busy);
178 204 dgisselq
                        }
179
 
180
                        // Let the algorithm work for another clock tick.
181
                        tick();
182
                } if (dbg) dbgdump();
183
 
184
                // Insist that the core not be busy any more, now that a valid
185
                // result has been produced.
186
                if (m_core->o_busy) {
187
                        closetrace();
188 207 dgisselq
                        DIVASSERT(!m_core->o_busy);
189 204 dgisselq
                }
190
 
191
                if (dbg) {
192
                        printf("%s%s: %d / %d =? %d\n",
193
                                (m_core->o_valid)?"V":" ",
194
                                (m_core->o_err)?"E":" ",
195
                                n, d, m_core->o_quotient);
196
                }
197
 
198
 
199
                // Now that we're done, we need to check the result.
200
                //
201
                // First case to check: was there an error condition or, if not,
202
                // should there have been one?
203
                if (d == 0) {
204
                        // We attempted to divide by zero, the result should've
205
                        // been an error condition.  Let's check:
206
                        // Then insist on a division by zero error
207
                        if (!m_core->o_err) {
208
                                // Don't forget to close the trace before the
209
                                // assert, lest the file not get the final
210
                                // values into it.
211
                                closetrace();
212 207 dgisselq
                                DIVASSERT(m_core->o_err);
213 204 dgisselq
                        }
214
                } else if (m_core->o_err) {
215
                        // Otherwise, there should not have been any divide
216
                        // errors.  The only errors allowed should be the
217
                        // divide by zero.  So, this is an error.  Let's
218
                        // stop and report it.
219
                        closetrace();
220 207 dgisselq
                        DIVASSERT(!m_core->o_err);
221 204 dgisselq
                } else if (ans != (uint32_t)m_core->o_quotient) {
222
                        // The other problem we might encounter would be if the
223
                        // result doesn't match the one we are expecting.
224
                        //
225
                        // Stop on this bug as well.
226
                        //
227
                        closetrace();
228 207 dgisselq
                        DIVASSERT(ans == (uint32_t)m_core->o_quotient);
229 204 dgisselq
                }
230 207 dgisselq
 
231
                if(((m_core->o_quotient == 0)&&((m_core->o_flags&1)==0))
232
                        ||((m_core->o_quotient!= 0)&&((m_core->o_flags&1)!=0))){
233
                        fprintf(stderr, "Z-FLAG DOES NOT MATCH: FLAGS = %d, QUOTIENT = %08x\n", m_core->o_flags, m_core->o_quotient);
234
                        DIVASSERT((m_core->o_quotient!= 0)^(m_core->o_flags&1));
235
                }
236 204 dgisselq
        }
237
 
238
        // Test a signed divide
239
        void    divs(int n, int d) {
240
                int     ans;
241
                // Calculate the answer we *should* get from the divide
242
                ans = (d==0)?0:   (n / d);
243
 
244
                divtest((uint32_t)n, (uint32_t)d, (uint32_t)ans, true);
245
        }
246
 
247
        // Test an unsigned divide
248
        void    divu(unsigned n, unsigned d) {
249
                unsigned        ans;
250
 
251
                // Pre-Calculate the answer we *should* get from the divide
252
                ans = (d==0)?0:   (n / d);
253
 
254
                divtest((uint32_t)n, (uint32_t)d, (uint32_t)ans, false);
255
        }
256
 
257
        // divide() is just another name for a signed divide--just switch to
258
        // that function call instead.
259
        void    divide(int n, int d) {
260
                divs(n,d);
261
        }
262
};
263
 
264
//
265
// Standard usage functions.
266
//
267
// Notice that the test bench provides no options.  Everything is
268
// self-contained.
269
void    usage(void) {
270
        printf("USAGE: div_tb\n");
271
        printf("\n");
272
        printf("\t\n");
273
}
274
 
275
//
276
int     main(int argc, char **argv) {
277
        // Setup
278
        Verilated::commandArgs(argc, argv);
279
        DIV_TB  *tb = new DIV_TB();
280
 
281
        tb->reset();
282
        // tb->opentrace("div_tb.vcd");
283
 
284
        // Now we're ready.  All we need to do to test the divide of two
285
        // numbers is to call the respective divide(), divs(), or divu()
286
        // functions.  The program will crash on an assert error if anything
287
        // goes wrong.
288
        tb->divu((unsigned)-1,10);
289
        tb->divide(125,7);
290
        // And give us an extra clock tick in-between each test for good
291
        // measure.
292
        tb->tick();
293
 
294
        // Some other gentle tests
295
        tb->divide(125,-7);
296
        tb->tick();
297
        tb->divu((1u<<31),7);
298
        // Now some boundary conditions
299
        tb->divu((7u<<29),(1u<<31));
300
        tb->tick();
301
        tb->divs(32768,0);
302
        tb->tick();
303
        tb->divu((1u<<31),0);
304
        tb->tick();
305
        tb->divs((1u<<30),0);
306
        tb->tick();
307
        //
308
        // Now we switch to a more thorough test set.  It's not complete, just
309
        // ... more thorough.
310
        for(int i=32767; i>=0; i--) {
311
                tb->divs((1u<<30),i);
312
                tb->tick();
313
        } for(int i=32767; i>=0; i--) {
314
                // tb->divu(-1, i);
315
                tb->divu((1u<<31), i);
316
                tb->tick();
317
        } for(int i=32767; i>=0; i--) {
318
                tb->divide(32768, i);
319
                tb->tick();
320
        }
321
 
322
        /*
323
         * While random data is a nice test idea, the following just never
324
         * really tested the divide unit thoroughly enough.
325
         *
326
        tb->divide(rand(),rand()/2);
327
        tb->tick();
328
        tb->divide(rand(),rand()/2);
329
        tb->tick();
330
        tb->divide(rand(),rand()/2);
331
        tb->tick();
332
        tb->divide(rand(),rand()/2);
333
        */
334
 
335
        // Any failures above will be captured with a failed assert.  If we
336
        // get here, it means things worked.  Close up shop ...
337
        //
338
        // This closes any potential trace file
339
        delete  tb;
340
 
341
        // And declare success
342
        printf("SUCCESS!\n");
343
        exit(EXIT_SUCCESS);
344
}
345
 

powered by: WebSVN 2.1.0

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