URL
https://opencores.org/ocsvn/zipcpu/zipcpu/trunk
Subversion Repositories zipcpu
Compare Revisions
- This comparison shows the changes necessary to convert path
/zipcpu
- from Rev 203 to Rev 204
- ↔ Reverse comparison
Rev 203 → Rev 204
/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; |
} |
|
/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 = .; |
} |
/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 |
/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; |
} |
|
|
/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 |
|
/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 **§ions) |
{ |
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); |
} |
|
/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 **§ions); |
|
#endif |
/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); |
} |
} |
} |
|
/trunk/sim/verilator/.gitignore
0,0 → 1,8
div_tb |
mpy_tb |
*debug.txt |
*dump.txt |
pdump |
zippy_tb |
pfcache_tb |
zipmmu_tb |
/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 |
/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; |
} |
|
|
/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 |
/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); |
} |
|
/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); |
} |
} |
} |
} |
|
|
/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 |
/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); |
} |
|
/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; |
} |
|
/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); |
} |
|
/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 |
/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; |
} |
|
|
/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 |
|
/trunk/sim/verilator/zipelf.cpp
0,0 → 1,46
link ../cpp/zipelf.cpp |
trunk/sim/verilator/zipelf.cpp
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/sim/verilator/zipelf.h
===================================================================
--- trunk/sim/verilator/zipelf.h (nonexistent)
+++ trunk/sim/verilator/zipelf.h (revision 204)
@@ -0,0 +1 @@
+link ../cpp/zipelf.h
\ No newline at end of file
trunk/sim/verilator/zipelf.h
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/sim/verilator/zipmmu_tb.cpp
===================================================================
--- trunk/sim/verilator/zipmmu_tb.cpp (nonexistent)
+++ 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: trunk/sim/verilator/zippy_tb.cpp
===================================================================
--- trunk/sim/verilator/zippy_tb.cpp (nonexistent)
+++ 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: trunk/sim/zip-sim.exp
===================================================================
--- trunk/sim/zip-sim.exp (nonexistent)
+++ 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
+
+