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

Subversion Repositories zipcpu

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

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

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

powered by: WebSVN 2.1.0

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