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

Subversion Repositories zipcpu

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 196 to Rev 197
    Reverse comparison

Rev 196 → Rev 197

/zipcpu/trunk/bench/cpp/Makefile
58,6 → 58,16
# debugging output) if successful. To actually run this test,
# you'll need to run ./div_tb (no arguments necessary).
#
# mpy_tb
# A raw test bench to test the multiply instructions within the
# cpuops (ALU) unit separate from the rest of the CPU. For more
# details, look at the usage statement wtihin mpy_tb.
#
# zipmmu_tb
# Like div_tb, this is another raw component test bench. In this
# case, zipmmu_tb tests whether or not the MMU works when
# separated from the rest of the CPU.
#
# pdump
# zippy_tb can be configured to produce a profile output that is
# very useful when debugging the Dhrystone benchmark. (It is
97,15 → 107,17
#
################################################################################
#
all: zippy_tb pdump div_tb
all: zippy_tb pdump div_tb mpy_tb
 
CXX := g++
FLAGS := -Wall -Og -g
ZASM := ../../sw/zasm
RTLD := ../../rtl
INCS := -I$(RTLD)/obj_dir/ -I$(RTLD) -I/usr/share/verilator/include -I$(ZASM)
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"')
VROOT := $(VERILATOR_ROOT)
INCS := -I$(RTLD)/obj_dir/ -I$(RTLD) -I$(VROOT)/include -I$(ZASM)
SOURCES := zippy_tb.cpp memsim.cpp twoc.cpp $(ZASM)/zopcodes.cpp $(ZASM)/zparser.cpp
VLIB := /usr/share/verilator/include/verilated.cpp
VLIB := $(VROOT)/include/verilated.cpp
RAWLIB := $(VLIB) $(RTLD)/obj_dir/Vzipsystem__ALL.a
LIBS := $(RAWLIB) -lncurses -lelf
TESTF := $(ZASM)/z.out
118,6 → 130,12
div_tb: div_tb.cpp twoc.cpp $(VLIB) $(RTLD)/obj_dir/Vdiv__ALL.a testb.h
$(CXX) $(FLAGS) $(INCS) div_tb.cpp twoc.cpp $(VLIB) $(RTLD)/obj_dir/Vdiv__ALL.a -o $@
 
mpy_tb: mpy_tb.cpp twoc.cpp $(VLIB) $(RTLD)/obj_dir/Vcpuops__ALL.a testb.h
$(CXX) $(FLAGS) $(INCS) mpy_tb.cpp twoc.cpp $(VLIB) $(RTLD)/obj_dir/Vcpuops__ALL.a -o $@
 
zipmmu_tb: zipmmu_tb.cpp $(VLIB) ../rtl/obj_dir/Vzipmmu_tb__ALL.a
$(CXX) $(FLAGS) $(INCS) -I ../rtl/obj_dir zipmmu_tb.cpp $(VLIB) ../rtl/obj_dir/Vzipmmu_tb__ALL.a -o $@
 
pdump: pdump.cpp $(ZASM)/zopcodes.cpp $(ZASM)/zparser.cpp
pdump: $(ZASM)/zopcodes.h $(ZASM)/zparser.h testb.h twoc.cpp
$(CXX) $(FLAGS) $(INCS) pdump.cpp $(ZASM)/zopcodes.cpp $(ZASM)/zparser.cpp twoc.cpp -lelf -o $@
140,4 → 158,4
 
.PHONY: clean
clean:
rm ./zippy_tb pdump div_tb
rm ./zippy_tb pdump div_tb mpy_tb
/zipcpu/trunk/bench/cpp/memsim.cpp
47,6 → 47,7
;
m_len = nxt; m_mask = nxt-1;
m_mem = new BUSW[m_len];
m_nxt_ack = 0;
}
 
MEMSIM::~MEMSIM(void) {
83,13 → 84,25
const unsigned char wb_stb, const unsigned char wb_we,
const BUSW wb_addr, const BUSW wb_data,
unsigned char &o_ack, unsigned char &o_stall, BUSW &o_data) {
o_ack = m_nxt_ack;
o_data= m_nxt_data;
m_nxt_data = wb_data;
o_stall= 0;
if ((wb_cyc)&&(wb_stb)&&(clk)) {
if (wb_we)
m_mem[wb_addr & m_mask] = wb_data;
o_ack = 1;
o_stall= 0;
o_data = m_mem[wb_addr & m_mask];
m_nxt_ack = 1;
m_nxt_data = m_mem[wb_addr & m_mask];
// o_ack = 1;
 
{
extern FILE *gbl_dbgfp;
if (gbl_dbgfp) {
if (wb_we) fprintf(gbl_dbgfp, "MEMSIM::MEM[%08x] = %08x\n", wb_addr&m_mask, wb_data);
else
fprintf(gbl_dbgfp, "MEMSIM::BUS = MEM[%08x] = %08x\n", wb_addr&m_mask, m_nxt_data);
}
}
/*
printf("MEMBUS -- ACK %s 0x%08x - 0x%08x\n",
(wb_we)?"WRITE":"READ",
96,7 → 109,7
wb_addr, o_data);
*/
} else if (clk) {
o_ack = 0;
m_nxt_ack = 0;
o_stall = 0;
}
}
/zipcpu/trunk/bench/cpp/memsim.h
46,6 → 46,8
typedef unsigned char uchar;
 
BUSW *m_mem, m_len, m_mask;
int m_nxt_ack;
BUSW m_nxt_data;
 
MEMSIM(const unsigned int nwords);
/zipcpu/trunk/bench/cpp/mpy_tb.cpp
0,0 → 1,342
///////////////////////////////////////////////////////////////////////////////
//
// Filename: mpy_tb.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Bench testing for the multiply ALU instructions used within the
// Zip CPU. This depends upon the cpuops.v module, but should be
// independent of the internal settings within the module.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
//
//
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>
 
#include <stdlib.h>
#include <ctype.h>
 
#include "verilated.h"
#include "Vcpuops.h"
 
#include "testb.h"
#include "cpudefs.h"
// #include "twoc.h"
 
class CPUOPS_TB : public TESTB<Vcpuops> {
public:
// Nothing special to do in a startup.
CPUOPS_TB(void) {}
 
// ~CPUOPS_TB(void) {}
 
//
// Calls TESTB<>::reset to reset the core. Makes sure the i_ce line
// is low during this reset.
//
void reset(void) {
// m_flash.debug(false);
m_core->i_ce = 0;
 
TESTB<Vcpuops>::reset();
}
 
//
// dbgdump();
//
// Just before the positive edge of every clock, we call this function
// (if the debug flag is set). This prints out a line of information
// telling us what is going on within the logic, allowing us access
// for debugging purposes to inspect things.
//
// Other than debugging, this isn't necessary for the functioning of the
// test bench. At the same time, what are you using a test bench for if
// not for debugging?
//
void dbgdump(void) {
char outstr[2048], *s;
sprintf(outstr, "Tick %4ld %s%s ",
m_tickcount,
(m_core->i_rst)?"R":" ",
(m_core->i_ce)?"CE":" ");
switch(m_core->i_op) {
case 0: strcat(outstr, " SUB"); break;
case 1: strcat(outstr, " AND"); break;
case 2: strcat(outstr, " ADD"); break;
case 3: strcat(outstr, " OR"); break;
case 4: strcat(outstr, " XOR"); break;
case 5: strcat(outstr, " LSR"); break;
case 6: strcat(outstr, " LSL"); break;
case 7: strcat(outstr, " ASR"); break;
case 8: strcat(outstr, " MPY"); break;
case 9: strcat(outstr, "LODILO"); break;
case 10: strcat(outstr, "MPYUHI"); break;
case 11: strcat(outstr, "MPYSHI"); break;
case 12: strcat(outstr, " BREV"); break;
case 13: strcat(outstr, " POPC"); break;
case 14: strcat(outstr, " ROL"); break;
case 15: strcat(outstr, " MOV"); break;
default: strcat(outstr, "UNKWN!"); break;
} s = &outstr[strlen(outstr)];
sprintf(s, "(%x) 0x%08x 0x%08x -> 0x%08x [%x] %s%s",
m_core->i_op,
m_core->i_a, m_core->i_b,
m_core->o_c, m_core->o_f,
(m_core->o_valid)?"V":" ",
(m_core->o_busy)?"B":" ");
s = &outstr[strlen(outstr)];
 
#if(OPT_MULTIPLY==1)
sprintf(s, "1,MPY[][][%016lx]",
m_core->v__DOT__mpy_result);
s = &outstr[strlen(outstr)];
#elif(OPT_MULTIPLY==2)
sprintf(s, "2,MPY[%016lx][%016lx][%016lx]",
m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_a_input,
m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_b_input,
m_core->v__DOT__mpy_result);
s = &outstr[strlen(outstr)];
#elif(OPT_MULTIPLY==3)
sprintf(s, "3,MPY[%08x][%08x][%016lx], P[%d]",
m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_a_input,
m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_mpy_b_input,
m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__r_smpy_result,
m_core->v__DOT__genblk2__DOT__genblk2__DOT__genblk2__DOT__genblk1__DOT__mpypipe);
 
#endif
 
#if(OPT_MULTIPLY != 1)
if (m_core->v__DOT__this_is_a_multiply_op)
strcat(s, " MPY-OP");
#endif
puts(outstr);
}
 
//
// tick()
//
// Call this to step the processor.
//
// This is a bit unusual compared to other tick() functions I have in
// my simulators in that there are a lot of calls to eval() with clk==0.
// This is because the multiply logic for OPT_MULTIPLY < 3 depends upon
// it to be valid. I assume any true Xilinx, or even higher level,
// implementation wouldn't have this problem.
//
void tick(void) {
bool debug = true;
 
m_core->i_clk = 0;
m_core->eval();
if (debug)
dbgdump();
#if(OPT_MULTIPLY == 1)
m_core->i_clk = 0;
m_core->eval();
#endif
assert((!m_core->o_busy)||(!m_core->o_valid));
TESTB<Vcpuops>::tick();
m_core->i_clk = 0;
m_core->eval();
}
 
//
// clear_ops
//
// Runs enough clocks through the device until it is neither busy nor
// valid. At this point, the ALU should be thoroughly clear. Then
// we tick things once more.
//
void clear_ops(void) {
m_core->i_ce = 0;
m_core->i_op = 0;
 
do {
tick();
} while((m_core->o_busy)||(m_core->o_valid));
tick();
}
 
//
// This is a fairly generic CPU operation call. What makes it less
// than generic are two things: 1) the ALU is cleared before any
// new instruction, and 2) the tick count at the end is compared
// against the tick count OPT_MULTIPLY says we should be getting.
// A third difference between this call in simulation and a real
// call within the CPU is that we never set the reset mid-call, whereas
// the CPU may need to do that if a jump is made and the pipeline needs
// to be cleared.
//
unsigned op(int op, int a, int b) {
if (m_core->o_valid)
clear_ops();
m_core->i_ce = 1;
m_core->i_op = op;
m_core->i_a = a;
m_core->i_b = b;
 
unsigned long now = m_tickcount;
 
tick();
m_core->i_ce = 0;
m_core->i_a = 0;
m_core->i_b = 0;
 
while(!m_core->o_valid)
tick();
if(1) {
if((m_tickcount - now)!=OPT_MULTIPLY) {
printf("%ld ticks seen, %d ticks expected\n",
m_tickcount-now, OPT_MULTIPLY);
dbgdump();
} assert((m_tickcount - now)==OPT_MULTIPLY);
}
return m_core->o_c;
}
 
//
// Here's our testing function. Pardon the verbosity of the error
// messages within it, but ... well, hopefully you won't ever encounter
// any of those errors. ;)
//
// The function works by applying the two inputs to all three of the
// multiply functions, MPY, MPSHI, and MPYUHI. Results are compared
// against a local multiply on the local (host) machine. If there's
// any mismatch, an error message is printed and the test fails.
void mpy_test(int a, int b) {
const int OP_MPY = 0x08, OP_MPYSHI=0xb, OP_MPYUHI=0x0a;
long ia, ib, sv;
unsigned long ua, ub, uv;
unsigned r, s, u;
 
clear_ops();
 
printf("MPY-TEST: 0x%08x x 0x%08x\n", a, b);
 
ia = (long)a; ib = (long)b; sv = ia * ib;
ua = ((unsigned long)a)&0x0ffffffffu;
ub = ((unsigned long)b)&0x0ffffffffu;
uv = ua * ub;
 
r = op(OP_MPY, a, b);
s = op(OP_MPYSHI, a, b);
u = op(OP_MPYUHI, a, b);
tick();
 
if ((r ^ sv)&0x0ffffffffu) {
printf("TEST FAILURE(MPY), MPY #1\n");
printf("Comparing 0x%08x to 0x%016lx\n", r, sv);
printf("TEST-FAILURE!\n");
exit(EXIT_FAILURE);
} if ((r ^ uv)&0x0ffffffffu) {
printf("TEST FAILURE(MPY), MPY #2\n");
printf("Comparing 0x%08x to 0x%016lx\n", r, uv);
printf("TEST-FAILURE!\n");
exit(EXIT_FAILURE);
}
 
if ((s^(sv>>32))&0x0ffffffffu) {
printf("TEST FAILURE(MPYSHI), MPY #3\n");
printf("Comparing 0x%08x to 0x%016lx\n", s, sv);
printf("TEST-FAILURE!\n");
exit(EXIT_FAILURE);
} if ((u^(uv>>32))&0x0ffffffffu) {
printf("TEST FAILURE(MPYUHI), MPY #4\n");
printf("Comparing 0x%08x to 0x%016lx\n", u, uv);
printf("TEST-FAILURE!\n");
exit(EXIT_FAILURE);
}
}
};
 
void usage(void) {
printf("USAGE: mpy_tb [a b]\n");
printf("\n");
printf(
"The test is intended to be run with no arguments. When run in this fashion,\n"
"a series of multiplcation tests will be conducted using all three multiply\n"
"instructions. Any test failure will terminate the program with an exit\n"
"condition. Test success will terminate with a clear test condition. \n"
"During the test, you may expect a large amount of debug output to be\n"
"produced. This is a normal part of testing. For the meaning of the debug\n"
"output, please consider the source code. The last line of the debug output,\n"
"however, will always include either the word \"FAIL\" or \"SUCCESS\"\n"
"depending on whether the test succeeds or fails.\n\n"
"If the two arguments a and b are given, they will be interpreted according\n"
"to the form of strtol, and the test will only involve testing those two\n"
"parameters\n\n");
}
 
int main(int argc, char **argv) {
// Setup verilator
Verilated::commandArgs(argc, argv);
// Now, create a test bench.
CPUOPS_TB *tb = new CPUOPS_TB();
int rcode = EXIT_SUCCESS;
 
// Get us started by a couple of clocks past reset. This isn't that
// unreasonable, since the CPU needs to load up the pipeline before
// any first instruction will be executed.
tb->reset();
tb->tick();
tb->tick();
tb->tick();
 
// Look for options, such as '-h'. Trap those here, and produce a usage
// statement.
if ((argc > 1)&&(argv[1][0]=='-')&&(isalpha(argv[1][1]))) {
usage();
exit(EXIT_SUCCESS);
}
 
if (argc == 3) {
// Were we given enough arguments to run a user-specified test?
tb->mpy_test(
strtol(argv[1], NULL, 0),
strtol(argv[2], NULL, 0));
} else {
// Otherwise we run through a canned set of tests.
tb->mpy_test(0,0);
tb->mpy_test(-1,0);
tb->mpy_test(-1,-1);
tb->mpy_test(1,-1);
tb->mpy_test(1,0);
tb->mpy_test(0,1);
tb->mpy_test(1,1);
 
for(int a=0; ((a&0xfff00000)==0); a+=137)
tb->mpy_test(139, a);
 
for(int a=0; ((a&0x80000000)==0); a+=0x197e2)
tb->mpy_test(0xf97e27ab, a);
}
 
printf("SUCCESS!\n");
exit(rcode);
}
 
/zipcpu/trunk/bench/cpp/zippy_tb.cpp
792,7 → 792,7
printw("%8s","");
mvprintw(ln-1, 48, "%s%s%s ",
(m_core->v__DOT__thecpu__DOT__alu_valid)?"A"
:((m_core->v__DOT__thecpu__DOT__doalu__DOT__genblk2__DOT__r_busy)?"a":" "),
:((m_core->v__DOT__thecpu__DOT__doalu__DOT__r_busy)?"a":" "),
(m_core->v__DOT__thecpu__DOT__div_valid)?"D"
:((m_core->v__DOT__thecpu__DOT__div_busy)?"d":" "),
(m_core->v__DOT__thecpu__DOT__div_valid)?"F"

powered by: WebSVN 2.1.0

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