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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [bench/] [cpp/] [mpy_tb.cpp] - Blame information for rev 197

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 197 dgisselq
///////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    mpy_tb.cpp
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7
// Purpose:     Bench testing for the multiply ALU instructions used within the
8
//              Zip CPU.  This depends upon the cpuops.v module, but should be
9
//      independent of the internal settings within the module.
10
//
11
//
12
// Creator:     Dan Gisselquist, Ph.D.
13
//              Gisselquist Technology, LLC
14
//
15
///////////////////////////////////////////////////////////////////////////////
16
//
17
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
18
//
19
// This program is free software (firmware): you can redistribute it and/or
20
// modify it under the terms of  the GNU General Public License as published
21
// by the Free Software Foundation, either version 3 of the License, or (at
22
// your option) any later version.
23
//
24
// This program is distributed in the hope that it will be useful, but WITHOUT
25
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
26
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27
// for more details.
28
//
29
// License:     GPL, v3, as defined and found on www.gnu.org,
30
//              http://www.gnu.org/licenses/gpl.html
31
//
32
//
33
///////////////////////////////////////////////////////////////////////////////
34
//
35
//
36
#include <signal.h>
37
#include <time.h>
38
#include <unistd.h>
39
#include <assert.h>
40
 
41
#include <stdlib.h>
42
#include <ctype.h>
43
 
44
#include "verilated.h"
45
#include "Vcpuops.h"
46
 
47
#include "testb.h"
48
#include "cpudefs.h"
49
// #include "twoc.h"
50
 
51
class   CPUOPS_TB : public TESTB<Vcpuops> {
52
public:
53
        // Nothing special to do in a startup.
54
        CPUOPS_TB(void) {}
55
 
56
        // ~CPUOPS_TB(void) {}
57
 
58
        //
59
        // Calls TESTB<>::reset to reset the core.  Makes sure the i_ce line
60
        // is low during this reset.
61
        //
62
        void    reset(void) {
63
                // m_flash.debug(false);
64
                m_core->i_ce = 0;
65
 
66
                TESTB<Vcpuops>::reset();
67
        }
68
 
69
        //
70
        // dbgdump();
71
        //
72
        // Just before the positive edge of every clock, we call this function
73
        // (if the debug flag is set).  This prints out a line of information
74
        // telling us what is going on within the logic, allowing us access
75
        // for debugging purposes to inspect things.
76
        //
77
        // Other than debugging, this isn't necessary for the functioning of the
78
        // test bench.  At the same time, what are you using a test bench for if
79
        // not for debugging?
80
        //
81
        void    dbgdump(void) {
82
                char    outstr[2048], *s;
83
                sprintf(outstr, "Tick %4ld %s%s ",
84
                        m_tickcount,
85
                        (m_core->i_rst)?"R":" ",
86
                        (m_core->i_ce)?"CE":"  ");
87
                switch(m_core->i_op) {
88
                case  0: strcat(outstr, "   SUB"); break;
89
                case  1: strcat(outstr, "   AND"); break;
90
                case  2: strcat(outstr, "   ADD"); break;
91
                case  3: strcat(outstr, "    OR"); break;
92
                case  4: strcat(outstr, "   XOR"); break;
93
                case  5: strcat(outstr, "   LSR"); break;
94
                case  6: strcat(outstr, "   LSL"); break;
95
                case  7: strcat(outstr, "   ASR"); break;
96
                case  8: strcat(outstr, "   MPY"); break;
97
                case  9: strcat(outstr, "LODILO"); break;
98
                case 10: strcat(outstr, "MPYUHI"); break;
99
                case 11: strcat(outstr, "MPYSHI"); break;
100
                case 12: strcat(outstr, "  BREV"); break;
101
                case 13: strcat(outstr, "  POPC"); break;
102
                case 14: strcat(outstr, "   ROL"); break;
103
                case 15: strcat(outstr, "   MOV"); break;
104
                default: strcat(outstr, "UNKWN!"); break;
105
                } s = &outstr[strlen(outstr)];
106
                sprintf(s, "(%x) 0x%08x 0x%08x -> 0x%08x [%x] %s%s",
107
                        m_core->i_op,
108
                        m_core->i_a, m_core->i_b,
109
                        m_core->o_c, m_core->o_f,
110
                        (m_core->o_valid)?"V":" ",
111
                        (m_core->o_busy)?"B":" ");
112
                s = &outstr[strlen(outstr)];
113
 
114
#if(OPT_MULTIPLY==1)
115
                sprintf(s, "1,MPY[][][%016lx]",
116
                        m_core->v__DOT__mpy_result);
117
                s = &outstr[strlen(outstr)];
118
#elif(OPT_MULTIPLY==2)
119
                sprintf(s, "2,MPY[%016lx][%016lx][%016lx]",
120
                        m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_a_input,
121
                        m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_b_input,
122
                        m_core->v__DOT__mpy_result);
123
                s = &outstr[strlen(outstr)];
124
#elif(OPT_MULTIPLY==3)
125
                sprintf(s, "3,MPY[%08x][%08x][%016lx], P[%d]",
126
                        m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_a_input,
127
                        m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_b_input,
128
                        m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_smpy_result,
129
                        m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__mpypipe);
130
 
131
#endif
132
 
133
#if(OPT_MULTIPLY != 1)
134
                if (m_core->v__DOT__this_is_a_multiply_op)
135
                        strcat(s, " MPY-OP");
136
#endif
137
                puts(outstr);
138
        }
139
 
140
        //
141
        // tick()
142
        //
143
        // Call this to step the processor.
144
        //
145
        // This is a bit unusual compared to other tick() functions I have in
146
        // my simulators in that there are a lot of calls to eval() with clk==0.
147
        // This is because the multiply logic for OPT_MULTIPLY < 3 depends upon
148
        // it to be valid.  I assume any true Xilinx, or even higher level,
149
        // implementation wouldn't have this problem.
150
        //
151
        void    tick(void) {
152
                bool    debug = true;
153
 
154
                m_core->i_clk = 0;
155
                m_core->eval();
156
                if (debug)
157
                        dbgdump();
158
#if(OPT_MULTIPLY == 1)
159
                m_core->i_clk = 0;
160
                m_core->eval();
161
#endif
162
                assert((!m_core->o_busy)||(!m_core->o_valid));
163
                TESTB<Vcpuops>::tick();
164
                m_core->i_clk = 0;
165
                m_core->eval();
166
        }
167
 
168
        //
169
        // clear_ops
170
        //
171
        // Runs enough clocks through the device until it is neither busy nor
172
        // valid.  At this point, the ALU should be thoroughly clear.  Then
173
        // we tick things once more.
174
        //
175
        void    clear_ops(void) {
176
                m_core->i_ce    = 0;
177
                m_core->i_op    = 0;
178
 
179
                do {
180
                        tick();
181
                } while((m_core->o_busy)||(m_core->o_valid));
182
                tick();
183
        }
184
 
185
        //
186
        // This is a fairly generic CPU operation call.  What makes it less
187
        // than generic are two things: 1) the ALU is cleared before any
188
        // new instruction, and 2) the tick count at the end is compared
189
        // against the tick count OPT_MULTIPLY says we should be getting.
190
        // A third difference between this call in simulation and a real
191
        // call within the CPU is that we never set the reset mid-call, whereas
192
        // the CPU may need to do that if a jump is made and the pipeline needs
193
        // to be cleared.
194
        //
195
        unsigned        op(int op, int a, int b) {
196
                if (m_core->o_valid)
197
                        clear_ops();
198
                m_core->i_ce    = 1;
199
                m_core->i_op    = op;
200
                m_core->i_a     = a;
201
                m_core->i_b     = b;
202
 
203
                unsigned long now = m_tickcount;
204
 
205
                tick();
206
                m_core->i_ce    = 0;
207
                m_core->i_a     = 0;
208
                m_core->i_b     = 0;
209
 
210
                while(!m_core->o_valid)
211
                        tick();
212
if(1) {
213
                if((m_tickcount - now)!=OPT_MULTIPLY) {
214
                        printf("%ld ticks seen, %d ticks expected\n",
215
                                m_tickcount-now, OPT_MULTIPLY);
216
                        dbgdump();
217
                } assert((m_tickcount - now)==OPT_MULTIPLY);
218
}
219
                return m_core->o_c;
220
        }
221
 
222
        //
223
        // Here's our testing function.  Pardon the verbosity of the error
224
        // messages within it, but ...  well, hopefully you won't ever encounter
225
        // any of those errors. ;)
226
        //
227
        // The function works by applying the two inputs to all three of the
228
        // multiply functions, MPY, MPSHI, and MPYUHI.  Results are compared
229
        // against a local multiply on the local (host) machine.  If there's
230
        // any mismatch, an error message is printed and the test fails.
231
        void    mpy_test(int a, int b) {
232
                const   int OP_MPY = 0x08, OP_MPYSHI=0xb, OP_MPYUHI=0x0a;
233
                long    ia, ib, sv;
234
                unsigned long   ua, ub, uv;
235
                unsigned        r, s, u;
236
 
237
                clear_ops();
238
 
239
                printf("MPY-TEST: 0x%08x x 0x%08x\n", a, b);
240
 
241
                ia = (long)a; ib = (long)b; sv = ia * ib;
242
                ua = ((unsigned long)a)&0x0ffffffffu;
243
                ub = ((unsigned long)b)&0x0ffffffffu;
244
                uv = ua * ub;
245
 
246
                r = op(OP_MPY, a, b);
247
                s = op(OP_MPYSHI, a, b);
248
                u = op(OP_MPYUHI, a, b);
249
                tick();
250
 
251
                if ((r ^ sv)&0x0ffffffffu) {
252
                        printf("TEST FAILURE(MPY), MPY #1\n");
253
                        printf("Comparing 0x%08x to 0x%016lx\n", r, sv);
254
                        printf("TEST-FAILURE!\n");
255
                        exit(EXIT_FAILURE);
256
                } if ((r ^ uv)&0x0ffffffffu) {
257
                        printf("TEST FAILURE(MPY), MPY #2\n");
258
                        printf("Comparing 0x%08x to 0x%016lx\n", r, uv);
259
                        printf("TEST-FAILURE!\n");
260
                        exit(EXIT_FAILURE);
261
                }
262
 
263
                if ((s^(sv>>32))&0x0ffffffffu) {
264
                        printf("TEST FAILURE(MPYSHI), MPY #3\n");
265
                        printf("Comparing 0x%08x to 0x%016lx\n", s, sv);
266
                        printf("TEST-FAILURE!\n");
267
                        exit(EXIT_FAILURE);
268
                } if ((u^(uv>>32))&0x0ffffffffu) {
269
                        printf("TEST FAILURE(MPYUHI), MPY #4\n");
270
                        printf("Comparing 0x%08x to 0x%016lx\n", u, uv);
271
                        printf("TEST-FAILURE!\n");
272
                        exit(EXIT_FAILURE);
273
                }
274
        }
275
};
276
 
277
void    usage(void) {
278
        printf("USAGE: mpy_tb [a b]\n");
279
        printf("\n");
280
        printf(
281
"The test is intended to be run with no arguments.  When run in this fashion,\n"
282
"a series of multiplcation tests will be conducted using all three multiply\n"
283
"instructions.  Any test failure will terminate the program with an exit\n"
284
"condition.  Test success will terminate with a clear test condition.  \n"
285
"During the test, you may expect a large amount of debug output to be\n"
286
"produced.  This is a normal part of testing.  For the meaning of the debug\n"
287
"output, please consider the source code.  The last line of the debug output,\n"
288
"however, will always include either the word \"FAIL\" or \"SUCCESS\"\n"
289
"depending on whether the test succeeds or fails.\n\n"
290
"If the two arguments a and b are given, they will be interpreted according\n"
291
"to the form of strtol, and the test will only involve testing those two\n"
292
"parameters\n\n");
293
}
294
 
295
int     main(int argc, char **argv) {
296
        // Setup verilator
297
        Verilated::commandArgs(argc, argv);
298
        // Now, create a test bench.
299
        CPUOPS_TB       *tb = new CPUOPS_TB();
300
        int     rcode = EXIT_SUCCESS;
301
 
302
        // Get us started by a couple of clocks past reset.  This isn't that
303
        // unreasonable, since the CPU needs to load up the pipeline before
304
        // any first instruction will be executed.
305
        tb->reset();
306
        tb->tick();
307
        tb->tick();
308
        tb->tick();
309
 
310
        // Look for options, such as '-h'.  Trap those here, and produce a usage
311
        // statement.
312
        if ((argc > 1)&&(argv[1][0]=='-')&&(isalpha(argv[1][1]))) {
313
                usage();
314
                exit(EXIT_SUCCESS);
315
        }
316
 
317
        if (argc == 3) {
318
                // Were we given enough arguments to run a user-specified test?
319
                tb->mpy_test(
320
                        strtol(argv[1], NULL, 0),
321
                        strtol(argv[2], NULL, 0));
322
        } else {
323
                // Otherwise we run through a canned set of tests.
324
                tb->mpy_test(0,0);
325
                tb->mpy_test(-1,0);
326
                tb->mpy_test(-1,-1);
327
                tb->mpy_test(1,-1);
328
                tb->mpy_test(1,0);
329
                tb->mpy_test(0,1);
330
                tb->mpy_test(1,1);
331
 
332
                for(int a=0; ((a&0xfff00000)==0); a+=137)
333
                        tb->mpy_test(139, a);
334
 
335
                for(int a=0; ((a&0x80000000)==0); a+=0x197e2)
336
                        tb->mpy_test(0xf97e27ab, a);
337
        }
338
 
339
        printf("SUCCESS!\n");
340
        exit(rcode);
341
}
342
 

powered by: WebSVN 2.1.0

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