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 203 to Rev 204
    Reverse comparison

Rev 203 → Rev 204

/zipcpu/trunk/bench/cpp/helloworld.c
0,0 → 1,42
////////////////////////////////////////////////////////////////////////////////
//
// Filename: helloworld.c
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: The original Helllo World program. If everything works, this
// will print Hello World to the UART, and then halt the CPU--if
// run with no O/S.
//
//
// 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 <stdio.h>
 
int main(int argc, char **argv) {
printf("Hello, World!\r\n");
return 0;
}
 
/zipcpu/trunk/bench/zipsim.ld
0,0 → 1,74
/*******************************************************************************
*
* Filename: zipsim.ld
*
* Project: Zip CPU -- a small, lightweight, RISC CPU soft core
*
* Purpose: This script provides a description of the memory on the Arty,
* for the purposes of where to place programs in memory during
* linking.
*
* Creator: Dan Gisselquist, Ph.D.
* Gisselquist Technology, LLC
*
********************************************************************************
*
* Copyright (C) 2017, 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.
*
* 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,
* http://www.gnu.org/licenses/gpl.html
*
*
*******************************************************************************/
 
ENTRY(_start)
 
MEMORY
{
flash (wx) : ORIGIN = 0x01000000, LENGTH = 0x01000000 /* 2^24 = 16MB */
sdram (wx) : ORIGIN = 0x10000000, LENGTH = 0x10000000 /* 2^28 = 256MB */
}
 
_flash = ORIGIN(flash);
_blkram = 0;
_sdram = ORIGIN(sdram);
_top_of_stack = ORIGIN(sdram) + LENGTH(sdram) - 4;
 
SECTIONS
{
.rocode ORIGIN(flash) : {
_boot_address = .;
*(.start)
} > flash
_kernel_image_start = . ;
_kernel_image_end = . ;
_sdram_image_start = . ;
.ramcode ORIGIN(sdram) : {
*(.kernel)
*(.text.startup)
*(.text)
*(.rodata*) *(.strings)
*(.data) *(COMMON)
}> sdram AT> flash
_sdram_image_end = . ;
.bss : {
*(.bss)
_bss_image_end = . ;
} > sdram
_top_of_heap = .;
}
/zipcpu/trunk/sim/cpp/Makefile
0,0 → 1,50
################################################################################
#
# Filename: Makefile
#
# Project: Zip CPU -- a small, lightweight, RISC CPU soft core
#
# Purpose:
#
# Targets:
#
#
# Creator: Dan Gisselquist, Ph.D.
# Gisselquist Technology, LLC
#
################################################################################
#
# Copyright (C) 2017, 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
#
#
################################################################################
#
all: zsim
 
CXX := g++
FLAGS := -Wall -g
INCS :=
SOURCES := zsim.cpp twoc.cpp zipelf.cpp
LIBS := -lelf
TESTF := $(ZASM)/z.out
DHRYSTONEF := ../asm/zipdhry.z
 
zsim: $(SOURCES) zipelf.h twoc.h
$(CXX) $(FLAGS) $(INCS) $(SOURCES) $(LIBS) -o $@
 
.PHONY: clean
clean:
rm -f zsim
/zipcpu/trunk/sim/cpp/twoc.cpp
0,0 → 1,55
////////////////////////////////////////////////////////////////////////////
//
// Filename: twoc.cpp
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: Some various two's complement related C++ helper routines.
// Specifically, these help extract signed numbers from
// packed bitfields, while guaranteeing that the upper bits
// are properly sign extended (or not) as desired.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
#include "twoc.h"
 
long sbits(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
}
 
unsigned long ubits(const long val, const int bits) {
unsigned long r = val & ((1l<<bits)-1);
return r;
}
 
 
/zipcpu/trunk/sim/cpp/twoc.h
0,0 → 1,46
////////////////////////////////////////////////////////////////////////////
//
// Filename: twoc.h
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: Some various two's complement related C++ helper routines.
// Specifically, these help extract signed numbers from
// packed bitfields, while guaranteeing that the upper bits
// are properly sign extended (or not) as desired.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
#ifndef TWOC_H
#define TWOC_H
 
extern long sbits(const long val, const int bits);
extern unsigned long ubits(const long val, const int bits);
 
#endif
 
/zipcpu/trunk/sim/cpp/zipelf.cpp
0,0 → 1,246
///////////////////////////////////////////////////////////////////////////////
//
// Filename: zipelf.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose:
//
//
// 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 <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libelf.h>
#include <assert.h>
#include <gelf.h>
#include <string.h>
 
#include "zipelf.h"
 
bool
iself(const char *fname)
{
FILE *fp;
bool ret = true;
fp = fopen(fname, "rb");
 
if (!fp) return false;
if (0x7f != fgetc(fp)) ret = false;
if ('E' != fgetc(fp)) ret = false;
if ('L' != fgetc(fp)) ret = false;
if ('F' != fgetc(fp)) ret = false;
fclose(fp);
return ret;
}
 
void elfread(const char *fname, unsigned &entry, ELFSECTION **&sections)
{
Elf *e;
int fd, i;
size_t n;
char *id;
Elf_Kind ek;
GElf_Ehdr ehdr;
GElf_Phdr phdr;
const bool dbg = false;
 
if (elf_version(EV_CURRENT) == EV_NONE) {
fprintf(stderr, "ELF library initialization err, %s\n", elf_errmsg(-1));
perror("O/S Err:");
exit(EXIT_FAILURE);
} if ((fd = open(fname, O_RDONLY, 0)) < 0) {
fprintf(stderr, "Could not open %s\n", fname);
perror("O/S Err:");
exit(EXIT_FAILURE);
} if ((e = elf_begin(fd, ELF_C_READ, NULL))==NULL) {
fprintf(stderr, "Could not run elf_begin, %s\n", elf_errmsg(-1));
exit(EXIT_FAILURE);
}
 
ek = elf_kind(e);
if (ek == ELF_K_ELF) {
; // This is the kind of file we should expect
} else if (ek == ELF_K_AR) {
fprintf(stderr, "Cannot run an archive!\n");
exit(EXIT_FAILURE);
} else if (ek == ELF_K_NONE) {
;
} else {
fprintf(stderr, "Unexpected ELF file kind!\n");
exit(EXIT_FAILURE);
}
 
if (gelf_getehdr(e, &ehdr) == NULL) {
fprintf(stderr, "getehdr() failed: %s\n", elf_errmsg(-1));
exit(EXIT_FAILURE);
} if ((i=gelf_getclass(e)) == ELFCLASSNONE) {
fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1));
exit(EXIT_FAILURE);
} if ((id = elf_getident(e, NULL)) == NULL) {
fprintf(stderr, "getident() failed: %s\n", elf_errmsg(-1));
exit(EXIT_FAILURE);
} if (i != ELFCLASS32) {
fprintf(stderr, "This is a 64-bit ELF file, ZipCPU ELF files are all 32-bit\n");
exit(EXIT_FAILURE);
}
 
if (dbg) {
printf(" %-20s 0x%jx\n", "e_type", (uintmax_t)ehdr.e_type);
printf(" %-20s 0x%jx\n", "e_machine", (uintmax_t)ehdr.e_machine);
printf(" %-20s 0x%jx\n", "e_version", (uintmax_t)ehdr.e_version);
printf(" %-20s 0x%jx\n", "e_entry", (uintmax_t)ehdr.e_entry);
printf(" %-20s 0x%jx\n", "e_phoff", (uintmax_t)ehdr.e_phoff);
printf(" %-20s 0x%jx\n", "e_shoff", (uintmax_t)ehdr.e_shoff);
printf(" %-20s 0x%jx\n", "e_flags", (uintmax_t)ehdr.e_flags);
printf(" %-20s 0x%jx\n", "e_ehsize", (uintmax_t)ehdr.e_ehsize);
printf(" %-20s 0x%jx\n", "e_phentsize", (uintmax_t)ehdr.e_phentsize);
printf(" %-20s 0x%jx\n", "e_shentsize", (uintmax_t)ehdr.e_shentsize);
printf("\n");
}
 
 
// Check whether or not this is an ELF file for the ZipCPU ...
if (ehdr.e_machine != 0x0dad1) {
fprintf(stderr, "This is not a ZipCPU/8 ELF file\n");
exit(EXIT_FAILURE);
}
 
// Get our entry address
entry = ehdr.e_entry;
 
 
// Now, let's go look at the program header
if (elf_getphdrnum(e, &n) != 0) {
fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1));
exit(EXIT_FAILURE);
}
 
assert(n != 0);
 
unsigned total_octets = 0, current_offset=0, current_section=0;
for(i=0; i<(int)n; i++) {
total_octets += sizeof(ELFSECTION *)+sizeof(ELFSECTION);
 
if (gelf_getphdr(e, i, &phdr) != &phdr) {
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1));
exit(EXIT_FAILURE);
}
 
if (dbg) {
printf(" %-20s 0x%x\n", "p_type", phdr.p_type);
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset);
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr);
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr);
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz);
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz);
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags);
 
if (phdr.p_flags & PF_X) printf(" Execute");
if (phdr.p_flags & PF_R) printf(" Read");
if (phdr.p_flags & PF_W) printf(" Write");
printf("]\n");
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align);
}
 
total_octets += phdr.p_memsz;
}
 
char *d = (char *)malloc(total_octets + sizeof(ELFSECTION)+sizeof(ELFSECTION *));
memset(d, 0, total_octets);
 
ELFSECTION **r = sections = (ELFSECTION **)d;
current_offset = (n+1)*sizeof(ELFSECTION *);
current_section = 0;
 
for(i=0; i<(int)n; i++) {
r[i] = (ELFSECTION *)(&d[current_offset]);
 
if (gelf_getphdr(e, i, &phdr) != &phdr) {
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1));
exit(EXIT_FAILURE);
}
 
if (dbg) {
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset);
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr);
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr);
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz);
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz);
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags);
 
if (phdr.p_flags & PF_X) printf(" Execute");
if (phdr.p_flags & PF_R) printf(" Read");
if (phdr.p_flags & PF_W) printf(" Write");
printf("]\n");
 
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align);
}
 
current_section++;
 
r[i]->m_start = phdr.p_paddr;
r[i]->m_len = phdr.p_filesz;
 
current_offset += phdr.p_memsz + sizeof(ELFSECTION);
 
// Now, let's read in our section ...
if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) {
fprintf(stderr, "Could not seek to file position %08lx\n", phdr.p_offset);
perror("O/S Err:");
exit(EXIT_FAILURE);
} if (phdr.p_filesz > phdr.p_memsz)
phdr.p_filesz = 0;
if (read(fd, r[i]->m_data, phdr.p_filesz) != (int)phdr.p_filesz) {
fprintf(stderr, "Didnt read entire section\n");
perror("O/S Err:");
exit(EXIT_FAILURE);
}
 
/*
// Next, we need to byte swap it from big to little endian
for(unsigned j=0; j<r[i]->m_len; j++)
r[i]->m_data[j] = byteswap(r[i]->m_data[j]);
*/
 
if (dbg) for(unsigned j=0; j<r[i]->m_len; j++)
fprintf(stderr, "ADR[%04x] = %02x\n", r[i]->m_start+j,
r[i]->m_data[j] & 0x0ff);
}
 
r[i] = (ELFSECTION *)(&d[current_offset]);
r[current_section]->m_start = 0;
r[current_section]->m_len = 0;
 
elf_end(e);
close(fd);
}
 
/zipcpu/trunk/sim/cpp/zipelf.h
0,0 → 1,48
///////////////////////////////////////////////////////////////////////////////
//
// Filename: zipelf.h
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose:
//
//
// 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
//
//
///////////////////////////////////////////////////////////////////////////////
//
//
#ifndef ZIPELF_H
#define ZIPELF_H
 
#include <stdint.h>
 
class ELFSECTION {
public:
uint32_t m_start, m_len;
char m_data[4];
};
 
bool iself(const char *fname);
void elfread(const char *fname, uint32_t &entry, ELFSECTION **&sections);
 
#endif
/zipcpu/trunk/sim/cpp/zsim.cpp
0,0 → 1,1102
////////////////////////////////////////////////////////////////////////////////
//
// Filename: zsim.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: The main portion of a Simulator, not based upon any RTL or
// Verilog code. Why? To get something up and running and testing
// faster (even though the Verilog should be working/running?).
//
//
// 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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <vector>
#include <ctype.h>
#include "twoc.h"
#include "zipelf.h"
 
#define CC_CLRCACHE (1<<14)
#define CC_PHASE_BIT (1<<13)
#define CC_PHASE (1<<13)
#define CC_FPUERR (1<<12)
#define CC_DIVERR (1<<11)
#define CC_BUSERR (1<<10)
#define CC_TRAP (1<<9)
#define CC_ILL (1<<8)
#define CC_BREAK (1<<7)
#define CC_STEP (1<<6)
#define CC_GIE (1<<5)
#define CC_SLEEP (1<<4)
#define CC_V (1<<3)
#define CC_N (1<<2)
#define CC_C (1<<1)
#define CC_Z (1 )
 
class SIMDEV {
public:
virtual uint32_t lw(uint32_t addr) = 0;
virtual void sw(uint32_t addr, uint32_t vl) = 0;
 
virtual uint32_t lb(uint32_t addr) {
uint32_t v = lw(addr&-4);
 
// fprintf(stderr, "\tLH(%08x) -> %08x", addr, v);
v >>= (8*(3-(addr&3)));
// fprintf(stderr, " -> %08x", v);
v &= 0x0ff;
// fprintf(stderr, " -> %02x\n", v);
return v;
}
virtual uint32_t lh(uint32_t addr) {
uint32_t v = lw(addr&-4);
 
// fprintf(stderr, "\tLH(%08x) -> %08x", addr, v);
if ((addr&2)==0)
v >>= 16;
// fprintf(stderr, " -> %08x", v);
v &= 0x0ffff;
// fprintf(stderr, " -> %04x\n", v);
return v;
}
 
virtual void sh(uint32_t addr, uint32_t vl) {
uint32_t v = (vl & 0x0ffff);
v = v | (v<<16);
sw(addr, v);
}
 
virtual void sb(uint32_t addr, uint32_t vl) {
uint32_t v = (vl & 0x0ff);
v = v | (v<<16);
v = v | (v<<8);
sw(addr, v);
}
 
virtual bool interrupt(void) { return false; };
virtual void tick(void) {};
 
virtual void load(uint32_t addr, const char *buf, size_t ln) {}
};
 
class UARTDEV : public SIMDEV {
uint32_t m_setup;
bool m_debug;
public:
UARTDEV(void) { m_setup = 868; m_debug = false; }
 
virtual uint32_t lw(uint32_t addr) {
switch(addr&0x0c) {
case 0: return m_setup;
case 4: return 0;
case 8: return 0x100;
case 12: return 0;
} return 0;
}
virtual void sw(uint32_t addr, uint32_t vl) {
if (m_debug) fprintf(stderr,
"UART->SW(%08x, %08x)\n", addr, vl);
switch(addr&0x0c) {
case 0: m_setup = vl & 0x3fffffff; break;
case 4: break;
case 8: break;
case 12: putchar(vl & 0x0ff);
}
}
};
 
 
class MEMDEV : public SIMDEV {
protected:
char *m_mem;
bool m_dbg;
public:
MEMDEV(int nbits) {
m_mem = new char[(1<<nbits)];
m_dbg = false;
}
 
virtual uint32_t lw(uint32_t addr) {
unsigned char a, b, c, d;
uint32_t v;
 
a = m_mem[addr];
b = m_mem[addr+1];
c = m_mem[addr+2];
d = m_mem[addr+3];
v = (a<<24)|(b<<16)|(c<<8)|d;
 
if (m_dbg) fprintf(stderr,
"\tReading %08x -> %02x:%02x:%02x:%02x -> v=%08x\n", addr,
a, b, c, d, v);
 
return v;
}
 
virtual void sw(uint32_t addr, uint32_t vl) {
uint32_t maddr = addr & -4;
m_mem[(maddr) ] = (vl >>24)&0x0ff;
m_mem[(maddr)+1] = (vl >>16)&0x0ff;
m_mem[(maddr)+2] = (vl >> 8)&0x0ff;
m_mem[(maddr)+3] = (vl )&0x0ff;
 
if (m_dbg)
fprintf(stderr,
"\tSW %08x <- %08x - %02x:%02x:%02x:%02x\n",
addr, vl, m_mem[(maddr) ] & 0x0ff,
m_mem[(maddr)+1] & 0x0ff,
m_mem[(maddr)+2] & 0x0ff,
m_mem[(maddr)+3] & 0x0ff);
}
 
virtual void sh(uint32_t addr, uint32_t vl) {
uint32_t maddr = addr & -2;
m_mem[(maddr) ] = (vl >> 8)&0x0ff;
m_mem[(maddr)+1] = (vl )&0x0ff;
if (m_dbg)
fprintf(stderr, "\tSH %08x <- %04x - %02x:%02x\n",
addr, vl & 0x0ffff, m_mem[(maddr) ] & 0x0ff,
m_mem[(maddr)+1] & 0x0ff);
}
 
virtual void sb(uint32_t addr, uint32_t vl) {
m_mem[addr] = vl;
if (m_dbg)
fprintf(stderr, "\tSB %08x <- %02x\n",
addr, vl & 0x0ff);
}
 
void load(uint32_t addr, const char *src, size_t n) {
memcpy(&m_mem[addr], src, n);
}
};
 
class ROMDEV : public MEMDEV {
public:
ROMDEV(int nbits) : MEMDEV(nbits) {}
 
// virtual uint32_t lw(uint32_t addr);
virtual void sw(uint32_t addr, uint32_t vl) {}
virtual void sh(uint32_t addr, uint32_t vl) {}
virtual void sb(uint32_t addr, uint32_t vl) {}
void load(uint32_t addr, const char *src, size_t n) {
memcpy(&m_mem[addr], src, n);
}
};
 
#ifndef L_OK
#define L_OK 8 // Okay for loads
#endif
 
class SIMENTRY {
public:
SIMDEV *m_dev;
uint32_t m_addr, m_mask;
int m_flags;
char *m_name;
};
 
class SIMBUS {
bool m_buserr;
std::vector<SIMENTRY *> m_devlist;
int getdev(uint32_t addr) {
for(size_t i=0; i<m_devlist.size(); i++)
if ((addr&m_devlist[i]->m_mask)==m_devlist[i]->m_addr){
return i;
}
 
/*
fprintf(stderr, "GETDEV(0x%08x) - not found\n", addr);
for(size_t i=0; i<m_devlist.size(); i++) {
fprintf(stderr, "ADDR(0x%08x) & 0x%08x = %08x != %08x\n",
addr, m_devlist[i]->m_mask,
addr & m_devlist[i]->m_mask,
m_devlist[i]->m_addr);
} */
 
return -1;
}
int getwrdev(uint32_t addr) {
int devid = getdev(addr);
if (0 <= devid) {
if (m_devlist[devid]->m_flags & W_OK)
return devid;
fprintf(stderr, "ADDRESS %08x in %s is not writable!!\n", addr, m_devlist[devid]->m_name);
}
else fprintf(stderr, "ADDRESS %08x not found\n", addr);
return -1;
}
int getexdev(uint32_t addr) {
int devid = getdev(addr);
if (0 <= devid) {
if (m_devlist[devid]->m_flags & X_OK)
return devid;
fprintf(stderr, "Address in %s is not executable\n", m_devlist[devid]->m_name);
}
fprintf(stderr, "ExDEV not found (0x%08x), devid = %d\n", addr, devid);
return -1;
}
public:
SIMBUS(void) { m_buserr = false; }
void add(SIMDEV *dev, uint32_t addr, uint32_t mask, const char *p, const char *name = "") {
SIMENTRY *s = new SIMENTRY;
 
s->m_dev = dev;
s->m_addr= addr;
s->m_mask= mask;
s->m_name= strdup(name);
s->m_flags= 0;
 
if ((strchr(p, 'w'))||(strchr(p, 'W')))
s->m_flags |= W_OK;
if ((strchr(p, 'r'))||(strchr(p, 'R')))
s->m_flags |= R_OK;
if ((strchr(p, 'x'))||(strchr(p, 'X')))
s->m_flags |= X_OK;
if ((strchr(p, 'l'))||(strchr(p, 'L')))
s->m_flags |= L_OK;
m_devlist.push_back(s);
}
 
uint32_t lb(uint32_t addr) {
int devid;
if (0 <= (devid = getdev(addr)))
return m_devlist[devid]->m_dev->lb(addr & (~m_devlist[devid]->m_mask));
m_buserr = true;
return 0;
}
uint32_t lh(uint32_t addr) {
int devid;
if (0 <= (devid = getdev(addr)))
return m_devlist[devid]->m_dev->lh(addr & ((~m_devlist[devid]->m_mask)&-2));
m_buserr = true;
return 0;
}
uint32_t lw(uint32_t addr) {
int devid;
if (0 <= (devid = getdev(addr)))
return m_devlist[devid]->m_dev->lw(addr & ((~m_devlist[devid]->m_mask)&-4));
m_buserr = true;
return 0;
}
uint32_t lx(uint32_t addr) {
int devid;
if (0 <= (devid = getexdev(addr)))
return m_devlist[devid]->m_dev->lw(addr & ((~m_devlist[devid]->m_mask)&-4));
m_buserr = true;
return 0;
}
void sb(uint32_t addr, uint32_t vl) {
int devid;
if (0 <= (devid = getwrdev(addr))) {
return m_devlist[devid]->m_dev->sb(addr & (~m_devlist[devid]->m_mask), vl & 0x0ff);
} else {
fprintf(stderr, "No such address, %08x\n", addr);
}
m_buserr = true;
return;
}
void sh(uint32_t addr, uint32_t vl) {
int devid;
if (0 <= (devid = getwrdev(addr)))
return m_devlist[devid]->m_dev->sh(addr & -2 & (~m_devlist[devid]->m_mask), vl & 0x0ffff);
m_buserr = true;
return;
}
void sw(uint32_t addr, uint32_t vl) {
int devid;
if (0 <= (devid = getwrdev(addr)))
return m_devlist[devid]->m_dev->sw(addr & -4 & (~m_devlist[devid]->m_mask), vl);
m_buserr = true;
return;
}
bool interrupt(void) { return false; };
 
bool error(void) {
bool tmp = m_buserr;
m_buserr = false;
return tmp;
}
 
void tick(void) {
for(size_t i=0; i<m_devlist.size(); i++)
m_devlist[i]->m_dev->tick();
}
 
void load(uint32_t addr, const char *data, size_t len) {
int devid;
if ((0 <= (devid = getdev(addr)))
&&(m_devlist[devid]->m_flags & L_OK))
m_devlist[devid]->m_dev->load(
addr & (~m_devlist[devid]->m_mask), data, len);
else {
fprintf(stderr, "DEVID = %d\n", devid);
m_buserr = true;
} return;
}
};
 
class ZIPMACHINE {
bool m_gie, m_jumped, m_advance_pc, m_locked;
int m_lockcount;
unsigned long m_icount;
public:
uint32_t m_r[32];
SIMBUS *m_bus;
FILE *m_mapf;
 
ZIPMACHINE(void) {
m_locked = false; m_lockcount = 0;
m_mapf = NULL;
m_bus = NULL;
m_gie = false;
m_jumped= m_advance_pc = false;
m_icount = 0;
}
 
void dump() {
fflush(stderr);
fflush(stdout);
printf("ZIPM--DUMP: ");
if (gie())
printf("Interrupts-enabled\n");
else
printf("Supervisor mode\n");
printf("\n");
 
printf("sR0 : %08x ", m_r[0]);
printf("sR1 : %08x ", m_r[1]);
printf("sR2 : %08x ", m_r[2]);
printf("sR3 : %08x\n",m_r[3]);
printf("sR4 : %08x ", m_r[4]);
printf("sR5 : %08x ", m_r[5]);
printf("sR6 : %08x ", m_r[6]);
printf("sR7 : %08x\n",m_r[7]);
printf("sR8 : %08x ", m_r[8]);
printf("sR9 : %08x ", m_r[9]);
printf("sR10: %08x ", m_r[10]);
printf("sR11: %08x\n",m_r[11]);
printf("sR12: %08x ", m_r[12]);
printf("sSP : %08x ", m_r[13]);
printf("sCC : %08x ",(m_r[14] & (~CC_GIE)));
printf("sPC : %08x\n",m_r[15]);
 
printf("\n");
 
printf("uR0 : %08x ", m_r[16]);
printf("uR1 : %08x ", m_r[17]);
printf("uR2 : %08x ", m_r[18]);
printf("uR3 : %08x\n",m_r[19]);
printf("uR4 : %08x ", m_r[20]);
printf("uR5 : %08x ", m_r[21]);
printf("uR6 : %08x ", m_r[22]);
printf("uR7 : %08x\n",m_r[23]);
printf("uR8 : %08x ", m_r[24]);
printf("uR9 : %08x ", m_r[25]);
printf("uR10: %08x ", m_r[26]);
printf("uR11: %08x\n",m_r[27]);
printf("uR12: %08x ", m_r[28]);
printf("uSP : %08x ", m_r[29]);
printf("uCC : %08x ",(m_r[30]|CC_GIE));
printf("uPC : %08x\n",m_r[31]);
printf("\n");
fflush(stderr);
fflush(stdout);
}
 
void ccodes(uint32_t newflags) {
m_r[14+rbase()] = (cc() & -16)|(newflags&0x0f);
}
 
int rbase(void) { return m_gie?16:0; }
bool gie() { return m_gie; };
bool locked() { return m_locked; };
bool sleeping() {
return (gie())&&(m_r[14+16]&CC_SLEEP)?true:false;
};
bool sleep(bool nv) {
if (nv) {
m_r[14 ] |= CC_SLEEP;
m_r[14+16] |= CC_SLEEP;
} else {
m_r[14 ] &= (~CC_SLEEP);
m_r[14+16] &= (~CC_SLEEP);
} return sleeping();
};
bool halted() {
return (!gie()) && (m_r[14]&CC_SLEEP);
};
uint32_t cc() { return m_r[14+rbase()]|((m_gie)?CC_GIE:0); };
bool fault() {
if (cc() & (CC_PHASE|CC_ILL|CC_BREAK|CC_BUSERR|CC_DIVERR))
return true;
return false;
}
bool gie(bool v) {
m_jumped = (m_gie != v);
m_gie = v;
return v;
}
bool jumped(void) { return m_jumped; };
void pc_advance(bool pcgie) {
m_r[15+((pcgie)?16:0)] += 4;
m_r[15+((pcgie)?16:0)] &= -4;
} void pc_advance(void) { pc_advance(gie()); }
uint32_t pc(void) {
return m_r[15+rbase()];
}
 
static uint32_t bitreverse(uint32_t bv) {
uint32_t b, r=0;
for(b=0; b<32; b++, bv>>=1)
r = (r<<1)|(bv&1);
return r;
}
 
void init(SIMBUS *bus) {
m_bus = bus;
for(int i=0; i<32; i++)
m_r[i] = 0;
m_gie = false;
}
 
void siminsn(uint32_t insn) {
// fprintf(stderr, "SIM-INSN(0x%08x)\n", insn);
if ((insn & 0x0fffff)==0x00100) {
// SIM Exit(0)
exit(0);
} else if ((insn & 0x0ffff0)==0x00310) {
// SIM Exit(User-Reg)
int rcode;
rcode = m_r[(insn&0x0f)+16] & 0x0ff;
exit(rcode);
} else if ((insn & 0x0ffff0)==0x00300) {
// SIM Exit(Reg)
int rcode;
rcode = m_r[(insn&0x0f)+rbase()] & 0x0ff;
exit(rcode);
} else if ((insn & 0x0fff00)==0x00100) {
// SIM Exit(Imm)
int rcode;
rcode = insn & 0x0ff;
exit(rcode);
} else if ((insn & 0x0fffff)==0x002ff) {
// Full/unconditional dump
fprintf(stderr, "SIM-DUMP\n");
dump();
} else if ((insn & 0x0ffff0)==0x00200) {
// Dump a register
int rid = (insn&0x0f)+rbase();
fprintf(stderr, "R[%2d] = 0x%08x\n", rid, m_r[rid]);
} else if ((insn & 0x0ffff0)==0x00210) {
// Dump a user register
int rid = (insn&0x0f);
fprintf(stderr, "uR[%2d] = 0x%08x\n", rid, m_r[rid+16]);
} else if ((insn & 0x0ffff0)==0x00230) {
// SOUT[User Reg]
int rid = (insn&0x0f)+16;
fprintf(stderr, "%c", m_r[rid]&0x0ff);
} else if ((insn & 0x0fffe0)==0x00220) {
// SOUT[User Reg]
int rid = (insn&0x0f)+rbase();
fprintf(stderr, "%c", m_r[rid]&0x0ff);
} else if ((insn & 0x0fff00)==0x00400) {
// SOUT[Imm]
fprintf(stderr, "%c", insn&0x0ff);
} else { // if ((insn & 0x0f7c00000)==0x77800000)
uint32_t imm = insn & 0x03fffff;
// Simm instruction that we dont recognize
// if (imm)
fprintf(stderr, "SIM 0x%08x\n", imm);
}
}
 
void fullinsn(uint32_t insn) {
bool wf, wb, fpu, noop, lock, wbreak, cmptst, mem,
sto, ldi, mov, div, execinsn;
bool diverr, illegal;
uint32_t av, bv, result, f, arg, brg, opc;
int32_t imm;
int rb, cnd;
const bool dbg = false;
 
m_icount ++ ;
 
if (dbg) {
fprintf(stderr, "%8ld INSN(@0x%08x, %08x)", m_icount, pc(), insn);
if (m_mapf) {
// bool dbg = pc() == 0x040003cc;
char line[512], needle[512], *ptr = NULL,*lp;
sprintf(needle, "%08x", pc());
rewind(m_mapf);
while(NULL != (lp = fgets(line, sizeof(line), m_mapf))) {
while((*lp)&&(isspace(*lp)))
lp++;
if ((*lp != '0')||(tolower(*lp) == 'x'))
continue;
// if (dbg)fprintf(stderr, "\tMAP (%s?) %s\n", needle, lp);
if (NULL != (ptr = strstr(lp, needle))){
break;
}
} if (ptr) {
if (strlen(ptr) > 8)
ptr += 8;
while((*ptr)&&(isspace(*ptr)))
ptr++;
int ln = strlen(ptr);
while((ln > 0)&&(isspace(ptr[ln-1])))
ptr[--ln] = '\0';
fprintf(stderr, "\t%s", ptr);
} else if (0x7b400000 == (insn&0x7fffffff))
fprintf(stderr, "\treturn");
} else fprintf(stderr, "\tNO-MAPF");
fprintf(stderr, "\n");
}
m_jumped = false;
m_advance_pc = true;
illegal = false;
noop = false;
lock = false;
wbreak = false;
 
if (m_locked) {
m_lockcount--;
if (m_lockcount <= 0)
m_locked = false;
}
 
m_r[14+rbase()]
&= ~(CC_ILL|CC_BREAK|CC_BUSERR|CC_DIVERR);
 
opc = (insn >> 22) & 0x01f;
arg = (insn >> 27) & 0x0f;
brg = (insn >> 14) & 0x0f;
 
cmptst=((opc&0x1e)==0x010);
mem = ((opc&0x1c) == 0x014)||((opc&0x1e) == 0x012);
sto = (mem)&&(opc&1);
fpu =(((opc&0x1c)==0x1c) // Top four FPU ops
||((opc&0x1e)==0x1a)); // Bottom two FPU ops
div =((opc&0x1e)==0x0e);
ldi =((opc&0x1e)==0x18);
mov =((opc&0x1f)==0x0d);
 
if (ldi) imm = sbits(insn, 23);
else if (mov) imm = sbits(insn, 13);
else if (insn & 0x040000)
imm = sbits(insn, 14);
else imm = sbits(insn, 18);
 
// Do we read the B register?
rb = (mov)||(((insn>>18)&1)&&(!ldi));
 
// WriteBack
wb = (!cmptst)&&(!sto);
 
// Do we write flags back?
wf = true;
if (ldi) wf = false;
if (mov) wf = false;
if (mem) wf = false;
if (opc==0x08) wf = false; // BREV
if (opc==0x09) wf = false; // LDILO
if ((!cmptst)&&((arg & 0x0e)==0x0e)) // Writes to CC or PC
wf = false; // dont set the flags.
 
cnd = (ldi) ? 0 : ((insn >> 19) & 7);
 
if (fpu & ((arg&0x0e)==0x0e)) {
fpu = false;
noop = ((opc&0x1e) == 0x1e);
lock = ((opc&0x1f) == 0x1d);
wbreak = ((opc&0x1f) == 0x1c);
illegal = !(noop|lock|wbreak);
wb = false;
wf = false;
cnd = 0;
} else if (div & ((arg&0x0e)==0x0e)) {
illegal = true;
}
 
if (cnd != 0) {
if (!cmptst)
wf = false;
int ccodes = cc() & 0x0f;
switch(cnd) {
case 1: execinsn = (ccodes & CC_Z); break;
case 2: execinsn = (ccodes & CC_N); break;
case 3: execinsn = (ccodes & CC_C); break;
case 4: execinsn = (ccodes & CC_V); break;
case 5: execinsn = ((ccodes & CC_Z)==0); break; // NZ
case 6: execinsn = ((ccodes & CC_N)==0); break; // GE
case 7: execinsn = ((ccodes & CC_C)==0); break; // NC
default: execinsn = true; break;
}
} else
execinsn = true;
 
if ((mov)&&(!gie())) {
// Supervisor can read all registers
arg |= (insn&0x40000)?0x10:0;
brg |= (insn&0x02000)?0x10:0;
} else {
arg |= (gie())?0x10:0;
brg |= (gie())?0x10:0;
}
result = 0;
 
bv = imm;
if (rb) {
if ((brg&0x0f)==15) { // PC
bv = (imm << 2) + m_r[brg];
if (gie()) {
if (brg & 0x010)
bv += 4;
} else if ((brg & 0x10)==0)
bv += 4;
} else
bv += m_r[brg];
}
av = m_r[arg];
if ((int)arg == 15 + rbase())
av += 4;
 
if (execinsn) {
f = 0; // Resulting flags
if (fpu) {
float fva, fvb, fvr;
fva = *(float *)&av;
fvb = *(float *)&bv;
 
switch(opc) {
case 26: fvr = fva + fvb; break;
case 27: fvr = fva - fvb; break;
case 28: fvr = fva * fvb; break;
case 29: fvr = fva / fvb; break;
case 30: fvr = (float)bv; break;
case 31: result = (int)fvb; break;
default: illegal = true;
} if (opc != 31)
result = *(uint32_t *)&fvr;
if (result == 0)
f = CC_Z;
if (opc == 31) {
if (result & 0x80000000)
f |= CC_N;
} else if (fvr < 0.0)
f |= CC_N;
} else if (noop) {
if (insn != 0x7fc00000)
siminsn(insn);
} else if (wbreak) {
wf = wb = false;
m_advance_pc = false;
if (gie()) {
m_r[16+14] &= CC_BREAK;
gie(false);
} else {
fprintf(stderr, "BREAK!\n");
dump();
exit(EXIT_FAILURE);
}
} else if (lock) {
m_locked = true;
m_lockcount = 3;
} else {
uint32_t presign = (av>>31)&1, nsgn;
switch(opc) {
case 0: case 16: { // SUB, or CMP
result = av - bv;
if (av < bv)
f |= CC_C;
nsgn = (result >> 31)&1;
if (presign != nsgn)
f |= CC_V;
} break;
case 1: case 17: result = bv & av; break;//AND or TST
case 2: { // ADD
result = bv + av;
if (result<(uint64_t)bv+(uint64_t)av)
f |= CC_C;
nsgn = (result >> 31)&1;
if (presign != nsgn)
f |= CC_V;
} break;
case 3: result = bv | av; break; // OR
case 4: result = bv ^ av; break; // XOR
case 5: { // LSR
uint32_t nsgn;
if (bv >= 32)
result = 0;
else
result = ((uint32_t)av >> bv);
nsgn = (result >> 31)&1;
if (presign != nsgn)
f |= CC_V;
 
if ((bv !=0)&&(bv<33)&&(av&(1<<(bv-1))))
f |= CC_C;
} break;
case 6: { // LSL
uint32_t nsgn;
if (bv >= 32)
result = 0;
else
result = av << bv;
nsgn = (result >> 31)&1;
if (presign != nsgn)
f |= CC_V;
if((bv !=0)&&(bv<33)&&(av&(1<<(33-bv))))
f |= CC_C;
} break;
case 7: { // ASR
if ((bv >= 32)&&(av & 0x80000000))
result = -1;
else if (bv >= 32)
result = 0;
else
result = ((int)av >> bv);
 
if (av & 0x80000000) {
// Signed carry
if (bv >= 31)
f |= CC_C;
else if((bv != 0)
&&(av&(1<<(33-bv))))
f |= CC_C;
} else {
// Unsigned carry
if((bv !=0)&&(bv<32)
&&(av&(1<<(33-bv))))
f |= CC_C;
}
} break;
case 8: result = bitreverse(bv); break; // BREV
case 9: result = (av&0xffff0000)|(bv&0x0ffff); break; // LDILO
case 10: { // MPYUHI
uint64_t ulv = av * bv;
result = (ulv >> 32);
} break;
case 11: { // MPYSHI
int64_t lv = av * bv;
result = (lv >> 32);
} break;
case 12: { // MPY
int64_t ulv = av * bv;
// bool sn = (av<0)^(bv<0);
result = (int32_t)(ulv & 0x0ffffffff);
//if (((result&0x80000000)?1:0)
// ^ ((sn)?1:0))
// f |= CC_V;
} break;
case 13: result = bv; break; // MOV
case 14: { // DIVU
if (bv == 0)
diverr = true;
else
result = (uint32_t)av
/ (uint32_t)bv;
} break;
case 15: { // DIVS
if (bv == 0)
diverr = true;
else
result =(int32_t)av/(int32_t)bv;
} break;
// case 16: result = av - bv; break;
// case 17: result = av & bv; break;
case 18: result = m_bus->lw(bv);
break;// LW
case 19:
m_bus->sw(bv, av); break;// SW
case 20: result = m_bus->lh(bv);break;// LH
case 21: m_bus->sh(bv, av); break;// SH
case 22: result = m_bus->lb(bv);break;// LB
case 23: m_bus->sb(bv, av); break;// SB
case 24: result = bv; break;// LDI
case 25: result = bv; break;// LDI
default: illegal = true;
}
if (result == 0)
f |= CC_Z;
if (result & 0x80000000)
f |= CC_N;
}
 
if (illegal) {
if (gie()) {
m_r[16+14] |= CC_ILL;
gie(false);
m_jumped = true;
m_advance_pc = false;
} else {
m_r[14] |= CC_ILL;
fprintf(stderr, "ILLegal Instruction Exception\n");
dump();
exit(EXIT_FAILURE);
}
} else if ((mem)&&(m_bus->error())) {
if (gie()) {
m_r[16+14] |= CC_BUSERR;
gie(false);
m_jumped = true;
m_advance_pc = false;
} else {
m_r[14] |= CC_BUSERR;
fprintf(stderr, "BUS ERR\n");
dump();
exit(EXIT_FAILURE);
}
} else if ((div)&&(diverr)) {
if (gie()) {
m_r[16+14] |= CC_DIVERR;
gie(false);
m_jumped = true;
m_advance_pc = false;
} else {
m_r[14] |= CC_DIVERR;
fprintf(stderr, "DIV ERR: division by zero\n");
dump();
exit(EXIT_FAILURE);
}
} if (wf)
ccodes(f);
if (wb) {
if (arg == (uint32_t)(15+rbase()))
m_jumped = true;
else if (arg == (uint32_t)(14+rbase())) {
if (gie()) {
if ((result & CC_GIE)==0) {
result |= CC_TRAP;
result &= (~(CC_SLEEP
|CC_ILL
|CC_BREAK
|CC_BUSERR
|CC_DIVERR
|CC_FPUERR
|CC_STEP
|CC_SLEEP));
}
} else if (result & CC_GIE) {
// Returning to userspace
m_r[16+14] &= (~(CC_ILL
|CC_BREAK
|CC_BUSERR
|CC_DIVERR
|CC_FPUERR));
}
}
if (dbg) fprintf(stderr,
"\tREG[%02x] = %08x\n", arg, result);
m_r[arg] = result;
if ((int)arg == 15+rbase())
m_advance_pc = false;
if (((int)arg==14+rbase())&&(((m_gie)?1:0)^((result&CC_GIE)?1:0))) {
gie((result&CC_GIE)?true:false);
// Prevent us from advancing the PC
m_jumped = true;
// m_advance_pc = true;
}
// Some CC bits are constant. Keep them that
// way.
m_r[14 ] &= (~CC_GIE);
m_r[14+16] |= ( CC_GIE);
m_r[15 ] &= -4;
m_r[15+16] &= -4;
}
}
}
 
void cisinsn(uint16_t insn) {
uint32_t imm;
int dr, br, cisop, fullop;
 
cisop = (insn >> 8) & 0x07;
switch(cisop) {
case 0: fullop = 0; break; // SUB
case 1: fullop = 1; break; // AND
case 2: fullop = 2; break; // ADD
case 3: fullop = 16; break; // CMP
case 4: fullop = 18; break; // LW
case 5: fullop = 19; break; // SW
case 6: fullop = 24; break; // LDI
case 7: fullop = 13; break; // MOV
}
 
dr = (insn>>11) & 0x0f;
 
if (fullop == 24) {
// LDI
imm = sbits(insn, 8) & 0x07fffff;
fullinsn(0x80000000 | (dr<<27) | (fullop<<22) | imm);
} else if (fullop == 13) {
// MOV
br = (insn >> 3) & 0x0f;
imm = sbits(insn, 3) & 0x01fff;
fullinsn(0x80000000 | (dr << 27) | (fullop<<22) | (br<<14) | imm);
} else if (insn & 0x80) {
// Uses a breg
br = (insn >> 3) & 0x0f;
imm = sbits(insn, 3) & 0x3fff;
fullinsn(0x80040000 | (dr << 27) | (fullop<<22) | (br<<14) | imm);
} else if ((fullop == 18)||(fullop == 19)) {
// Load or store, breg is assumed to be SP
// 0x04844000
br = 13;
imm = sbits(insn, 7) & 0x3fff;
fullinsn(0x80040000 | (dr << 27) | (fullop<<22) | (br<<14) | imm);
} else {
imm = sbits(insn, 7) & 0x03ffff;
fullinsn(0x80000000 | (dr << 27) | (fullop<<22) | imm);
}
}
 
void execute(uint32_t insn) {
/// fprintf(stderr, "EXEC-INSN(@0x%08x - %08x)\n", pc(), insn);
bool igie = gie();
if (insn & 0x80000000) {
int ibase = rbase();
cisinsn((insn>>16) & 0x0ffff);
if (m_advance_pc)
m_r[14+ibase] |= (CC_PHASE);
if ((!m_jumped)&&(igie == gie())) {
cisinsn(insn & 0x0ffff);
m_r[14+ibase] &= ~(CC_PHASE);
} if (m_advance_pc)
pc_advance(igie);
m_jumped = false;
} else {
m_r[14+rbase()] &= ~(CC_PHASE);
fullinsn(insn);
 
if (m_advance_pc)
pc_advance(igie);
 
if ((gie())&&(cc() & CC_STEP))
gie(false);
}
}
};
 
int main(int argc, char **argv) {
const char *executable = "a.out";
SIMBUS *bus;
bool done;
ZIPMACHINE *zipm;
ELFSECTION **secpp, *secp;
uint32_t entry;
 
if (argc > 1)
executable = argv[1];
if (access(executable, R_OK)!=0) {
fprintf(stderr, "Cannot read %s\n", executable);
exit(EXIT_FAILURE);
} elfread(executable, entry, secpp);
if (0 == secpp[0]->m_len) {
fprintf(stderr, "Executable file has no contents!\n");
exit(EXIT_FAILURE);
}
 
// Timer at 0x0100?
// Buserr at 0x0101?
// Addresses are given in 32-bit glory, so they reference 8-bit bytes
bus = new SIMBUS();
// BUSITEM net = new NETDEV();
 
bus->add(new UARTDEV(), 0x00000150, 0xfffffff0, "RW", "UART");// 4 words
// bus->add(new SDCDEV(12), 0x00000420, 0xfffffff0, "RW");// 4 words
// bus->add(net->ctrl, 0x00000440, 0xffffffe0, "RW");// 8 words
// bus->add(net->data, 0x00002000, 0xffffe000, "R"); // 8 words
// bus->add(net->data, 0x00003000, 0xffffe000, "R"); // 8 words
bus->add(new MEMDEV(17), 0x0020000, 0x7fe0000, "RWX", "BlockRAM");// Block RAM
bus->add(new ROMDEV(24),0x01000000,0xff000000, "RXL", "Flash"); // Flash
bus->add(new MEMDEV(28),0x10000000,0xf0000000, "RWX", "SDRAM");// SDRAM
 
for(int s=0; secpp[s]->m_len; s++) {
secp = secpp[s];
if (false) fprintf(stderr,
"Attempting to LOAD->(%08x, ..., %d)\n",
secp->m_start, secp->m_len);
bus->load(secp->m_start, (const char *)&secp->m_data[0], secp->m_len);
if (bus->error()) {
fprintf(stderr, "LOAD: Error writing to mem @ 0x%08x\n", secp->m_start);
// exit(EXIT_FAILURE);
}
}
 
if(bus->error()) {
fprintf(stderr, "ERR: Executable file doesn\'t fit in simulator\n");
exit(EXIT_FAILURE);
}
 
done = false;
zipm = new ZIPMACHINE;
if (access("map.txt", R_OK)==0)
zipm->m_mapf = fopen("map.txt","r");
zipm->init(bus);
zipm->m_r[15] = entry;
while(!done) {
uint32_t insn;
insn = bus->lx(zipm->pc());
 
if (bus->error()) {
if (zipm->gie()) {
zipm->m_r[14+16] |= CC_BUSERR;
zipm->gie(false);
continue;
} else {
zipm->m_r[14] |= CC_BUSERR;
fprintf(stderr, "IFetch BUSERR, %08x\n", zipm->pc());
zipm->dump();
exit(EXIT_FAILURE);
}
} else {
if (!zipm->sleeping())
zipm->execute(insn);
}
 
if (zipm->halted()) {
fflush(stderr);
fflush(stdout);
printf("CPU HALT\n");
done = true;
break;
}
 
bus->tick();
if ((bus->interrupt())&&(zipm->gie())&&(!zipm->locked())) {
zipm->gie(false);
zipm->sleep(false);
}
}
}
 
/zipcpu/trunk/sim/verilator/.gitignore
0,0 → 1,8
div_tb
mpy_tb
*debug.txt
*dump.txt
pdump
zippy_tb
pfcache_tb
zipmmu_tb
/zipcpu/trunk/sim/verilator/Makefile
0,0 → 1,208
################################################################################
#
# Filename: Makefile
#
# Project: Zip CPU -- a small, lightweight, RISC CPU soft core
#
# Purpose: This makefile builds the final verilator simulation of the
# zipsystem. Specifically, it builds the final C++ portion
# of the simulator, and thus the final simulator executable.
#
# This simulator depends upon the libelf and ncurses libraries.
#
# Useful targets of this makefile include:
#
# zippy_tb (default)
# This is the test bench program / simulator that is built by
# this directory.
#
# test
# Runs the simulator on a test program found in the trunk/sw/zasm
# directory. That program needs to be built via 'make test' in
# that directory before this make test will work. Changes to the
# test itself will require a 'make test' in trunk/sw/zasm as well
# as 'make test' in this directory.
#
# The test itself consists of two tests. The first, the "step"
# test, tests whether the test works via "step"ing the CPU.
# This would be the interface to the CPU were the CPU placed in
# a device.
#
# The second test is an internal test which works by just running
# the CPU without step instructions.
#
# In either case the test is over upon reaching either a HALT
# or a BUSY instruction. A HALT instruction indicates success,
# BUSY a failure.
#
# stest
# Runs the test in "step" mode as described above.
#
# itest
# Runs the test file in interactive mode. The CPU will not
# execute any instructions without user interaction. This is
# useful for actually debugging the test. The other two modes
# are useful for quickly determining that the CPU does (or
# doesn't) work.
#
# dhrystone
# Runs a hand-optimized version of the dhrystone benchmark.
# Using the instructions at the top of the dhrystone assembly
# file, you should be able to convert the result to DMIPS or even
# DMIPS/MHz.
#
# div_tb
# A raw test bench to test the divide unit separate from the
# rest of the CPU. This test will fail with a failed assert()
# if unsuccessful, or complete with no error (but lots of
# 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.
#
# pfcache_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
# so configured by default.) This file will be name pfile.bin.
# pdump is a very simple program designed to read this file and
# produce some (very raw) information from it. To use this,
# type pdump and the name of the executable file, such as
# ../asm/zipdhry.z, and examine how many times each instruction
# was executed, and how many stalls took place between each
# instruction and the next.
#
# clean
# Removes all products of compilation--specifically zippy_tb,
# pdump and div_tb.
#
#
# Creator: Dan Gisselquist, Ph.D.
# Gisselquist Technology, LLC
#
################################################################################
#
# Copyright (C) 2015-2017, 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
#
#
################################################################################
#
all: zippy_tb pdump div_tb mpy_tb pfcache_tb # zipmmu_tb
 
CXX := g++
CFLAGS := -Wall -Og -g
OBJDIR := obj-pc
ZASM := ../../sw/zasm
RTLD := ../../rtl
RTLOBJD := $(RTLD)/obj_dir
BENCHOBJD:= ../../bench/rtl/obj_dir
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"')
VROOT := $(VERILATOR_ROOT)
VINCS := -I$(VROOT)/include -I$(VROOT)/include/vltstd
INCS := -I$(RTLOBJD) -I$(RTLD) -I$(ZASM) $(VINCS)
ZLIBSRCS:= zipelf.cpp twoc.cpp byteswap.cpp
SOURCES := $(ZLIBSRCS) pdump.cpp zippy_tb.cpp memsim.cpp
ZDSMSRCS:= zopcodes.cpp
ZOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(ZLIBSRCS) $(ZDSMSRCS)))
SIMSRCS := zippy_tb.cpp memsim.cpp $(ZLIBSRCS) $(ZDMSRCS)
SIMOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SIMSRCS) $(ZDSMSRCS)))
VLSRCS := verilated.cpp verilated_vcd_c.cpp
VLOBJS := $(OBJDIR)/verilated.o $(OBJDIR)/verilated_vcd_c.o
VLIB := $(addprefix $(VROOT)/include/,$(VLSRCS))
RAWLIB := $(RTLOBJD)/Vzipsystem__ALL.a
LIBS := $(RAWLIB) -lncurses -lelf
TESTF := $(ZASM)/z.out
DHRYSTONEF := ../asm/zipdhry.z
 
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CFLAGS) $(INCS) -c $< -o $@
 
$(OBJDIR)/%.o: $(ZASM)/%.cpp
$(CXX) $(CFLAGS) $(INCS) -c $< -o $@
 
$(OBJDIR)/%.o: $(VROOT)/include/%.cpp
$(CXX) $(CFLAGS) $(INCS) -c $< -o $@
 
zippy_tb: $(SIMOBJS) $(VLOBJS) $(RAWLIB)
$(CXX) $(CFLAGS) $(INCS) $(SIMOBJS) $(VLOBJS) $(RAWLIB) $(LIBS) -o $@
 
div_tb: div_tb.cpp twoc.cpp $(VLIB) $(RTLOBJD)/Vdiv__ALL.a testb.h
$(CXX) $(CFLAGS) $(INCS) div_tb.cpp twoc.cpp $(VLIB) $(RTLOBJD)/Vdiv__ALL.a -o $@
 
mpy_tb: mpy_tb.cpp twoc.cpp $(VLIB) $(RTLOBJD)/Vcpuops__ALL.a testb.h
$(CXX) $(CFLAGS) $(INCS) mpy_tb.cpp twoc.cpp $(VLIB) $(RTLOBJD)/Vcpuops__ALL.a -o $@
 
zipmmu_tb: zipmmu_tb.cpp $(VLIB) $(BENCHOBJD)/Vzipmmu_tb__ALL.a
$(CXX) $(CFLAGS) $(INCS) -I$(BENCHOBJD) zipmmu_tb.cpp $(VLIB) $(BENCHOBJD)/Vzipmmu_tb__ALL.a -o $@
 
pfcache_tb: $(OBJDIR)/pfcache_tb.o $(OBJDIR)/memsim.o $(OBJDIR)/byteswap.o
pfcache_tb: $(VLIB) $(RTLOBJD)/Vpfcache__ALL.a
$(CXX) $(CFLAGS) $(INCS) -I$(RTLOBJD) $(OBJDIR)/pfcache_tb.o $(OBJDIR)/memsim.o $(OBJDIR)/byteswap.o $(VLIB) $(RTLOBJD)/Vpfcache__ALL.a -o $@
 
pdump: pdump.cpp $(ZOBJS) $(OBJDIR)/zopcodes.o $(OBJDIR)/pdump.o
pdump: $(ZASM)/zopcodes.h testb.h byteswap.h zipelf.h
$(CXX) $(CFLAGS) $(INCS) $(OBJDIR)/pdump.o $(ZOBJS) -lelf -o $@
 
.PHONY: stest
stest: zippy_tb
./zippy_tb -s $(TESTF)
 
.PHONY: itest
itest: zippy_tb
./zippy_tb $(TESTF)
 
.PHONY: test
test: zippy_tb stest
./zippy_tb -a $(TESTF)
 
.PHONY: dhrystone
dhrystone: zippy_tb
./zippy_tb -a $(DHRYSTONEF)
 
define build-depends
@echo "Building dependencies"
@$(CXX) $(CPPFLAGS) $(INCS) -MM $(VLIB) $(SOURCES) > $(OBJDIR)/xdepends.txt
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt
@rm $(OBJDIR)/xdepends.txt
endef
 
tags: $(VLIB) $(SOURCES)
@ctags $(SOURCES) $(VLIB)
 
.PHONY: depends
depends: tags $(OBJDIR)/
$(build-depends)
 
$(OBJDIR)/:
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR)/; fi"
 
$(OBJDIR)/depends.txt: $(OBJDIR)/ depends
 
.PHONY: clean
clean:
rm -rf $(OBJDIR)/
rm -rf ./zippy_tb pdump div_tb mpy_tb
 
-include $(OBJDIR)/depends.txt
/zipcpu/trunk/sim/verilator/byteswap.cpp
0,0 → 1,114
////////////////////////////////////////////////////////////////////////////////
//
// Filename: byteswap.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: To convert between little endian and big endian byte orders,
// and to handle conversions between character strings and
// bit-endian words made from those characters.
//
//
// 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdint.h>
#include "byteswap.h"
 
/*
* byteswap
*
* Given a big (or little) endian word, return a little (or big) endian word.
*/
uint32_t
byteswap(uint32_t v) {
uint32_t r = 0;
 
r = (v & 0x0ff);
r <<= 8; v >>= 8;
r |= (v & 0x0ff);
r <<= 8; v >>= 8;
r |= (v & 0x0ff);
r <<= 8; v >>= 8;
r |= (v & 0x0ff);
 
return r;
}
 
 
/*
* byteswapbuf
*
* To swap from the byte order of every 32-bit word in the given buffer.
*/
void
byteswapbuf(int ln, uint32_t *buf) {
for(int i=0; i<ln; i++)
buf[i] = byteswap(buf[i]);
}
 
/*
* buildword
*
* Given a pointer within an array of characters, build a 32-bit big-endian
* word from those characters. Does not require the character pointer to be
* aligned.
*/
uint32_t
buildword(const unsigned char *p) {
uint32_t r = 0;
 
r = (*p++); r <<= 8;
r |= (*p++); r <<= 8;
r |= (*p++); r <<= 8;
r |= (*p );
 
return r;
}
 
/*
* buildswap
*
* Same as buildword, except that we build a little endian word from the
* characters given to us. Hence the first character is the low order octet
* of the word.
*/
uint32_t
buildswap(const unsigned char *p) {
uint32_t r = 0;
 
r = p[3]; r <<= 8;
r |= p[2]; r <<= 8;
r |= p[1]; r <<= 8;
r |= p[0];
 
return r;
}
 
 
/zipcpu/trunk/sim/verilator/byteswap.h
0,0 → 1,90
////////////////////////////////////////////////////////////////////////////////
//
// Filename: byteswap.h
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: To convert between little endian and big endian byte orders,
// and to handle conversions between character strings and
// bit-endian words made from those characters.
//
//
// 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef BYTESWAP_H
#define BYTESWAP_H
 
#include <stdint.h>
 
/*
* The byte swapping routines below are designed to support conversions from a little endian
* machine/host (such as my PC) to the big endian byte order used on the ZipCPU. If the current
* machine is already little endian, no byte swapping is required.
*/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/*
* byteswap
*
* Given a big (or little) endian word, return a little (or big) endian word.
*/
extern uint32_t
byteswap(uint32_t v);
 
/*
* byteswapbuf
*
* To swap from the byte order of every 32-bit word in the given buffer.
*/
extern void byteswapbuf(int ln, uint32_t *buf);
 
#else
#define byteswap(A) (A)
#define byteswapbuf(A, B)
#endif
 
/*
* buildword
*
* Given a pointer within an array of characters, build a 32-bit big-endian
* word from those characters. Does not require the character pointer to be
* aligned.
*/
extern uint32_t buildword(const unsigned char *p);
 
/*
* buildswap
*
* Same as buildword, except that we build a little endian word from the
* characters given to us. Hence the first character is the low order octet
* of the word.
*/
extern uint32_t buildswap(const unsigned char *p);
 
#endif
/zipcpu/trunk/sim/verilator/div_tb.cpp
0,0 → 1,323
///////////////////////////////////////////////////////////////////////////////
//
// Filename: div_tb.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Bench testing for the divide unit found within the Zip CPU.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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 <stdint.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>
 
#include <ctype.h>
 
#include "verilated.h"
#include "Vdiv.h"
 
#include "testb.h"
// #include "twoc.h"
 
class DIV_TB : public TESTB<Vdiv> {
public:
DIV_TB(void) {
}
 
~DIV_TB(void) {}
 
void reset(void) {
// m_flash.debug(false);
TESTB<Vdiv>::reset();
}
 
bool on_tick(void) {
tick();
return true;
}
 
void bprint(char *str, int nbits, unsigned long v) {
while(*str)
str++;
for(int i=0; i<nbits; i++) {
if ((1l<<(nbits-1-i))&v)
*str++ = '1';
else
*str++ = '0';
if (((nbits-1-i)&3)==0)
*str++ = ' ';
} *str = '\0';
}
 
void dbgdump(void) {
char outstr[2048], *s;
sprintf(outstr, "Tick %4ld %s%s%s%s%s%s%s %2d(%s= 0)",
m_tickcount,
(m_core->o_busy)?"B":" ",
(m_core->v__DOT__r_busy)?"R":" ",
(m_core->o_valid)?"V":" ",
(m_core->i_wr)?"W":" ",
(m_core->v__DOT__pre_sign)?"+":" ",
(m_core->v__DOT__r_sign)?"-":" ",
(m_core->v__DOT__r_z)?"Z":" ",
m_core->v__DOT__r_bit,
(m_core->v__DOT__last_bit)?"=":"!");
s = &outstr[strlen(outstr)];
sprintf(s, "%s\n%10s %40s",s, "Div","");
s = &s[strlen(s)];
bprint( s, 32, m_core->v__DOT__r_dividend);
s=&s[strlen(s)];
sprintf(s, "%s\n%10s ",s, "Div"); s = &s[strlen(s)];
bprint( s, 64, m_core->v__DOT__r_divisor);
s=&s[strlen(s)];
sprintf(s, "%s\n%10s %40s",s, "Q",""); s=&s[strlen(s)];
bprint( s, 32, m_core->o_quotient); s = &s[strlen(s)];
sprintf(s, "%s\n%10s %38s",s, "Diff","");
s=&s[strlen(s)];
bprint( s, 33, m_core->v__DOT__diff); s = &s[strlen(s)];
strcat(s, "\n");
puts(outstr);
}
 
void tick(void) {
bool debug = false;
 
if (debug)
dbgdump();
TESTB<Vdiv>::tick();
}
 
void divtest(uint32_t n, uint32_t d, uint32_t ans, bool issigned) {
const bool dbg = false;
 
// The test bench is supposed to assert that we are idle when
// we come in here.
assert(m_core->o_busy == 0);
 
// Request a divide
m_core->i_rst = 0;
m_core->i_wr = 1;
m_core->i_signed = (issigned)?1:0;
m_core->i_numerator = n;
m_core->i_denominator = d;
 
// Tick once for the request to be registered
tick();
 
// Clear the input lines.
m_core->i_wr = 0;
m_core->i_signed = 0;
m_core->i_numerator = 0;
m_core->i_denominator = 0;
 
// Make certain busy is immediately true upon the first clock
// after we issue the divide, and that our result is not also
// listed as a valid result.
if (!m_core->o_busy) {
closetrace();
assert(m_core->o_busy);
} if (m_core->o_valid != 0) {
closetrace();
assert(m_core->o_valid == 0);
}
 
// while((!m_core->o_valid)&&(!m_core->o_err))
while(!m_core->o_valid) {
// If we aren't yet valid, we'd better at least
// be busy--the CPU requires this.
if (!m_core->o_busy) {
// We aren't valid, and we aren't busy. This
// is a test failure.
dbgdump();
closetrace();
assert(m_core->o_busy);
}
 
// Let the algorithm work for another clock tick.
tick();
} if (dbg) dbgdump();
 
// Insist that the core not be busy any more, now that a valid
// result has been produced.
if (m_core->o_busy) {
closetrace();
assert(!m_core->o_busy);
}
 
if (dbg) {
printf("%s%s: %d / %d =? %d\n",
(m_core->o_valid)?"V":" ",
(m_core->o_err)?"E":" ",
n, d, m_core->o_quotient);
}
 
 
// Now that we're done, we need to check the result.
//
// First case to check: was there an error condition or, if not,
// should there have been one?
if (d == 0) {
// We attempted to divide by zero, the result should've
// been an error condition. Let's check:
// Then insist on a division by zero error
if (!m_core->o_err) {
// Don't forget to close the trace before the
// assert, lest the file not get the final
// values into it.
closetrace();
assert(m_core->o_err);
}
} else if (m_core->o_err) {
// Otherwise, there should not have been any divide
// errors. The only errors allowed should be the
// divide by zero. So, this is an error. Let's
// stop and report it.
closetrace();
assert(!m_core->o_err);
} else if (ans != (uint32_t)m_core->o_quotient) {
// The other problem we might encounter would be if the
// result doesn't match the one we are expecting.
//
// Stop on this bug as well.
//
closetrace();
assert(ans == (uint32_t)m_core->o_quotient);
}
}
 
// Test a signed divide
void divs(int n, int d) {
int ans;
// Calculate the answer we *should* get from the divide
ans = (d==0)?0: (n / d);
 
divtest((uint32_t)n, (uint32_t)d, (uint32_t)ans, true);
}
 
// Test an unsigned divide
void divu(unsigned n, unsigned d) {
unsigned ans;
 
// Pre-Calculate the answer we *should* get from the divide
ans = (d==0)?0: (n / d);
 
divtest((uint32_t)n, (uint32_t)d, (uint32_t)ans, false);
}
 
// divide() is just another name for a signed divide--just switch to
// that function call instead.
void divide(int n, int d) {
divs(n,d);
}
};
 
//
// Standard usage functions.
//
// Notice that the test bench provides no options. Everything is
// self-contained.
void usage(void) {
printf("USAGE: div_tb\n");
printf("\n");
printf("\t\n");
}
 
//
int main(int argc, char **argv) {
// Setup
Verilated::commandArgs(argc, argv);
DIV_TB *tb = new DIV_TB();
 
// tb->opentrace("divtrace.vcd");
 
tb->reset();
// tb->opentrace("div_tb.vcd");
 
// Now we're ready. All we need to do to test the divide of two
// numbers is to call the respective divide(), divs(), or divu()
// functions. The program will crash on an assert error if anything
// goes wrong.
tb->divu((unsigned)-1,10);
tb->divide(125,7);
// And give us an extra clock tick in-between each test for good
// measure.
tb->tick();
 
// Some other gentle tests
tb->divide(125,-7);
tb->tick();
tb->divu((1u<<31),7);
// Now some boundary conditions
tb->divu((7u<<29),(1u<<31));
tb->tick();
tb->divs(32768,0);
tb->tick();
tb->divu((1u<<31),0);
tb->tick();
tb->divs((1u<<30),0);
tb->tick();
//
// Now we switch to a more thorough test set. It's not complete, just
// ... more thorough.
for(int i=32767; i>=0; i--) {
tb->divs((1u<<30),i);
tb->tick();
} for(int i=32767; i>=0; i--) {
// tb->divu(-1, i);
tb->divu((1u<<31), i);
tb->tick();
} for(int i=32767; i>=0; i--) {
tb->divide(32768, i);
tb->tick();
}
 
/*
* While random data is a nice test idea, the following just never
* really tested the divide unit thoroughly enough.
*
tb->divide(rand(),rand()/2);
tb->tick();
tb->divide(rand(),rand()/2);
tb->tick();
tb->divide(rand(),rand()/2);
tb->tick();
tb->divide(rand(),rand()/2);
*/
 
// Any failures above will be captured with a failed assert. If we
// get here, it means things worked. Close up shop ...
//
// This closes any potential trace file
delete tb;
 
// And declare success
printf("SUCCESS!\n");
exit(EXIT_SUCCESS);
}
 
/zipcpu/trunk/sim/verilator/memsim.cpp
0,0 → 1,140
////////////////////////////////////////////////////////////////////////////////
//
// Filename: memsim.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: This creates a memory like device to act on a WISHBONE bus.
// It doesn't exercise the bus thoroughly, but does give some
// exercise to the bus to see whether or not the bus master
// can control it.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include "byteswap.h"
#include "memsim.h"
 
MEMSIM::MEMSIM(const unsigned int nwords) {
unsigned int nxt;
 
for(nxt=1; nxt < nwords; nxt<<=1)
;
m_len = nxt; m_mask = nxt-1;
m_mem = new BUSW[m_len];
m_nxt_ack = 0;
}
 
MEMSIM::~MEMSIM(void) {
delete[] m_mem;
}
 
void MEMSIM::load(const char *fname) {
FILE *fp;
unsigned int nr;
 
fp = fopen(fname, "r");
if (!fp) {
fprintf(stderr, "Could not open/load file \'%s\'\n",
fname);
perror("O/S Err:");
fprintf(stderr, "\tInitializing memory with zero instead.\n");
nr = 0;
} else {
nr = fread(m_mem, sizeof(BUSW), m_len, fp);
fclose(fp);
 
if (nr != m_len) {
fprintf(stderr, "Only read %d of %d words\n",
nr, m_len);
fprintf(stderr, "\tFilling the rest with zero.\n");
}
}
 
for(; nr<m_len; nr++)
m_mem[nr] = 0l;
}
 
void MEMSIM::load(const unsigned addr, const char *buf, const unsigned len) {
memcpy(&m_mem[addr], buf, len);
byteswapbuf((len>>2), &m_mem[addr]);
}
 
void MEMSIM::apply(const uchar wb_cyc,
const uchar wb_stb, const uchar wb_we,
const BUSW wb_addr, const BUSW wb_data, const uchar wb_sel,
uchar &o_ack, uchar &o_stall, BUSW &o_data) {
unsigned sel = 0;
 
if (wb_sel&0x8)
sel |= 0x0ff000000;
if (wb_sel&0x4)
sel |= 0x000ff0000;
if (wb_sel&0x2)
sel |= 0x00000ff00;
if (wb_sel&0x1)
sel |= 0x0000000ff;
 
o_ack = (m_nxt_ack) && (wb_cyc);
o_data= m_nxt_data;
m_nxt_data = wb_data;
m_nxt_ack = 0;
o_stall= 0;
if ((wb_cyc)&&(wb_stb)) {
if (wb_we) {
if (sel == 0xffffffffu)
m_mem[wb_addr & m_mask] = wb_data;
else {
uint32_t memv = m_mem[wb_addr & m_mask];
memv &= ~sel;
memv |= (wb_data & sel);
m_mem[wb_addr & m_mask] = memv;
}
}
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);
}
}
}
}
 
 
/zipcpu/trunk/sim/verilator/memsim.h
0,0 → 1,74
////////////////////////////////////////////////////////////////////////////////
//
// Filename: memsim.h
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: This creates a memory like device to act on a WISHBONE bus.
// It doesn't exercise the bus thoroughly, but does give some
// exercise to the bus to see whether or not the bus master
// can control it.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef MEMSIM_H
#define MEMSIM_H
 
class MEMSIM {
public:
typedef unsigned int BUSW;
typedef unsigned char uchar;
 
BUSW *m_mem, m_len, m_mask;
int m_nxt_ack;
BUSW m_nxt_data;
 
MEMSIM(const unsigned int nwords);
~MEMSIM(void);
void load(const char *fname);
void load(const unsigned addr, const char *buf,const unsigned len);
void apply(const uchar wb_cyc, const uchar wb_stb,
const uchar wb_we,
const BUSW wb_addr, const BUSW wb_data,
const uchar wb_sel,
uchar &o_ack, uchar &o_stall, BUSW &o_data);
void operator()(const uchar wb_cyc, const uchar wb_stb,
const uchar wb_we,
const BUSW wb_addr, const BUSW wb_data,
const uchar wb_sel,
uchar &o_ack, uchar &o_stall, BUSW &o_data) {
apply(wb_cyc, wb_stb, wb_we, wb_addr, wb_data, wb_sel, o_ack, o_stall, o_data);
}
BUSW &operator[](const BUSW addr) { return m_mem[addr&m_mask]; }
};
 
#endif
/zipcpu/trunk/sim/verilator/mpy_tb.cpp
0,0 → 1,359
///////////////////////////////////////////////////////////////////////////////
//
// 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 = false;
 
// Insist that we are never both busy and producing a valid
// result at the same time. One or the other may be true,
// but never both.
assert((!m_core->o_busy)||(!m_core->o_valid));
//
TESTB<Vcpuops>::tick();
 
if (debug)
dbgdump();
}
 
//
// 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) {
// Make sure we start witht he core idle
if (m_core->o_valid)
clear_ops();
 
// Set the arguments to the CPUOPS core to get a multiple
// started
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 once to get it going
tick();
 
// Clear the input arguments to the multiply
m_core->i_ce = 0;
m_core->i_a = 0;
m_core->i_b = 0;
 
// Wait for the result to be valid
while(!m_core->o_valid)
tick();
 
// Check that we used the number of clock ticks we said we'd
// be using. OPT_MULTIPLY is *supposed* to be equal to this
// number.
if((m_tickcount - now)!=OPT_MULTIPLY) {
printf("%ld ticks seen, %d ticks expected\n",
m_tickcount-now, OPT_MULTIPLY);
dbgdump();
printf("TEST-FAILURE!\n");
closetrace();
exit(EXIT_FAILURE);
}
 
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();
 
// Let's check our answers, and see if we got the right results
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");
closetrace();
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");
closetrace();
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");
closetrace();
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");
closetrace();
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;
// tb->opentrace("mpy_tb.vcd");
 
// 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/sim/verilator/pdump.cpp
0,0 → 1,146
////////////////////////////////////////////////////////////////////////////////
//
// Filename: pdump.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: Disassemble machine code files onto the stdout file. Unlike
// the zip-objdump program that is part of the binutils suite, this
// program takes the pfile.bin output of the bench test suite and adds
// profiling information to the output. It's useful for finding out where,
// at least in simulation, your time is being spent. It can also be used,
// after the fact, to get a trace of what instructions the CPU executed.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
 
#include "zipelf.h"
#include "zopcodes.h"
#include "byteswap.h"
 
typedef uint32_t ZIPI; // A ZipCPU instruction word
 
typedef struct { unsigned clks, addr; } ALT;
bool altcmp(const ALT &a, const ALT &b) {
return a.clks < b.clks;
}
 
 
void dump_file(const char *fn) {
const int NZIP = 4096;
char lna[NZIP], lnb[NZIP];
FILE *pf;
unsigned addr=0x0100000, mina = -1, maxa = 0,
*pfcnt = NULL, *pfclk = NULL;
 
pf = fopen("pfile.bin","rb");
if (pf) {
ALT *pfalt;
unsigned buf[2], total_clks = 0;
while(2 == fread(buf, sizeof(unsigned), 2, pf)) {
if (mina > buf[0])
mina = buf[0];
if (maxa < buf[0])
maxa = buf[0];
}
 
addr = mina;
pfcnt = new unsigned[(maxa+2-mina)];
pfclk = new unsigned[(maxa+2-mina)];
pfalt = new ALT[(maxa+2-mina)];
unsigned ncnt = maxa+2-mina;
for(int i=0; i<(int)ncnt; i++)
pfcnt[i] = pfclk[i] = 0;
for(int i=0; i<(int)ncnt; i++)
pfalt[i].addr = pfalt[i].clks = 0;
 
rewind(pf);
while(2 == fread(buf, sizeof(unsigned), 2, pf)) {
pfcnt[buf[0]-addr]++;
pfclk[buf[0]-addr] += buf[1];
pfalt[buf[0]-addr].clks += buf[1];
pfalt[buf[0]-addr].addr = buf[0];
total_clks += buf[1];
 
printf("%08x\n", buf[0]);
} fclose(pf);
 
printf("%08x (%8d) total clocks\n", total_clks, total_clks);
 
std::sort(&pfalt[0], &pfalt[ncnt], altcmp);
 
for(int i=0; i<(int)ncnt; i++)
printf("%08x: %8d\n", pfalt[i].addr, pfalt[i].clks);
}
 
printf("%s:\n", fn);
if (iself(fn)) {
ELFSECTION **secpp=NULL, *secp;
unsigned entry;
elfread(fn, entry, secpp);
for(int i=0; secpp[i]->m_len; i++) {
secp = secpp[i];
for(unsigned j=0; j<secp->m_len; j+=4) {
uint32_t w, a;
 
a = secp->m_start+(j<<2);
w = buildword((const unsigned char *)&secp->m_data[(j<<2)]);
zipi_to_double_string(a, w, lna, lnb);
// printf("%s\n", ln);
printf("%08x[%08x-%08x]: (0x%08x %c%c%c%c) ",
a, maxa, mina, w,
isgraph((w>>24)&0x0ff)?((w>>24)&0x0ff) : '.',
isgraph((w>>16)&0x0ff)?((w>>16)&0x0ff) : '.',
isgraph((w>> 8)&0x0ff)?((w>> 8)&0x0ff) : '.',
isgraph((w )&0x0ff)?((w )&0x0ff) : '.'
);
if ((a>=mina)&&(a<maxa)&&(pfcnt))
printf("%8d %8d ", pfcnt[a-mina], pfclk[a-mina]);
printf("%s\n", lna);
if (lnb[0])
printf("-%24s%s\n", "", lnb);
}
}
}
}
 
int main(int argc, char **argv) {
if (argc <= 1)
printf("USAGE: pdump <dump-file> | less\n");
for(int argn=1; argn<argc; argn++) {
if(access(argv[argn], R_OK)==0)
dump_file(argv[argn]);
}
 
return 0;
}
 
/zipcpu/trunk/sim/verilator/pfcache_tb.cpp
0,0 → 1,320
///////////////////////////////////////////////////////////////////////////////
//
// Filename: pfcache_tb.cpp
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Bench testing for the prefetch cache used within the ZipCPU
// when it is in pipelind mode. Whether or not this module is
// used depends upon how the CPU is set up in cpudefs.v.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, 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 "verilated_vcd_c.h"
#include "Vpfcache.h"
 
#include "testb.h"
#include "cpudefs.h"
#include "memsim.h"
 
#define RAMBASE (1<<20)
#define RAMWORDS RAMBASE
#define MAXTIMEOUT 128
 
FILE *gbl_dbgfp = NULL; // Can also be set to stdout
 
class PFCACHE_TB : public TESTB<Vpfcache> {
public:
MEMSIM m_mem;
bool m_bomb;
 
// Nothing special to do in a startup.
PFCACHE_TB(void) : m_mem(RAMWORDS), m_bomb(false) {}
 
void randomize_memory(void) {
m_mem.load("/dev/urandom");
}
 
// ~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_core->i_rst = 0;
m_core->i_pc = RAMBASE;
m_core->i_new_pc = 0;
m_core->i_clear_cache = 1;
m_core->i_stall_n = 1;
m_core->i_stall_n = 1;
 
TESTB<Vpfcache>::reset();
}
 
//
// dbgdump();
//
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":" ");
s = &outstr[strlen(outstr)];
 
puts(outstr);
*/
}
 
bool valid_mem(uint32_t addr) {
if (addr < RAMBASE)
return false;
if (addr >= RAMBASE + RAMWORDS)
return false;
return true;
}
 
//
// tick()
//
// Call this to step the module under test.
//
void tick(void) {
bool debug = false;
 
if ((m_core->o_wb_cyc)&&(m_core->o_wb_stb)) {
if (!valid_mem(m_core->o_wb_addr))
m_core->i_wb_err = 1;
} else if (m_core->o_wb_stb) {
m_bomb = true;
}
 
if (m_core->o_wb_we)
m_bomb = true;
if (m_core->o_wb_data != 0)
m_bomb = true;
 
if (debug)
dbgdump();
 
unsigned mask = (RAMBASE-1);
 
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->i_wb_ack, m_core->i_wb_stall,m_core->i_wb_data);
 
TESTB<Vpfcache>::tick();
 
if (m_core->o_v) {
uint32_t pc, insn;
 
pc = m_core->o_pc;
insn = m_core->o_i;
if (insn != m_mem[pc & (RAMWORDS-1)]) {
fprintf(stderr, "ERR: PF[%08x] = %08x != %08x\n", pc,
insn, m_mem[pc & (RAMWORDS-1)]);
closetrace();
assert(insn == m_mem[pc & (RAMWORDS-1)]);
}
}
}
 
//
// fetch_insn()
//
void fetch_insn(void) {
uint32_t timeout = 0;
 
if ((m_core->o_v)&&(m_core->i_stall_n))
m_core->i_pc++;
 
m_core->i_rst = 0;
m_core->i_new_pc = 0;
m_core->i_clear_cache = 0;
m_core->i_stall_n = 1;
do {
tick();
} while((!m_core->o_v)&&(!m_core->o_illegal)&&(timeout++ < MAXTIMEOUT));
 
if (timeout >= MAXTIMEOUT)
m_bomb = true;
}
 
//
// skip_fetch()
//
void skip_fetch(void) {
uint32_t prevalid, insn;
 
if ((m_core->o_v)&&(m_core->i_stall_n))
m_core->i_pc++;
 
m_core->i_rst = 0;
m_core->i_new_pc = 0;
m_core->i_clear_cache = 0;
m_core->i_stall_n = 0;
insn = m_core->o_i;
prevalid= m_core->o_v;
 
tick();
 
if (prevalid) {
// if (!m_core->o_v) {
// fprintf(stderr, "ERR: VALID dropped on stall!\n");
// closetrace();
// assert(m_core->o_v);
// }
if (insn != m_core->o_i) {
fprintf(stderr, "ERR: VALID INSN CHANGED on stall!\n");
closetrace();
assert(insn == m_core->o_i);
}
}
}
 
 
//
// jump
//
void jump(unsigned target) {
uint32_t timeout = 0;
 
m_core->i_rst = 0;
m_core->i_new_pc = 1;
m_core->i_clear_cache = 0;
m_core->i_stall_n = 1;
m_core->i_pc = target;
 
tick();
m_core->i_pc++;
m_core->i_new_pc = 0;
m_core->i_stall_n = 0;
 
while((!m_core->o_v)&&(timeout++ < MAXTIMEOUT))
tick();
 
if (timeout >= MAXTIMEOUT)
m_bomb = true;
if (m_core->o_v)
assert(m_core->o_pc == target);
}
};
 
void usage(void) {
printf("USAGE: pfcache_tb\n");
printf("\n");
}
 
int main(int argc, char **argv) {
// Setup verilator
Verilated::commandArgs(argc, argv);
// Now, create a test bench.
PFCACHE_TB *tb = new PFCACHE_TB();
int rcode = EXIT_SUCCESS;
 
tb->opentrace("pfcache.vcd");
tb->randomize_memory();
 
tb->jump(RAMBASE);
 
// Simulate running straight through code
for(int i=0; i<130; i++) {
// printf("FETCH\n");
tb->fetch_insn();
}
 
// Now, let's bounce around through the cache
for(int j=0; j<20; j++) {
tb->jump(RAMBASE+j);
for(int i=0; i<130; i++) {
// printf("FETCH\n");
tb->fetch_insn();
}
 
if (tb->m_bomb) {
printf("TEST FAILURE!\n");
delete tb;
exit(EXIT_FAILURE);
}
}
 
// Now, add in some CIS-type instructions
for(int i=0; i<130; i++) {
unsigned v = rand() & 0x0f;
 
if ((v&3)==2) {
// printf("SKIP\n");
tb->skip_fetch();
} else {
// printf("FETCH\n");
tb->fetch_insn();
}
 
if (tb->m_bomb) {
printf("TEST FAILURE!\n");
delete tb;
exit(EXIT_FAILURE);
}
}
 
// Finally, try it all: stalls, CIS, and jumps
for(int i=0; i<10000; i++) {
unsigned v = rand() & 0x0f;
if (v == 0) {
uint32_t target = rand() & (RAMWORDS-1);
target += RAMBASE;
// printf("JUMP TO %08x\n", target);
tb->jump(target);
} else if ((v & 3)==2) {
// printf("SKIP\n");
tb->skip_fetch();
} else {
// printf("FETCH\n");
tb->fetch_insn();
}
if (tb->m_bomb) {
printf("TEST FAILURE!\n");
delete tb;
exit(EXIT_FAILURE);
}
}
 
printf("SUCCESS!\n");
exit(rcode);
}
 
/zipcpu/trunk/sim/verilator/testb.h
0,0 → 1,100
////////////////////////////////////////////////////////////////////////////////
//
// Filename: testb.h
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: A wrapper for a common interface to a clocked FPGA core
// begin exercised in Verilator.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef TESTB_H
#define TESTB_H
 
#include <stdio.h>
#include <stdint.h>
#include <verilated_vcd_c.h>
 
template <class VA> class TESTB {
public:
VA *m_core;
VerilatedVcdC* m_trace;
unsigned long m_tickcount;
 
TESTB(void) : m_trace(NULL), m_tickcount(0l) {
m_core = new VA;
Verilated::traceEverOn(true);
}
virtual ~TESTB(void) {
if (m_trace) m_trace->close();
delete m_core;
m_core = NULL;
}
 
virtual void opentrace(const char *vcdname) {
m_trace = new VerilatedVcdC;
m_core->trace(m_trace, 99);
m_trace->open(vcdname);
}
 
virtual void closetrace(void) {
if (m_trace) {
m_trace->close();
m_trace = NULL;
}
}
 
virtual void eval(void) {
m_core->eval();
}
 
virtual void tick(void) {
m_tickcount++;
 
//if((m_trace)&&(m_tickcount)) m_trace->dump(10*m_tickcount-4);
eval();
if ((m_trace)&&(m_tickcount)) m_trace->dump(10*m_tickcount-2);
m_core->i_clk = 1;
eval();
if (m_trace) m_trace->dump(10*m_tickcount);
m_core->i_clk = 0;
eval();
if (m_trace) m_trace->dump(10*m_tickcount+5);
 
}
 
virtual void reset(void) {
m_core->i_rst = 1;
tick();
m_core->i_rst = 0;
// printf("RESET\n");
}
};
 
#endif
/zipcpu/trunk/sim/verilator/twoc.cpp
0,0 → 1,55
////////////////////////////////////////////////////////////////////////////
//
// Filename: twoc.cpp
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: Some various two's complement related C++ helper routines.
// Specifically, these help extract signed numbers from
// packed bitfields, while guaranteeing that the upper bits
// are properly sign extended (or not) as desired.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
#include "twoc.h"
 
long sbits(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
}
 
unsigned long ubits(const long val, const int bits) {
unsigned long r = val & ((1l<<bits)-1);
return r;
}
 
 
/zipcpu/trunk/sim/verilator/twoc.h
0,0 → 1,46
////////////////////////////////////////////////////////////////////////////
//
// Filename: twoc.h
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: Some various two's complement related C++ helper routines.
// Specifically, these help extract signed numbers from
// packed bitfields, while guaranteeing that the upper bits
// are properly sign extended (or not) as desired.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// 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,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
#ifndef TWOC_H
#define TWOC_H
 
extern long sbits(const long val, const int bits);
extern unsigned long ubits(const long val, const int bits);
 
#endif
 
/zipcpu/trunk/sim/verilator/zipelf.cpp
0,0 → 1,46
link ../cpp/zipelf.cpp
zipcpu/trunk/sim/verilator/zipelf.cpp Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: zipcpu/trunk/sim/verilator/zipelf.h =================================================================== --- zipcpu/trunk/sim/verilator/zipelf.h (nonexistent) +++ zipcpu/trunk/sim/verilator/zipelf.h (revision 204) @@ -0,0 +1 @@ +link ../cpp/zipelf.h \ No newline at end of file
zipcpu/trunk/sim/verilator/zipelf.h Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: zipcpu/trunk/sim/verilator/zipmmu_tb.cpp =================================================================== --- zipcpu/trunk/sim/verilator/zipmmu_tb.cpp (nonexistent) +++ zipcpu/trunk/sim/verilator/zipmmu_tb.cpp (revision 204) @@ -0,0 +1,810 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Filename: zipmmu_tb.cpp +// +// Project: Zip CPU -- a small, lightweight, RISC CPU soft core +// +// Purpose: A quick test bench to determine if the zipmmu module works. +// This test bench does nothing to determine whether or not it +// is connected properly, but only tests whether or not the zipmmu works +// as it is supposed to. +// +// +// 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 + +#include +#include +#include "testb.h" +#include "Vzipmmu_tb.h" + +#define MMUFLAG_RONW 8 // Read only (not writeable) +#define MMUFLAG_ACCS 4 // Accessed +#define MMUFLAG_CCHE 2 // Cachable +#define MMUFLAG_THSP 1 // Page has this context + +const int BOMBCOUNT = 32, + LGMEMSIZE = 15; + +class ZIPMMU_TB : public TESTB { + long m_tickcount; + bool m_bomb, m_miss, m_err, m_debug; + int m_last_tlb_index; +public: + + ZIPMMU_TB(void) { + m_debug = true; + m_last_tlb_index = 0; + } + +#define v__DOT__mem_stb v__DOT__mut__DOT__r_valid + void tick(void) { + + TESTB::tick(); + + bool writeout = true; + + if ((m_debug)&&(writeout)) { + printf("%08lx-MMU: ", m_tickcount); + printf("(%s%s%s%s) %08x (%s%s%s)%08x%s %s %08x/%08x %s%s%s%s%s", + (m_core->i_ctrl_cyc_stb)?"CT":" ", + (m_core->i_wbm_cyc)?"CYC":" ", + (m_core->i_wbm_stb)?"STB":" ", + (m_core->i_wb_we)?"WE":" ", + (m_core->i_wb_addr), + (m_core->v__DOT__mem_cyc)?"CYC":" ", + (m_core->v__DOT__mem_stb)?"STB":" ", +#define v__DOT__mem_we v__DOT__mut__DOT__r_we + (m_core->v__DOT__mem_we)?"WE":" ", + (m_core->v__DOT__mem_addr), + (m_core->v__DOT__mem_err)?"ER":" ", + (m_core->i_wb_we)?"<-":"->", + (m_core->i_wb_we)?m_core->i_wb_data:m_core->o_rtn_data, + (m_core->v__DOT__mem_we)?m_core->v__DOT__mut__DOT__r_data:m_core->v__DOT__mem_odata, + (m_core->o_rtn_stall)?"STALL":" ", + (m_core->v__DOT__mut__DOT__setup_ack)?"S":" ", + (m_core->o_rtn_ack )?"ACK":" ", + (m_core->o_rtn_miss)?"MISS":" ", + (m_core->o_rtn_err )?"ERR":" "); + + printf("[%d,%d]", + m_core->v__DOT__mut__DOT__wr_vtable, + m_core->v__DOT__mut__DOT__wr_ptable); + printf("[%d,%d,%04x]", + m_core->v__DOT__mut__DOT__wr_control, + m_core->v__DOT__mut__DOT__z_context, + m_core->v__DOT__mut__DOT__r_context_word); + /* + printf("[%08x,%08x-%08x]", + m_core->v__DOT__mut__DOT__w_vtable_reg, + m_core->v__DOT__mut__DOT__w_ptable_reg, + m_core->v__DOT__mut__DOT__setup_data); + */ + printf(" %s[%s%s@%08x,%08x]", + (m_core->v__DOT__mut__DOT__r_pending)?"R":" ", + (m_core->v__DOT__mut__DOT__r_we)?"W":" ", + (m_core->v__DOT__mut__DOT__r_valid)?"V":" ", + (m_core->v__DOT__mut__DOT__r_addr), + (m_core->v__DOT__mut__DOT__r_data)); + printf("@%2x[%s%s%s][%s%s%s%s]", + (m_core->v__DOT__mut__DOT__s_tlb_addr), + (m_core->v__DOT__mut__DOT__s_pending)?"P":" ", + (m_core->v__DOT__mut__DOT__s_tlb_hit)?"HT":" ", + (m_core->v__DOT__mut__DOT__s_tlb_miss)?"MS":" ", + (m_core->v__DOT__mut__DOT__ro_flag)?"RO":" ", + (m_core->v__DOT__mut__DOT__simple_miss)?"SM":" ", + (m_core->v__DOT__mut__DOT__ro_miss)?"RM":" ", + (m_core->v__DOT__mut__DOT__table_err)?"TE":" "); + //(m_core->v__DOT__mut__DOT__cachable)?"CH":" "); + /* + printf(" M[%016lx]", + m_core->v__DOT__mut__DOT__r_tlb_match); + printf(" P[%3d] = 0x%08x, V=0x%08x, C=0x%08x, CTXT=%04x", + m_last_tlb_index, + m_core->v__DOT__mut__DOT__tlb_pdata[m_last_tlb_index], + m_core->v__DOT__mut__DOT__tlb_vdata[m_last_tlb_index], + m_core->v__DOT__mut__DOT__tlb_cdata[m_last_tlb_index], + m_core->v__DOT__mut__DOT__r_context_word); + */ + printf("\n"); + } + } + + void reset(void) { + m_core->i_rst = 1; + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + m_core->i_rst = 0; + } + + void wb_tick(void) { + m_core->i_rst = 0; + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + assert(!m_core->o_rtn_ack); + assert(!m_core->o_rtn_err); + } + + unsigned operator[](unsigned a) { + a &= ((1<v__DOT__ram__DOT__mem[a]; + } + + unsigned setup_read(unsigned a) { + int errcount = 0; + unsigned result; + m_miss = false; m_err = false; + + printf("WB-READS(%08x)\n", a); + + m_core->i_ctrl_cyc_stb = 1; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + m_core->i_wb_we = 0; + m_core->i_wb_addr= a; + + if (m_core->o_rtn_stall) { + while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) + tick(); + } tick(); + + m_core->i_ctrl_cyc_stb = 0; + + while((errcount++ < BOMBCOUNT)&&(!m_core->o_rtn_ack)) { + tick(); + } + + + result = m_core->o_rtn_data; + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_miss); + + if(errcount >= BOMBCOUNT) { + printf("SETTING ERR TO TRUE!!!!! (BOMB)\n"); + m_bomb = true; + } else if (!m_core->o_rtn_ack) { + printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n"); + m_bomb = true; + } + tick(); + + assert(!m_core->o_rtn_ack); + assert(!m_core->o_rtn_miss); + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_stall); + + return result; + } + + void setup_write(unsigned a, unsigned v) { + int errcount = 0; + m_miss = false; m_err = false; + + printf("WB-WRITES(%08x,%08x)\n", a,v); + + m_core->i_ctrl_cyc_stb = 1; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + m_core->i_wb_we = 1; + m_core->i_wb_addr= a; + m_core->i_wb_data= v; + + if (a & 0x080) + m_last_tlb_index = (a>>1)&0x3f; + + if (m_core->o_rtn_stall) { + while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) + tick(); + } tick(); + + m_core->i_ctrl_cyc_stb = 0; + + while((errcount++ < BOMBCOUNT)&&(!m_core->o_rtn_ack)) { + tick(); + } + + + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_miss); + + if(errcount >= BOMBCOUNT) { + printf("SETTING ERR TO TRUE!!!!! (BOMB)\n"); + m_bomb = true; + } else if (!m_core->o_rtn_ack) { + printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n"); + m_bomb = true; + } + tick(); + + assert(!m_core->o_rtn_ack); + assert(!m_core->o_rtn_miss); + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_stall); + } + + unsigned wb_read(unsigned a, bool *err) { + int errcount = 0; + unsigned result; + if (err) *err = false; + + printf("WB-READM(%08x)\n", a); + + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 1; + m_core->i_wbm_stb = 1; + m_core->i_wb_we = 0; + m_core->i_wb_addr= a; + + if (m_core->o_rtn_stall) { + while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) { + tick(); + if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return 0; + } + } + } tick(); + + m_core->i_wbm_stb = 0; + + while((errcount++ < BOMBCOUNT)&&(!m_core->o_rtn_ack)) { + tick(); + if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return 0; + } + } + + + result = m_core->o_rtn_data; + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_miss); + + // Release the bus? + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + + if(errcount >= BOMBCOUNT) { + printf("SETTING ERR TO TRUE!!!!! (BOMB)\n"); + m_bomb = true; + } else if (!m_core->o_rtn_ack) { + printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n"); + m_bomb = true; + } + tick(); + + assert(!m_core->o_rtn_ack); + assert(!m_core->o_rtn_miss); + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_stall); + + return result; + } + + void wb_read(unsigned a, int len, unsigned *buf, bool *err) { + int errcount = 0; + int THISBOMBCOUNT = BOMBCOUNT * len; + int cnt, rdidx, inc; + + if (err) *err = false; + printf("WB-READM(%08x, %d)\n", a, len); + + while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) + wb_tick(); + + if (errcount >= BOMBCOUNT) { + printf("WB-READ(%d): Setting bomb to true (errcount = %d)\n", __LINE__, errcount); + m_bomb = true; + return; + } + + errcount = 0; + + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 1; + m_core->i_wbm_stb = 1; + m_core->i_wb_we = 0; + m_core->i_wb_addr = a; + + rdidx =0; cnt = 0; + inc = 1; + + do { + int s; + s = (m_core->o_rtn_stall==0)?0:1; + tick(); + if (!s) + m_core->i_wb_addr += inc; + cnt += (s==0)?1:0; + if (m_core->o_rtn_ack) + buf[rdidx++] = m_core->o_rtn_data; + if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + } while((cnt < len)&&(errcount++ < THISBOMBCOUNT)); + + m_core->i_wbm_stb = 0; + + while((rdidx < len)&&(errcount++ < THISBOMBCOUNT)) { + tick(); + if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + if (m_core->o_rtn_ack) + buf[rdidx++] = m_core->o_rtn_data; + } + + // Release the bus? + m_core->i_wbm_cyc = 0; + + if(errcount >= THISBOMBCOUNT) { + printf("SETTING ERR TO TRUE!!!!! (errcount=%08x, THISBOMBCOUNT=%08x)\n", errcount, THISBOMBCOUNT); + m_bomb = true; + } else if (!m_core->o_rtn_ack) { + printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n"); + m_bomb = true; + } + tick(); + assert(!m_core->o_rtn_ack); + assert(!m_core->o_rtn_miss); + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_stall); + } + + void wb_write(unsigned a, unsigned v, bool *err) { + int errcount = 0; + + if (err) *err = false; + printf("WB-WRITEM(%08x) <= %08x\n", a, v); + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 1; + m_core->i_wbm_stb = 1; + m_core->i_wb_we = 1; + m_core->i_wb_addr= a; + m_core->i_wb_data= v; + + if (m_core->o_rtn_stall) + while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) { + printf("Stalled, so waiting, errcount=%d\n", errcount); + tick(); + if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + } + tick(); + if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + + m_core->i_wbm_stb = 0; + + while((errcount++ < BOMBCOUNT)&&(!m_core->o_rtn_ack)) { + tick(); + if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + } tick(); + if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + + // Release the bus? + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + + if(errcount >= BOMBCOUNT) { + printf("SETTING ERR TO TRUE!!!!! (BOMB) (LINE=%d, count=%d)\n",__LINE__, errcount); + m_bomb = true; + } tick(); + assert(!m_core->o_rtn_ack); + assert(!m_core->o_rtn_miss); + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_stall); + } + + void wb_write(unsigned a, unsigned int ln, unsigned *buf, bool *err) { + unsigned errcount = 0, nacks = 0; + if (err) *err = false; + + printf("WB-WRITEM(%08x, %d, ...)\n", a, ln); + m_core->i_ctrl_cyc_stb = 0; + m_core->i_wbm_cyc = 1; + m_core->i_wbm_stb = 1; + m_core->i_wb_we = 1; + for(unsigned stbcnt=0; stbcnti_wb_addr= a+stbcnt; + m_core->i_wb_data= buf[stbcnt]; + errcount = 0; + + while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) { + tick(); + if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + if (m_core->o_rtn_ack) nacks++; + } + // Tick, now that we're not stalled. This is the tick + // that gets accepted. + tick(); if (m_core->o_rtn_ack) nacks++; + if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + } + + m_core->i_wbm_stb = 0; + + errcount = 0; + while((nacks < ln)&&(errcount++ < BOMBCOUNT)) { + tick(); + if (m_core->o_rtn_ack) { + nacks++; + errcount = 0; + } + if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) { + if (!*err) { + m_miss = (m_core->o_rtn_miss); + m_err = (m_core->o_rtn_err); + } *err = true; + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + tick(); + return; + } + } + + // Release the bus + m_core->i_wbm_cyc = 0; + m_core->i_wbm_stb = 0; + + if(errcount >= BOMBCOUNT) { + printf("SETTING ERR TO TRUE!!!!! (BOMB)\n"); + m_bomb = true; + } tick(); + assert(!m_core->o_rtn_ack); + assert(!m_core->o_rtn_miss); + assert(!m_core->o_rtn_err); + assert(!m_core->o_rtn_stall); + } + + bool miss(void) { + return m_miss; + } bool err(void) { + return m_err; + } + + bool bombed(void) const { return m_bomb; } + + bool debug(void) const { return m_debug; } + bool debug(bool nxtv) { return m_debug = nxtv; } +}; + +void uload(unsigned len, unsigned *buf) { + FILE *fp = fopen("/dev/urandom", "r"); + + if ((NULL == fp)||(len != fread(buf, sizeof(unsigned), len, fp))) { + for(int i=0; i<(int)len; i++) + buf[i] = ((unsigned)rand()); + } if (NULL == fp) + fclose(fp); +} + +void install_page(ZIPMMU_TB *tb, int idx, unsigned va, unsigned pa, int flags) { + int LGTBL, LGPGSZ, LGCTXT; + int c; + unsigned base; + bool hdebug = tb->debug(); + + tb->debug(false); + c=tb->setup_read(0); + printf("CONTEXT-REG = %08x\n", c); + LGTBL = ((c>>24)&15); + LGPGSZ= (((c>>20)&15)+8)&31; + LGCTXT= (((c>>16)&15)+1)&31; + c &= ((1< %08xP %s%s\n", + idx, c, va, pa, + (flags&MMUFLAG_RONW)?"RO":" ", + (flags&MMUFLAG_CCHE)?"Cachable":""); + tb->setup_write(base , va|(( c &0x0ff)<<4)|flags); + tb->setup_write(base+1, pa|(((c>>8)&0x0ff)<<4)|flags); + tb->debug(hdebug); +} + +int main(int argc, char **argv) { + Verilated::commandArgs(argc, argv); + ZIPMMU_TB *tb = new ZIPMMU_TB; + unsigned *rdbuf; // *mbuf; + unsigned mlen = (1<opentrace("zipmmu_tb.vcd"); + printf("Giving the core 2 cycles to start up\n"); + // Before testing, let's give the unit time enough to warm up + tb->reset(); + for(int i=0; i<2; i++) + tb->wb_tick(); + + mlen = 1<<16; + + printf("Getting some memory ...\n"); + rdbuf = new unsigned[mlen]; + // mbuf = new unsigned[mlen]; // Match buffer + printf("Charging my memory with random values\n"); + uload(mlen, rdbuf); + + + int LGADR, LGTBL, LGPGSZ, LGCTXT, sr; + + c=tb->setup_read(0); + printf("CONTROL-REG = %08x\n = %2d\n", c, c); + sr = tb->setup_read(1); + printf("STATUS-REG = %08x = %2d\n", sr, sr); + LGADR = (((c>>28)&15)+17)&31; + LGTBL = ((c>>24)&15); + LGPGSZ= (((c>>20)&15)+8)&31; + LGCTXT= (((c>>16)&15)+1)&31; + printf("LGADR = %08x = %2d\n", LGADR, LGADR); + printf("LGTBL = %08x = %2d\n", LGTBL, LGTBL); + printf("LGPGSZ = %08x = %2d\n", LGPGSZ, LGPGSZ); + printf("LGCTXT = %08x = %2d\n", LGCTXT, LGCTXT); + + // First, let's make sure we can read/write the context + printf("\n\nTest: Can we read/write the context register?\n"); + tb->setup_write(0,0x01fec); + c=tb->setup_read(0); + printf("CONTEXT = %08x (0x1fec?)\n", c&0x0ffff); + if ((c&0x0ffff) != 0x01fec) + goto test_failure; + + // Load the table with TLB misses + printf("\n\nTest: Can we load the table with TLB misses? (%d entries)\n", (1<setup_write((2<setup_write((2<setup_read((2<setup_read((2< %08x\n", i, v, p); + if (v != (unsigned)(0x00f72+(((1<wb_write(0xffffffff, 0x0fe, &tberr); + if ((!tberr)||(!tb->miss())||(tb->err())) { + printf("TBERR = %s\nMISS = %s\nERR = %s\n", + (tberr)?"true":"false", (tb->miss())?"true":"false", + (tb->err())?"true":"false"); + goto test_failure; + } + + tberr = false; + install_page(tb, 0, 0x0ffffffff, (1<wb_write(0xffffffff, 0x0fe, &tberr); + if ((!tberr)||(!tb->miss())||(tb->err())) { + printf("TBERR = %s\nMISS = %s\nERR = %s\n", + (tberr)?"true":"false", (tb->miss())?"true":"false", + (tb->err())?"true":"false"); + goto test_failure; + } + + tberr = false; + printf("\n\nTest: What if we make this into a writeable page?\n"); + install_page(tb, 0, 0xffffffff, (1<wb_write(0xffffffff, 0x0fe, &tberr); + if (tberr) { + printf("TBERR = %s\nMISS = %s\nERR = %s\n", + (tberr)?"true":"false", (tb->miss())?"true":"false", + (tb->err())?"true":"false"); + goto test_failure; + } + printf("\n\nTest: Is the next access done w/in a single clock?\n"); + tb->wb_write(0xfffffff7, 0xdeadbeef, &tberr); + if (tberr) { + printf("TBERR = %s\nMISS = %s\nERR = %s\n", + (tberr)?"true":"false", (tb->miss())?"true":"false", + (tb->err())?"true":"false"); + goto test_failure; + } + + + tberr = false; + printf("\n\nTest: What if we make this into a writeable page?\n"); + install_page(tb, 0, 0xffffffff, (1<wb_write(0xffffffff, 0x0fe, &tberr); + if ((tberr)||((*tb)[0x0fff]!=0x0fe)) { + unsigned v; + v = ((*tb)[0x0fff]!=0x0fe); + printf("V = 0x%08x (!= 0x0fe?)\nTBERR = %s\nMISS = %s\nERR = %s\n", + v, (tberr)?"true":"false", (tb->miss())?"true":"false", + (tb->err())?"true":"false"); + goto test_failure; + } + + tberr = false; + printf("\n\nTest: How about a read from the same location?\n"); + { + unsigned v; + v = tb->wb_read(0xffffffff, &tberr); + if ((tberr)||(v != 0x0fe)) { + printf("V = 0x%08x (!= 0x0fe?)\nTBERR = %s\nMISS = %s\nERR = %s\n", + v, + (tberr)?"true":"false", (tb->miss())?"true":"false", + (tb->err())?"true":"false"); + goto test_failure; + } + } + + printf("Test: Burst write, within page\n"); + tb->setup_write(0, 0x0dad); + install_page(tb, 0, ((0x0ffffffffl)&(-(1l<wb_write(((0xffffffff)&(-(1l<miss())?"true":"false", + (tb->err())?"true":"false"); + printf("STATUS= %08x\n", tb->setup_read(1)); + goto test_failure; + } for(unsigned i=0; iwb_read(((0xffffffff)&(-(1<miss())?"true":"false", + (tb->err())?"true":"false"); + printf("STATUS= %08x\n", tb->setup_read(1)); + goto test_failure; + } for(unsigned i=0; itick(); + printf("TEST FAILED\n"); + exit(-1); +} Index: zipcpu/trunk/sim/verilator/zippy_tb.cpp =================================================================== --- zipcpu/trunk/sim/verilator/zippy_tb.cpp (nonexistent) +++ zipcpu/trunk/sim/verilator/zippy_tb.cpp (revision 204) @@ -0,0 +1,2135 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Filename: zippy_tb.cpp +// +// Project: Zip CPU -- a small, lightweight, RISC CPU soft core +// +// Purpose: A bench simulator for the CPU. Eventually, you should be +// able to give this program the name of a piece of compiled +// code to load into memory. For now, we hand assemble with the computers +// help. +// +// +// Creator: Dan Gisselquist, Ph.D. +// Gisselquist Technology, LLC +// +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015-2017, 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "verilated.h" +#include "verilated_vcd_c.h" +#include "Vzipsystem.h" +#include "cpudefs.h" + +#include "testb.h" +#include "zipelf.h" +// #include "twoc.h" +// #include "qspiflashsim.h" +#include "byteswap.h" +#include "memsim.h" +#include "zopcodes.h" + +#define CMD_REG 0 +#define CMD_DATA 1 +#define CMD_GIE (1<<13) +#define CMD_SLEEP (1<<12) +#define CMD_CLEAR_CACHE (1<<11) +#define CMD_HALT (1<<10) +#define CMD_STALL (1<<9) +#define CMD_INT (1<<7) +#define CMD_RESET (1<<6) +#define CMD_STEP ((1<<8)|CMD_HALT) + +#define KEY_ESCAPE 27 +#define KEY_RETURN 10 +#define CTRL(X) ((X)&0x01f) + +#define MAXERR 10000 + +/* +// We are just a raw CPU with memory. There is no flash. +#define LGFLASHLEN 24 +#define FLASHBASE 0x01000000 +#define FLASHWORDS (1<>2) + +class SPARSEMEM { +public: + bool m_valid; + unsigned int m_a, m_d; +}; + +class ZIPSTATE { +public: + bool m_valid, m_gie, m_last_pc_valid; + unsigned int m_sR[16], m_uR[16]; + unsigned int m_p[20]; + unsigned int m_last_pc, m_pc, m_sp; + SPARSEMEM m_smem[5]; // Nearby stack memory + SPARSEMEM m_imem[5]; // Nearby instruction memory + ZIPSTATE(void) : m_valid(false), m_last_pc_valid(false) {} + + void step(void) { + m_last_pc_valid = true; + m_last_pc = m_pc; + } +}; + +extern FILE *gbl_dbgfp; +FILE *gbl_dbgfp = NULL; + +// No particular "parameters" need definition or redefinition here. +class ZIPPY_TB : public TESTB { +public: + unsigned long m_mem_size; + MEMSIM m_mem; + // QSPIFLASHSIM m_flash; + FILE *m_dbgfp, *m_profile_fp; + bool dbg_flag, m_bomb, m_show_user_timers; + int m_cursor; + unsigned long m_last_instruction_tickcount; + ZIPSTATE m_state; + + ZIPPY_TB(void) : m_mem_size(RAMWORDS), m_mem(m_mem_size) { + if (true) { + m_dbgfp = fopen("debug.txt", "w"); + dbg_flag = true; + gbl_dbgfp = m_dbgfp; + } else { + m_dbgfp = NULL; + dbg_flag = false; + gbl_dbgfp = NULL; + } + + if(true) { + // TESTB::opentrace("trace.vcd"); + opentrace("trace.vcd"); + } else { + m_trace = NULL; + } + + m_bomb = false; + m_cursor = 0; + m_show_user_timers = false; + + m_last_instruction_tickcount = 0l; + if (true) { + m_profile_fp = fopen("pfile.bin","wb"); + } else { + m_profile_fp = NULL; + } + } + + ~ZIPPY_TB(void) { + if (m_dbgfp) + fclose(m_dbgfp); + if (m_profile_fp) + fclose(m_profile_fp); + if (m_trace) + m_trace->close(); + } + + void reset(void) { + // m_flash.debug(false); + TESTB::reset(); + } + + void step(void) { + wb_write(CMD_REG, CMD_STEP); + m_state.step(); + } + + void read_raw_state(void) { + m_state.m_valid = false; + for(int i=0; i<16; i++) + m_state.m_sR[i] = cmd_read(i); + for(int i=0; i<16; i++) + m_state.m_uR[i] = cmd_read(i+16); + for(int i=0; i<20; i++) + m_state.m_p[i] = cmd_read(i+32); + + m_state.m_gie = wb_read(CMD_REG) & CMD_GIE; + m_state.m_pc = (m_state.m_gie) ? (m_state.m_uR[15]):(m_state.m_sR[15]); + m_state.m_sp = (m_state.m_gie) ? (m_state.m_uR[13]):(m_state.m_sR[13]); + + if (m_state.m_last_pc_valid) + m_state.m_imem[0].m_a = m_state.m_last_pc; + else + m_state.m_imem[0].m_a = m_state.m_pc - 1; + m_state.m_imem[0].m_d = m_mem[m_state.m_imem[0].m_a & 0x0fffff]; + m_state.m_imem[0].m_valid = ((m_state.m_imem[0].m_a & 0xfff00000)==0x00100000); + m_state.m_imem[1].m_a = m_state.m_pc; + m_state.m_imem[1].m_valid = ((m_state.m_imem[1].m_a & 0xfff00000)==0x00100000); + m_state.m_imem[1].m_d = m_mem[m_state.m_imem[1].m_a & 0x0fffff]; + + for(int i=1; i<4; i++) { + if (!m_state.m_imem[i].m_valid) { + m_state.m_imem[i+1].m_valid = false; + m_state.m_imem[i+1].m_a = m_state.m_imem[i].m_a+1; + continue; + } + m_state.m_imem[i+1].m_a = zop_early_branch( + m_state.m_imem[i].m_a, + m_state.m_imem[i].m_d); + m_state.m_imem[i+1].m_d = m_mem[m_state.m_imem[i].m_a & 0x0fffff]; + m_state.m_imem[i+1].m_valid = ((m_state.m_imem[i].m_a&0xfff00000)==0x00100000); + } + + m_state.m_smem[0].m_a = m_state.m_sp; + for(int i=1; i<5; i++) + m_state.m_smem[i].m_a = m_state.m_smem[i-1].m_a+1; + for(int i=0; i<5; i++) { + m_state.m_smem[i].m_valid = + (m_state.m_imem[i].m_a > 0x10000); + m_state.m_smem[i].m_d = m_mem[m_state.m_imem[i].m_a & 0x0fffff]; + } + m_state.m_valid = true; + } + + void read_raw_state_cheating(void) { + m_state.m_valid = false; + for(int i=0; i<16; i++) + m_state.m_sR[i] = m_core->v__DOT__thecpu__DOT__regset[i]; + m_state.m_sR[14] = (m_state.m_sR[14]&0xffffe000)|m_core->v__DOT__thecpu__DOT__w_iflags; + m_state.m_sR[15] = m_core->v__DOT__thecpu__DOT__ipc; + for(int i=0; i<16; i++) + m_state.m_uR[i] = m_core->v__DOT__thecpu__DOT__regset[i+16]; + m_state.m_uR[14] = (m_state.m_uR[14]&0xffffe000)|m_core->v__DOT__thecpu__DOT__w_uflags; + m_state.m_uR[15] = m_core->v__DOT__thecpu__DOT__r_upc; + + m_state.m_gie = m_core->v__DOT__thecpu__DOT__r_gie; + m_state.m_pc = (m_state.m_gie) ? (m_state.m_uR[15]):(m_state.m_sR[15]); + m_state.m_sp = (m_state.m_gie) ? (m_state.m_uR[13]):(m_state.m_sR[13]); + + m_state.m_p[0] = m_core->v__DOT__pic_data; + m_state.m_p[1] = m_core->v__DOT__watchdog__DOT__r_value; + if (!m_show_user_timers) { + m_state.m_p[2] = m_core->v__DOT__watchbus__DOT__r_value; + } else { + m_state.m_p[2] = m_core->v__DOT__r_wdbus_data; + } + + m_state.m_p[3] = m_core->v__DOT__genblk7__DOT__ctri__DOT__r_int_state; + m_state.m_p[4] = m_core->v__DOT__timer_a__DOT__r_value; + m_state.m_p[5] = m_core->v__DOT__timer_b__DOT__r_value; + m_state.m_p[6] = m_core->v__DOT__timer_c__DOT__r_value; + m_state.m_p[7] = m_core->v__DOT__jiffies__DOT__r_counter; + + m_state.m_p[ 8] = m_core->v__DOT__utc_data; + m_state.m_p[ 9] = m_core->v__DOT__uoc_data; + m_state.m_p[10] = m_core->v__DOT__upc_data; + m_state.m_p[11] = m_core->v__DOT__uic_data; + + m_state.m_p[12] = m_core->v__DOT__mtc_data; + m_state.m_p[13] = m_core->v__DOT__moc_data; + m_state.m_p[14] = m_core->v__DOT__mpc_data; + m_state.m_p[15] = m_core->v__DOT__mic_data; + + } + + void showval(int y, int x, const char *lbl, unsigned int v, bool c) { + if (c) + mvprintw(y,x, ">%s> 0x%08x<", lbl, v); + else + mvprintw(y,x, " %s: 0x%08x ", lbl, v); + } + + void dispreg(int y, int x, const char *n, unsigned int v, bool c) { + // 4,4,8,1 = 17 of 20, +3 = 19 + if (c) + mvprintw(y, x, ">%s> 0x%08x<", n, v); + else + mvprintw(y, x, " %s: 0x%08x ", n, v); + } + + void dbgreg(FILE *fp, int id, const char *n, unsigned int v) { + /* + if ((id == 14)||(id == 14+16)) { + //char buf[64]; + //fprintf(fp, " %s:", + fprintf(fp, " %s: 0x%08x ", n, v); + } else + */ + fprintf(fp, " %s: 0x%08x ", n, v); + } + + void showreg(int y, int x, const char *n, int r, bool c) { + if (r < 16) + dispreg(y, x, n, m_state.m_sR[r], c); + else + dispreg(y, x, n, m_state.m_uR[r-16], c); + move(y,x+17); + +#ifdef OPT_PIPELINED + addch( ((r == (int)(dcd_Aid()&0x01f))&&(dcd_valid()) + &&(m_core->v__DOT__thecpu__DOT__dcd_rA)) + ?'a':((c)?'<':' ')); + addch( ((r == (int)(dcd_Bid()&0x01f))&&(dcd_valid()) + &&(m_core->v__DOT__thecpu__DOT__dcd_rB)) + ?'b':' '); + addch( ((r == m_core->v__DOT__thecpu__DOT__wr_reg_id) + &&(m_core->v__DOT__thecpu__DOT__wr_reg_ce)) + ?'W':' '); +#else + addch( ((r == m_core->v__DOT__thecpu__DOT__wr_reg_id) + &&(m_core->v__DOT__thecpu__DOT__wr_reg_ce)) + ?'W':((c)?'<':' ')); +#endif + } + + void showins(int y, const char *lbl, const int ce, const int valid, + const int gie, const int stall, const unsigned int pc, + const bool phase) { + char la[80], lb[80]; + + if (ce) + mvprintw(y, 0, "Ck "); + else + mvprintw(y, 0, " "); + if (stall) + printw("Stl "); + else + printw(" "); + printw("%s%c 0x%08x", lbl, (phase)?'/':':', pc); + + if (valid) { + if (gie) attroff(A_BOLD); + else attron(A_BOLD); + zipi_to_double_string(pc, m_mem[pc>>2], la, lb); + if (((m_mem[pc>>2]&0x80000000)==0)||(phase)) + printw(" %-24s", la); + else + printw(" %-24s", lb); + } else { + attroff(A_BOLD); + printw(" (0x%08x)%28s", m_mem[pc>>2],""); + } + attroff(A_BOLD); + } + + void dbgins(const char *lbl, const int ce, const int valid, + const int gie, const int stall, const unsigned int pc, + const bool phase, const bool illegal) { + char la[80], lb[80]; + + if (!m_dbgfp) + return; + + if (ce) + fprintf(m_dbgfp, "%s Ck ", lbl); + else + fprintf(m_dbgfp, "%s ", lbl); + if (stall) + fprintf(m_dbgfp, "Stl "); + else + fprintf(m_dbgfp, " "); + fprintf(m_dbgfp, "0x%08x%s: ", pc, (phase)?"/P":" "); + + if (valid) { + zipi_to_double_string(pc, m_mem[pc>>2], la, lb); + if ((phase)||((m_mem[pc>>2]&0x80000000)==0)) + fprintf(m_dbgfp, " %-24s", la); + else + fprintf(m_dbgfp, " %-24s", lb); + } else { + fprintf(m_dbgfp, " (0x%08x)", m_mem[pc]); + } if (illegal) + fprintf(m_dbgfp, " (Illegal)"); + fprintf(m_dbgfp, "\n"); + } + + void show_state(void) { + int ln= 0; + + read_raw_state_cheating(); + + mvprintw(ln,0, "Peripherals-SS"); ln++; +#ifdef OPT_ILLEGAL_INSTRUCTION + printw(" %s", + // (m_core->v__DOT__thecpu__DOT__pf_illegal)?"PI":" ", + (m_core->v__DOT__thecpu__DOT__dcd_illegal)?"DI":" " + ); +#endif + +#ifdef OPT_EARLY_BRANCHING + printw(" %s", + (m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__genblk3__DOT__r_early_branch)?"EB":" "); + if (m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__genblk3__DOT__r_early_branch) + printw(" 0x%08x", m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__genblk3__DOT__r_branch_pc); + else printw(" %10s", ""); + printw(" %s", + (m_core->v__DOT__thecpu__DOT____Vcellinp__pf____pinNumber3)?"-> P3":" "); +#endif + + showval(ln, 0, "PIC ", m_state.m_p[0], (m_cursor==0)); + showval(ln,20, "WDT ", m_state.m_p[1], (m_cursor==1)); + // showval(ln,40, "CACH", m_core->v__DOT__manualcache__DOT__cache_base, (m_cursor==2)); + + if (!m_show_user_timers) { + showval(ln,40, "WBUS", m_core->v__DOT__watchbus__DOT__r_value, false); + } else { + showval(ln,40, "UBUS", m_core->v__DOT__r_wdbus_data, false); + } + + showval(ln,60, "PIC2", m_state.m_p[3], (m_cursor==3)); + + ln++; + showval(ln, 0, "TMRA", m_state.m_p[4], (m_cursor==4)); + showval(ln,20, "TMRB", m_state.m_p[5], (m_cursor==5)); + showval(ln,40, "TMRC", m_state.m_p[6], (m_cursor==6)); + showval(ln,60, "JIF ", m_state.m_p[7], (m_cursor==7)); + + + if (!m_show_user_timers) { + ln++; + showval(ln, 0, "MTSK", m_state.m_p[12], (m_cursor==8)); + showval(ln,20, "MOST", m_state.m_p[13], (m_cursor==9)); + showval(ln,40, "MPST", m_state.m_p[14], (m_cursor==10)); + showval(ln,60, "MICT", m_state.m_p[15], (m_cursor==11)); + } else { + ln++; + showval(ln, 0, "UTSK", m_state.m_p[ 8], (m_cursor==8)); + showval(ln,20, "UOST", m_state.m_p[ 9], (m_cursor==9)); + showval(ln,40, "UPST", m_state.m_p[10], (m_cursor==10)); + showval(ln,60, "UICT", m_state.m_p[11], (m_cursor==11)); + } + + ln++; + mvprintw(ln, 40, "%s %s", + (m_core->v__DOT__cpu_halt)? "CPU-HALT": " ", + (m_core->v__DOT__cpu_reset)?"CPU-RESET":" "); ln++; + mvprintw(ln, 40, "%s %s %s 0x%02x %s %s", + (m_core->v__DOT__cmd_halt)? "HALT": " ", + (m_core->v__DOT__cmd_reset)?"RESET":" ", + (m_core->v__DOT__cmd_step)? "STEP" :" ", + (m_core->v__DOT__cmd_addr)&0x3f, + (m_core->v__DOT__thecpu__DOT__master_ce)? "*CE*" :"(ce)", + (m_core->v__DOT__cpu_reset)? "*RST*" :"(rst)"); + if (m_core->v__DOT__thecpu__DOT__r_gie) + attroff(A_BOLD); + else + attron(A_BOLD); + mvprintw(ln, 0, "Supervisor Registers"); + ln++; + + showreg(ln, 0, "sR0 ", 0, (m_cursor==12)); + showreg(ln,20, "sR1 ", 1, (m_cursor==13)); + showreg(ln,40, "sR2 ", 2, (m_cursor==14)); + showreg(ln,60, "sR3 ", 3, (m_cursor==15)); ln++; + + showreg(ln, 0, "sR4 ", 4, (m_cursor==16)); + showreg(ln,20, "sR5 ", 5, (m_cursor==17)); + showreg(ln,40, "sR6 ", 6, (m_cursor==18)); + showreg(ln,60, "sR7 ", 7, (m_cursor==19)); ln++; + + showreg(ln, 0, "sR8 ", 8, (m_cursor==20)); + showreg(ln,20, "sR9 ", 9, (m_cursor==21)); + showreg(ln,40, "sR10", 10, (m_cursor==22)); + showreg(ln,60, "sR11", 11, (m_cursor==23)); ln++; + + showreg(ln, 0, "sR12", 12, (m_cursor==24)); + showreg(ln,20, "sSP ", 13, (m_cursor==25)); + + unsigned int cc = m_state.m_sR[14]; + if (false) { + mvprintw(ln,40, "%ssCC : 0x%08x", + (m_cursor==26)?">":" ", cc); + } else { + mvprintw(ln,40, "%ssCC :%s%s%s%s%s%s%s", + (m_cursor==26)?">":" ", + (cc&0x01000)?"FE":"", + (cc&0x00800)?"DE":"", + (cc&0x00400)?"BE":"", + (cc&0x00200)?"TP":"", + (cc&0x00100)?"IL":"", + (cc&0x00080)?"BK":"", + ((m_state.m_gie==0)&&(cc&0x010))?"HLT":""); + mvprintw(ln, 54, "%s%s%s%s", + (cc&8)?"V":" ", + (cc&4)?"N":" ", + (cc&2)?"C":" ", + (cc&1)?"Z":" "); + } + showval(ln,60, "sPC ", m_state.m_sR[15], (m_cursor==27)); + mvprintw(ln,60,"%s", + (m_core->v__DOT__thecpu__DOT__wr_reg_id == 0x0e) + &&(m_core->v__DOT__thecpu__DOT__wr_reg_ce) + ?"V" + :(((m_core->v__DOT__thecpu__DOT__wr_flags_ce) + &&(!m_core->v__DOT__thecpu__DOT__r_alu_gie))?"+" + :" ")); + ln++; + + if (m_core->v__DOT__thecpu__DOT__r_gie) + attron(A_BOLD); + else + attroff(A_BOLD); + mvprintw(ln, 0, "User Registers"); + mvprintw(ln, 42, "DCDR=%02x %s%s", + dcd_R(), + (m_core->v__DOT__thecpu__DOT__dcd_wR)?"W":" ", + (m_core->v__DOT__thecpu__DOT__dcd_wF)?"F":" "); + mvprintw(ln, 62, "OPR =%02x %s%s", + m_core->v__DOT__thecpu__DOT__r_op_R, + (m_core->v__DOT__thecpu__DOT__op_wR)?"W":" ", + (m_core->v__DOT__thecpu__DOT__op_wF)?"F":" "); + ln++; + showreg(ln, 0, "uR0 ", 16, (m_cursor==28)); + showreg(ln,20, "uR1 ", 17, (m_cursor==29)); + showreg(ln,40, "uR2 ", 18, (m_cursor==30)); + showreg(ln,60, "uR3 ", 19, (m_cursor==31)); ln++; + + showreg(ln, 0, "uR4 ", 20, (m_cursor==32)); + showreg(ln,20, "uR5 ", 21, (m_cursor==33)); + showreg(ln,40, "uR6 ", 22, (m_cursor==34)); + showreg(ln,60, "uR7 ", 23, (m_cursor==35)); ln++; + + showreg(ln, 0, "uR8 ", 24, (m_cursor==36)); + showreg(ln,20, "uR9 ", 25, (m_cursor==37)); + showreg(ln,40, "uR10", 26, (m_cursor==38)); + showreg(ln,60, "uR11", 27, (m_cursor==39)); ln++; + + showreg(ln, 0, "uR12", 28, (m_cursor==40)); + showreg(ln,20, "uSP ", 29, (m_cursor==41)); + cc = m_state.m_uR[14]; + if (false) { + mvprintw(ln,40, "%cuCC : 0x%08x", + (m_cursor == 42)?'>':' ', cc); + } else { + mvprintw(ln,40, "%cuCC :%s%s%s%s%s%s%s", + (m_cursor == 42)?'>':' ', + (cc & 0x1000)?"FE":"", + (cc & 0x0800)?"DE":"", + (cc & 0x0400)?"BE":"", + (cc & 0x0200)?"TP":"", + (cc & 0x0100)?"IL":"", + (cc & 0x0040)?"ST":"", + ((m_state.m_gie)&&(cc & 0x010))?"SL":""); + mvprintw(ln, 54, "%s%s%s%s", + (cc&8)?"V":" ", + (cc&4)?"N":" ", + (cc&2)?"C":" ", + (cc&1)?"Z":" "); + } + showval(ln,60, "uPC ", m_state.m_uR[15], (m_cursor==43)); + mvprintw(ln,60,"%s", + (m_core->v__DOT__thecpu__DOT__wr_reg_id == 0x1e) + &&(m_core->v__DOT__thecpu__DOT__wr_reg_ce) + ?"V" + :(((m_core->v__DOT__thecpu__DOT__wr_flags_ce) + &&(m_core->v__DOT__thecpu__DOT__r_alu_gie))?"+" + :" ")); + + attroff(A_BOLD); + ln+=1; + +#ifdef OPT_SINGLE_FETCH + ln++; + mvprintw(ln, 0, "PF BUS: %3s %3s %s @0x%08x[0x%08x] -> %s %s %08x", + (m_core->v__DOT__thecpu__DOT__pf_cyc)?"CYC":" ", + (m_core->v__DOT__thecpu__DOT__pf_stb)?"STB":" ", + " ", // (m_core->v__DOT__thecpu__DOT__pf_we )?"WE":" ", + (m_core->v__DOT__thecpu__DOT__pf_addr<<2), + 0, // (m_core->v__DOT__thecpu__DOT__pf_data), + (m_core->v__DOT__thecpu__DOT__pf_ack)?"ACK":" ", + " ",//(m_core->v__DOT__thecpu__DOT__pf_stall)?"STL":" ", + (m_core->v__DOT__wb_data)); ln++; +#else + + mvprintw(ln, 0, "PFCACH: v=%08x, %s%s, tag=%08x, pf_pc=%08x, lastpc=%08x", + m_core->v__DOT__thecpu__DOT__pf__DOT__vmask, + (m_core->v__DOT__thecpu__DOT__pf__DOT__r_v)?"V":" ", + (m_core->v__DOT__thecpu__DOT__pf_illegal)?"I":" ", + (m_core->v__DOT__thecpu__DOT__pf__DOT__tagsrc) + ?(m_core->v__DOT__thecpu__DOT__pf__DOT__tagvalipc) + :(m_core->v__DOT__thecpu__DOT__pf__DOT__tagvallst), + m_core->v__DOT__thecpu__DOT__pf_pc, + m_core->v__DOT__thecpu__DOT__pf__DOT__lastpc); + + ln++; + mvprintw(ln, 0, "PF BUS: %3s %3s %s @0x%08x[0x%08x] -> %s %s %08x", + (m_core->v__DOT__thecpu__DOT__pf_cyc)?"CYC":" ", + (m_core->v__DOT__thecpu__DOT__pf_stb)?"STB":" ", + " ", // (m_core->v__DOT__thecpu__DOT__pf_we )?"WE":" ", + (m_core->v__DOT__thecpu__DOT__pf_addr<<2), + 0, // (m_core->v__DOT__thecpu__DOT__pf_data), + (m_core->v__DOT__thecpu__DOT__pf_ack)?"ACK":" ", + (pfstall())?"STL":" ", + (m_core->v__DOT__wb_data)); ln++; +#endif + + mvprintw(ln, 0, "MEMBUS: %3s %3s %s @0x%08x[0x%08x] -> %s %s %08x", + (m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_gbl)?"GCY" + :((m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_lcl)?"LCY":" "), + (m_core->v__DOT__thecpu__DOT__mem_stb_gbl)?"GSB" + :((m_core->v__DOT__thecpu__DOT__mem_stb_lcl)?"LSB":" "), + (m_core->v__DOT__thecpu__DOT__mem_we )?"WE":" ", + (m_core->v__DOT__thecpu__DOT__mem_addr<<2), + (m_core->v__DOT__thecpu__DOT__mem_data), + (m_core->v__DOT__thecpu__DOT__mem_ack)?"ACK":" ", + (m_core->v__DOT__thecpu__DOT__mem_stall)?"STL":" ", + (m_core->v__DOT__thecpu__DOT__mem_result)); +// #define OPT_PIPELINED_BUS_ACCESS +#ifdef OPT_PIPELINED_BUS_ACCESS + printw(" %x%x%c%c", + (m_core->v__DOT__thecpu__DOT__domem__DOT__wraddr), + (m_core->v__DOT__thecpu__DOT__domem__DOT__rdaddr), + (m_core->v__DOT__thecpu__DOT__r_op_pipe)?'P':'-', + (mem_pipe_stalled())?'S':'-'); ln++; +#else + ln++; +#endif + + mvprintw(ln, 0, "SYSBS%c: %3s %3s %s @0x%08x[0x%08x] -> %s %s %08x %s", + (m_core->v__DOT__thecpu__DOT__pformem__DOT__r_a_owner)?'M':'P', + (m_core->o_wb_cyc)?"CYC":" ", + (m_core->o_wb_stb)?"STB":" ", + (m_core->o_wb_we )?"WE":" ", + (m_core->o_wb_addr<<2), + (m_core->o_wb_data), + (m_core->i_wb_ack)?"ACK":" ", + (m_core->i_wb_stall)?"STL":" ", + (m_core->i_wb_data), + (m_core->i_wb_err)?"(ER!)":" "); ln+=2; +#ifdef OPT_PIPELINED_BUS_ACCESS + mvprintw(ln-1, 0, "Mem CE: %d = %d%d%d%d%d, stall: %d = %d%d(%d|%d%d|..)", + (m_core->v__DOT__thecpu__DOT__mem_ce), + (m_core->v__DOT__thecpu__DOT__master_ce), //1 + (m_core->v__DOT__thecpu__DOT__op_valid_mem), //0 + (!m_core->v__DOT__thecpu__DOT__new_pc), //1 + // (!m_core->v__DOT__thecpu__DOT__clear_pipeline), //1 + (m_core->v__DOT__thecpu__DOT__set_cond), //1 + (!mem_stalled()), //1 + + (mem_stalled()), + (m_core->v__DOT__thecpu__DOT__op_valid_mem), + (m_core->v__DOT__thecpu__DOT__master_ce), + (mem_pipe_stalled()), + (!m_core->v__DOT__thecpu__DOT__r_op_pipe), + (m_core->v__DOT__thecpu__DOT__domem__DOT__cyc) + ); + printw(" op_pipe = %d", m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__r_pipe); + // mvprintw(4,4,"r_dcdI = 0x%06x", + // (m_core->v__DOT__thecpu__DOT__dcdI)&0x0ffffff); +#endif + mvprintw(4,42,"0x%08x", m_core->v__DOT__thecpu__DOT__pf_instruction); +#ifdef OPT_SINGLE_CYCLE + printw(" A:%c%c B:%c%c", + (m_core->v__DOT__thecpu__DOT__op_A_alu)?'A':'-', + (m_core->v__DOT__thecpu__DOT__op_A_mem)?'M':'-', + (m_core->v__DOT__thecpu__DOT__op_B_alu)?'A':'-', + (m_core->v__DOT__thecpu__DOT__op_B_mem)?'M':'-'); +#else + printw(" A:xx B:xx"); +#endif + printw(" PFPC=%08x", m_core->v__DOT__thecpu__DOT__pf_pc); + + + showins(ln, "I ", +#ifdef OPT_PIPELINED + !m_core->v__DOT__thecpu__DOT__dcd_stalled, +#else + 1, +#endif + m_core->v__DOT__thecpu__DOT__pf_valid, + //m_core->v__DOT__thecpu__DOT__instruction_gie, + m_core->v__DOT__thecpu__DOT__r_gie, + 0, + (m_core->v__DOT__thecpu__DOT__pf_instruction_pc)<<2, + false); ln++; + // m_core->v__DOT__thecpu__DOT__pf_pc); ln++; + + showins(ln, "Dc", + dcd_ce(), dcd_valid(), + m_core->v__DOT__thecpu__DOT__dcd_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__dcd_stalled, +#else + 0, +#endif + (m_core->v__DOT__thecpu__DOT__dcd_pc-1)<<2, +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__r_phase +#else + false +#endif + ); ln++; +#ifdef OPT_ILLEGAL_INSTRUCTION + if (m_core->v__DOT__thecpu__DOT__dcd_illegal) + mvprintw(ln-1,10,"I"); + else +#endif + if (m_core->v__DOT__thecpu__DOT__dcd_M) + mvprintw(ln-1,10,"M"); + + showins(ln, "Op", + op_ce(), + m_core->v__DOT__thecpu__DOT__op_valid, + m_core->v__DOT__thecpu__DOT__r_op_gie, + m_core->v__DOT__thecpu__DOT__op_stall, + op_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_op_phase +#else + false +#endif + ); ln++; +#ifdef OPT_ILLEGAL_INSTRUCTION + if (m_core->v__DOT__thecpu__DOT__op_illegal) + mvprintw(ln-1,10,"I"); + else +#endif + if (m_core->v__DOT__thecpu__DOT__op_valid_mem) + mvprintw(ln-1,10,"M"); + else if (m_core->v__DOT__thecpu__DOT__op_valid_alu) + mvprintw(ln-1,10,"A"); + + if (m_core->v__DOT__thecpu__DOT__op_valid_mem) { + showins(ln, "Mm", + m_core->v__DOT__thecpu__DOT__mem_ce, + m_core->v__DOT__thecpu__DOT__mem_pc_valid, + m_core->v__DOT__thecpu__DOT__r_alu_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__mem_stall, +#else + 0, +#endif + alu_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_alu_phase +#else + false +#endif + ); + } else { + showins(ln, "Al", + m_core->v__DOT__thecpu__DOT__alu_ce, + m_core->v__DOT__thecpu__DOT__alu_pc_valid, + m_core->v__DOT__thecpu__DOT__r_alu_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__alu_stall, +#else + 0, +#endif + alu_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_alu_phase +#else + false +#endif + ); + } ln++; + if (m_core->v__DOT__thecpu__DOT__wr_reg_ce) + mvprintw(ln-1,10,"W"); + else if (m_core->v__DOT__thecpu__DOT__alu_valid) + mvprintw(ln-1,10,(m_core->v__DOT__thecpu__DOT__alu_wR)?"w":"V"); + else if (m_core->v__DOT__thecpu__DOT__mem_valid) + mvprintw(ln-1,10,"v"); +#ifdef OPT_ILLEGAL_INSTRUCTION + else if (m_core->v__DOT__thecpu__DOT__r_alu_illegal) + mvprintw(ln-1,10,"I"); +#endif + // else if (m_core->v__DOT__thecpu__DOT__alu_illegal_op) + // mvprintw(ln-1,10,"i"); + + mvprintw(ln-5, 65,"%s %s", + (m_core->v__DOT__thecpu__DOT__r_op_break)?"OB":" ", + (m_core->v__DOT__thecpu__DOT__new_pc)?"CLRP":" "); + mvprintw(ln-4, 48, + (m_core->v__DOT__thecpu__DOT__new_pc)?"new-pc":" "); + printw("(%s:%02x,%x)", + (m_core->v__DOT__thecpu__DOT__set_cond)?"SET":" ", + (m_core->v__DOT__thecpu__DOT__op_F&0x0ff), + (m_core->v__DOT__thecpu__DOT__r_op_gie) + ? (m_core->v__DOT__thecpu__DOT__w_uflags) + : (m_core->v__DOT__thecpu__DOT__w_iflags)); + + printw("(%s%s%s:%02x)", + (m_core->v__DOT__thecpu__DOT__op_wF)?"OF":" ", + (m_core->v__DOT__thecpu__DOT__alu_wF)?"FL":" ", + (m_core->v__DOT__thecpu__DOT__wr_flags_ce)?"W":" ", + (m_core->v__DOT__thecpu__DOT__alu_flags)); + mvprintw(ln-3, 48, "Op(%x)%8x,%8x->", + m_core->v__DOT__thecpu__DOT__r_op_opn, + m_core->v__DOT__thecpu__DOT__op_Aid, + m_core->v__DOT__thecpu__DOT__op_Bid); + if (m_core->v__DOT__thecpu__DOT__alu_valid) + printw("%08x", m_core->v__DOT__thecpu__DOT__alu_result); + else + 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__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" + :((m_core->v__DOT__thecpu__DOT__div_busy)?"f":" ")); + printw("MEM: %s%s %s%s %s %-5s", + (m_core->v__DOT__thecpu__DOT__op_valid_mem)?"M":" ", + (m_core->v__DOT__thecpu__DOT__mem_ce)?"CE":" ", + (m_core->v__DOT__thecpu__DOT__mem_we)?"Wr ":"Rd ", + (mem_stalled())?"PIPE":" ", + (m_core->v__DOT__thecpu__DOT__mem_valid)?"V":" ", + zip_regstr[(m_core->v__DOT__thecpu__DOT__mem_wreg&0x1f)^0x10]); + } + + void show_user_timers(bool v) { + m_show_user_timers = v; + } + + unsigned int cmd_read(unsigned int a) { + int errcount = 0; + if (m_dbgfp) { + dbg_flag= true; + fprintf(m_dbgfp, "CMD-READ(%d)\n", a); + } + wb_write(CMD_REG, CMD_HALT|(a&0x3f)); + while(((wb_read(CMD_REG) & CMD_STALL) == 0)&&(errcount= MAXERR) { + endwin(); + + printf("ERR: errcount >= MAXERR on wb_read(a=%x)\n", a); + // printf("Clear-Pipeline = %d\n", m_core->v__DOT__thecpu__DOT__clear_pipeline); + printf("cpu-dbg-stall = %d\n", m_core->v__DOT__thecpu__DOT__r_halted); + printf("pf_cyc = %d\n", m_core->v__DOT__thecpu__DOT__pf_cyc); + printf("mem_cyc_gbl = %d\n", (m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_gbl)); + printf("mem_cyc_lcl = %d\n", m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_lcl); + printf("op_valid = %d\n", m_core->v__DOT__thecpu__DOT__op_valid); + printf("dcd_valid = %d\n", dcd_valid()?1:0); + printf("dcd_ce = %d\n", dcd_ce()?1:0); +#ifdef OPT_PIPELINED + printf("dcd_stalled = %d\n", m_core->v__DOT__thecpu__DOT__dcd_stalled); +#endif + printf("pf_valid = %d\n", m_core->v__DOT__thecpu__DOT__pf_valid); +// #ifdef OPT_EARLY_BRANCHING + // printf("dcd_early_branch=%d\n", m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__genblk1__DOT__r_early_branch); +// #endif + + exit(-2); + } + + assert(errcount < MAXERR); + unsigned int v = wb_read(CMD_DATA); + + if (dbg_flag) + fprintf(m_dbgfp, "CMD-READ(%d) = 0x%08x\n", a, v); + dbg_flag = false; + return v; + } + + void cmd_write(unsigned int a, int v) { + int errcount = 0; + if ((a&0x0f)==0x0f) + dbg_flag = true; + wb_write(CMD_REG, CMD_HALT|(a&0x3f)); + while(((wb_read(CMD_REG) & CMD_STALL) == 0)&&(errcount < MAXERR)) + errcount++; + assert(errcount < MAXERR); + if (dbg_flag) + fprintf(m_dbgfp, "CMD-WRITE(%d) <= 0x%08x\n", a, v); + wb_write(CMD_DATA, v); + } + + bool halted(void) { + return (m_core->v__DOT__cmd_halt != 0); + } + + void read_state(void) { + int ln= 0; + bool gie; + + read_raw_state(); + if (m_cursor < 0) + m_cursor = 0; + else if (m_cursor >= 44) + m_cursor = 43; + + mvprintw(ln,0, "Peripherals-RS"); + mvprintw(ln,40,"%-40s", "CPU State: "); + { + unsigned int v = wb_read(CMD_REG); + mvprintw(ln,51, ""); + if (v & 0x010000) + printw("EXT-INT "); + if ((v & 0x003000) == 0x03000) + printw("Halted "); + else if (v & 0x001000) + printw("Sleeping "); + else if (v & 0x002000) + printw("User Mod "); + if (v & 0x008000) + printw("Break-Enabled "); + if (v & 0x000080) + printw("PIC Enabled "); + } ln++; + showval(ln, 0, "PIC ", m_state.m_p[0], (m_cursor==0)); + showval(ln,20, "WDT ", m_state.m_p[1], (m_cursor==1)); + showval(ln,40, "WBUS", m_state.m_p[2], false); + showval(ln,60, "PIC2", m_state.m_p[3], (m_cursor==3)); + ln++; + showval(ln, 0, "TMRA", m_state.m_p[4], (m_cursor==4)); + showval(ln,20, "TMRB", m_state.m_p[5], (m_cursor==5)); + showval(ln,40, "TMRC", m_state.m_p[6], (m_cursor==6)); + showval(ln,60, "JIF ", m_state.m_p[7], (m_cursor==7)); + + ln++; + if (!m_show_user_timers) { + showval(ln, 0, "MTSK", m_state.m_p[12], (m_cursor==8)); + showval(ln,20, "MMST", m_state.m_p[13], (m_cursor==9)); + showval(ln,40, "MPST", m_state.m_p[14], (m_cursor==10)); + showval(ln,60, "MICT", m_state.m_p[15], (m_cursor==11)); + } else { + showval(ln, 0, "UTSK", m_state.m_p[ 8], (m_cursor==8)); + showval(ln,20, "UMST", m_state.m_p[ 9], (m_cursor==9)); + showval(ln,40, "UPST", m_state.m_p[10], (m_cursor==10)); + showval(ln,60, "UICT", m_state.m_p[11], (m_cursor==11)); + } + + ln++; + ln++; + unsigned int cc = m_state.m_sR[14]; + if (m_dbgfp) fprintf(m_dbgfp, "CC = %08x, gie = %d\n", cc, + m_core->v__DOT__thecpu__DOT__r_gie); + gie = (cc & 0x020); + if (gie) + attroff(A_BOLD); + else + attron(A_BOLD); + mvprintw(ln, 0, "Supervisor Registers"); + ln++; + + dispreg(ln, 0, "sR0 ", m_state.m_sR[ 0], (m_cursor==12)); + dispreg(ln,20, "sR1 ", m_state.m_sR[ 1], (m_cursor==13)); + dispreg(ln,40, "sR2 ", m_state.m_sR[ 2], (m_cursor==14)); + dispreg(ln,60, "sR3 ", m_state.m_sR[ 3], (m_cursor==15)); ln++; + + dispreg(ln, 0, "sR4 ", m_state.m_sR[ 4], (m_cursor==16)); + dispreg(ln,20, "sR5 ", m_state.m_sR[ 5], (m_cursor==17)); + dispreg(ln,40, "sR6 ", m_state.m_sR[ 6], (m_cursor==18)); + dispreg(ln,60, "sR7 ", m_state.m_sR[ 7], (m_cursor==19)); ln++; + + dispreg(ln, 0, "sR8 ", m_state.m_sR[ 8], (m_cursor==20)); + dispreg(ln,20, "sR9 ", m_state.m_sR[ 9], (m_cursor==21)); + dispreg(ln,40, "sR10", m_state.m_sR[10], (m_cursor==22)); + dispreg(ln,60, "sR11", m_state.m_sR[11], (m_cursor==23)); ln++; + + dispreg(ln, 0, "sR12", m_state.m_sR[12], (m_cursor==24)); + dispreg(ln,20, "sSP ", m_state.m_sR[13], (m_cursor==25)); + + if (true) { + mvprintw(ln,40, "%ssCC : 0x%08x", + (m_cursor==26)?">":" ", cc); + } else { + mvprintw(ln,40, "%ssCC :%s%s%s%s%s%s%s", + (m_cursor==26)?">":" ", + (cc&0x01000)?"FE":"", + (cc&0x00800)?"DE":"", + (cc&0x00400)?"BE":"", + (cc&0x00200)?"TP":"", + (cc&0x00100)?"IL":"", + (cc&0x00080)?"BK":"", + ((m_state.m_gie==0)&&(cc&0x010))?"HLT":""); + mvprintw(ln, 54, "%s%s%s%s", + (cc&8)?"V":" ", + (cc&4)?"N":" ", + (cc&2)?"C":" ", + (cc&1)?"Z":" "); + } + dispreg(ln,60, "sPC ", cmd_read(15), (m_cursor==27)); + ln++; + + if (gie) + attron(A_BOLD); + else + attroff(A_BOLD); + mvprintw(ln, 0, "User Registers"); + mvprintw(ln, 42, "DCDR=%02x %s", + dcd_R(), (m_core->v__DOT__thecpu__DOT__dcd_wR)?"W":" "); + mvprintw(ln, 62, "OPR =%02x %s%s", + m_core->v__DOT__thecpu__DOT__r_op_R, + (m_core->v__DOT__thecpu__DOT__op_wR)?"W":" ", + (m_core->v__DOT__thecpu__DOT__op_wF)?"F":" "); + ln++; + dispreg(ln, 0, "uR0 ", m_state.m_uR[ 0], (m_cursor==28)); + dispreg(ln,20, "uR1 ", m_state.m_uR[ 1], (m_cursor==29)); + dispreg(ln,40, "uR2 ", m_state.m_uR[ 2], (m_cursor==30)); + dispreg(ln,60, "uR3 ", m_state.m_uR[ 3], (m_cursor==31)); ln++; + + dispreg(ln, 0, "uR4 ", m_state.m_uR[ 4], (m_cursor==32)); + dispreg(ln,20, "uR5 ", m_state.m_uR[ 5], (m_cursor==33)); + dispreg(ln,40, "uR6 ", m_state.m_uR[ 6], (m_cursor==34)); + dispreg(ln,60, "uR7 ", m_state.m_uR[ 7], (m_cursor==35)); ln++; + + dispreg(ln, 0, "uR8 ", m_state.m_uR[ 8], (m_cursor==36)); + dispreg(ln,20, "uR9 ", m_state.m_uR[ 9], (m_cursor==37)); + dispreg(ln,40, "uR10", m_state.m_uR[10], (m_cursor==38)); + dispreg(ln,60, "uR11", m_state.m_uR[11], (m_cursor==39)); ln++; + + dispreg(ln, 0, "uR12", m_state.m_uR[12], (m_cursor==40)); + dispreg(ln,20, "uSP ", m_state.m_uR[13], (m_cursor==41)); + cc = m_state.m_uR[14]; + if (false) { + mvprintw(ln,40, "%cuCC : 0x%08x", + (m_cursor == 42)?'>':' ', cc); + } else { + mvprintw(ln,40, "%cuCC :%s%s%s%s%s%s%s", + (m_cursor == 42)?'>':' ', + (cc & 0x1000)?"FE":"", + (cc & 0x0800)?"DE":"", + (cc & 0x0400)?"BE":"", + (cc & 0x0200)?"TP":"", + (cc & 0x0100)?"IL":"", + (cc & 0x0040)?"ST":"", + ((m_state.m_gie)&&(cc & 0x010))?"SL":""); + mvprintw(ln, 54, "%s%s%s%s", + (cc&8)?"V":" ", + (cc&4)?"N":" ", + (cc&2)?"C":" ", + (cc&1)?"Z":" "); + } + dispreg(ln,60, "uPC ", m_state.m_uR[15], (m_cursor==43)); + + attroff(A_BOLD); + ln+=2; + + ln+=3; + + showins(ln, "I ", +#ifdef OPT_PIPELINED + !m_core->v__DOT__thecpu__DOT__dcd_stalled, +#else + 1, +#endif + m_core->v__DOT__thecpu__DOT__pf_valid, + m_core->v__DOT__thecpu__DOT__r_gie, + 0, + m_core->v__DOT__thecpu__DOT__pf_instruction_pc, + true); ln++; + // m_core->v__DOT__thecpu__DOT__pf_pc); ln++; + + showins(ln, "Dc", + dcd_ce(), dcd_valid(), + m_core->v__DOT__thecpu__DOT__dcd_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__dcd_stalled, +#else + 0, +#endif + m_core->v__DOT__thecpu__DOT__dcd_pc-1, +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__dcd_phase +#else + false +#endif + ); ln++; + + showins(ln, "Op", + op_ce(), + m_core->v__DOT__thecpu__DOT__op_valid, + m_core->v__DOT__thecpu__DOT__r_op_gie, + m_core->v__DOT__thecpu__DOT__op_stall, + op_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_op_phase +#else + false +#endif + ); ln++; + + if (m_core->v__DOT__thecpu__DOT__op_valid_mem) { + showins(ln, "Mm", + m_core->v__DOT__thecpu__DOT__mem_ce, + m_core->v__DOT__thecpu__DOT__mem_pc_valid, + m_core->v__DOT__thecpu__DOT__r_alu_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__mem_stall, +#else + 0, +#endif + alu_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_alu_phase +#else + false +#endif + ); + } else { + showins(ln, "Al", + m_core->v__DOT__thecpu__DOT__alu_ce, + m_core->v__DOT__thecpu__DOT__alu_pc_valid, + m_core->v__DOT__thecpu__DOT__r_alu_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__alu_stall, +#else + 0, +#endif + alu_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_alu_phase +#else + false +#endif + ); + } ln++; + } + + void tick(void) { + int gie = m_core->v__DOT__thecpu__DOT__r_gie; + /* + m_core->i_qspi_dat = m_flash(m_core->o_qspi_cs_n, + m_core->o_qspi_sck, + m_core->o_qspi_dat); + */ + + int stb = m_core->o_wb_stb, mask = (RAMBASE-1); + unsigned addr = m_core->o_wb_addr<<2; + + m_core->i_wb_err = 0; + if ((addr & (~mask))!=RAMBASE) + stb = 0; + if ((m_core->o_wb_cyc)&&(m_core->o_wb_stb)&&(!stb)) { + m_core->i_wb_ack = 1; + m_core->i_wb_err = 1; + m_bomb = true; + if (m_dbgfp) fprintf(m_dbgfp, + "BOMB!! (Attempting to access %08x/%08x->%08x)\n", + addr, RAMBASE, ((addr)&(~mask))); + } else if ((!m_core->o_wb_cyc)&&(m_core->o_wb_stb)) { + if (m_dbgfp) fprintf(m_dbgfp, + "BOMB!! (Strobe high, CYC low)\n"); + m_bomb = true; + } + + if ((dbg_flag)&&(m_dbgfp)) { + fprintf(m_dbgfp, "BUS %s %s %s @0x%08x/[0x%08x 0x%08x] %s %s\n", + (m_core->o_wb_cyc)?"CYC":" ", + (m_core->o_wb_stb)?"STB":" ", + (m_core->o_wb_we)?"WE":" ", + (m_core->o_wb_addr<<2), + (m_core->o_wb_data), + (m_core->i_wb_data), + (m_core->i_wb_stall)?"STALL":" ", + (m_core->i_wb_ack)?"ACK":" "); + fprintf(m_dbgfp, "DBG %s %s %s @0x%08x/%d[0x%08x] %s %s [0x%08x] %s %s %s%s%s%s%s%s%s%s%s\n", + (m_core->i_dbg_cyc)?"CYC":" ", + (m_core->i_dbg_stb)?"STB": + ((m_core->v__DOT__dbg_stb)?"DBG":" "), + ((m_core->i_dbg_we)?"WE":" "), + (m_core->i_dbg_addr),0, + m_core->i_dbg_data, + (m_core->o_dbg_ack)?"ACK":" ", + (m_core->o_dbg_stall)?"STALL":" ", + (m_core->o_dbg_data), + (m_core->v__DOT__cpu_halt)?"CPU-HALT ":"", + (m_core->v__DOT__thecpu__DOT__r_halted)?"CPU-DBG_STALL":"", + (dcd_valid())?"DCDV ":"", + (m_core->v__DOT__thecpu__DOT__op_valid)?"OPV ":"", + (m_core->v__DOT__thecpu__DOT__pf_cyc)?"PCYC ":"", + (m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_gbl)?"GC":" ", + (m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_lcl)?"LC":" ", + (m_core->v__DOT__thecpu__DOT__alu_wR)?"ALUW ":"", + (m_core->v__DOT__thecpu__DOT__alu_ce)?"ALCE ":"", + (m_core->v__DOT__thecpu__DOT__alu_valid)?"ALUV ":"", + (m_core->v__DOT__thecpu__DOT__mem_valid)?"MEMV ":""); + fprintf(m_dbgfp, " SYS %s %s %s @0x%08x/%d[0x%08x] %s [0x%08x]\n", + (m_core->v__DOT__sys_cyc)?"CYC":" ", + (m_core->v__DOT__sys_stb)?"STB":" ", + (m_core->v__DOT__sys_we)?"WE":" ", + (m_core->v__DOT__sys_addr<<2), + (m_core->v__DOT__dbg_addr<<2), + (m_core->v__DOT__sys_data), + (m_core->v__DOT__dbg_ack)?"ACK":" ", + (m_core->v__DOT__wb_data)); + } + + if (m_dbgfp) + fprintf(m_dbgfp, "CEs %d/0x%08x,%d/0x%08x DCD: ->%02x, OP: ->%02x, ALU: halt=%d,%d ce=%d, valid=%d, wr=%d Reg=%02x, IPC=%08x, UPC=%08x\n", + dcd_ce(), + m_core->v__DOT__thecpu__DOT__dcd_pc, + op_ce(), + op_pc(), + dcd_Aid()&0x01f, + m_core->v__DOT__thecpu__DOT__r_op_R, + m_core->v__DOT__cmd_halt, + m_core->v__DOT__cpu_halt, + m_core->v__DOT__thecpu__DOT__alu_ce, + m_core->v__DOT__thecpu__DOT__alu_valid, + m_core->v__DOT__thecpu__DOT__alu_wR, + m_core->v__DOT__thecpu__DOT__alu_reg, + m_core->v__DOT__thecpu__DOT__ipc, + m_core->v__DOT__thecpu__DOT__r_upc); + + if ((m_dbgfp)&&(!gie)&&(m_core->v__DOT__thecpu__DOT__w_release_from_interrupt)) { + fprintf(m_dbgfp, "RELEASE: int=%d, %d/%02x[%08x] ?/%02x[0x%08x], ce=%d %d,%d,%d\n", + m_core->v__DOT__genblk9__DOT__pic__DOT__r_interrupt, + m_core->v__DOT__thecpu__DOT__wr_reg_ce, + m_core->v__DOT__thecpu__DOT__wr_reg_id, + m_core->v__DOT__thecpu__DOT__wr_spreg_vl, + m_core->v__DOT__cmd_addr<<2, + m_core->v__DOT__dbg_idata, + m_core->v__DOT__thecpu__DOT__master_ce, + m_core->v__DOT__thecpu__DOT__alu_wR, + m_core->v__DOT__thecpu__DOT__alu_valid, + m_core->v__DOT__thecpu__DOT__mem_valid); + } else if ((m_dbgfp)&&(gie)&&(m_core->v__DOT__thecpu__DOT__w_switch_to_interrupt)) { + fprintf(m_dbgfp, "SWITCH: %d/%02x[%08x] ?/%02x[0x%08x], ce=%d %d,%d,%d, F%02x,%02x\n", + m_core->v__DOT__thecpu__DOT__wr_reg_ce, + m_core->v__DOT__thecpu__DOT__wr_reg_id, + m_core->v__DOT__thecpu__DOT__wr_spreg_vl, + m_core->v__DOT__cmd_addr<<2, + m_core->v__DOT__dbg_idata, + m_core->v__DOT__thecpu__DOT__master_ce, + m_core->v__DOT__thecpu__DOT__alu_wR, + m_core->v__DOT__thecpu__DOT__alu_valid, + m_core->v__DOT__thecpu__DOT__mem_valid, + m_core->v__DOT__thecpu__DOT__w_iflags, + m_core->v__DOT__thecpu__DOT__w_uflags); + fprintf(m_dbgfp, "\tbrk=%s %d,%d\n", + (m_core->v__DOT__thecpu__DOT__master_ce)?"CE":" ", + m_core->v__DOT__thecpu__DOT__break_en, + m_core->v__DOT__thecpu__DOT__r_op_break); + } else if ((m_dbgfp)&& + ((m_core->v__DOT__thecpu__DOT__r_op_break) + ||(m_core->v__DOT__thecpu__DOT__r_alu_illegal) + ||(m_core->v__DOT__thecpu__DOT__dcd_break))) { + fprintf(m_dbgfp, "NOT SWITCHING TO GIE (gie = %d)\n", gie); + fprintf(m_dbgfp, "\tbrk=%s breaken=%d,dcdbreak=%d,opbreak=%d,alu_illegal=%d\n", + (m_core->v__DOT__thecpu__DOT__master_ce)?"CE":" ", + m_core->v__DOT__thecpu__DOT__break_en, + m_core->v__DOT__thecpu__DOT__dcd_break, + m_core->v__DOT__thecpu__DOT__r_op_break, + m_core->v__DOT__thecpu__DOT__r_alu_illegal); + } + + if (m_dbgfp) { + // if(m_core->v__DOT__thecpu__DOT__clear_pipeline) + // fprintf(m_dbgfp, "\tClear Pipeline\n"); + if(m_core->v__DOT__thecpu__DOT__new_pc) + fprintf(m_dbgfp, "\tNew PC\n"); + } + + if (m_dbgfp) + fprintf(m_dbgfp, "----------- TICK (%08x) ----------%s\n", + m_core->v__DOT__jiffies__DOT__r_counter, + (m_bomb)?" BOMBED!!":""); + 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, m_core->o_wb_sel & 0x0f, + m_core->i_wb_ack, m_core->i_wb_stall,m_core->i_wb_data); + + + TESTB::tick(); + + if ((m_dbgfp)&&(gie != m_core->v__DOT__thecpu__DOT__r_gie)) { + fprintf(m_dbgfp, "SWITCH FROM %s to %s: sPC = 0x%08x uPC = 0x%08x pf_pc = 0x%08x\n", + (gie)?"User":"Supervisor", + (gie)?"Supervisor":"User", + m_core->v__DOT__thecpu__DOT__ipc, + m_core->v__DOT__thecpu__DOT__r_upc, + m_core->v__DOT__thecpu__DOT__pf_pc); + } if (m_dbgfp) { +#ifdef OPT_TRADITIONAL_PFCACHE + fprintf(m_dbgfp, "PFCACHE %s(%08x,%08x%s),%08x - %08x %s%s%s\n", + (m_core->v__DOT__thecpu__DOT__new_pc)?"N":" ", + m_core->v__DOT__thecpu__DOT__pf_pc, + m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__genblk3__DOT__r_branch_pc, + ((m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__genblk3__DOT__r_early_branch) + &&(dcd_valid()) + &&(!m_core->v__DOT__thecpu__DOT__new_pc))?"V":"-", + m_core->v__DOT__thecpu__DOT__pf__DOT__lastpc, + m_core->v__DOT__thecpu__DOT__pf_instruction_pc, + (m_core->v__DOT__thecpu__DOT__pf__DOT__r_v)?"R":" ", + (m_core->v__DOT__thecpu__DOT__pf_valid)?"V":" ", + (m_core->v__DOT__thecpu__DOT__pf_illegal)?"I":" "); +#endif + dbgins("Dc - ", + dcd_ce(), dcd_valid(), + m_core->v__DOT__thecpu__DOT__dcd_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__dcd_stalled, +#else + 0, +#endif + (m_core->v__DOT__thecpu__DOT__dcd_pc-1)<<2, +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__instruction_decoder__DOT__r_phase, +#else + false, +#endif +#ifdef OPT_ILLEGAL_INSTRUCTION + m_core->v__DOT__thecpu__DOT__dcd_illegal +#else + false +#endif + ); + if (m_dbgfp) { + fprintf(m_dbgfp, "\t\t\tR[%2d] = (*Dc=%d%s)[ A[%2d], B[%2d] + %08x], dcd_pc = %08x\n", + m_core->v__DOT__thecpu__DOT____Vcellout__instruction_decoder____pinNumber14, + m_core->v__DOT__thecpu__DOT__dcd_opn, + (m_core->v__DOT__thecpu__DOT__dcd_M)?"M":" ", + m_core->v__DOT__thecpu__DOT____Vcellout__instruction_decoder____pinNumber15&0x0f, + m_core->v__DOT__thecpu__DOT____Vcellout__instruction_decoder____pinNumber16&0x0f, + m_core->v__DOT__thecpu__DOT__dcd_I, + m_core->v__DOT__thecpu__DOT__dcd_pc); + } + dbgins("Op - ", + op_ce(), + m_core->v__DOT__thecpu__DOT__op_valid, + m_core->v__DOT__thecpu__DOT__r_op_gie, + m_core->v__DOT__thecpu__DOT__op_stall, + op_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_op_phase, +#else + false, +#endif +#ifdef OPT_ILLEGAL_INSTRUCTION + m_core->v__DOT__thecpu__DOT__op_illegal +#else + false +#endif + ); + if (m_dbgfp) { + fprintf(m_dbgfp, "\t\t\t(*OP=%d)[ A = 0x%08x , B = 0x%08x ], op_pc= %08x\n", + m_core->v__DOT__thecpu__DOT__r_op_opn, + m_core->v__DOT__thecpu__DOT__op_Av, + m_core->v__DOT__thecpu__DOT__op_Bv, + m_core->v__DOT__thecpu__DOT__op_pc); + } + dbgins("Al - ", + m_core->v__DOT__thecpu__DOT__alu_ce, + m_core->v__DOT__thecpu__DOT__alu_pc_valid, + m_core->v__DOT__thecpu__DOT__r_alu_gie, +#ifdef OPT_PIPELINED + m_core->v__DOT__thecpu__DOT__alu_stall, +#else + 0, +#endif + alu_pc(), +#ifdef OPT_CIS + m_core->v__DOT__thecpu__DOT__r_alu_phase, +#else + false, +#endif +#ifdef OPT_ILLEGAL_INSTRUCTION + m_core->v__DOT__thecpu__DOT__r_alu_illegal +#else + false +#endif + ); + if (m_core->v__DOT__thecpu__DOT__wr_reg_ce) + fprintf(m_dbgfp, "WB::Reg[%2x] <= %08x\n", + m_core->v__DOT__thecpu__DOT__wr_reg_id, + m_core->v__DOT__thecpu__DOT__wr_gpreg_vl); + + } + + if ((m_dbgfp)&&((m_core->v__DOT__thecpu__DOT__div_valid) + ||(m_core->v__DOT__thecpu__DOT__div_ce) + ||(m_core->v__DOT__thecpu__DOT__div_busy) + )) { + fprintf(m_dbgfp, "DIV: %s %s %s %s[%2x] GP:%08x/SP:%08x %s:0x%08x\n", + (m_core->v__DOT__thecpu__DOT__div_ce)?"CE":" ", + (m_core->v__DOT__thecpu__DOT__div_busy)?"BUSY":" ", + (m_core->v__DOT__thecpu__DOT__div_valid)?"VALID":" ", + (m_core->v__DOT__thecpu__DOT__wr_reg_ce)?"REG-CE":" ", + m_core->v__DOT__thecpu__DOT__wr_reg_id, + m_core->v__DOT__thecpu__DOT__wr_gpreg_vl, + m_core->v__DOT__thecpu__DOT__wr_spreg_vl, + (m_core->v__DOT__thecpu__DOT__alu_pc_valid)?"PCV":" ", + alu_pc()); + + fprintf(m_dbgfp, "ALU-PC: %08x %s %s\n", + alu_pc(), + (m_core->v__DOT__thecpu__DOT__r_alu_pc_valid)?"VALID":"", + (m_core->v__DOT__thecpu__DOT__r_alu_gie)?"ALU-GIE":""); + } + + if (m_core->v__DOT__dma_controller__DOT__dma_state) { + fprintf(m_dbgfp, "DMA[%d]%s%s%s%s@%08x,%08x [%d%d/%4d/%4d] -> [%d%d/%04d/%04d]\n", + m_core->v__DOT__dma_controller__DOT__dma_state, + (m_core->v__DOT__dc_cyc)?"C":" ", + (m_core->v__DOT__dc_stb)?"S":" ", + (m_core->v__DOT__dc_ack)?"A":" ", + (m_core->v__DOT__dc_err)?"E":" ", + m_core->v__DOT__dc_addr<<2, + (m_core->v__DOT__dc_data), + m_core->v__DOT__dma_controller__DOT__last_read_request, + m_core->v__DOT__dma_controller__DOT__last_read_ack, + m_core->v__DOT__dma_controller__DOT__nracks, + m_core->v__DOT__dma_controller__DOT__nread, + m_core->v__DOT__dma_controller__DOT__last_write_request, + m_core->v__DOT__dma_controller__DOT__last_write_ack, + m_core->v__DOT__dma_controller__DOT__nwacks, + m_core->v__DOT__dma_controller__DOT__nwritten); + } + if (((m_core->v__DOT__thecpu__DOT__alu_pc_valid) + ||(m_core->v__DOT__thecpu__DOT__mem_pc_valid)) + &&(!m_core->v__DOT__thecpu__DOT__new_pc)) { + unsigned long iticks = m_tickcount - m_last_instruction_tickcount; + if (m_profile_fp) { + unsigned buf[2]; + buf[0] = alu_pc(); + buf[1] = iticks; + fwrite(buf, sizeof(unsigned), 2, m_profile_fp); + } + m_last_instruction_tickcount = m_tickcount; + } + } + + bool test_success(void) { + return ((!m_core->v__DOT__thecpu__DOT__r_gie) + &&(m_core->v__DOT__thecpu__DOT__sleep)); + } + + unsigned op_pc(void) { + return (m_core->v__DOT__thecpu__DOT__op_pc<<2)-4; + } + + bool dcd_ce(void) { + if (m_core->v__DOT__thecpu__DOT__new_pc) + return false; + if (!dcd_valid()) + return true; + if (!m_core->v__DOT__thecpu__DOT__dcd_stalled) + return true; + return false; + } bool dcd_valid(void) { + return (m_core->v__DOT__thecpu__DOT__r_dcd_valid !=0); + } + bool pfstall(void) { + return((!(m_core->v__DOT__thecpu__DOT__pformem__DOT__r_a_owner)) + ||(m_core->v__DOT__cpu_stall)); + } + unsigned dcd_R(void) { + return (m_core->v__DOT__thecpu__DOT____Vcellout__instruction_decoder____pinNumber14); + } + unsigned dcd_Aid(void) { + return (m_core->v__DOT__thecpu__DOT____Vcellout__instruction_decoder____pinNumber15); + } + unsigned dcd_Bid(void) { + return (m_core->v__DOT__thecpu__DOT____Vcellout__instruction_decoder____pinNumber16); + } + + bool op_ce(void) { + return dcd_valid(); + } bool op_valid(void) { + return (m_core->v__DOT__thecpu__DOT__op_valid !=0); + } + + bool mem_busy(void) { + // return m_core->v__DOT__thecpu__DOT__mem_busy; +#ifdef OPT_PIPELINED + return m_core->v__DOT__thecpu__DOT__domem__DOT__cyc; +#else + return 0; +#endif + } + + bool mem_stalled(void) { + bool a, b, c, d, wr_write_cc, wr_write_pc, op_gie; + + wr_write_cc=((m_core->v__DOT__thecpu__DOT__wr_reg_id&0x0f)==0x0e); + wr_write_pc=((m_core->v__DOT__thecpu__DOT__wr_reg_id&0x0f)==0x0f); + op_gie = m_core->v__DOT__thecpu__DOT__r_op_gie; + +#ifdef OPT_PIPELINED_BUS_ACCESS + //a = m_core->v__DOT__thecpu__DOT__mem_pipe_stalled; + a = mem_pipe_stalled(); + b = (!m_core->v__DOT__thecpu__DOT__r_op_pipe)&&(mem_busy()); +#else + a = false; + b = false; +#endif + d = ((wr_write_pc)||(wr_write_cc)); + c = ((m_core->v__DOT__thecpu__DOT__wr_reg_ce) + &&(((m_core->v__DOT__thecpu__DOT__wr_reg_id&0x010)?true:false)==op_gie) + &&d); + d =(m_core->v__DOT__thecpu__DOT__op_valid_mem)&&((a)||(b)||(c)); + return ((!m_core->v__DOT__thecpu__DOT__master_ce)||(d)); + } + + unsigned alu_pc(void) { + /* + unsigned r = op_pc(); + if (m_core->v__DOT__thecpu__DOT__op_valid) + r--; + return r; + */ + return (m_core->v__DOT__thecpu__DOT__r_alu_pc<<2)-4; + } + +#ifdef OPT_PIPELINED_BUS_ACCESS + bool mem_pipe_stalled(void) { + int r = 0; + r = ((m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_gbl) + ||(m_core->v__DOT__thecpu__DOT__domem__DOT__r_wb_cyc_lcl)); + r = r && ((m_core->v__DOT__thecpu__DOT__mem_stall) + ||( + ((!m_core->v__DOT__thecpu__DOT__mem_stb_gbl) + &&(!m_core->v__DOT__thecpu__DOT__mem_stb_lcl)))); + return r; + // return m_core->v__DOT__thecpu__DOT__mem_pipe_stalled; + } +#endif + + bool test_failure(void) { + if (m_core->v__DOT__thecpu__DOT__sleep) + return 0; + else if (m_core->v__DOT__thecpu__DOT__r_gie) + return (m_mem[m_core->v__DOT__thecpu__DOT__r_upc] == 0x7bc3dfff); + else if (m_mem[m_core->v__DOT__thecpu__DOT__ipc] == 0x7883ffff) + return true; // ADD to PC instruction + else // MOV to PC instruction + return (m_mem[m_core->v__DOT__thecpu__DOT__ipc] == 0x7bc3dfff); + /* + return ((m_core->v__DOT__thecpu__DOT__alu_pc_valid) + &&(m_mem[alu_pc()] == 0x2f0f7fff) + &&(!m_core->v__DOT__thecpu__DOT__clear_pipeline)); + */ + } + + void wb_write(unsigned a, unsigned int v) { + int errcount = 0; + mvprintw(0,35, "%40s", ""); + mvprintw(0,40, "wb_write(%d,%x)", a, v); + m_core->i_dbg_cyc = 1; + m_core->i_dbg_stb = 1; + m_core->i_dbg_we = 1; + m_core->i_dbg_addr = (a>>2) & 1; + m_core->i_dbg_data = v; + + while((errcount++ < 100)&&(m_core->o_dbg_stall)) + tick(); + tick(); + + m_core->i_dbg_stb = 0; + while((errcount++ < 100)&&(!m_core->o_dbg_ack)) + tick(); + + // Release the bus + m_core->i_dbg_cyc = 0; + m_core->i_dbg_stb = 0; + tick(); + mvprintw(0,35, "%40s", ""); + mvprintw(0,40, "wb_write -- complete"); + + + if (errcount >= 100) { + if (m_dbgfp) fprintf(m_dbgfp, "WB-WRITE: ERRCount = %d, BOMB!!\n", errcount); + m_bomb = true; + } + } + + unsigned long wb_read(unsigned a) { + unsigned int v; + int errcount = 0; + mvprintw(0,35, "%40s", ""); + mvprintw(0,40, "wb_read(0x%08x)", a); + m_core->i_dbg_cyc = 1; + m_core->i_dbg_stb = 1; + m_core->i_dbg_we = 0; + m_core->i_dbg_addr = (a>>2) & 1; + + while((errcount++<100)&&(m_core->o_dbg_stall)) + tick(); + tick(); + + m_core->i_dbg_stb = 0; + while((errcount++<100)&&(!m_core->o_dbg_ack)) + tick(); + v = m_core->o_dbg_data; + + // Release the bus + m_core->i_dbg_cyc = 0; + m_core->i_dbg_stb = 0; + tick(); + + mvprintw(0,35, "%40s", ""); + mvprintw(0,40, "wb_read = 0x%08x", v); + + if (errcount >= 100) { + if (m_dbgfp) fprintf(m_dbgfp, "WB-READ: ERRCount = %d, BOMB!!\n", errcount); + m_bomb = true; + } + return v; + } + + void cursor_up(void) { + if (m_cursor > 3) + m_cursor -= 4; + } void cursor_down(void) { + if (m_cursor < 40) + m_cursor += 4; + } void cursor_left(void) { + if (m_cursor > 0) + m_cursor--; + else m_cursor = 43; + } void cursor_right(void) { + if (m_cursor < 43) + m_cursor++; + else m_cursor = 0; + } + + int cursor(void) { return m_cursor; } + + void jump_to(ZIPI address) { + if (m_dbgfp) + fprintf(m_dbgfp, "JUMP_TO(%08x) ... Setting PC to %08x\n", address, address & -4); + m_core->v__DOT__thecpu__DOT__pf_pc = address & -4; + m_core->v__DOT__thecpu__DOT__pf_request_address = address >> 2; + // m_core->v__DOT__thecpu__DOT__clear_pipeline = 1; + m_core->v__DOT__thecpu__DOT__new_pc = 1; + } + + void dump_state(void) { + if (m_dbgfp) + dump_state(m_dbgfp); + } + + void dump_state(FILE *fp) { + if (!fp) + return; + fprintf(fp, "FINAL STATE: %s\n", + (m_state.m_gie)?"GIE(User-Mode)":"Supervisor-mode"); + fprintf(fp, "Supervisor Registers\n"); + for(int i=0; i<16; i++) { + char str[16]; + if (i==13) + sprintf(str, "sSP"); + else if (i==14) + sprintf(str, "sCC"); + else if (i==15) + sprintf(str, "sPC"); + else // if (i<=12) + sprintf(str, "s-%2d", i); + dbgreg(fp, i, str, m_state.m_sR[i]); + if ((i&3)==3) + fprintf(fp, "\n"); + } + fprintf(fp, "User Registers\n"); + for(int i=0; i<16; i++) { + char str[16]; + if (i==13) + sprintf(str, "uSP"); + else if (i==14) + sprintf(str, "uCC"); + else if (i==15) + sprintf(str, "uPC"); + else // if (i<=12) + sprintf(str, "u-%2d", i); + dbgreg(fp, i, str, m_state.m_uR[i]); + if ((i&3)==3) + fprintf(fp, "\n"); + } + } +}; + +void get_value(ZIPPY_TB *tb) { + int wy, wx, ra; + int c = tb->cursor(); + + wx = (c & 0x03) * 20 + 9; + wy = (c>>2); + if (wy >= 3+4) + wy++; + if (wy > 3) + wy += 2; + wy++; + + if (c >= 12) + ra = c - 12; + else + ra = c + 32; + + bool done = false; + char str[16]; + int pos = 0; str[pos] = '\0'; + while(!done) { + int chv = getch(); + switch(chv) { + case KEY_ESCAPE: + pos = 0; str[pos] = '\0'; done = true; + break; + case KEY_RETURN: case KEY_ENTER: case KEY_UP: case KEY_DOWN: + done = true; + break; + case KEY_LEFT: case KEY_BACKSPACE: + if (pos > 0) pos--; + break; + case CTRL('L'): redrawwin(stdscr); break; + case KEY_CLEAR: + pos = 0; + break; + case '0': case ' ': str[pos++] = '0'; break; + case '1': str[pos++] = '1'; break; + case '2': str[pos++] = '2'; break; + case '3': str[pos++] = '3'; break; + case '4': str[pos++] = '4'; break; + case '5': str[pos++] = '5'; break; + case '6': str[pos++] = '6'; break; + case '7': str[pos++] = '7'; break; + case '8': str[pos++] = '8'; break; + case '9': str[pos++] = '9'; break; + case 'A': case 'a': str[pos++] = 'A'; break; + case 'B': case 'b': str[pos++] = 'B'; break; + case 'C': case 'c': str[pos++] = 'C'; break; + case 'D': case 'd': str[pos++] = 'D'; break; + case 'E': case 'e': str[pos++] = 'E'; break; + case 'F': case 'f': str[pos++] = 'F'; break; + } + + if (pos > 8) + pos = 8; + str[pos] = '\0'; + + attron(A_NORMAL | A_UNDERLINE); + mvprintw(wy, wx, "%-8s", str); + if (pos > 0) { + attron(A_NORMAL | A_UNDERLINE | A_BLINK); + mvprintw(wy, wx+pos-1, "%c", str[pos-1]); + } + attrset(A_NORMAL); + } + + if (pos > 0) { + int v; + v = strtoul(str, NULL, 16); + if (!tb->halted()) { + switch(ra) { + case 15: + tb->m_core->v__DOT__thecpu__DOT__ipc = v; + if (!tb->m_core->v__DOT__thecpu__DOT__r_gie) { + tb->jump_to(v); + // tb->m_core->v__DOT__thecpu__DOT__clear_pipeline = 1; + tb->m_core->v__DOT__thecpu__DOT__alu_pc_valid = 0; +#ifdef OPT_PIPELINED + // tb->m_core->v__DOT__thecpu__DOT__dcd_ce = 0; + tb->m_core->v__DOT__thecpu__DOT__r_dcd_valid = 0; +#endif + tb->m_core->v__DOT__thecpu__DOT__op_valid = 0; + } + break; + case 31: + tb->m_core->v__DOT__thecpu__DOT__r_upc = v; + if (tb->m_core->v__DOT__thecpu__DOT__r_gie) { + tb->jump_to(v); + // tb->m_core->v__DOT__thecpu__DOT__clear_pipeline = 1; + tb->m_core->v__DOT__thecpu__DOT__alu_pc_valid = 0; +#ifdef OPT_PIPELINED + tb->m_core->v__DOT__thecpu__DOT__r_dcd_valid = 0; +#endif + tb->m_core->v__DOT__thecpu__DOT__op_valid = 0; + } + break; + case 32: tb->m_core->v__DOT__pic_data = v; break; + case 33: tb->m_core->v__DOT__watchdog__DOT__r_value = v; break; + // case 34: tb->m_core->v__DOT__manualcache__DOT__cache_base = v; break; + case 35: tb->m_core->v__DOT__genblk7__DOT__ctri__DOT__r_int_state = v; break; + case 36: tb->m_core->v__DOT__timer_a__DOT__r_value = v; break; + case 37: tb->m_core->v__DOT__timer_b__DOT__r_value = v; break; + case 38: tb->m_core->v__DOT__timer_c__DOT__r_value = v; break; + case 39: tb->m_core->v__DOT__jiffies__DOT__r_counter = v; break; + case 44: tb->m_core->v__DOT__utc_data = v; break; + case 45: tb->m_core->v__DOT__uoc_data = v; break; + case 46: tb->m_core->v__DOT__upc_data = v; break; + case 47: tb->m_core->v__DOT__uic_data = v; break; + default: + tb->m_core->v__DOT__thecpu__DOT__regset[ra] = v; + break; + } + } else + tb->cmd_write(ra, v); + } +} + + + +void usage(void) { + printf("USAGE: zippy_tb [-a] \n"); + printf("\n"); + printf("\tWhere testfile.out is an output file from the assembler.\n"); + printf("\tThis file needs to be in a raw format and not an ELF\n"); + printf("\texecutable. It will be inserted into memory at a memory\n"); + printf("\taddress of 0x0100000. The memory device itself, the only\n"); + printf("\tdevice supported by this simulator, occupies addresses from\n"); + printf("\t0x0100000 to 0x01fffff.\n"); + printf("\n"); + printf("\t-a\tSets the testbench to run automatically without any\n"); + printf("\t\tuser interaction.\n"); + printf("\n"); + printf("\tUser Commands:\n"); + printf("\t\tWhen the test bench is run interactively, the following\n"); + printf("\t\tkey strokes are recognized:\n"); + printf("\t\t\'h\'\tHalt the processor using the external interface.\n"); + printf("\t\t\'g\'\tLet the processor run at full throttle with no.\n"); + printf("\t\t\tuser intervention.\n"); + printf("\t\t\'q\'\tQuit the simulation.\n"); + printf("\t\t\'r\'\tReset the processor.\n"); + printf("\t\t\'s\'\tStep the CPU using the external stepping command\n"); + printf("\t\t\tThis may consume more than one tick.\n"); + printf("\t\t\'t\'\tClock a single tick through the system.\n"); +} + +bool signalled = false; + +void sigint(int v) { + signalled = true; +} + +int main(int argc, char **argv) { + Verilated::commandArgs(argc, argv); + ZIPPY_TB *tb = new ZIPPY_TB(); + bool autorun = false, exit_on_done = false, autostep=false; + ZIPI entry = RAMBASE; + + signal(SIGINT, sigint); + + if (argc <= 1) { + usage(); + exit(-1); + } else { + for(int argn=1; argnm_len; i++) { + const char *data; + + secp = secpp[i]; + assert(secp->m_start >= RAMBASE); + assert(secp->m_start+secp->m_len <= RAMBASE+RAMWORDS); + assert((secp->m_len & 3)==0); + + data = &secp->m_data[0]; + tb->m_mem.load((secp->m_start-RAMBASE)>>2, data, secp->m_len); + } + } else { + fprintf(stderr, "No access to %s, or unknown arg\n", argv[argn]); + exit(-2); + } + } + } + + + if (autorun) { + bool done = false; + + printf("Running in non-interactive mode\n"); + tb->reset(); + for(int i=0; i<2; i++) + tb->tick(); + tb->m_core->v__DOT__cmd_halt = 0; + tb->wb_write(CMD_REG, CMD_HALT|CMD_RESET|15); + tb->wb_write(CMD_DATA, entry); + tb->wb_write(CMD_REG, 15); + while(!done) { + tb->tick(); + + // tb->m_core->v__DOT__thecpu__DOT__step = 0; + // tb->m_core->v__DOT__cmd_halt = 0; + // tb->m_core->v__DOT__cmd_step = 0; + + /* + printf("PC = %08x:%08x (%08x)\n", + tb->m_core->v__DOT__thecpu__DOT__ipc, + tb->m_core->v__DOT__thecpu__DOT__r_upc, + tb->m_core->v__DOT__thecpu__DOT__alu_pc); + */ + + done = (tb->test_success())||(tb->test_failure()); + done = done || signalled; + } + } else if (autostep) { + bool done = false; + + printf("Running in non-interactive mode, via step commands\n"); + tb->wb_write(CMD_REG, CMD_HALT|CMD_RESET|15); + tb->wb_write(CMD_DATA, entry); + tb->wb_write(CMD_REG, 15); + while(!done) { + tb->wb_write(CMD_REG, CMD_STEP); + done = (tb->test_success())||(tb->test_failure()); + done = done || signalled; + } + } else { // Interactive + initscr(); + raw(); + noecho(); + keypad(stdscr, true); + + // tb->reset(); + // for(int i=0; i<2; i++) + // tb->tick(); + tb->m_core->v__DOT__cmd_reset = 1; + tb->m_core->v__DOT__cmd_halt = 1; + tb->tick(); + + tb->m_core->v__DOT__cmd_reset = 0; + tb->m_core->v__DOT__cmd_halt = 0; + tb->tick(); + tb->jump_to(entry); + tb->tick(); + tb->jump_to(entry); + tb->tick(); + tb->jump_to(entry); + + + // For debugging purposes: do we wish to skip some number of + // instructions to fast forward to a time of interest?? + for(int i=0; i<0; i++) { + tb->m_core->v__DOT__cmd_halt = 0; + tb->tick(); + } + + int chv = 'q'; + + bool done = false, halted = true, manual = true, + high_speed = false; + + halfdelay(1); + // tb->wb_write(CMD_REG, CMD_HALT | CMD_RESET); + // while((tb->wb_read(CMD_REG) & (CMD_HALT|CMD_STALL))==(CMD_HALT|CMD_STALL)) + // tb->show_state(); + + while(!done) { + if ((high_speed)&&(!manual)&&(!halted)) { + // chv = getch(); + + struct pollfd fds[1]; + fds[0].fd = STDIN_FILENO; + fds[0].events = POLLIN; + + if (poll(fds, 1, 0) > 0) + chv = getch(); + else + chv = ERR; + + } else { + chv = getch(); + } + switch(chv) { + case 'h': case 'H': + tb->wb_write(CMD_REG, CMD_HALT); + if (!halted) + erase(); + halted = true; + break; + case 'G': + high_speed = true; + // cbreak(); + case 'g': + tb->wb_write(CMD_REG, 0); + if (halted) + erase(); + halted = false; + manual = false; + break; + case 'm': + tb->show_user_timers(false); + break; + case 'q': case 'Q': + done = true; + break; + case 'r': case 'R': + if (manual) + tb->reset(); + else + tb->wb_write(CMD_REG, CMD_RESET|CMD_HALT); + halted = true; + erase(); + break; + case 's': + if (!halted) + erase(); + tb->step(); + manual = false; + halted = true; + // if (high_speed) + // halfdelay(1); + high_speed = false; + break; + case 'S': + if ((!manual)||(halted)) + erase(); + manual = true; + halted = true; + // if (high_speed) + // halfdelay(1); + high_speed = false; + tb->m_core->v__DOT__cmd_halt = 0; + tb->m_core->v__DOT__cmd_step = 1; + tb->eval(); + tb->tick(); + break; + case 'T': // + if ((!manual)||(halted)) + erase(); + manual = true; + halted = true; + // if (high_speed) + // halfdelay(1); + high_speed = false; + tb->m_core->v__DOT__cmd_halt = 1; + tb->m_core->v__DOT__cmd_step = 0; + tb->eval(); + tb->tick(); + break; + case 't': + if ((!manual)||(halted)) + erase(); + manual = true; + halted = false; + // if (high_speed) + // halfdelay(1); + high_speed = false; + // tb->m_core->v__DOT__thecpu__DOT__step = 0; + tb->m_core->v__DOT__cmd_halt = 0; + // tb->m_core->v__DOT__cmd_step = 0; + tb->tick(); + break; + case 'u': + tb->show_user_timers(true); + break; + case KEY_IC: case KEY_ENTER: case KEY_RETURN: + get_value(tb); + break; + case KEY_UP: tb->cursor_up(); break; + case KEY_DOWN: tb->cursor_down(); break; + case KEY_LEFT: tb->cursor_left(); break; + case KEY_RIGHT: tb->cursor_right(); break; + case CTRL('L'): redrawwin(stdscr); break; + case ERR: case KEY_CLEAR: + default: + if (!manual) + tb->tick(); + } + + if (manual) { + tb->show_state(); + } else if (halted) { + if (tb->m_dbgfp) + fprintf(tb->m_dbgfp, "\n\nREAD-STATE ******\n"); + tb->read_state(); + } else + tb->show_state(); + + if (tb->m_core->i_rst) + done =true; + if ((tb->m_bomb)||(signalled)) + done = true; + + if (exit_on_done) { + if (tb->test_success()) + done = true; + if (tb->test_failure()) + done = true; + } + } + endwin(); + } +#ifdef MANUAL_STEPPING_MODE + else { // Manual stepping mode + tb->jump_to(entry); + tb->show_state(); + + while('q' != tolower(chv = getch())) { + tb->tick(); + tb->show_state(); + + if (tb->test_success()) + break; + else if (tb->test_failure()) + break; + else if (signalled) + break; + } + } +#endif + + printf("\n"); + if (tb->test_failure()) { + tb->dump_state(); + } + + printf("Clocks used : %08x\n", tb->m_core->v__DOT__mtc_data); + printf("Instructions Issued : %08x\n", tb->m_core->v__DOT__mic_data); + printf("Tick Count : %08lx\n", tb->m_tickcount); + if (tb->m_core->v__DOT__mtc_data != 0) + printf("Instructions / Clock: %.2f\n", + (double)tb->m_core->v__DOT__mic_data + / (double)tb->m_core->v__DOT__mtc_data); + + int rcode = 0; + if (tb->m_bomb) { + printf("TEST BOMBED\n"); + rcode = -1; + } else if (tb->test_success()) { + printf("SUCCESS!\n"); + } else if (tb->test_failure()) { + rcode = -2; + printf("TEST FAILED!\n"); + } else + printf("User quit\n"); + delete tb; + exit(rcode); +} + Index: zipcpu/trunk/sim/zip-sim.exp =================================================================== --- zipcpu/trunk/sim/zip-sim.exp (nonexistent) +++ zipcpu/trunk/sim/zip-sim.exp (revision 204) @@ -0,0 +1,58 @@ +# +set_board_info target_install "{zip}" + +# Load the generic configuration for the board. This will define a basic +# set of routines needed by the tool to communicate with the board. +load_generic_config "sim" + + +# basic-sim.exp is a basic description for the standard Cygnus simulator +load_base_board_description "basic-sim" + +# zip is the name of the sim subdir +setup_sim zip + +# No multilib options needed by default +process_multilib_options "" + +# The compiler used to build for this board. This has *nothing* to do with what +# compiler is tested if we're testing gcc. +set_board_info compiler "[find_gcc]" + +# We only support newlib on this targte. +# However, we include libgloss so we can find the linker scripts +set_board_info cflags "[newlib_include_flags] [libgloss_include_flags]" +set_board_info ldflags "[newlib_link_flags] -lzipbasic" + +# For now, the simulator won't return an exit status and we'll need to indicate +# this, the standard GCC wrapper will work with this target. +set_board_info needs_status_wrapper 1 + +# The linker script for this board +set_board_info ldscript "-Tzipsim.ld" + +# Can't pass arguments to this target +set_board_info noargs 1 + +# No signals +set_board_info gdb,nosignals 1 +# Cant return results +set_board_info gdb,noresults 1 +# Doesnt do inferiori +set_board_info gdb,noinferiorio 1 + +# And it can't call functions +set_board_info gdb,cannot_call_functions 1 + + +# +# +# Okay, so some of my own fields here +# +# First, the command to run the ZipCPU simulator +set_board_info sim zip-sim +set_board_info objcopy zip-objcopy +set_board_info is_simulator 1 +set_board_info gdb,reload_on_run 1 + +

powered by: WebSVN 2.1.0

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