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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [sim/] [verilator/] [pfcache_tb.cpp] - Diff between revs 204 and 209

Only display areas with differences | Details | Blame | View Log

Rev 204 Rev 209
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename:    pfcache_tb.cpp
// Filename:    pfcache_tb.cpp
//
//
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
//
//
// Purpose:     Bench testing for the prefetch cache used within the ZipCPU
// Purpose:     Bench testing for the prefetch cache used within the ZipCPU
//              when it is in pipelind mode.  Whether or not this module is
//              when it is in pipelind mode.  Whether or not this module is
//      used depends upon how the CPU is set up in cpudefs.v.
//      used depends upon how the CPU is set up in cpudefs.v.
//
//
//
//
// Creator:     Dan Gisselquist, Ph.D.
// Creator:     Dan Gisselquist, Ph.D.
//              Gisselquist Technology, LLC
//              Gisselquist Technology, LLC
//
//
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
//
// This program is free software (firmware): you can redistribute it and/or
// 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
// 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
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
// your option) any later version.
//
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
// for more details.
//
//
 
// You should have received a copy of the GNU General Public License along
 
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
 
// target there if the PDF file isn't present.)  If not, see
 
// <http://www.gnu.org/licenses/> for a copy.
 
//
// License:     GPL, v3, as defined and found on www.gnu.org,
// License:     GPL, v3, as defined and found on www.gnu.org,
//              http://www.gnu.org/licenses/gpl.html
//              http://www.gnu.org/licenses/gpl.html
//
//
//
//
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
#include <signal.h>
#include <signal.h>
#include <time.h>
#include <time.h>
#include <unistd.h>
#include <unistd.h>
#include <assert.h>
#include <assert.h>
 
 
#include <stdlib.h>
#include <stdlib.h>
#include <ctype.h>
#include <ctype.h>
 
 
#include "verilated.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "verilated_vcd_c.h"
#include "Vpfcache.h"
#include "Vpfcache.h"
 
 
#include "testb.h"
#include "testb.h"
#include "cpudefs.h"
#include "cpudefs.h"
#include "memsim.h"
#include "memsim.h"
 
 
#define RAMBASE         (1<<20)
#define RAMBASE         (1<<20)
#define RAMWORDS        RAMBASE
#define RAMWORDS        RAMBASE
#define MAXTIMEOUT      128
#define MAXTIMEOUT      128
 
 
FILE    *gbl_dbgfp = NULL; // Can also be set to stdout
FILE    *gbl_dbgfp = NULL; // Can also be set to stdout
 
 
class   PFCACHE_TB : public TESTB<Vpfcache> {
class   PFCACHE_TB : public TESTB<Vpfcache> {
public:
public:
        MEMSIM  m_mem;
        MEMSIM  m_mem;
        bool    m_bomb;
        bool    m_bomb;
 
 
        // Nothing special to do in a startup.
        // Nothing special to do in a startup.
        PFCACHE_TB(void) : m_mem(RAMWORDS), m_bomb(false) {}
        PFCACHE_TB(void) : m_mem(RAMWORDS), m_bomb(false) {}
 
 
        void    randomize_memory(void) {
        void    randomize_memory(void) {
                m_mem.load("/dev/urandom");
                m_mem.load("/dev/urandom");
        }
        }
 
 
        // ~CPUOPS_TB(void) {}
        // ~CPUOPS_TB(void) {}
 
 
        //
        //
        // Calls TESTB<>::reset to reset the core.  Makes sure the i_ce line
        // Calls TESTB<>::reset to reset the core.  Makes sure the i_ce line
        // is low during this reset.
        // is low during this reset.
        //
        //
        void    reset(void) {
        void    reset(void) {
                m_core->i_rst         = 0;
                m_core->i_reset       = 0;
                m_core->i_pc          = RAMBASE;
                m_core->i_pc          = RAMBASE<<2;
                m_core->i_new_pc = 0;
                m_core->i_new_pc = 0;
                m_core->i_clear_cache = 1;
                m_core->i_clear_cache = 1;
                m_core->i_stall_n = 1;
                m_core->i_stall_n = 1;
                m_core->i_stall_n = 1;
                m_core->i_stall_n = 1;
 
 
                TESTB<Vpfcache>::reset();
                TESTB<Vpfcache>::reset();
        }
        }
 
 
        //
        //
        // dbgdump();
        // dbgdump();
        //
        //
        void    dbgdump(void) {
        void    dbgdump(void) {
                /*
                /*
                char    outstr[2048], *s;
                char    outstr[2048], *s;
                sprintf(outstr, "Tick %4ld %s%s ",
                sprintf(outstr, "Tick %4ld %s%s ",
                        m_tickcount,
                        m_tickcount,
                        (m_core->i_rst)?"R":" ",
                        (m_core->i_rst)?"R":" ",
                        (m_core->i_ce)?"CE":"  ");
                        (m_core->i_ce)?"CE":"  ");
                s = &outstr[strlen(outstr)];
                s = &outstr[strlen(outstr)];
 
 
                puts(outstr);
                puts(outstr);
                */
                */
        }
        }
 
 
        bool    valid_mem(uint32_t addr) {
        bool    valid_mem(uint32_t addr) {
                if (addr < RAMBASE)
                if (addr < RAMBASE)
                        return false;
                        return false;
                if (addr >= RAMBASE + RAMWORDS)
                if (addr >= RAMBASE + RAMWORDS)
                        return false;
                        return false;
                return true;
                return true;
        }
        }
 
 
        //
        //
        // tick()
        // tick()
        //
        //
        // Call this to step the module under test.
        // Call this to step the module under test.
        //
        //
        void    tick(void) {
        void    tick(void) {
                bool    debug = false;
                bool    debug = false;
 
 
                if ((m_core->o_wb_cyc)&&(m_core->o_wb_stb)) {
                if ((m_core->o_wb_cyc)&&(m_core->o_wb_stb)) {
                        if (!valid_mem(m_core->o_wb_addr))
                        if (!valid_mem(m_core->o_wb_addr))
                                m_core->i_wb_err = 1;
                                m_core->i_wb_err = 1;
                } else if (m_core->o_wb_stb) {
                } else if (m_core->o_wb_stb) {
                        m_bomb = true;
                        m_bomb = true;
                }
                }
 
 
                if (m_core->o_wb_we)
                if (m_core->o_wb_we)
                        m_bomb = true;
                        m_bomb = true;
                if (m_core->o_wb_data != 0)
                if (m_core->o_wb_data != 0)
                        m_bomb = true;
                        m_bomb = true;
 
 
                if (debug)
                if (debug)
                        dbgdump();
                        dbgdump();
 
 
                unsigned mask = (RAMBASE-1);
                unsigned mask = (RAMBASE-1);
 
 
                m_mem(m_core->o_wb_cyc, m_core->o_wb_stb, m_core->o_wb_we,
                m_mem(m_core->o_wb_cyc, m_core->o_wb_stb, m_core->o_wb_we,
                        m_core->o_wb_addr & mask, m_core->o_wb_data, 0,
                        m_core->o_wb_addr & mask, m_core->o_wb_data, 0,
                        m_core->i_wb_ack, m_core->i_wb_stall,m_core->i_wb_data);
                        m_core->i_wb_ack, m_core->i_wb_stall,m_core->i_wb_data);
 
 
                TESTB<Vpfcache>::tick();
                TESTB<Vpfcache>::tick();
 
 
                if (m_core->o_v) {
                if (m_core->o_valid) {
                        uint32_t        pc, insn;
                        uint32_t        pc, insn;
 
 
                        pc   = m_core->o_pc;
                        pc   = m_core->o_pc;
                        insn = m_core->o_i;
                        insn = m_core->o_insn;
                        if (insn != m_mem[pc & (RAMWORDS-1)]) {
                        if (insn != m_mem[(pc>>2) & (RAMWORDS-1)]) {
                                fprintf(stderr, "ERR: PF[%08x] = %08x != %08x\n", pc,
                                fprintf(stderr, "ERR: PF[%08x] = %08x != %08x\n", pc,
                                        insn, m_mem[pc & (RAMWORDS-1)]);
                                        insn, m_mem[(pc>>2) & (RAMWORDS-1)]);
                                closetrace();
                                closetrace();
                                assert(insn == m_mem[pc & (RAMWORDS-1)]);
                                assert(insn == m_mem[(pc>>2) & (RAMWORDS-1)]);
                        }
                        }
                }
                }
        }
        }
 
 
        //
        //
        // fetch_insn()
        // fetch_insn()
        //
        //
        void fetch_insn(void) {
        void fetch_insn(void) {
                uint32_t        timeout = 0;
                uint32_t        timeout = 0;
 
 
                if ((m_core->o_v)&&(m_core->i_stall_n))
                if ((m_core->o_valid)&&(m_core->i_stall_n))
                        m_core->i_pc++;
                        m_core->i_pc++;
 
 
                m_core->i_rst         = 0;
                m_core->i_reset       = 0;
                m_core->i_new_pc      = 0;
                m_core->i_new_pc      = 0;
                m_core->i_clear_cache = 0;
                m_core->i_clear_cache = 0;
                m_core->i_stall_n     = 1;
                m_core->i_stall_n     = 1;
                do {
                do {
                        tick();
                        tick();
                } while((!m_core->o_v)&&(!m_core->o_illegal)&&(timeout++ < MAXTIMEOUT));
                } while((!m_core->o_valid)&&(!m_core->o_illegal)&&(timeout++ < MAXTIMEOUT));
 
 
                if (timeout >= MAXTIMEOUT)
                if (timeout >= MAXTIMEOUT)
                        m_bomb = true;
                        m_bomb = true;
        }
        }
 
 
        //
        //
        // skip_fetch()
        // skip_fetch()
        //
        //
        void    skip_fetch(void) {
        void    skip_fetch(void) {
                uint32_t        prevalid, insn;
                uint32_t        prevalid, insn;
 
 
                if ((m_core->o_v)&&(m_core->i_stall_n))
                if ((m_core->o_valid)&&(m_core->i_stall_n))
                        m_core->i_pc++;
                        m_core->i_pc++;
 
 
                m_core->i_rst         = 0;
                m_core->i_reset       = 0;
                m_core->i_new_pc      = 0;
                m_core->i_new_pc      = 0;
                m_core->i_clear_cache = 0;
                m_core->i_clear_cache = 0;
                m_core->i_stall_n     = 0;
                m_core->i_stall_n     = 0;
                insn = m_core->o_i;
                insn = m_core->o_insn;
                prevalid= m_core->o_v;
                prevalid= m_core->o_valid;
 
 
                tick();
                tick();
 
 
                if (prevalid) {
                if (prevalid) {
                        // if (!m_core->o_v) {
                        // if (!m_core->o_valid) {
                                // fprintf(stderr, "ERR: VALID dropped on stall!\n");
                                // fprintf(stderr, "ERR: VALID dropped on stall!\n");
                                // closetrace();
                                // closetrace();
                                // assert(m_core->o_v);
                                // assert(m_core->o_valid);
                        // }
                        // }
                        if (insn != m_core->o_i) {
                        if (insn != m_core->o_insn) {
                                fprintf(stderr, "ERR: VALID INSN CHANGED on stall!\n");
                                fprintf(stderr, "ERR: VALID INSN CHANGED on stall!\n");
                                closetrace();
                                closetrace();
                                assert(insn == m_core->o_i);
                                assert(insn == m_core->o_insn);
                        }
                        }
                }
                }
        }
        }
 
 
 
 
        //
        //
        // jump
        // jump
        //
        //
        void    jump(unsigned target) {
        void    jump(unsigned target) {
                uint32_t        timeout = 0;
                uint32_t        timeout = 0;
 
 
                m_core->i_rst         = 0;
                m_core->i_reset       = 0;
                m_core->i_new_pc      = 1;
                m_core->i_new_pc      = 1;
                m_core->i_clear_cache = 0;
                m_core->i_clear_cache = 0;
                m_core->i_stall_n     = 1;
                m_core->i_stall_n     = 1;
                m_core->i_pc          = target;
                m_core->i_pc          = target;
 
 
                tick();
                tick();
                m_core->i_pc++;
                m_core->i_pc++;
                m_core->i_new_pc      = 0;
                m_core->i_new_pc      = 0;
                m_core->i_stall_n     = 0;
                m_core->i_stall_n     = 0;
 
 
                while((!m_core->o_v)&&(timeout++ < MAXTIMEOUT))
                while((!m_core->o_valid)&&(timeout++ < MAXTIMEOUT))
                        tick();
                        tick();
 
 
                if (timeout >= MAXTIMEOUT)
                if (timeout >= MAXTIMEOUT)
                        m_bomb = true;
                        m_bomb = true;
                if (m_core->o_v)
                if (m_core->o_valid)
                        assert(m_core->o_pc == target);
                        assert(m_core->o_pc == target);
        }
        }
};
};
 
 
void    usage(void) {
void    usage(void) {
        printf("USAGE: pfcache_tb\n");
        printf("USAGE: pfcache_tb\n");
        printf("\n");
        printf("\n");
}
}
 
 
int     main(int argc, char **argv) {
int     main(int argc, char **argv) {
        // Setup verilator
        // Setup verilator
        Verilated::commandArgs(argc, argv);
        Verilated::commandArgs(argc, argv);
        // Now, create a test bench.
        // Now, create a test bench.
        PFCACHE_TB      *tb = new PFCACHE_TB();
        PFCACHE_TB      *tb = new PFCACHE_TB();
        int     rcode = EXIT_SUCCESS;
        int     rcode = EXIT_SUCCESS;
 
 
        tb->opentrace("pfcache.vcd");
        tb->opentrace("pfcache.vcd");
        tb->randomize_memory();
        tb->randomize_memory();
 
 
        tb->jump(RAMBASE);
        tb->jump(RAMBASE<<2);
 
 
        // Simulate running straight through code
        // Simulate running straight through code
        for(int i=0; i<130; i++) {
        for(int i=0; i<130; i++) {
                // printf("FETCH\n");
                // printf("FETCH\n");
                tb->fetch_insn();
                tb->fetch_insn();
        }
        }
 
 
        // Now, let's bounce around through the cache
        // Now, let's bounce around through the cache
        for(int j=0; j<20; j++) {
        for(int j=0; j<20; j++) {
                tb->jump(RAMBASE+j);
                tb->jump((RAMBASE+j)<<2);
                for(int i=0; i<130; i++) {
                for(int i=0; i<130; i++) {
                        // printf("FETCH\n");
                        // printf("FETCH\n");
                        tb->fetch_insn();
                        tb->fetch_insn();
                }
                }
 
 
                if (tb->m_bomb) {
                if (tb->m_bomb) {
                        printf("TEST FAILURE!\n");
                        printf("TEST FAILURE!\n");
                        delete  tb;
                        delete  tb;
                        exit(EXIT_FAILURE);
                        exit(EXIT_FAILURE);
                }
                }
        }
        }
 
 
        // Now, add in some CIS-type instructions
        // Now, add in some CIS-type instructions
        for(int i=0; i<130; i++) {
        for(int i=0; i<130; i++) {
                unsigned v = rand() & 0x0f;
                unsigned v = rand() & 0x0f;
 
 
                if ((v&3)==2) {
                if ((v&3)==2) {
                        // printf("SKIP\n");
                        // printf("SKIP\n");
                        tb->skip_fetch();
                        tb->skip_fetch();
                } else {
                } else {
                        // printf("FETCH\n");
                        // printf("FETCH\n");
                        tb->fetch_insn();
                        tb->fetch_insn();
                }
                }
 
 
                if (tb->m_bomb) {
                if (tb->m_bomb) {
                        printf("TEST FAILURE!\n");
                        printf("TEST FAILURE!\n");
                        delete  tb;
                        delete  tb;
                        exit(EXIT_FAILURE);
                        exit(EXIT_FAILURE);
                }
                }
        }
        }
 
 
        // Finally, try it all: stalls, CIS, and jumps
        // Finally, try it all: stalls, CIS, and jumps
        for(int i=0; i<10000; i++) {
        for(int i=0; i<10000; i++) {
                unsigned v = rand() & 0x0f;
                unsigned v = rand() & 0x0f;
                if (v == 0) {
                if (v == 0) {
                        uint32_t target = rand() & (RAMWORDS-1);
                        uint32_t target = rand() & (RAMWORDS-1);
                        target += RAMBASE;
                        target += RAMBASE;
                        // printf("JUMP TO %08x\n", target);
                        // printf("JUMP TO %08x\n", target);
                        tb->jump(target);
                        tb->jump(target<<2);
                } else if ((v & 3)==2) {
                } else if ((v & 3)==2) {
                        // printf("SKIP\n");
                        // printf("SKIP\n");
                        tb->skip_fetch();
                        tb->skip_fetch();
                } else {
                } else {
                        // printf("FETCH\n");
                        // printf("FETCH\n");
                        tb->fetch_insn();
                        tb->fetch_insn();
                }
                }
 
 
                if (tb->m_bomb) {
                if (tb->m_bomb) {
                        printf("TEST FAILURE!\n");
                        printf("TEST FAILURE!\n");
                        delete  tb;
                        delete  tb;
                        exit(EXIT_FAILURE);
                        exit(EXIT_FAILURE);
                }
                }
        }
        }
 
 
        printf("SUCCESS!\n");
        printf("SUCCESS!\n");
        exit(rcode);
        exit(rcode);
}
}
 
 
 
 

powered by: WebSVN 2.1.0

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