Merge remote-tracking branch 'origin/main' into use-fat-jar

This commit is contained in:
abejgonzalez
2023-05-17 18:12:21 -07:00
176 changed files with 4080 additions and 2798 deletions

View File

@@ -1,3 +1,4 @@
#include <cstdint>
#include <vector>
#include <string>
#include <riscv/sim.h>
@@ -5,6 +6,25 @@
#include <svdpi.h>
#include <sstream>
#include <set>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#if __has_include ("cospike_dtm.h")
#define COSPIKE_DTM
#include "testchip_dtm.h"
extern testchip_dtm_t* dtm;
bool spike_loadarch_done = false;
#endif
#if __has_include ("mm.h")
#define COSPIKE_SIMDRAM
#include "mm.h"
extern std::map<long long int, backing_data_t> backing_mem_data;
#endif
#define CLINT_BASE (0x2000000)
#define CLINT_SIZE (0x1000)
@@ -20,6 +40,7 @@ typedef struct system_info_t {
system_info_t* info = NULL;
sim_t* sim = NULL;
bool cospike_debug;
reg_t tohost_addr = 0;
reg_t fromhost_addr = 0;
std::set<reg_t> magic_addrs;
@@ -42,7 +63,8 @@ extern "C" void cospike_set_sysinfo(char* isa, int pmpregions,
) {
if (!info) {
info = new system_info_t;
info->isa = std::string(isa);
// technically the targets aren't zicntr compliant, but they implement the zicntr registers
info->isa = std::string(isa) + "_zicntr";
info->pmpregions = pmpregions;
info->mem0_base = mem0_base;
info->mem0_size = mem0_size;
@@ -64,10 +86,11 @@ extern "C" void cospike_cosim(long long int cycle,
int raise_exception,
int raise_interrupt,
unsigned long long int cause,
unsigned long long int wdata)
unsigned long long int wdata,
int priv)
{
assert(info);
if (!sim) {
if (unlikely(!sim)) {
printf("Configuring spike cosim\n");
std::vector<mem_cfg_t> mem_cfg;
std::vector<size_t> hartids;
@@ -110,7 +133,7 @@ extern "C" void cospike_cosim(long long int cycle,
abort();
std::vector<std::string> htif_args;
bool in_permissive = false;
bool cospike_debug = false;
cospike_debug = false;
for (int i = 1; i < vinfo.argc; i++) {
std::string arg(vinfo.argv[i]);
if (arg == "+permissive") {
@@ -136,7 +159,7 @@ extern "C" void cospike_cosim(long long int cycle,
.support_impebreak = true
};
printf("%s\n", info->isa.c_str());
printf("isa string is %s\n", info->isa.c_str());
for (int i = 0; i < htif_args.size(); i++) {
printf("%s\n", htif_args[i].c_str());
}
@@ -146,13 +169,29 @@ extern "C" void cospike_cosim(long long int cycle,
plugin_devices,
htif_args,
dm_config,
nullptr,
"cospike.log",
false,
nullptr,
false,
nullptr
);
#ifdef COSPIKE_SIMDRAM
// match sim_t's backing memory with the SimDRAM memory
bus_t temp_mem_bus;
for (auto& pair : mems) temp_mem_bus.add_device(pair.first, pair.second);
for (auto& pair : backing_mem_data) {
size_t base = pair.first;
size_t size = pair.second.size;
printf("Matching spike memory initial state for region %lx-%lx\n", base, base + size);
if (!temp_mem_bus.store(base, size, pair.second.data)) {
printf("Error, unable to match memory at address %lx\n", base);
abort();
}
}
#endif
sim->configure_log(true, true);
// Use our own reset vector
for (int i = 0; i < info->nharts; i++) {
@@ -166,93 +205,207 @@ extern "C" void cospike_cosim(long long int cycle,
fromhost_addr = ((htif_t*)sim)->get_fromhost_addr();
printf("Tohost : %lx\n", tohost_addr);
printf("Fromhost: %lx\n", fromhost_addr);
printf("Memory base : %lx\n", info->mem0_base);
printf("Memory Size : %lx\n", info->mem0_size);
}
if (priv & 0x4) { // debug
return;
}
processor_t* p = sim->get_core(hartid);
state_t* s = p->get_state();
#ifdef COSPIKE_DTM
if (dtm && dtm->loadarch_done && !spike_loadarch_done) {
printf("Restoring spike state from testchip_dtm loadarch\n");
// copy the loadarch state into the cosim
loadarch_state_t &ls = dtm->loadarch_state[hartid];
s->pc = ls.pc;
s->prv = ls.prv;
s->csrmap[CSR_MSTATUS]->write(s->csrmap[CSR_MSTATUS]->read() | MSTATUS_VS | MSTATUS_XS | MSTATUS_FS);
#define RESTORE(CSRID, csr) s->csrmap[CSRID]->write(ls.csr);
RESTORE(CSR_FCSR , fcsr);
RESTORE(CSR_VSTART , vstart);
RESTORE(CSR_VXSAT , vxsat);
RESTORE(CSR_VXRM , vxrm);
RESTORE(CSR_VCSR , vcsr);
RESTORE(CSR_VTYPE , vtype);
RESTORE(CSR_STVEC , stvec);
RESTORE(CSR_SSCRATCH , sscratch);
RESTORE(CSR_SEPC , sepc);
RESTORE(CSR_SCAUSE , scause);
RESTORE(CSR_STVAL , stval);
RESTORE(CSR_SATP , satp);
RESTORE(CSR_MSTATUS , mstatus);
RESTORE(CSR_MEDELEG , medeleg);
RESTORE(CSR_MIDELEG , mideleg);
RESTORE(CSR_MIE , mie);
RESTORE(CSR_MTVEC , mtvec);
RESTORE(CSR_MSCRATCH , mscratch);
RESTORE(CSR_MEPC , mepc);
RESTORE(CSR_MCAUSE , mcause);
RESTORE(CSR_MTVAL , mtval);
RESTORE(CSR_MIP , mip);
RESTORE(CSR_MCYCLE , mcycle);
RESTORE(CSR_MINSTRET , minstret);
if (ls.VLEN != p->VU.VLEN) {
printf("VLEN mismatch loadarch: $d != spike: $d\n", ls.VLEN, p->VU.VLEN);
abort();
}
if (ls.ELEN != p->VU.ELEN) {
printf("ELEN mismatch loadarch: $d != spike: $d\n", ls.ELEN, p->VU.ELEN);
abort();
}
for (size_t i = 0; i < 32; i++) {
s->XPR.write(i, ls.XPR[i]);
s->FPR.write(i, { (uint64_t)ls.FPR[i], (uint64_t)-1 });
memcpy(p->VU.reg_file + i * ls.VLEN / 8, ls.VPR[i], ls.VLEN / 8);
}
spike_loadarch_done = true;
p->clear_waiting_for_interrupt();
}
#endif
uint64_t s_pc = s->pc;
uint64_t interrupt_cause = cause & 0x7FFFFFFFFFFFFFFF;
bool ssip_interrupt = interrupt_cause == 0x1;
bool msip_interrupt = interrupt_cause == 0x3;
bool debug_interrupt = interrupt_cause == 0xe;
if (raise_interrupt) {
printf("%d interrupt %lx\n", cycle, cause);
uint64_t interrupt_cause = cause & 0x7FFFFFFFFFFFFFFF;
if (interrupt_cause == 3) {
if (ssip_interrupt) {
// do nothing
} else if (msip_interrupt) {
s->mip->backdoor_write_with_mask(MIP_MSIP, MIP_MSIP);
} else if (debug_interrupt) {
return;
} else {
printf("Unknown interrupt %lx\n", interrupt_cause);
abort();
}
}
if (raise_exception)
printf("%d exception %lx\n", cycle, cause);
if (valid) {
printf("%d Cosim: %lx", cycle, iaddr);
if (has_wdata) {
printf(" %lx", wdata);
}
// if (has_wdata) {
// printf(" s: %lx", wdata);
// }
printf("\n");
}
if (valid || raise_interrupt || raise_exception)
if (valid || raise_interrupt || raise_exception) {
p->step(1);
if (unlikely(cospike_debug)) {
printf("spike pc is %lx\n", s->pc);
printf("spike mstatus is %lx\n", s->mstatus->read());
printf("spike mip is %lx\n", s->mip->read());
printf("spike mie is %lx\n", s->mie->read());
}
}
if (valid) {
if (valid && !raise_exception) {
if (s_pc != iaddr) {
printf("%d PC mismatch %lx != %lx\n", cycle, s_pc, iaddr);
printf("%d PC mismatch spike %llx != DUT %llx\n", cycle, s_pc, iaddr);
if (unlikely(cospike_debug)) {
printf("spike mstatus is %lx\n", s->mstatus->read());
printf("spike mcause is %lx\n", s->mcause->read());
printf("spike mtval is %lx\n" , s->mtval->read());
printf("spike mtinst is %lx\n", s->mtinst->read());
}
exit(1);
}
// Try to remember magic_mem addrs, and ignore these in the future
auto& mem_write = s->log_mem_write;
if (!mem_write.empty() && tohost_addr && std::get<0>(mem_write[0]) == tohost_addr) {
reg_t wdata = std::get<1>(mem_write[0]);
if (wdata >= info->mem0_base && wdata < (info->mem0_base + info->mem0_size)) {
printf("Probable magic mem %x\n", wdata);
magic_addrs.insert(wdata);
auto& log = s->log_reg_write;
auto& mem_read = s->log_mem_read;
for (auto memwrite : mem_write) {
reg_t waddr = std::get<0>(memwrite);
uint64_t w_data = std::get<1>(memwrite);
if ((waddr == CLINT_BASE + 4*hartid) && w_data == 0) {
s->mip->backdoor_write_with_mask(MIP_MSIP, 0);
}
// Try to remember magic_mem addrs, and ignore these in the future
if ( waddr == tohost_addr && w_data >= info->mem0_base && w_data < (info->mem0_base + info->mem0_size)) {
printf("Probable magic mem %lx\n", w_data);
magic_addrs.insert(w_data);
}
// Try to remember magic_mem addrs, and ignore these in the future
if ( waddr == tohost_addr && w_data >= info->mem0_base && w_data < (info->mem0_base + info->mem0_size)) {
printf("Probable magic mem %lx\n", w_data);
magic_addrs.insert(w_data);
}
}
if (has_wdata) {
auto& log = s->log_reg_write;
auto& mem_read = s->log_mem_read;
bool scalar_wb = false;
bool vector_wb = false;
uint32_t vector_cnt = 0;
for (auto &regwrite : log) {
//TODO: scaling to multi issue reads?
reg_t mem_read_addr = mem_read.empty() ? 0 : std::get<0>(mem_read[0]);
for (auto regwrite : log) {
int rd = regwrite.first >> 4;
int type = regwrite.first & 0xf;
// 0 => int
// 1 => fp
// 2 => vec
// 3 => vec hint
// 4 => csr
if ((rd != 0 && type == 0) || type == 1) {
// Override reads from some CSRs
uint64_t csr_addr = (insn >> 20) & 0xfff;
bool csr_read = (insn & 0x7f) == 0x73;
if (csr_read) printf("CSR read %lx\n", csr_addr);
if (csr_read && (
(csr_addr == 0x301) || // misa
(csr_addr == 0xf13) || // mimpid
(csr_addr == 0xf12) || // marchid
(csr_addr == 0xf11) || // mvendorid
(csr_addr == 0xb00) || // mcycle
(csr_addr == 0xb02) || // minstret
(csr_addr >= 0x3b0 && csr_addr <= 0x3ef) // pmpaddr
)) {
printf("CSR override\n");
s->XPR.write(rd, wdata);
} else if (!mem_read.empty() && ((magic_addrs.count(mem_read_addr) ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr) ||
(CLINT_BASE <= mem_read_addr && mem_read_addr < (CLINT_BASE + CLINT_SIZE))
))) {
// Don't check reads from tohost, reads from magic memory, or reads from clint
// Technically this could be buggy because log_mem_read only reports vaddrs, but
// no software ever should access tohost/fromhost/clint with vaddrs anyways
printf("Read override %lx\n", mem_read_addr);
s->XPR.write(rd, wdata);
} else if (wdata != regwrite.second.v[0]) {
printf("%d wdata mismatch reg %d %lx != %lx\n", cycle, rd, regwrite.second.v[0], wdata);
exit(1);
}
}
int rd = regwrite.first >> 4;
int type = regwrite.first & 0xf;
// 0 => int
// 1 => fp
// 2 => vec
// 3 => vec hint
// 4 => csr
bool ignore_read = (!mem_read.empty() &&
((magic_addrs.count(mem_read_addr) ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr) ||
(CLINT_BASE <= mem_read_addr && mem_read_addr < (CLINT_BASE + CLINT_SIZE)))));
// check the type is compliant with writeback first
if ((type == 0 || type == 1))
scalar_wb = true;
if (type == 2) {
vector_wb = true;
}
if (type == 3) continue;
if ((rd != 0 && type == 0) || type == 1) {
// Override reads from some CSRs
uint64_t csr_addr = (insn >> 20) & 0xfff;
bool csr_read = (insn & 0x7f) == 0x73;
if (csr_read)
printf("CSR read %lx\n", csr_addr);
if (csr_read && ((csr_addr == 0xf13) || // mimpid
(csr_addr == 0xf12) || // marchid
(csr_addr == 0xf11) || // mvendorid
(csr_addr == 0xb00) || // mcycle
(csr_addr == 0xb02) || // minstret
(csr_addr >= 0x7a0 && csr_addr <= 0x7aa) || // debug trigger registers
(csr_addr >= 0x3b0 && csr_addr <= 0x3ef) // pmpaddr
)) {
printf("CSR override\n");
s->XPR.write(rd, wdata);
} else if (ignore_read) {
// Don't check reads from tohost, reads from magic memory, or reads
// from clint Technically this could be buggy because log_mem_read
// only reports vaddrs, but no software ever should access
// tohost/fromhost/clint with vaddrs anyways
printf("Read override %lx\n", mem_read_addr);
s->XPR.write(rd, wdata);
} else if (wdata != regwrite.second.v[0]) {
printf("%d wdata mismatch reg %d %lx != %lx\n", cycle, rd,
regwrite.second.v[0], wdata);
exit(1);
}
}
// TODO FIX: Rocketchip TracedInstruction.wdata should be Valid(UInt)
// if (scalar_wb ^ has_wdata) {
// printf("Scalar wdata behavior divergence between spike and DUT\n");
// exit(-1);
// }
}
}
}
// }

View File

@@ -1,394 +0,0 @@
// See LICENSE.SiFive for license details.
// See LICENSE.Berkeley for license details.
#if VM_TRACE
#include <memory>
#if CY_FST_TRACE
#include "verilated_fst_c.h"
#else
#include "verilated.h"
#include "verilated_vcd_c.h"
#endif // CY_FST_TRACE
#endif // VM_TRACE
#include <fesvr/dtm.h>
#include <fesvr/tsi.h>
#include "remote_bitbang.h"
#include <iostream>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
// For option parsing, which is split across this file, Verilog, and
// FESVR's HTIF, a few external files must be pulled in. The list of
// files and what they provide is enumerated:
//
// $RISCV/include/fesvr/htif.h:
// defines:
// - HTIF_USAGE_OPTIONS
// - HTIF_LONG_OPTIONS_OPTIND
// - HTIF_LONG_OPTIONS
// $(ROCKETCHIP_DIR)/generated-src(-debug)?/$(CONFIG).plusArgs:
// defines:
// - PLUSARG_USAGE_OPTIONS
// variables:
// - static const char * verilog_plusargs
extern tsi_t* tsi;
extern dtm_t* dtm;
extern remote_bitbang_t * jtag;
static uint64_t trace_count = 0;
bool verbose = false;
bool done_reset = false;
void handle_sigterm(int sig)
{
dtm->stop();
}
double sc_time_stamp()
{
return trace_count;
}
static void usage(const char * program_name)
{
printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n",
program_name);
fputs("\
Run a BINARY on the Rocket Chip emulator.\n\
\n\
Mandatory arguments to long options are mandatory for short options too.\n\
\n\
EMULATOR OPTIONS\n\
-c, --cycle-count Print the cycle count before exiting\n\
+cycle-count\n\
-h, --help Display this help and exit\n\
-m, --max-cycles=CYCLES Kill the emulation after CYCLES\n\
+max-cycles=CYCLES\n\
-s, --seed=SEED Use random number seed SEED\n\
-r, --rbb-port=PORT Use PORT for remote bit bang (with OpenOCD and GDB) \n\
If not specified, a random port will be chosen\n\
automatically.\n\
-V, --verbose Enable all Chisel printfs (cycle-by-cycle info)\n\
+verbose\n\
", stdout);
#if VM_TRACE == 0
fputs("\
\n\
EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n",
stdout);
#endif
fputs("\
-v, --vcd=FILE, Write vcd trace to FILE (or '-' for stdout)\n\
-x, --dump-start=CYCLE Start VCD tracing at CYCLE\n\
+dump-start\n\
", stdout);
fputs("\n" PLUSARG_USAGE_OPTIONS, stdout);
fputs("\n" HTIF_USAGE_OPTIONS, stdout);
printf("\n"
"EXAMPLES\n"
" - run a bare metal test:\n"
" %s $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
" - run a bare metal test showing cycle-by-cycle information:\n"
" %s +verbose $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add 2>&1 | spike-dasm\n"
#if VM_TRACE
" - run a bare metal test to generate a VCD waveform:\n"
" %s -v rv64ui-p-add.vcd $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
#endif
" - run an ELF (you wrote, called 'hello') using the proxy kernel:\n"
" %s pk hello\n",
program_name, program_name, program_name
#if VM_TRACE
, program_name
#endif
);
}
int main(int argc, char** argv)
{
unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid();
uint64_t max_cycles = -1;
int ret = 0;
bool print_cycles = false;
// Port numbers are 16 bit unsigned integers.
uint16_t rbb_port = 0;
#if VM_TRACE
const char* vcdfile_name = NULL;
FILE * vcdfile = NULL;
uint64_t start = 0;
#endif
int verilog_plusargs_legal = 1;
int verilated_argc = 1;
char** verilated_argv = new char*[argc];
verilated_argv[0] = argv[0];
opterr = 1;
while (1) {
static struct option long_options[] = {
{"cycle-count", no_argument, 0, 'c' },
{"help", no_argument, 0, 'h' },
{"max-cycles", required_argument, 0, 'm' },
{"seed", required_argument, 0, 's' },
{"rbb-port", required_argument, 0, 'r' },
{"verbose", no_argument, 0, 'V' },
{"permissive", no_argument, 0, 'p' },
{"permissive-off", no_argument, 0, 'o' },
#if VM_TRACE
{"vcd", required_argument, 0, 'v' },
{"dump-start", required_argument, 0, 'x' },
#endif
HTIF_LONG_OPTIONS
};
int option_index = 0;
#if VM_TRACE
int c = getopt_long(argc, argv, "-chm:s:r:v:Vx:po", long_options, &option_index);
#else
int c = getopt_long(argc, argv, "-chm:s:r:Vpo", long_options, &option_index);
#endif
if (c == -1) break;
retry:
switch (c) {
// Process long and short EMULATOR options
case '?': usage(argv[0]); return 1;
case 'c': print_cycles = true; break;
case 'h': usage(argv[0]); return 0;
case 'm': max_cycles = atoll(optarg); break;
case 's': random_seed = atoi(optarg); break;
case 'r': rbb_port = atoi(optarg); break;
case 'V': verbose = true; break;
case 'p': opterr = 0; break;
case 'o': opterr = 1; break;
#if VM_TRACE
case 'v': {
vcdfile_name = optarg;
vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w");
if (!vcdfile) {
std::cerr << "Unable to open " << optarg << " for VCD write\n";
return 1;
}
break;
}
case 'x': start = atoll(optarg); break;
#endif
// Process legacy '+' EMULATOR arguments by replacing them with
// their getopt equivalents
case 1: {
std::string arg = optarg;
if (arg.substr(0, 1) != "+") {
optind--;
goto done_processing;
}
if (arg == "+verbose")
c = 'V';
else if (arg.substr(0, 12) == "+max-cycles=") {
c = 'm';
optarg = optarg+12;
}
#if VM_TRACE
else if (arg.substr(0, 12) == "+dump-start=") {
c = 'x';
optarg = optarg+12;
}
#endif
else if (arg.substr(0, 12) == "+cycle-count")
c = 'c';
else if (arg == "+permissive")
{
c = 'p';
verilated_argv[verilated_argc++] = optarg;
}
else if (arg == "+permissive-off")
{
c = 'o';
verilated_argv[verilated_argc++] = optarg;
}
// If we don't find a legacy '+' EMULATOR argument, it still could be
// a VERILOG_PLUSARG and not an error.
else if (verilog_plusargs_legal) {
const char ** plusarg = &verilog_plusargs[0];
int legal_verilog_plusarg = 0;
while (*plusarg && (legal_verilog_plusarg == 0)){
if (arg.substr(1, strlen(*plusarg)) == *plusarg) {
legal_verilog_plusarg = 1;
}
plusarg ++;
}
if (!legal_verilog_plusarg) {
verilog_plusargs_legal = 0;
} else {
c = 'P';
}
goto retry;
}
// If we STILL don't find a legacy '+' argument, it still could be
// an HTIF (HOST) argument and not an error. If this is the case, then
// we're done processing EMULATOR and VERILOG arguments.
else {
static struct option htif_long_options [] = { HTIF_LONG_OPTIONS };
struct option * htif_option = &htif_long_options[0];
while (htif_option->name) {
if (arg.substr(1, strlen(htif_option->name)) == htif_option->name) {
optind--;
goto done_processing;
}
htif_option++;
}
if(opterr) {
std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \""
<< arg << "\"\n";
c = '?';
} else {
c = 'P';
}
}
goto retry;
}
case 'P': // Verilog PlusArg, add to the argument list for verilator environment
verilated_argv[verilated_argc++] = optarg;
break;
// Realize that we've hit HTIF (HOST) arguments or error out
default:
if (c >= HTIF_LONG_OPTIONS_OPTIND) {
optind--;
goto done_processing;
}
c = '?';
goto retry;
}
}
done_processing:
if (optind == argc) {
std::cerr << "No binary specified for emulator\n";
usage(argv[0]);
return 1;
}
// Copy remaining HTIF arguments (if any) and the binary file name into the verilator argument stack
while (optind < argc) verilated_argv[verilated_argc++] = argv[optind++];
if (verbose)
fprintf(stderr, "using random seed %u\n", random_seed);
srand(random_seed);
srand48(random_seed);
Verilated::randReset(2);
Verilated::commandArgs(verilated_argc, verilated_argv);
TEST_HARNESS *tile = new TEST_HARNESS;
#if VM_TRACE
Verilated::traceEverOn(true); // Verilator must compute traced signals
#if CY_FST_TRACE
std::unique_ptr<VerilatedFstC> tfp(new VerilatedFstC);
#else
std::unique_ptr<VerilatedVcdFILE> vcdfd(new VerilatedVcdFILE(vcdfile));
std::unique_ptr<VerilatedVcdC> tfp(new VerilatedVcdC(vcdfd.get()));
#endif // CY_FST_TRACE
if (vcdfile_name) {
tile->trace(tfp.get(), 99); // Trace 99 levels of hierarchy
tfp->open(vcdfile_name);
}
#endif // VM_TRACE
// RocketChip currently only supports RBB port 0, so this needs to stay here
jtag = new remote_bitbang_t(rbb_port);
signal(SIGTERM, handle_sigterm);
bool dump;
// start reset off low so a rising edge triggers async reset
tile->reset = 0;
tile->clock = 0;
tile->eval();
// reset for several cycles to handle pipelined reset
for (int i = 0; i < 100; i++) {
tile->reset = 1;
tile->clock = 0;
tile->eval();
#if VM_TRACE
dump = tfp && trace_count >= start;
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2));
#endif
tile->clock = 1;
tile->eval();
#if VM_TRACE
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
#endif
trace_count ++;
}
tile->reset = 0;
done_reset = true;
do {
tile->clock = 0;
tile->eval();
#if VM_TRACE
dump = tfp && trace_count >= start;
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2));
#endif
tile->clock = 1;
tile->eval();
#if VM_TRACE
if (dump)
tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
#endif
trace_count++;
}
// for verilator multithreading. need to do 1 loop before checking if
// tsi exists, since tsi is created by verilated thread on the first
// serial_tick.
while ((!dtm || !dtm->done()) &&
(!jtag || !jtag->done()) &&
(!tsi || !tsi->done()) &&
!tile->io_success && trace_count < max_cycles);
#if VM_TRACE
if (tfp)
tfp->close();
if (vcdfile)
fclose(vcdfile);
#endif
if (dtm && dtm->exit_code())
{
fprintf(stderr, "*** FAILED *** via dtm (code = %d, seed %d) after %ld cycles\n", dtm->exit_code(), random_seed, trace_count);
ret = dtm->exit_code();
}
else if (tsi && tsi->exit_code())
{
fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %ld cycles\n", tsi->exit_code(), random_seed, trace_count);
ret = tsi->exit_code();
}
else if (jtag && jtag->exit_code())
{
fprintf(stderr, "*** FAILED *** via jtag (code = %d, seed %d) after %ld cycles\n", jtag->exit_code(), random_seed, trace_count);
ret = jtag->exit_code();
}
else if (trace_count == max_cycles)
{
fprintf(stderr, "*** FAILED *** via trace_count (timeout, seed %d) after %ld cycles\n", random_seed, trace_count);
ret = 2;
}
else if (verbose || print_cycles)
{
fprintf(stderr, "*** PASSED *** Completed after %ld cycles\n", trace_count);
}
if (dtm) delete dtm;
if (tsi) delete tsi;
if (jtag) delete jtag;
if (tile) delete tile;
if (verilated_argv) delete[] verilated_argv;
return ret;
}

View File

@@ -2,11 +2,23 @@
#include <riscv/processor.h>
#include <riscv/log_file.h>
#include <fesvr/context.h>
#include <fesvr/htif.h>
#include <fesvr/memif.h>
#include <fesvr/elfloader.h>
#include <map>
#include <sstream>
#include <vpi_user.h>
#include <svdpi.h>
#if __has_include("spiketile_tsi.h")
#define SPIKETILE_HTIF_TSI
extern htif_t* tsi;
#endif
#if __has_include("spiketile_dtm.h")
#define SPIKETILE_HTIF_DTM
extern htif_t* dtm;
#endif
enum transfer_t {
NToB,
NToT,
@@ -73,8 +85,18 @@ public:
void dcache_b(uint64_t address, uint64_t source, int param);
bool dcache_c(uint64_t *address, uint64_t* source, int* param, unsigned char* voluntary, unsigned char* has_data, uint64_t* data[8]);
void dcache_d(uint64_t sourceid, uint64_t data[8], unsigned char has_data, unsigned char grantack);
void tcm_a(uint64_t address, uint64_t data, uint32_t mask, uint32_t opcode, uint32_t size);
bool tcm_d(uint64_t *data);
void loadmem(size_t base, const char* fname);
void drain_stq();
bool stq_empty() { return st_q.size() == 0; };
void flush_icache();
const cfg_t &get_cfg() const { return cfg; }
const std::map<size_t, processor_t*>& get_harts() const { return harts; }
~chipyard_simif_t() { };
chipyard_simif_t(size_t icache_ways,
@@ -86,9 +108,18 @@ public:
char* readonly_uncacheable,
char* executable,
size_t icache_sourceids,
size_t dcache_sourceids);
size_t dcache_sourceids,
size_t tcm_base,
size_t tcm_size,
const char* isastr,
size_t pmpregions);
uint64_t cycle;
bool use_stq;
htif_t *htif;
bool fast_clint;
cfg_t cfg;
std::map<size_t, processor_t*> harts;
bool accessed_tofrom_host;
private:
bool handle_cache_access(reg_t addr, size_t len,
uint8_t* load_bytes,
@@ -133,6 +164,11 @@ private:
uint64_t mmio_stdata;
size_t mmio_len;
uint64_t mmio_lddata;
uint64_t tcm_base;
uint64_t tcm_size;
uint8_t* tcm;
std::vector<uint64_t> tcm_q;
};
class tile_t {
@@ -163,6 +199,7 @@ extern "C" void spike_tile(int hartid, char* isa,
int dcache_sets, int dcache_ways,
char* cacheable, char* uncacheable, char* readonly_uncacheable, char* executable,
int icache_sourceids, int dcache_sourceids,
long long int tcm_base, long long int tcm_size,
long long int reset_vector,
long long int ipc,
long long int cycle,
@@ -237,7 +274,18 @@ extern "C" void spike_tile(int hartid, char* isa,
int* mmio_a_size,
unsigned char mmio_d_valid,
long long int mmio_d_data
long long int mmio_d_data,
unsigned char tcm_a_valid,
long long int tcm_a_address,
long long int tcm_a_data,
int tcm_a_mask,
int tcm_a_opcode,
int tcm_a_size,
unsigned char* tcm_d_valid,
unsigned char tcm_d_ready,
long long int* tcm_d_data
)
{
if (!host) {
@@ -248,36 +296,26 @@ extern "C" void spike_tile(int hartid, char* isa,
if (tiles.find(hartid) == tiles.end()) {
printf("Constructing spike processor_t\n");
isa_parser_t *isa_parser = new isa_parser_t(isa, "MSU");
std::string* isastr = new std::string(isa);
chipyard_simif_t* simif = new chipyard_simif_t(icache_ways, icache_sets,
dcache_ways, dcache_sets,
cacheable, uncacheable, readonly_uncacheable, executable,
icache_sourceids, dcache_sourceids);
std::string* isastr = new std::string(isa);
cfg_t* cfg = new cfg_t(std::make_pair(0, 0),
nullptr,
isastr->c_str(),
"MSU",
"vlen:128,elen:64",
false,
endianness_little,
pmpregions,
std::vector<mem_cfg_t>(),
std::vector<size_t>(),
false,
0);
icache_sourceids, dcache_sourceids,
tcm_base, tcm_size,
isastr->c_str(), pmpregions);
processor_t* p = new processor_t(isa_parser,
cfg,
&simif->get_cfg(),
simif,
hartid,
false,
log_file->get(),
sout);
p->enable_log_commits();
simif->harts[hartid] = p;
s_vpi_vlog_info vinfo;
if (!vpi_get_vlog_info(&vinfo))
abort();
std::string loadmem_file = "";
for (int i = 1; i < vinfo.argc; i++) {
std::string arg(vinfo.argv[i]);
if (arg == "+spike-debug") {
@@ -286,7 +324,18 @@ extern "C" void spike_tile(int hartid, char* isa,
if (arg == "+spike-stq") {
simif->use_stq = true;
}
if (arg.find("+loadmem=") == 0) {
loadmem_file = arg.substr(strlen("+loadmem="));
}
if (arg == "+spike-fast-clint") {
simif->fast_clint = true;
}
if (arg == "+spike-verbose") {
p->enable_log_commits();
}
}
if (loadmem_file != "" && tcm_size > 0)
simif->loadmem(tcm_base, loadmem_file.c_str());
p->reset();
p->get_state()->pc = reset_vector;
@@ -296,11 +345,22 @@ extern "C" void spike_tile(int hartid, char* isa,
tile_t* tile = tiles[hartid];
chipyard_simif_t* simif = tile->simif;
processor_t* proc = tile->proc;
#if defined(SPIKETILE_HTIF_TSI)
if (!simif->htif && tsi)
simif->htif = tsi;
#endif
#if defined(SPIKETILE_HTIF_DTM)
if (!simif->htif && dtm)
simif->htif = dtm;
#endif
simif->cycle = cycle;
if (debug) {
proc->halt_request = proc->HR_REGULAR;
}
if (!debug && proc->halt_request != proc->HR_NONE) {
proc->halt_request = proc->HR_NONE;
}
proc->get_state()->mip->backdoor_write_with_mask(MIP_MTIP, mtip ? MIP_MTIP : 0);
proc->get_state()->mip->backdoor_write_with_mask(MIP_MSIP, msip ? MIP_MSIP : 0);
@@ -309,6 +369,7 @@ extern "C" void spike_tile(int hartid, char* isa,
tile->max_insns = ipc;
uint64_t pre_insns = proc->get_state()->minstret->read();
simif->accessed_tofrom_host = false;
tile->spike_context.switch_to();
*insns_retired = proc->get_state()->minstret->read() - pre_insns;
if (simif->use_stq) {
@@ -357,6 +418,13 @@ extern "C" void spike_tile(int hartid, char* isa,
if (mmio_d_valid) {
simif->mmio_d(mmio_d_data);
}
if (tcm_a_valid) {
simif->tcm_a(tcm_a_address, tcm_a_data, tcm_a_mask, tcm_a_opcode, tcm_a_size);
}
if (tcm_d_ready) {
*tcm_d_valid = simif->tcm_d((uint64_t*)tcm_d_data);
}
}
@@ -369,14 +437,35 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
char* readonly_uncacheable,
char* executable,
size_t ic_sourceids,
size_t dc_sourceids
size_t dc_sourceids,
size_t tcm_base,
size_t tcm_size,
const char* isastr,
size_t pmpregions
) :
cycle(0),
use_stq(false),
htif(nullptr),
fast_clint(false),
cfg(std::make_pair(0, 0),
nullptr,
isastr,
"MSU",
"vlen:128,elen:64",
false,
endianness_little,
pmpregions,
std::vector<mem_cfg_t>(),
std::vector<size_t>(),
false,
0),
accessed_tofrom_host(false),
icache_ways(icache_ways),
icache_sets(icache_sets),
dcache_ways(dcache_ways),
dcache_sets(dcache_sets),
tcm_base(tcm_base),
tcm_size(tcm_size),
mmio_valid(false),
mmio_inflight(false)
{
@@ -432,6 +521,14 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
uint64_t size_int = std::stoul(size);
executables.push_back(mem_region_t { base_int, size_int });
}
tcm = (uint8_t*)malloc(tcm_size);
}
void chipyard_simif_t::flush_icache() {
for (auto &w : icache) {
for (size_t i = 0; i < icache_sets; i++) w[i].state = NONE;
}
}
bool chipyard_simif_t::reservable(reg_t addr) {
@@ -440,12 +537,20 @@ bool chipyard_simif_t::reservable(reg_t addr) {
return true;
}
}
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
return true;
}
return false;
}
bool chipyard_simif_t::mmio_fetch(reg_t addr, size_t len, uint8_t* bytes) {
bool executable = false;
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(bytes, tcm + addr - tcm_base, len);
return true;
}
for (auto& r: executables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
executable = true;
@@ -466,6 +571,16 @@ bool chipyard_simif_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes) {
bool found = false;
bool cacheable = false;
bool readonly = false;
reg_t tohost_addr = htif ? htif->get_tohost_addr() : 0;
reg_t fromhost_addr = htif ? htif->get_fromhost_addr() : 0;
if (addr == tohost_addr || addr == fromhost_addr) {
accessed_tofrom_host = true;
}
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(bytes, tcm + addr - tcm_base, len);
return true;
}
for (auto& r: cacheables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
cacheable = true;
@@ -497,6 +612,8 @@ bool chipyard_simif_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes) {
while (!handle_cache_access(addr, len, bytes, nullptr, LOAD)) {
host->switch_to();
}
uint64_t lddata = 0;
memcpy(&lddata, bytes, len);
} else {
handle_mmio_access(addr, len, bytes, nullptr, LOAD, readonly);
}
@@ -523,6 +640,7 @@ void chipyard_simif_t::handle_mmio_access(reg_t addr, size_t len,
mmio_st = type == STORE;
if (type == STORE) {
assert(len <= 8);
mmio_stdata = 0;
memcpy(&mmio_stdata, store_bytes, len);
}
mmio_len = len;
@@ -829,9 +947,21 @@ bool chipyard_simif_t::dcache_c(uint64_t* address, uint64_t* source, int* param,
}
bool chipyard_simif_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes) {
reg_t tohost_addr = htif ? htif->get_tohost_addr() : 0;
reg_t fromhost_addr = htif ? htif->get_fromhost_addr() : 0;
if (addr == tohost_addr || addr == fromhost_addr) {
accessed_tofrom_host = true;
}
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(tcm + addr - tcm_base, bytes, len);
return true;
}
bool found = false;
bool cacheable = false;
for (auto& r: cacheables) {
for (auto& r: cacheables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
cacheable = true;
found = true;
@@ -849,6 +979,8 @@ bool chipyard_simif_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes)
return false;
}
if (cacheable) {
uint64_t temp = 0;
memcpy(&temp, bytes, len);
if (use_stq) {
assert(len <= 8);
uint64_t stdata;
@@ -899,27 +1031,104 @@ void chipyard_simif_t::dcache_d(uint64_t sourceid, uint64_t data[8], unsigned ch
}
}
void chipyard_simif_t::tcm_a(uint64_t address, uint64_t data, uint32_t mask, uint32_t opcode, uint32_t size) {
bool load = opcode == 4;
uint64_t rdata = 0;
memcpy(&rdata, tcm + address - tcm_base, 8);
tcm_q.push_back(rdata);
if (!load) {
for (size_t i = 0; i < 8; i++) {
if ((mask >> i) & 1) {
memcpy(tcm + address - tcm_base + i, ((uint8_t*)&data) + i, 1);
}
}
}
}
bool chipyard_simif_t::tcm_d(uint64_t* data) {
if (tcm_q.size() == 0)
return false;
*data = tcm_q[0];
tcm_q.erase(tcm_q.begin());
return true;
}
void chipyard_simif_t::loadmem(size_t base, const char* fname) {
class loadmem_memif_t : public memif_t {
public:
loadmem_memif_t(chipyard_simif_t* _simif, size_t _start) : memif_t(nullptr), simif(_simif), start(_start) {}
void write(addr_t taddr, size_t len, const void* src) override
{
addr_t addr = taddr - start;
memcpy(simif->tcm + addr, src, len);
}
void read(addr_t taddr, size_t len, void* bytes) override {
assert(false);
}
endianness_t get_target_endianness() const override {
return endianness_little;
}
private:
chipyard_simif_t* simif;
size_t start;
} loadmem_memif(this, tcm_base);
reg_t entry;
load_elf(fname, &loadmem_memif, &entry);
}
bool insn_should_fence(uint64_t bits) {
uint8_t opcode = bits & 0x7f;
return opcode == 0b0101111 || opcode == 0b0001111;
}
bool insn_is_wfi(uint64_t bits) {
return bits == 0x10500073;
}
void spike_thread_main(void* arg)
{
tile_t* tile = (tile_t*) arg;
processor_t* proc = tile->proc;
chipyard_simif_t* simif = tile->simif;
state_t* state = proc->get_state();
while (true) {
while (tile->max_insns == 0) {
host->switch_to();
}
while (tile->max_insns != 0) {
// TODO: Fences don't work
// uint64_t last_bits = tile->proc->get_last_bits();
// if (insn_should_fence(last_bits) && !tile->simif->stq_empty()) {
//uint64_t last_bits = proc->get_last_bits();
// if (insn_should_fence(last_bits) && !simif->stq_empty()) {
// host->switch_to();
// }
tile->proc->step(1);
uint64_t old_minstret = state->minstret->read();
proc->step(1);
tile->max_insns--;
tile->proc->get_state()->mcycle->write(tile->simif->cycle);
if (proc->is_waiting_for_interrupt()) {
if (simif->fast_clint) {
state->mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP);
tile->max_insns = tile->max_insns <= 1 ? 0 : 1;
} else {
tile->max_insns = 0;
}
}
if (state->debug_mode) {
// TODO: Fix. This needs to apply the same hack as rocket-chip...
// JALRs in debug mode should flush the ICache.
// There is no API to determine if a JALR was executed, so hack the
// pc of the JALR in the debug rom here instead.
if (state->pc == 0x838) {
simif->flush_icache();
}
}
// If we get stuck in WFI, or we start polling tohost/fromhost, switch to host thread
if ((old_minstret == state->minstret->read()) || simif->accessed_tofrom_host) {
tile->max_insns = 0;
}
state->mcycle->write(simif->cycle);
}
}
}

View File

@@ -16,7 +16,8 @@ import "DPI-C" function void cospike_cosim(input longint cycle,
input bit raise_exception,
input bit raise_interrupt,
input longint cause,
input longint wdata
input longint wdata,
input int priv
);
@@ -42,6 +43,7 @@ module SpikeCosim #(
input [63:0] trace_0_cause,
input trace_0_has_wdata,
input [63:0] trace_0_wdata,
input [2:0] trace_0_priv,
input trace_1_valid,
input [63:0] trace_1_iaddr,
@@ -50,7 +52,8 @@ module SpikeCosim #(
input trace_1_interrupt,
input [63:0] trace_1_cause,
input trace_1_has_wdata,
input [63:0] trace_1_wdata
input [63:0] trace_1_wdata,
input [2:0] trace_1_priv
);
initial begin
@@ -62,12 +65,12 @@ module SpikeCosim #(
if (trace_0_valid || trace_0_exception || trace_0_cause) begin
cospike_cosim(cycle, hartid, trace_0_has_wdata, trace_0_valid, trace_0_iaddr,
trace_0_insn, trace_0_exception, trace_0_interrupt, trace_0_cause,
trace_0_wdata);
trace_0_wdata, trace_0_priv);
end
if (trace_1_valid || trace_1_exception || trace_1_cause) begin
cospike_cosim(cycle, hartid, trace_1_has_wdata, trace_1_valid, trace_1_iaddr,
trace_1_insn, trace_1_exception, trace_1_interrupt, trace_1_cause,
trace_1_wdata);
trace_1_wdata, trace_1_priv);
end
end
end

View File

@@ -13,6 +13,8 @@ import "DPI-C" function void spike_tile(input int hartid,
input string executable,
input int icache_sourceids,
input int dcache_sourceids,
input longint tcm_base,
input longint tcm_size,
input longint reset_vector,
input longint ipc,
input longint cycle,
@@ -89,7 +91,18 @@ import "DPI-C" function void spike_tile(input int hartid,
output int mmio_a_size,
input bit mmio_d_valid,
input longint mmio_d_data
input longint mmio_d_data,
input bit tcm_a_valid,
input longint tcm_a_address,
input longint tcm_a_data,
input int tcm_a_mask,
input int tcm_a_opcode,
input int tcm_a_size,
output bit tcm_d_valid,
input bit tcm_d_ready,
output longint tcm_d_data
);
@@ -106,7 +119,9 @@ module SpikeBlackBox #(
parameter READONLY_UNCACHEABLE,
parameter EXECUTABLE,
parameter ICACHE_SOURCEIDS,
parameter DCACHE_SOURCEIDS )(
parameter DCACHE_SOURCEIDS,
parameter TCM_BASE,
parameter TCM_SIZE)(
input clock,
input reset,
input [63:0] reset_vector,
@@ -185,7 +200,18 @@ module SpikeBlackBox #(
output [31:0] mmio_a_size,
input mmio_d_valid,
input [63:0] mmio_d_data
input [63:0] mmio_d_data,
input tcm_a_valid,
input [63:0] tcm_a_address,
input [63:0] tcm_a_data,
input [31:0] tcm_a_mask,
input [31:0] tcm_a_opcode,
input [31:0] tcm_a_size,
output tcm_d_valid,
input tcm_d_ready,
output [63:0] tcm_d_data
);
longint __insns_retired;
@@ -257,7 +283,13 @@ module SpikeBlackBox #(
reg [63:0] __dcache_c_data_6_reg;
reg [63:0] __dcache_c_data_7_reg;
wire __tcm_d_ready;
bit __tcm_d_valid;
longint __tcm_d_data;
reg __tcm_d_valid_reg;
reg [63:0] __tcm_d_data_reg;
always @(posedge clock) begin
@@ -322,12 +354,18 @@ module SpikeBlackBox #(
__dcache_c_data_6_reg <= 64'h0;
__dcache_c_data_7 = 64'h0;
__dcache_c_data_7_reg <= 64'h0;
__tcm_d_valid = 1'b0;
__tcm_d_valid_reg <= 1'b0;
__tcm_d_data = 64'h0;
__tcm_d_data_reg <= 64'h0;
spike_tile_reset(HARTID);
end else begin
spike_tile(HARTID, ISA, PMPREGIONS,
ICACHE_SETS, ICACHE_WAYS, DCACHE_SETS, DCACHE_WAYS,
CACHEABLE, UNCACHEABLE, READONLY_UNCACHEABLE, EXECUTABLE,
ICACHE_SOURCEIDS, DCACHE_SOURCEIDS,
TCM_BASE, TCM_SIZE,
reset_vector, ipc, cycle, __insns_retired,
debug, mtip, msip, meip, seip,
@@ -350,7 +388,10 @@ module SpikeBlackBox #(
dcache_d_data_4, dcache_d_data_5, dcache_d_data_6, dcache_d_data_7,
__mmio_a_ready, __mmio_a_valid, __mmio_a_address, __mmio_a_data, __mmio_a_store, __mmio_a_size,
mmio_d_valid, mmio_d_data
mmio_d_valid, mmio_d_data,
tcm_a_valid, tcm_a_address, tcm_a_data, tcm_a_mask, tcm_a_opcode, tcm_a_size,
__tcm_d_valid, __tcm_d_ready, __tcm_d_data
);
__insns_retired_reg <= __insns_retired;
@@ -385,6 +426,10 @@ module SpikeBlackBox #(
__mmio_a_data_reg <= __mmio_a_data;
__mmio_a_store_reg <= __mmio_a_store;
__mmio_a_size_reg <= __mmio_a_size;
__tcm_d_valid_reg <= __tcm_d_valid;
__tcm_d_data_reg <= __tcm_d_data;
end
end // always @ (posedge clock)
assign insns_retired = __insns_retired_reg;
@@ -424,6 +469,8 @@ module SpikeBlackBox #(
assign mmio_a_size = __mmio_a_size_reg;
assign __mmio_a_ready = mmio_a_ready;
assign tcm_d_valid = __tcm_d_valid_reg;
assign tcm_d_data = __tcm_d_data_reg;
assign __tcm_d_ready = tcm_d_ready;
endmodule;

View File

@@ -6,7 +6,7 @@ import scala.collection.mutable.{ArrayBuffer}
import freechips.rocketchip.prci.{ClockGroupIdentityNode, ClockSinkParameters, ClockSinkNode, ClockGroup}
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
import freechips.rocketchip.config.{Parameters, Field}
import org.chipsalliance.cde.config.{Parameters, Field}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, LazyRawModuleImp, LazyModuleImpLike, BindingScope}
import freechips.rocketchip.util.{ResetCatchAndSync}
import chipyard.iobinders._

View File

@@ -0,0 +1,19 @@
package chipyard
import org.reflections.Reflections
import org.reflections.scanners.Scanners.SubTypes
import scala.jdk.CollectionConverters._
import scala.collection.{SortedSet}
import org.chipsalliance.cde.config.{Config}
object ConfigFinder {
def main(args: Array[String]) = {
val reflections = new Reflections()
val classes = reflections.get(SubTypes.of(classOf[Config]).asClass()).asScala
val sortedClasses = SortedSet[String]() ++ classes.map(_.getName)
for (cls <- sortedClasses) {
println(cls)
}
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.experimental.{IntParam, StringParam, IO}
import chisel3.util._
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.devices.tilelink._
@@ -18,7 +18,8 @@ case class SpikeCosimConfig(
mem0_base: BigInt,
mem0_size: BigInt,
nharts: Int,
bootrom: String
bootrom: String,
has_dtm: Boolean
)
class SpikeCosim(cfg: SpikeCosimConfig) extends BlackBox(Map(
@@ -32,6 +33,7 @@ class SpikeCosim(cfg: SpikeCosimConfig) extends BlackBox(Map(
{
addResource("/csrc/cospike.cc")
addResource("/vsrc/cospike.v")
if (cfg.has_dtm) addResource("/csrc/cospike_dtm.h")
val io = IO(new Bundle {
val clock = Input(Clock())
val reset = Input(Bool())
@@ -46,6 +48,7 @@ class SpikeCosim(cfg: SpikeCosimConfig) extends BlackBox(Map(
val cause = UInt(64.W)
val has_wdata = Bool()
val wdata = UInt(64.W)
val priv = UInt(3.W)
}))
})
}
@@ -64,12 +67,8 @@ object SpikeCosim
require(trace.numInsns <= 2)
cosim.io.cycle := cycle
cosim.io.trace.map(t => {
t := DontCare
t.valid := false.B
t.iaddr := 0.U
t.insn := 0.U
t.exception := false.B
t.interrupt := false.B
t.cause := 0.U
})
cosim.io.hartid := hartid.U
for (i <- 0 until trace.numInsns) {
@@ -83,6 +82,7 @@ object SpikeCosim
cosim.io.trace(i).cause := trace.insns(i).cause
cosim.io.trace(i).has_wdata := trace.insns(i).wdata.isDefined.B
cosim.io.trace(i).wdata := trace.insns(i).wdata.getOrElse(0.U)
cosim.io.trace(i).priv := trace.insns(i).priv
}
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.system._
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.devices.tilelink._
// ------------------------------------
@@ -14,7 +14,7 @@ import freechips.rocketchip.devices.tilelink._
// DOC include start: DigitalTop
class DigitalTop(implicit p: Parameters) extends ChipyardSystem
with testchipip.CanHavePeripheryCustomBootPin // Enables optional custom boot pin
with testchipip.HasPeripheryBootAddrReg // Use programmable boot address register
with testchipip.CanHavePeripheryBootAddrReg // Use programmable boot address register
with testchipip.CanHaveTraceIO // Enables optionally adding trace IO
with testchipip.CanHaveBackingScratchpad // Enables optionally adding a backing scratchpad
with testchipip.CanHavePeripheryBlockDevice // Enables optionally adding the block device

View File

@@ -3,7 +3,7 @@ package chipyard.iobinders
import chisel3._
import chisel3.experimental.{Analog, IO, DataMirror}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.devices.debug._
import freechips.rocketchip.jtag.{JTAGIO}
@@ -25,7 +25,6 @@ import barstools.iocell.chisel._
import testchipip._
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
import chipyard.{CanHaveMasterTLMemPort}
import chipyard.clocking.{HasChipyardPRCI, DividerOnlyClockGenerator}
import scala.reflect.{ClassTag}
@@ -51,6 +50,12 @@ case object IOBinders extends Field[Map[String, Seq[IOBinderFunction]]](
Map[String, Seq[IOBinderFunction]]().withDefaultValue(Nil)
)
case object DontTouchIOBindersPorts extends Field[Boolean](true)
class WithDontTouchIOBinders(b: Boolean = true) extends Config((site, here, up) => {
case DontTouchIOBindersPorts => b
})
abstract trait HasIOBinders { this: LazyModule =>
val lazySystem: LazyModule
private val iobinders = p(IOBinders)
@@ -67,10 +72,33 @@ abstract trait HasIOBinders { this: LazyModule =>
})
// A publicly accessible list of IO cells (useful for a floorplanning tool, for example)
lazy val iocells = (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer
val iocells = InModuleBody { (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer }
// A mapping between stringified DigitalSystem traits and their corresponding ChipTop ports
lazy val portMap = iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap
val portMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap }
// A mapping between stringified DigitalSystem traits and their corresponding ChipTop iocells
val iocellMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._2 ++ impFlattened(k)._2)).toMap }
InModuleBody {
if (p(DontTouchIOBindersPorts)) {
portMap.values.foreach(_.foreach(dontTouch(_)))
}
println("IOCells generated by IOBinders:")
for ((k, v) <- iocellMap) {
if (!v.isEmpty) {
val cells = v.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size)
println(s" IOBinder for $k generated:")
for ((t, c) <- cells) { println(s" $c X $t") }
}
}
println()
val totals = iocells.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size)
println(s" Total generated ${iocells.size} IOCells:")
for ((t, c) <- totals) { println(s" $c X $t") }
}
}
// Note: The parameters instance is accessible only through LazyModule
@@ -219,7 +247,7 @@ class WithDebugIOCells extends OverrideLazyIOBinder({
def clockBundle = clockSinkNode.get.in.head._1
InModuleBody { system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripheryDebugModuleImp => {
InModuleBody { system.asInstanceOf[BaseSubsystem] match { case system: HasPeripheryDebug => {
system.debug.map({ debug =>
// We never use the PSDIO, so tie it off on-chip
system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) }
@@ -396,45 +424,4 @@ class WithDontTouchPorts extends OverrideIOBinder({
(system: DontTouch) => system.dontTouchPorts(); (Nil, Nil)
})
class ClockWithFreq(val freqMHz: Double) extends Bundle {
val clock = Clock()
}
class WithDividerOnlyClockGenerator extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
// Connect the implicit clock
implicit val p = GetSystemParameters(system)
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
InModuleBody {
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
}
// Connect all other requested clocks
val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
val dividerOnlyClockGen = LazyModule(new DividerOnlyClockGenerator("buildTopClockGenerator"))
(system.allClockGroupsNode
:= dividerOnlyClockGen.node
:= referenceClockSource)
InModuleBody {
val clock_wire = Wire(Input(new ClockWithFreq(dividerOnlyClockGen.module.referenceFreq)))
val reset_wire = Wire(Input(AsyncReset()))
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
referenceClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock
o.reset := reset_wire
}
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell)
}
}
})

View File

@@ -4,9 +4,10 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{IntParam, StringParam, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.devices.debug.{ExportDebug, DMI}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.rocket._
import freechips.rocketchip.tilelink._
@@ -15,8 +16,7 @@ import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.prci.ClockSinkParameters
case class SpikeCoreParams(
) extends CoreParams {
case class SpikeCoreParams() extends CoreParams {
val useVM = true
val useHypervisor = false
val useSupervisor = true
@@ -79,7 +79,8 @@ case class SpikeTileParams(
hartId: Int = 0,
val core: SpikeCoreParams = SpikeCoreParams(),
icacheParams: ICacheParams = ICacheParams(nWays = 32),
dcacheParams: DCacheParams = DCacheParams(nWays = 32)
dcacheParams: DCacheParams = DCacheParams(nWays = 32),
tcmParams: Option[MasterPortParams] = None // tightly coupled memory
) extends InstantiableTileParams[SpikeTile]
{
val name = Some("spike_tile")
@@ -145,6 +146,27 @@ class SpikeTile(
sourceId = IdRange(0, 1),
requestFifo = true))))))
tlSlaveXbar.node :*= slaveNode
val tcmNode = spikeTileParams.tcmParams.map { tcmP =>
val device = new MemoryDevice
val base = AddressSet.misaligned(tcmP.base, tcmP.size)
val tcmNode = TLManagerNode(Seq(TLSlavePortParameters.v1(
managers = Seq(TLSlaveParameters.v1(
address = base,
resources = device.reg,
regionType = RegionType.IDEMPOTENT, // not cacheable
executable = true,
supportsGet = TransferSizes(1, 8),
supportsPutFull = TransferSizes(1, 8),
supportsPutPartial = TransferSizes(1, 8),
fifoId = Some(0)
)),
beatBytes = 8
)))
connectTLSlave(tcmNode := TLBuffer(), 8)
tcmNode
}
tlOtherMastersNode := TLBuffer() := tlMasterXbar.node
masterNode :=* tlOtherMastersNode
tlMasterXbar.node := TLWidthWidget(64) := TLBuffer():= icacheNode
@@ -166,7 +188,10 @@ class SpikeBlackBox(
cacheable_regions: String,
uncacheable_regions: String,
readonly_uncacheable_regions: String,
executable_regions: String) extends BlackBox(Map(
executable_regions: String,
tcm_base: BigInt,
tcm_size: BigInt,
use_dtm: Boolean) extends BlackBox(Map(
"HARTID" -> IntParam(hartId),
"ISA" -> StringParam(isa),
"PMPREGIONS" -> IntParam(pmpregions),
@@ -179,7 +204,9 @@ class SpikeBlackBox(
"UNCACHEABLE" -> StringParam(uncacheable_regions),
"READONLY_UNCACHEABLE" -> StringParam(readonly_uncacheable_regions),
"CACHEABLE" -> StringParam(cacheable_regions),
"EXECUTABLE" -> StringParam(executable_regions)
"EXECUTABLE" -> StringParam(executable_regions),
"TCM_BASE" -> IntParam(tcm_base),
"TCM_SIZE" -> IntParam(tcm_size)
)) with HasBlackBoxResource {
val io = IO(new Bundle {
@@ -258,10 +285,30 @@ class SpikeBlackBox(
val data = Input(UInt(64.W))
}
}
val tcm = new Bundle {
val a = new Bundle {
val valid = Input(Bool())
val address = Input(UInt(64.W))
val data = Input(UInt(64.W))
val mask = Input(UInt(32.W))
val opcode = Input(UInt(32.W))
val size = Input(UInt(32.W))
}
val d = new Bundle {
val valid = Output(Bool())
val ready = Input(Bool())
val data = Output(UInt(64.W))
}
}
})
addResource("/vsrc/spiketile.v")
addResource("/csrc/spiketile.cc")
if (use_dtm) {
addResource("/csrc/spiketile_dtm.h")
} else {
addResource("/csrc/spiketile_tsi.h")
}
}
class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
@@ -285,11 +332,19 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
val (dcache_tl, dcacheEdge) = outer.dcacheNode.out(0)
val (mmio_tl, mmioEdge) = outer.mmioNode.out(0)
// Note: This assumes that if the debug module exposes the ClockedDMI port,
// then the DTM-based bringup with SimDTM will be used. This isn't required to be
// true, but it usually is
val useDTM = p(ExportDebug).protocols.contains(DMI)
val spike = Module(new SpikeBlackBox(hartId, isaDTS, tileParams.core.nPMPs,
tileParams.icache.get.nSets, tileParams.icache.get.nWays,
tileParams.dcache.get.nSets, tileParams.dcache.get.nWays,
tileParams.dcache.get.nMSHRs,
cacheable_regions, uncacheable_regions, readonly_uncacheable_regions, executable_regions))
cacheable_regions, uncacheable_regions, readonly_uncacheable_regions, executable_regions,
outer.spikeTileParams.tcmParams.map(_.base).getOrElse(0),
outer.spikeTileParams.tcmParams.map(_.size).getOrElse(0),
useDTM
))
spike.io.clock := clock.asBool
val cycle = RegInit(0.U(64.W))
cycle := cycle + 1.U
@@ -304,64 +359,63 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
spike.io.msip := int_bundle.msip
spike.io.meip := int_bundle.meip
spike.io.seip := int_bundle.seip.get
spike.io.ipc := PlusArg("spike-ipc", 10000, width=64)
spike.io.ipc := PlusArg("spike-ipc", width=32, default=10000)
val blockBits = log2Ceil(p(CacheBlockBytes))
val icache_a_q = Module(new Queue(new TLBundleA(icacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.icache.a.ready := icache_a_q.io.enq.ready && icache_a_q.io.count === 0.U
icache_tl.a <> icache_a_q.io.deq
icache_a_q.io.enq.valid := spike.io.icache.a.valid
icache_a_q.io.enq.bits := icacheEdge.Get(
spike.io.icache.a.ready := icache_tl.a.ready
icache_tl.a.valid := spike.io.icache.a.valid
icache_tl.a.bits := icacheEdge.Get(
fromSource = spike.io.icache.a.sourceid,
toAddress = (spike.io.icache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U)._2
icache_tl.d.ready := true.B
spike.io.icache.d.valid := icache_tl.d.valid
spike.io.icache.d.sourceid := icache_tl.d.bits.source
spike.io.icache.d.data := icache_tl.d.bits.data.asTypeOf(Vec(8, UInt(64.W)))
val dcache_a_q = Module(new Queue(new TLBundleA(dcacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.dcache.a.ready := dcache_a_q.io.enq.ready && dcache_a_q.io.count === 0.U
dcache_tl.a <> dcache_a_q.io.deq
dcache_a_q.io.enq.valid := spike.io.dcache.a.valid
dcache_a_q.io.enq.bits := dcacheEdge.AcquireBlock(
fromSource = spike.io.dcache.a.sourceid,
toAddress = (spike.io.dcache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U,
growPermissions = Mux(spike.io.dcache.a.state_old, 2.U, Mux(spike.io.dcache.a.state_new, 1.U, 0.U)))._2
spike.io.dcache.a.ready := dcache_tl.a.ready
dcache_tl.a.valid := spike.io.dcache.a.valid
if (dcacheEdge.manager.anySupportAcquireB) {
dcache_tl.a.bits := dcacheEdge.AcquireBlock(
fromSource = spike.io.dcache.a.sourceid,
toAddress = (spike.io.dcache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U,
growPermissions = Mux(spike.io.dcache.a.state_old, 2.U, Mux(spike.io.dcache.a.state_new, 1.U, 0.U)))._2
} else {
dcache_tl.a.bits := DontCare
}
dcache_tl.b.ready := true.B
spike.io.dcache.b.valid := dcache_tl.b.valid
spike.io.dcache.b.address := dcache_tl.b.bits.address
spike.io.dcache.b.source := dcache_tl.b.bits.source
spike.io.dcache.b.param := dcache_tl.b.bits.param
val dcache_c_q = Module(new Queue(new TLBundleC(dcacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.dcache.c.ready := dcache_c_q.io.enq.ready && dcache_c_q.io.count === 0.U
dcache_tl.c <> dcache_c_q.io.deq
dcache_c_q.io.enq.valid := spike.io.dcache.c.valid
dcache_c_q.io.enq.bits := Mux(spike.io.dcache.c.voluntary,
dcacheEdge.Release(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
shrinkPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt)._2,
Mux(spike.io.dcache.c.has_data,
dcacheEdge.ProbeAck(
spike.io.dcache.c.ready := dcache_tl.c.ready
dcache_tl.c.valid := spike.io.dcache.c.valid
if (dcacheEdge.manager.anySupportAcquireB) {
dcache_tl.c.bits := Mux(spike.io.dcache.c.voluntary,
dcacheEdge.Release(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt),
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param)
))
shrinkPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt)._2,
Mux(spike.io.dcache.c.has_data,
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt),
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param)
))
} else {
dcache_tl.c.bits := DontCare
}
val has_data = dcacheEdge.hasData(dcache_tl.d.bits)
val should_finish = dcacheEdge.isRequest(dcache_tl.d.bits)
@@ -376,12 +430,10 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
dcache_tl.e.valid := dcache_tl.d.valid && should_finish
dcache_tl.e.bits := dcacheEdge.GrantAck(dcache_tl.d.bits)
val mmio_a_q = Module(new Queue(new TLBundleA(mmioEdge.bundle), 1, flow=true, pipe=true))
spike.io.mmio.a.ready := mmio_a_q.io.enq.ready && mmio_a_q.io.count === 0.U
mmio_tl.a <> mmio_a_q.io.deq
mmio_a_q.io.enq.valid := spike.io.mmio.a.valid
val log_size = MuxCase(0.U, (0 until 3).map { i => (spike.io.mmio.a.size === (1 << i).U) -> i.U })
mmio_a_q.io.enq.bits := Mux(spike.io.mmio.a.store,
spike.io.mmio.a.ready := mmio_tl.a.ready
mmio_tl.a.valid := spike.io.mmio.a.valid
val log_size = (0 until 4).map { i => Mux(spike.io.mmio.a.size === (1 << i).U, i.U, 0.U) }.reduce(_|_)
mmio_tl.a.bits := Mux(spike.io.mmio.a.store,
mmioEdge.Put(0.U, spike.io.mmio.a.address, log_size, spike.io.mmio.a.data)._2,
mmioEdge.Get(0.U, spike.io.mmio.a.address, log_size)._2)
@@ -389,9 +441,33 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
spike.io.mmio.d.valid := mmio_tl.d.valid
spike.io.mmio.d.data := mmio_tl.d.bits.data
spike.io.tcm := DontCare
spike.io.tcm.a.valid := false.B
spike.io.tcm.d.ready := true.B
outer.tcmNode.map { tcmNode =>
val (tcm_tl, tcmEdge) = tcmNode.in(0)
val debug_tcm_tl = WireInit(tcm_tl)
dontTouch(debug_tcm_tl)
tcm_tl.a.ready := true.B
spike.io.tcm.a.valid := tcm_tl.a.valid
spike.io.tcm.a.address := tcm_tl.a.bits.address
spike.io.tcm.a.data := tcm_tl.a.bits.data
spike.io.tcm.a.mask := tcm_tl.a.bits.mask
spike.io.tcm.a.opcode := tcm_tl.a.bits.opcode
spike.io.tcm.a.size := tcm_tl.a.bits.size
spike.io.tcm.d.ready := tcm_tl.d.ready
tcm_tl.d.bits := tcmEdge.AccessAck(RegNext(tcm_tl.a.bits))
when (RegNext(tcm_tl.a.bits.opcode === TLMessages.Get)) {
tcm_tl.d.bits.opcode := TLMessages.AccessAckData
}
tcm_tl.d.valid := spike.io.tcm.d.valid
tcm_tl.d.bits.data := spike.io.tcm.d.data
}
}
class WithNSpikeCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
class WithNSpikeCores(n: Int = 1, tileParams: SpikeTileParams = SpikeTileParams(),
overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
// Calculate the next available hart ID (since hart ID cannot be duplicated)
val prev = up(TilesLocated(InSubsystem), site)
@@ -399,8 +475,21 @@ class WithNSpikeCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends
// Create TileAttachParams for every core to be instantiated
(0 until n).map { i =>
SpikeTileAttachParams(
tileParams = SpikeTileParams(hartId = i + idOffset)
tileParams = tileParams.copy(hartId = i + idOffset)
)
} ++ prev
}
})
class WithSpikeTCM extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
val prev = up(TilesLocated(InSubsystem))
require(prev.size == 1)
val spike = prev(0).asInstanceOf[SpikeTileAttachParams]
Seq(spike.copy(tileParams = spike.tileParams.copy(
tcmParams = Some(up(ExtMem).get.master)
)))
}
case ExtMem => None
case BankedL2Key => up(BankedL2Key).copy(nBanks = 0)
})

View File

@@ -9,9 +9,10 @@ import chisel3._
import chisel3.internal.sourceinfo.{SourceInfo}
import freechips.rocketchip.prci._
import freechips.rocketchip.config.{Field, Parameters}
import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp, ExportDebug, DebugModuleKey}
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, ExportDebug, DebugModuleKey}
import sifive.blocks.devices.uart.{HasPeripheryUART, PeripheryUARTKey}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
@@ -45,9 +46,35 @@ trait CanHaveHTIF { this: BaseSubsystem =>
}
}
// This trait adds the "chosen" node to DTS, which
// can be used to pass information to OS about the earlycon
case object ChosenInDTS extends Field[Boolean](true)
trait CanHaveChosenInDTS { this: BaseSubsystem =>
if (p(ChosenInDTS)) {
this match {
case t: HasPeripheryUART if (!p(PeripheryUARTKey).isEmpty) => {
val chosen = new Device {
def describe(resources: ResourceBindings): Description = {
val stdout = resources("stdout").map(_.value)
Description("chosen", resources("uart").headOption.map { case Binding(_, value) =>
"stdout-path" -> Seq(value)
}.toMap)
}
}
ResourceBinding {
t.uarts.foreach(u => Resource(chosen, "uart").bind(ResourceAlias(u.device.label)))
}
}
case _ =>
}
}
}
class ChipyardSubsystem(implicit p: Parameters) extends BaseSubsystem
with HasTiles
with HasPeripheryDebug
with CanHaveHTIF
with CanHaveChosenInDTS
{
def coreMonitorBundles = tiles.map {
case r: RocketTile => r.module.core.rocketImpl.coreMonitorBundle

View File

@@ -7,7 +7,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Parameters, Field}
import org.chipsalliance.cde.config.{Parameters, Field}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
@@ -31,6 +31,14 @@ class ChipyardSystem(implicit p: Parameters) extends ChipyardSubsystem
val bootROM = p(BootROMLocated(location)).map { BootROM.attach(_, this, CBUS) }
val maskROMs = p(MaskROMLocated(location)).map { MaskROM.attach(_, this, CBUS) }
// If there is no bootrom, the tile reset vector bundle will be tied to zero
if (bootROM.isEmpty) {
val fakeResetVectorSourceNode = BundleBridgeSource[UInt]()
InModuleBody { fakeResetVectorSourceNode.bundle := 0.U }
tileResetVectorNexusNode := fakeResetVectorSourceNode
}
override lazy val module = new ChipyardSystemModule(this)
}

View File

@@ -1,108 +0,0 @@
package chipyard
import chisel3._
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.util.{ResetCatchAndSync}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters}
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
import chipyard.iobinders.HasIOBinders
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
// -------------------------------
// Chipyard Test Harness
// -------------------------------
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz
trait HasHarnessSignalReferences {
implicit val p: Parameters
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
var refClockFreq: Double = p(DefaultClockFrequencyKey)
def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz }
def getRefClockFreq: Double = refClockFreq
def buildtopClock: Clock
def buildtopReset: Reset
def success: Bool
}
class HarnessClockInstantiator {
private val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty
// request a clock bundle at a particular frequency
def requestClockBundle(name: String, freqRequested: Double): ClockBundle = {
val clockBundle = Wire(new ClockBundle(ClockBundleParameters()))
_clockMap(name) = (freqRequested, clockBundle)
clockBundle
}
// connect all clock wires specified to a divider only PLL
def instantiateHarnessDividerPLL(refClock: ClockBundle): Unit = {
val sinks = _clockMap.map({ case (name, (freq, bundle)) =>
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name))
}).toSeq
val pllConfig = new SimplePllConfiguration("harnessDividerOnlyClockGenerator", sinks)
pllConfig.emitSummaries()
val dividedClocks = LinkedHashMap[Int, Clock]()
def instantiateDivider(div: Int): Clock = {
val divider = Module(new ClockDividerN(div))
divider.suggestName(s"ClockDivideBy${div}")
divider.io.clk_in := refClock.clock
dividedClocks(div) = divider.io.clk_out
divider.io.clk_out
}
// connect wires to clock source
for (sinkParams <- sinks) {
// bypass the reference freq. (don't create a divider + reset sync)
val (divClock, divReset) = if (sinkParams.take.get.freqMHz != pllConfig.referenceFreqMHz) {
val div = pllConfig.sinkDividerMap(sinkParams)
val divClock = dividedClocks.getOrElse(div, instantiateDivider(div))
(divClock, ResetCatchAndSync(divClock, refClock.reset.asBool))
} else {
(refClock.clock, refClock.reset)
}
_clockMap(sinkParams.name.get)._2.clock := divClock
_clockMap(sinkParams.name.get)._2.reset := divReset
}
}
}
case object HarnessClockInstantiatorKey extends Field[HarnessClockInstantiator](new HarnessClockInstantiator)
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
val io = IO(new Bundle {
val success = Output(Bool())
})
val buildtopClock = Wire(Clock())
val buildtopReset = Wire(Reset())
val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop")
val dut = Module(lazyDut.module)
io.success := false.B
val success = io.success
lazyDut match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
}
val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
buildtopClock := refClkBundle.clock
buildtopReset := WireInit(refClkBundle.reset)
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := clock
implicitHarnessClockBundle.reset := reset
p(HarnessClockInstantiatorKey).instantiateHarnessDividerPLL(implicitHarnessClockBundle)
}

View File

@@ -4,7 +4,7 @@ import scala.collection.mutable.{LinkedHashSet}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tile.{XLen, TileParams}
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite, RocketTestSuite}
/**

View File

@@ -0,0 +1,123 @@
package chipyard.clocking
import chisel3._
import chisel3.util._
import chipyard.iobinders.{OverrideLazyIOBinder, GetSystemParameters, IOCellKey}
import freechips.rocketchip.prci._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._
import barstools.iocell.chisel._
class ClockWithFreq(val freqMHz: Double) extends Bundle {
val clock = Clock()
}
// This uses the FakePLL, which uses a ClockAtFreq Verilog blackbox to generate
// the requested clocks. This also adds TileLink ClockDivider and ClockSelector
// blocks, which allow memory-mapped control of clock division, and clock muxing
// between the FakePLL and the slow off-chip clock
// Note: This will not simulate properly with firesim
class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
// Connect the implicit clock
implicit val p = GetSystemParameters(system)
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
InModuleBody {
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
}
val tlbus = system.asInstanceOf[BaseSubsystem].locateTLBusWrapper(system.prciParams.slaveWhere)
val baseAddress = system.prciParams.baseAddress
val clockDivider = system.prci_ctrl_domain { LazyModule(new TLClockDivider (baseAddress + 0x20000, tlbus.beatBytes)) }
val clockSelector = system.prci_ctrl_domain { LazyModule(new TLClockSelector(baseAddress + 0x30000, tlbus.beatBytes)) }
val pllCtrl = system.prci_ctrl_domain { LazyModule(new FakePLLCtrl (baseAddress + 0x40000, tlbus.beatBytes)) }
tlbus.toVariableWidthSlave(Some("clock-div-ctrl")) { clockDivider.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("clock-sel-ctrl")) { clockSelector.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("pll-ctrl")) { pllCtrl.tlNode := TLBuffer() }
system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode
// Connect all other requested clocks
val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
// The order of the connections to clockSelector.clockNode configures the inputs
// of the clockSelector's clockMux. Default to using the slowClockSource,
// software should enable the PLL, then switch to the pllClockSource
clockSelector.clockNode := slowClockSource
clockSelector.clockNode := pllClockSource
val pllCtrlSink = BundleBridgeSink[FakePLLCtrlBundle]()
pllCtrlSink := pllCtrl.ctrlNode
InModuleBody {
val clock_wire = Wire(Input(new ClockWithFreq(100)))
val reset_wire = Wire(Input(AsyncReset()))
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
slowClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock
o.reset := reset_wire
}
// For a real chip you should replace this ClockSourceAtFreqFromPlusArg
// with a blackbox of whatever PLL is being integrated
val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
fake_pll.io.power := pllCtrlSink.in(0)._1.power
fake_pll.io.gate := pllCtrlSink.in(0)._1.gate
pllClockSource.out.unzip._1.map { o =>
o.clock := fake_pll.io.clk
o.reset := reset_wire
}
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell)
}
}
})
// This passes all clocks through to the TestHarness
class WithPassthroughClockGenerator extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
// Connect the implicit clock
implicit val p = GetSystemParameters(system)
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
InModuleBody {
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
}
// This aggregate node should do nothing
val clockGroupAggNode = ClockGroupAggregateNode("fake")
val clockGroupsSourceNode = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
system.allClockGroupsNode := clockGroupAggNode := clockGroupsSourceNode
InModuleBody {
val reset_io = IO(Input(AsyncReset()))
require(clockGroupAggNode.out.size == 1)
val (bundle, edge) = clockGroupAggNode.out(0)
val clock_ios = (bundle.member.data zip edge.sink.members).map { case (b, m) =>
val freq = m.take.get.freqMHz
val clock_io = IO(Input(new ClockWithFreq(freq))).suggestName(s"clock_${m.name.get}")
b.clock := clock_io.clock
b.reset := reset_io
clock_io
}.toSeq
((clock_ios :+ reset_io), Nil)
}
}
})

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{Analog, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._

View File

@@ -2,7 +2,7 @@ package chipyard.clocking
import chisel3._
import freechips.rocketchip.config.{Parameters, Config, Field}
import org.chipsalliance.cde.config.{Parameters, Config, Field}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._

View File

@@ -2,7 +2,7 @@ package chipyard.clocking
import chisel3._
import freechips.rocketchip.config.{Parameters}
import org.chipsalliance.cde.config.{Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
import freechips.rocketchip.util.ElaborationArtefacts
@@ -92,57 +92,3 @@ class SimplePllConfiguration(
def referenceSinkParams(): ClockSinkParameters = sinkDividerMap.find(_._2 == 1).get._1
}
case class DividerOnlyClockGeneratorNode(pllName: String)(implicit valName: ValName)
extends MixedNexusNode(ClockImp, ClockGroupImp)(
dFn = { _ => ClockGroupSourceParameters() },
uFn = { u =>
require(u.size == 1)
require(!u.head.members.contains(None),
"All output clocks in group must set their take parameters. Use a ClockGroupDealiaser")
ClockSinkParameters(
name = Some(s"${pllName}_reference_input"),
take = Some(ClockParameters(new SimplePllConfiguration(pllName, u.head.members).referenceFreqMHz))) }
)
/**
* Generates a digital-divider-only PLL model that verilator can simulate.
* Inspects all take-specified frequencies in the output ClockGroup, calculates a
* fast reference clock (roughly LCM(requested frequencies)) which is passed up the
* diplomatic graph, and then generates dividers for each unique requested
* frequency.
*
* Output resets are not synchronized to generated clocks and should be
* synchronized by the user in a manner they see fit.
*
*/
class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName: ValName) extends LazyModule {
val node = DividerOnlyClockGeneratorNode(pllName)
lazy val module = new Impl
class Impl extends LazyRawModuleImp(this) {
require(node.out.size == 1, "Idealized PLL expects to generate a single output clock group. Use a ClockGroupAggregator")
val (refClock, ClockEdgeParameters(_, refSinkParam, _, _)) = node.in.head
val (outClocks, ClockGroupEdgeParameters(_, outSinkParams, _, _)) = node.out.head
val referenceFreq = refSinkParam.take.get.freqMHz
val pllConfig = new SimplePllConfiguration(pllName, outSinkParams.members)
pllConfig.emitSummaries()
val dividedClocks = mutable.HashMap[Int, Clock]()
def instantiateDivider(div: Int): Clock = {
val divider = Module(new ClockDividerN(div))
divider.suggestName(s"ClockDivideBy${div}")
divider.io.clk_in := refClock.clock
dividedClocks(div) = divider.io.clk_out
divider.io.clk_out
}
for (((sinkBName, sinkB), sinkP) <- outClocks.member.elements.zip(outSinkParams.members)) {
val div = pllConfig.sinkDividerMap(sinkP)
sinkB.clock := dividedClocks.getOrElse(div, instantiateDivider(div))
// Reset handling and synchronization is expected to be handled by a downstream node
sinkB.reset := refClock.reset
}
}
}

View File

@@ -0,0 +1,36 @@
package chipyard.clocking
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.util._
class FakePLLCtrlBundle extends Bundle {
val gate = Bool()
val power = Bool()
}
class FakePLLCtrl(address: BigInt, beatBytes: Int)(implicit p: Parameters) extends LazyModule
{
val device = new SimpleDevice(s"pll", Nil)
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
val ctrlNode = BundleBridgeSource(() => Output(new FakePLLCtrlBundle))
lazy val module = new LazyModuleImp(this) {
// This PLL only has 2 address, the gate and power
// Both should be set to turn on the PLL
// TODO: Should these be reset by the top level reset pin?
val gate_reg = Module(new AsyncResetRegVec(w=1, init=0))
val power_reg = Module(new AsyncResetRegVec(w=1, init=0))
ctrlNode.out(0)._1.gate := gate_reg.io.q
ctrlNode.out(0)._1.power := power_reg.io.q
tlNode.regmap(
0 -> Seq(RegField.rwReg(1, gate_reg.io)),
4 -> Seq(RegField.rwReg(1, power_reg.io))
)
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import scala.collection.mutable.{ArrayBuffer}
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
@@ -15,12 +15,13 @@ import freechips.rocketchip.tile._
import freechips.rocketchip.prci._
import testchipip.{TLTileResetCtrl}
import chipyard.{DefaultClockFrequencyKey}
import chipyard.harness.{DefaultClockFrequencyKey}
case class ChipyardPRCIControlParams(
slaveWhere: TLBusWrapperLocation = CBUS,
baseAddress: BigInt = 0x100000,
enableTileClockGating: Boolean = true
enableTileClockGating: Boolean = true,
enableTileResetSetting: Boolean = true
)
@@ -72,12 +73,13 @@ trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesTiles =>
val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
val clockGroupCombiner = ClockGroupCombiner()
val resetSynchronizer = ClockGroupResetSynchronizer()
val tileClockGater = prci_ctrl_domain {
TileClockGater(prciParams.baseAddress + 0x00000, tlbus, prciParams.enableTileClockGating)
}
val tileResetSetter = prci_ctrl_domain {
val tileClockGater = if (prciParams.enableTileClockGating) { prci_ctrl_domain {
TileClockGater(prciParams.baseAddress + 0x00000, tlbus)
} } else { ClockGroupEphemeralNode() }
val tileResetSetter = if (prciParams.enableTileResetSetting) { prci_ctrl_domain {
TileResetSetter(prciParams.baseAddress + 0x10000, tlbus, tile_prci_domains.map(_.tile_reset_domain.clockNode.portParams(0).name.get), Nil)
}
} } else { ClockGroupEphemeralNode() }
(aggregator
:= frequencySpecifier
:= clockGroupCombiner

View File

@@ -0,0 +1,56 @@
package chipyard.clocking
import chisel3._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.util._
import freechips.rocketchip.prci._
import freechips.rocketchip.util.ElaborationArtefacts
import testchipip._
// This module adds a TileLink memory-mapped clock divider to the clock graph
// The output clock/reset pairs from this module should be synchronized later
class TLClockDivider(address: BigInt, beatBytes: Int, divBits: Int = 8)(implicit p: Parameters) extends LazyModule {
val device = new SimpleDevice(s"clk-div-ctrl", Nil)
val clockNode = ClockGroupIdentityNode()
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
lazy val module = new LazyModuleImp(this) {
require (clockNode.out.size == 1)
val sources = clockNode.in.head._1.member.data.toSeq
val sinks = clockNode.out.head._1.member.elements.toSeq
require (sources.size == sinks.size)
val nSinks = sinks.size
val regs = (0 until nSinks) .map { i =>
val sinkName = sinks(i)._1
val asyncReset = sources(i).reset
val reg = withReset (asyncReset) {
Module(new AsyncResetRegVec(w=divBits, init=0))
}
println(s"${(address+i*4).toString(16)}: Clock domain $sinkName divider")
sinks(i)._2.clock := withClockAndReset(sources(i).clock, asyncReset) {
val divider = Module(new testchipip.ClockDivideOrPass(divBits, depth = 3, genClockGate = p(ClockGateImpl)))
divider.io.divisor := reg.io.q
divider.io.resetAsync := ResetStretcher(sources(i).clock, asyncReset, 20).asAsyncReset
divider.io.clockOut
}
// Note this is not synchronized to the output clock, which takes time to appear
// so this is still asyncreset
// Stretch the reset for 40 cycles, to give enough time to reset any downstream
// digital logic
sinks(i)._2.reset := ResetStretcher(sources(i).clock, asyncReset, 40).asAsyncReset
reg
}
tlNode.regmap((0 until nSinks).map { i =>
i * 4 -> Seq(RegField.rwReg(divBits, regs(i).io))
}: _*)
}
}

View File

@@ -0,0 +1,73 @@
package chipyard.clocking
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.util._
import freechips.rocketchip.prci._
import freechips.rocketchip.util.ElaborationArtefacts
import testchipip._
object ResetStretcher {
def apply(clock: Clock, reset: Reset, cycles: Int): Reset = {
withClockAndReset(clock, reset) {
val n = log2Ceil(cycles)
val count = Module(new AsyncResetRegVec(w=n, init=0))
val resetout = Module(new AsyncResetRegVec(w=1, init=1))
count.io.en := resetout.io.q
count.io.d := count.io.q + 1.U
resetout.io.en := resetout.io.q
resetout.io.d := count.io.q < (cycles-1).U
resetout.io.q.asBool
}
}
}
case class ClockSelNode()(implicit valName: ValName)
extends MixedNexusNode(ClockImp, ClockGroupImp)(
dFn = { d => ClockGroupSourceParameters() },
uFn = { u => ClockSinkParameters() }
)
// This module adds a TileLink memory-mapped clock mux for each downstream clock domain
// in the clock graph. The output clock/reset should be synchronized downstream
class TLClockSelector(address: BigInt, beatBytes: Int)(implicit p: Parameters) extends LazyModule {
val device = new SimpleDevice("clk-sel-ctrl", Nil)
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
val clockNode = ClockSelNode()
lazy val module = new LazyModuleImp(this) {
val asyncReset = clockNode.in.map(_._1).map(_.reset).toSeq(0)
val clocks = clockNode.in.map(_._1).map(_.clock)
val (outClocks, _) = clockNode.out.head
val (sinkNames, sinks) = outClocks.member.elements.toSeq.unzip
val regs = (0 until sinks.size).map { i =>
val sinkName = sinkNames(i)
val sel = Wire(UInt(log2Ceil(clocks.size).W))
val reg = withReset(asyncReset) { Module(new AsyncResetRegVec(w=log2Ceil(clocks.size), init=0)) }
sel := reg.io.q
println(s"${(address+i*4).toString(16)}: Clock domain $sinkName clock mux")
val mux = testchipip.ClockMutexMux(clocks).suggestName(s"${sinkName}_clkmux")
mux.io.sel := sel
mux.io.resetAsync := asyncReset.asAsyncReset
sinks(i).clock := mux.io.clockOut
// Stretch the reset for 20 cycles, to give time to reset any downstream digital logic
sinks(i).reset := ResetStretcher(clocks(0), asyncReset, 20).asAsyncReset
reg
}
tlNode.regmap((0 until sinks.size).map { i =>
i * 4 -> Seq(RegField.rwReg(log2Ceil(clocks.size), regs(i).io))
}: _*)
}
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{Analog, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
@@ -19,7 +19,7 @@ import freechips.rocketchip.subsystem._
* flag will generate the registers, preserving the same memory map and behavior, but will not
* generate any gaters
*/
class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit p: Parameters, valName: ValName) extends LazyModule
class TileClockGater(address: BigInt, beatBytes: Int)(implicit p: Parameters, valName: ValName) extends LazyModule
{
val device = new SimpleDevice(s"clock-gater", Nil)
val clockNode = ClockGroupIdentityNode()
@@ -31,8 +31,8 @@ class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit
val regs = (0 until nSinks).map({i =>
val sinkName = sinks(i)._1
val reg = withReset(sources(i).reset) { Module(new AsyncResetRegVec(w=1, init=1)) }
if (sinkName.contains("tile") && enable) {
println(s"ClockGate for ${sinkName} regmapped at ${(address+i*4).toString(16)}")
if (sinkName.contains("tile")) {
println(s"${(address+i*4).toString(16)}: Tile $sinkName clock gate")
sinks(i)._2.clock := ClockGate(sources(i).clock, reg.io.q.asBool)
sinks(i)._2.reset := sources(i).reset
} else {
@@ -47,8 +47,8 @@ class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit
}
object TileClockGater {
def apply(address: BigInt, tlbus: TLBusWrapper, enable: Boolean)(implicit p: Parameters, v: ValName) = {
val gater = LazyModule(new TileClockGater(address, tlbus.beatBytes, enable))
def apply(address: BigInt, tlbus: TLBusWrapper)(implicit p: Parameters, v: ValName) = {
val gater = LazyModule(new TileClockGater(address, tlbus.beatBytes))
tlbus.toVariableWidthSlave(Some("clock-gater")) { gater.tlNode := TLBuffer() }
gater.clockNode
}

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{Analog, IO}
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
@@ -39,16 +39,16 @@ class TileResetSetter(address: BigInt, beatBytes: Int, tileNames: Seq[String], i
}): _*)
val tileMap = tileNames.zipWithIndex.map({ case (n, i) =>
n -> (tile_async_resets(i), r_tile_resets(i).io.q)
n -> (tile_async_resets(i), r_tile_resets(i).io.q, address + i * 4)
})
(clockNode.out zip clockNode.in).map { case ((o, _), (i, _)) =>
(o.member.elements zip i.member.elements).foreach { case ((name, oD), (_, iD)) =>
oD.clock := iD.clock
oD.reset := iD.reset
for ((n, (rIn, rOut)) <- tileMap) {
for ((n, (rIn, rOut, addr)) <- tileMap) {
if (name.contains(n)) {
println(name, n)
println(s"${addr.toString(16)}: Tile $name reset control")
// Async because the reset coming out of the AsyncResetRegVec is
// clocked to the bus this is attached to, not the clock in this
// clock bundle. We expect a ClockGroupResetSynchronizer downstream

View File

@@ -1,6 +1,6 @@
package chipyard.config
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// --------------
// Chipyard abstract ("base") configuration
@@ -12,17 +12,18 @@ import freechips.rocketchip.config.{Config}
class AbstractConfig extends Config(
// The HarnessBinders control generation of hardware in the TestHarness
new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present
new chipyard.harness.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled
new chipyard.harness.WithSimSerial ++ // add external serial-adapter and RAM
new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled
new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present
new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled
new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
new chipyard.harness.WithCustomBootPinPlusArg ++
new chipyard.harness.WithClockAndResetFromHarness ++
new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present
new chipyard.harness.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled
new chipyard.harness.WithSimTSIOverSerialTL ++ // add external serial-adapter and RAM
new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled
new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present
new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled
new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
new chipyard.harness.WithCustomBootPinPlusArg ++ // drive custom-boot pin with a plusarg, if custom-boot-pin is present
new chipyard.harness.WithClockAndResetFromHarness ++ // all Clock/Reset I/O in ChipTop should be driven by harnessClockInstantiator
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // generate clocks in harness with unsynthesizable ClockSourceAtFreqMHz
// The IOBinders instantiate ChipTop IOs to match desired digital IOs
// IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through
@@ -40,18 +41,24 @@ class AbstractConfig extends Config(
new chipyard.iobinders.WithTraceIOPunchthrough ++
new chipyard.iobinders.WithExtInterruptIOCells ++
new chipyard.iobinders.WithCustomBootPin ++
new chipyard.iobinders.WithDividerOnlyClockGenerator ++
// By default, punch out IOs to the Harness
new chipyard.clocking.WithPassthroughClockGenerator ++
new testchipip.WithCustomBootPin ++ // add a custom-boot-pin to support pin-driven boot address
new testchipip.WithBootAddrReg ++ // add a boot-addr-reg for configurable boot address
new testchipip.WithSerialTLWidth(32) ++ // fatten the serialTL interface to improve testing performance
new testchipip.WithDefaultSerialTL ++ // use serialized tilelink port to external serialadapter/harnessRAM
new chipyard.config.WithDebugModuleAbstractDataWords(8) ++ // increase debug module data capacity
new chipyard.config.WithBootROM ++ // use default bootrom
new chipyard.config.WithUART ++ // add a UART
new chipyard.config.WithL2TLBs(1024) ++ // use L2 TLBs
new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks
new chipyard.config.WithInheritBusFrequencyAssignments ++ // Unspecified clocks within a bus will receive the bus frequency if set
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // Unspecified frequencies with match the pbus frequency (which is always set)
new chipyard.config.WithMemoryBusFrequency(100.0) ++ // Default 100 MHz mbus
new chipyard.config.WithPeripheryBusFrequency(100.0) ++ // Default 100 MHz pbus
new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus
new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus
new freechips.rocketchip.subsystem.WithNMemoryChannels(2) ++ // Default 2 memory channels
new freechips.rocketchip.subsystem.WithClockGateModel ++ // add default EICG_wrapper clock gate model
new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port
new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip)
@@ -60,4 +67,5 @@ class AbstractConfig extends Config(
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts
new freechips.rocketchip.subsystem.WithDontDriveBusClocksFromSBus ++ // leave the bus clocks undriven by sbus
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ // hierarchical buses including sbus/mbus/pbus/fbus/cbus/l2
new freechips.rocketchip.subsystem.WithDTS("ucb-bar,chipyard", Nil) ++ // custom device name for DTS
new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// BOOM Configs
@@ -53,3 +53,18 @@ class MediumBoomCosimConfig extends Config(
new chipyard.config.WithTraceIO ++ // enable the traceio
new boom.common.WithNMediumBooms(1) ++
new chipyard.config.AbstractConfig)
class dmiMediumBoomConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tl
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new boom.common.WithNMediumBooms(1) ++
new chipyard.config.AbstractConfig)
class dmiMediumBoomCosimConfig extends Config(
new chipyard.harness.WithCospike ++ // attach spike-cosim
new chipyard.config.WithTraceIO ++ // enable the traceio
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anythint to serial-tl
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new boom.common.WithNMediumBooms(1) ++
new chipyard.config.AbstractConfig)

View File

@@ -2,7 +2,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// CVA6 Configs
@@ -13,7 +13,7 @@ class CVA6Config extends Config(
new chipyard.config.AbstractConfig)
class dmiCVA6Config extends Config(
new chipyard.harness.WithSerialAdapterTiedOff ++ // Tie off the serial port, override default instantiation of SimSerial
new chipyard.harness.WithSerialTLTiedOff ++ // Tie off the serial-tilelink port
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new cva6.WithNCVA6Cores(1) ++ // single CVA6 core
new chipyard.config.AbstractConfig)

View File

@@ -0,0 +1,38 @@
package chipyard
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy._
// A simple config demonstrating how to set up a basic chip in Chipyard
class ChipLikeQuadRocketConfig extends Config(
//==================================
// Set up TestHarness
//==================================
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute frequencies for simulations in the harness
// NOTE: This only simulates properly in VCS
//==================================
// Set up tiles
//==================================
new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(3, 3) ++ // Add rational crossings between RocketTile and uncore
new freechips.rocketchip.subsystem.WithNBigCores(4) ++ // quad-core (4 RocketTiles)
//==================================
// Set up I/O
//==================================
new testchipip.WithSerialTLWidth(4) ++
new chipyard.harness.WithSimAXIMemOverSerialTL ++ // Attach fast SimDRAM to TestHarness
new chipyard.config.WithSerialTLBackingMemory ++ // Backing memory is over serial TL protocol
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 4L) ++ // 4GB max external memory
new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ // 1 memory channel
//==================================
// Set up clock./reset
//==================================
new chipyard.clocking.WithPLLSelectorDividerClockGenerator ++ // Use a PLL-based clock selector/divider generator structure
// Create the uncore clock group
new chipyard.clocking.WithClockGroupsCombinedByName("uncore", "implicit", "sbus", "mbus", "cbus", "system_bus", "fbus", "pbus") ++
new chipyard.config.AbstractConfig)

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// Heterogenous Configs

View File

@@ -2,7 +2,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// ---------------------
// Ibex Configs

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// ------------------------------
@@ -9,6 +9,7 @@ import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// DOC include start: FFTRocketConfig
class FFTRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC
new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers.
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
@@ -58,6 +59,7 @@ class LargeNVDLARocketConfig extends Config(
new chipyard.config.AbstractConfig)
class ManyMMIOAcceleratorRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC
new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers.
new nvidia.blocks.dla.WithNVDLA("small") ++ // add a small NVDLA
new chipyard.example.WithStreamingPassthrough ++ // use top with tilelink-controlled streaming passthrough

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
import freechips.rocketchip.subsystem.{SBUS, MBUS}

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// A empty config with no cores. Useful for testing
class NoCoresConfig extends Config(

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// ---------------------------------------------------------
@@ -58,7 +58,7 @@ class LBWIFRocketConfig extends Config(
// DOC include start: DmiRocket
class dmiRocketConfig extends Config(
new chipyard.harness.WithSerialAdapterTiedOff ++ // don't attach an external SimSerial
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tl
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// ------------------------------

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// --------------
@@ -12,6 +12,7 @@ class RocketConfig extends Config(
new chipyard.config.AbstractConfig)
class TinyRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO FIX: Don't dontTouch the ports
new chipyard.config.WithTLSerialLocation(
freechips.rocketchip.subsystem.FBUS,
freechips.rocketchip.subsystem.PBUS) ++ // attach TL serial adapter to f/p busses
@@ -85,6 +86,7 @@ class MbusScratchpadRocketConfig extends Config(
// DOC include end: mbusscratchpadrocket
class MulticlockRocketConfig extends Config(
new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(3, 3) ++ // Add async crossings between RocketTile and uncore
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
// Frequency specifications
new chipyard.config.WithTileFrequency(1600.0) ++ // Matches the maximum frequency of U540
@@ -95,7 +97,6 @@ class MulticlockRocketConfig extends Config(
// Crossing specifications
new chipyard.config.WithCbusToPbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between PBUS and CBUS
new chipyard.config.WithSbusToMbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossings between backside of L2 and MBUS
new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore
new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS
new chipyard.config.AbstractConfig)
@@ -124,5 +125,12 @@ class MulticlockAXIOverSerialConfig extends Config(
new chipyard.config.WithSerialTLBackingMemory ++ // remove axi4 mem port in favor of SerialTL memory
new freechips.rocketchip.subsystem.WithNBigCores(2) ++
new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ // 1 memory channel
new chipyard.config.AbstractConfig)
// DOC include end: MulticlockAXIOverSerialConfig
class CustomIOChipTopRocketConfig extends Config(
new chipyard.example.WithCustomChipTop ++
new chipyard.example.WithCustomIOCells ++
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core
new chipyard.config.AbstractConfig)

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// --------------

View File

@@ -2,7 +2,7 @@ package chipyard
import chisel3._
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
class Sodor1StageConfig extends Config(
// Create a Sodor 1-stage core

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
// Configs which instantiate a Spike-simulated
// tile that interacts with the Chipyard SoC
@@ -10,10 +10,47 @@ class SpikeConfig extends Config(
new chipyard.WithNSpikeCores(1) ++
new chipyard.config.AbstractConfig)
class dmiSpikeConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tilelink
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new SpikeConfig)
// Avoids polling on the UART registers
class SpikeFastUARTConfig extends Config(
new chipyard.WithNSpikeCores(1) ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(1) ++
new chipyard.config.WithPeripheryBusFrequency(1) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.AbstractConfig)
// Makes the UART fast, also builds no L2 and a ludicrous L1D
class SpikeUltraFastConfig extends Config(
new chipyard.WithSpikeTCM ++
new chipyard.WithNSpikeCores(1) ++
new testchipip.WithSerialPBusMem ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.WithBroadcastManager ++
new chipyard.config.AbstractConfig)
class dmiSpikeUltraFastConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tilelink
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new SpikeUltraFastConfig)
// Add the default firechip devices
class SpikeUltraFastDevicesConfig extends Config(
new chipyard.harness.WithSimBlockDevice ++
new chipyard.harness.WithLoopbackNIC ++
new icenet.WithIceNIC ++
new testchipip.WithBlockDevice ++
new chipyard.WithSpikeTCM ++
new chipyard.WithNSpikeCores(1) ++
new testchipip.WithSerialPBusMem ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.WithBroadcastManager ++
new chipyard.config.AbstractConfig)

View File

@@ -1,15 +1,16 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.rocket.{DCacheParams}
class AbstractTraceGenConfig extends Config(
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++
new chipyard.harness.WithBlackBoxSimMem ++
new chipyard.harness.WithTraceGenSuccess ++
new chipyard.harness.WithClockAndResetFromHarness ++
new chipyard.iobinders.WithAXI4MemPunchthrough ++
new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++
new chipyard.iobinders.WithDividerOnlyClockGenerator ++
new chipyard.clocking.WithPassthroughClockGenerator ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++

View File

@@ -1,6 +1,6 @@
package chipyard
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import constellation.channel._
import constellation.routing._
import constellation.topology._
@@ -77,6 +77,7 @@ class TutorialSha3BlackBoxConfig extends Config(
// Tutorial Phase 5: Map a multicore heterogeneous SoC with multiple cores and memory-mapped accelerators
class TutorialNoCConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++
// Try changing the dimensions of the Mesh topology
new constellation.soc.WithGlobalNoC(constellation.soc.GlobalNoCParams(
NoCParams(

View File

@@ -4,7 +4,7 @@ import scala.util.matching.Regex
import chisel3._
import chisel3.util.{log2Up}
import freechips.rocketchip.config.{Field, Parameters, Config}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.prci._
import freechips.rocketchip.diplomacy._
@@ -13,7 +13,7 @@ import freechips.rocketchip.tilelink.{HasTLBusParams}
import chipyard._
import chipyard.clocking._
import chipyard.harness.{DefaultClockFrequencyKey}
// The default RocketChip BaseSubsystem drives its diplomatic clock graph
// with the implicit clocks of Subsystem. Don't do that, instead we extend

View File

@@ -4,7 +4,7 @@ import scala.util.matching.Regex
import chisel3._
import chisel3.util.{log2Up}
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.devices.tilelink.{BootROMLocated, PLICKey}
import freechips.rocketchip.devices.debug.{Debug, ExportDebug, DebugModuleKey, DMI}
import freechips.rocketchip.stage.phases.TargetDirKey
@@ -87,3 +87,7 @@ class WithExtMemIdBits(n: Int) extends Config((site, here, up) => {
class WithNoPLIC extends Config((site, here, up) => {
case PLICKey => None
})
class WithDebugModuleAbstractDataWords(words: Int = 16) extends Config((site, here, up) => {
case DebugModuleKey => up(DebugModuleKey).map(_.copy(nAbstractDataWords=words))
})

View File

@@ -2,7 +2,7 @@ package chipyard.config
import chisel3._
import freechips.rocketchip.config.{Field, Parameters, Config}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.tile._
import freechips.rocketchip.diplomacy._

View File

@@ -1,6 +1,6 @@
package chipyard.config
import freechips.rocketchip.config.{Config}
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.subsystem.{SystemBusKey, BankedL2Key, CoherenceManagerWrapper}
import freechips.rocketchip.diplomacy.{DTSTimebase}

View File

@@ -2,7 +2,7 @@ package chipyard.config
import chisel3._
import freechips.rocketchip.config.{Field, Parameters, Config}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.tile._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams}

View File

@@ -1,6 +1,6 @@
package chipyard.config
import freechips.rocketchip.config.{Config, Field, Parameters}
import org.chipsalliance.cde.config.{Config, Field, Parameters}
import tracegen.{TraceGenSystem}
import chipyard.{BuildSystem}
import chipyard.clocking.{HasChipyardPRCI}

View File

@@ -0,0 +1,65 @@
package chipyard.example
import chisel3._
import chipyard.iobinders._
import org.chipsalliance.cde.config._
import freechips.rocketchip.diplomacy.{InModuleBody}
import barstools.iocell.chisel._
import chipyard._
import chipyard.harness.{BuildTop}
// A "custom" IOCell with additional I/O
// The IO don't do anything here in this example
class CustomDigitalInIOCellBundle extends DigitalInIOCellBundle {
val custom_out = Output(Bool())
val custom_in = Input(Bool())
}
// Using a custom digital in iocell instead of the default one
class CustomDigitalInIOCell extends RawModule with DigitalInIOCell {
val io = IO(new CustomDigitalInIOCellBundle)
io.i := io.pad
io.custom_out := io.pad
}
case class CustomIOCellParams() extends IOCellTypeParams {
def analog() = Module(new GenericAnalogIOCell)
def gpio() = Module(new GenericDigitalGPIOCell)
def input() = Module(new CustomDigitalInIOCell)
def output() = Module(new GenericDigitalOutIOCell)
}
class CustomChipTop(implicit p: Parameters) extends ChipTop {
// making the module name ChipTop instead of CustomChipTop means
// we don't have to set the TOP make variable to CustomChipTop
override lazy val desiredName = "ChipTop"
// InModuleBody blocks are executed within the LazyModuleImp of this block
InModuleBody {
iocellMap.foreach { case (interface, cells) => {
cells.foreach { _ match {
case c: CustomDigitalInIOCell => {
c.io.custom_in := false.B
}
case c: GenericDigitalOutIOCell => {
// do nothing
}
case c => {
require(false, "Unsupported iocell type ${c.getClass}")
}
}}
}}
// demonstrate accessing the iocellMap directly
val serialTLIOCells = iocellMap("interface testchipip.CanHavePeripheryTLSerial")
}
}
class WithCustomIOCells extends Config((site, here, up) => {
case IOCellKey => CustomIOCellParams()
})
class WithCustomChipTop extends Config((site, here, up) => {
case BuildTop => (p: Parameters) => new CustomChipTop()(p)
})

View File

@@ -0,0 +1,145 @@
package chipyard.example
import chisel3._
import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
import freechips.rocketchip.util._
import freechips.rocketchip.devices.debug.{ExportDebug, JtagDTMKey, Debug}
import freechips.rocketchip.tilelink.{TLBuffer}
import chipyard.{BuildSystem, DigitalTop}
import chipyard.clocking._
import chipyard.iobinders.{IOCellKey, JTAGChipIO}
import barstools.iocell.chisel._
// This "FlatChipTop" uses no IOBinders, so all the IO have
// to be explicitly constructed.
// This only supports the base "DigitalTop"
class FlatChipTop(implicit p: Parameters) extends LazyModule {
override lazy val desiredName = "ChipTop"
val system = LazyModule(p(BuildSystem)(p)).suggestName("system").asInstanceOf[DigitalTop]
//========================
// Diplomatic clock stuff
//========================
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
val tlbus = system.locateTLBusWrapper(system.prciParams.slaveWhere)
val baseAddress = system.prciParams.baseAddress
val clockDivider = system.prci_ctrl_domain { LazyModule(new TLClockDivider (baseAddress + 0x20000, tlbus.beatBytes)) }
val clockSelector = system.prci_ctrl_domain { LazyModule(new TLClockSelector(baseAddress + 0x30000, tlbus.beatBytes)) }
val pllCtrl = system.prci_ctrl_domain { LazyModule(new FakePLLCtrl (baseAddress + 0x40000, tlbus.beatBytes)) }
tlbus.toVariableWidthSlave(Some("clock-div-ctrl")) { clockDivider.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("clock-sel-ctrl")) { clockSelector.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("pll-ctrl")) { pllCtrl.tlNode := TLBuffer() }
system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode
// Connect all other requested clocks
val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
// The order of the connections to clockSelector.clockNode configures the inputs
// of the clockSelector's clockMux. Default to using the slowClockSource,
// software should enable the PLL, then switch to the pllClockSource
clockSelector.clockNode := slowClockSource
clockSelector.clockNode := pllClockSource
val pllCtrlSink = BundleBridgeSink[FakePLLCtrlBundle]()
pllCtrlSink := pllCtrl.ctrlNode
val debugClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters()))
debugClockSinkNode := system.locateTLBusWrapper(p(ExportDebug).slaveWhere).fixedClockNode
def debugClockBundle = debugClockSinkNode.in.head._1
override lazy val module = new FlatChipTopImpl
class FlatChipTopImpl extends LazyRawModuleImp(this) {
//=========================
// Clock/reset
//=========================
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
val clock_wire = Wire(Input(new ClockWithFreq(80)))
val reset_wire = Wire(Input(AsyncReset()))
val (clock_pad, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_pad, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
slowClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock
o.reset := reset_wire
}
// For a real chip you should replace this ClockSourceAtFreqFromPlusArg
// with a blackbox of whatever PLL is being integrated
val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
fake_pll.io.power := pllCtrlSink.in(0)._1.power
fake_pll.io.gate := pllCtrlSink.in(0)._1.gate
pllClockSource.out.unzip._1.map { o =>
o.clock := fake_pll.io.clk
o.reset := reset_wire
}
//=========================
// Custom Boot
//=========================
val (custom_boot_pad, customBootIOCell) = IOCell.generateIOFromSignal(system.custom_boot_pin.get.getWrappedValue, "custom_boot", p(IOCellKey))
//=========================
// Serialized TileLink
//=========================
val (serial_tl_pad, serialTLIOCells) = IOCell.generateIOFromSignal(system.serial_tl.get.getWrappedValue, "serial_tl", p(IOCellKey))
//=========================
// JTAG/Debug
//=========================
val debug = system.debug.get
// We never use the PSDIO, so tie it off on-chip
system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) }
system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := false.B } }
// Tie off extTrigger
debug.extTrigger.foreach { t =>
t.in.req := false.B
t.out.ack := t.out.req
}
// Tie off disableDebug
debug.disableDebug.foreach { d => d := false.B }
// Drive JTAG on-chip IOs
debug.systemjtag.map { j =>
j.reset := ResetCatchAndSync(j.jtag.TCK, debugClockBundle.reset.asBool)
j.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W)
j.part_number := p(JtagDTMKey).idcodePartNum.U(16.W)
j.version := p(JtagDTMKey).idcodeVersion.U(4.W)
}
Debug.connectDebugClockAndReset(Some(debug), debugClockBundle.clock)
// Add IOCells for the DMI/JTAG/APB ports
require(!debug.clockeddmi.isDefined)
require(!debug.apb.isDefined)
val (jtag_pad, jtagIOCells) = debug.systemjtag.map { j =>
val jtag_wire = Wire(new JTAGChipIO)
j.jtag.TCK := jtag_wire.TCK
j.jtag.TMS := jtag_wire.TMS
j.jtag.TDI := jtag_wire.TDI
jtag_wire.TDO := j.jtag.TDO.data
IOCell.generateIOFromSignal(jtag_wire, "jtag", p(IOCellKey), abstractResetAsAsync = true)
}.get
//==========================
// UART
//==========================
require(system.uarts.size == 1)
val (uart_pad, uartIOCells) = IOCell.generateIOFromSignal(system.module.uart.head, "uart_0", p(IOCellKey))
}
}

View File

@@ -0,0 +1,85 @@
package chipyard.example
import chisel3._
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.prci.{ClockSourceAtFreqFromPlusArg, ClockBundle, ClockBundleParameters}
import freechips.rocketchip.util.{PlusArg}
import freechips.rocketchip.subsystem.{CacheBlockBytes}
import freechips.rocketchip.devices.debug.{SimJTAG}
import freechips.rocketchip.jtag.{JTAGIO}
import testchipip.{SerialTLKey, UARTAdapter, SimDRAM, TSIHarness, SimTSI}
import chipyard.harness.{BuildTop}
// A "flat" TestHarness that doesn't use IOBinders
// use with caution.
// This example is hard-coded to work only for FlatChipTop, and the ChipLikeRocketConfig
class FlatTestHarness(implicit val p: Parameters) extends Module {
val io = IO(new Bundle {
val success = Output(Bool())
})
// This only works with FlatChipTop
val lazyDut = LazyModule(new FlatChipTop).suggestName("chiptop")
val dut = Module(lazyDut.module)
// Clock
val clock_source = Module(new ClockSourceAtFreqFromPlusArg("slow_clk_freq_mhz"))
clock_source.io.power := true.B
clock_source.io.gate := false.B
dut.clock_pad.clock := clock_source.io.clk
// Reset
dut.reset_pad := reset.asAsyncReset
// Custom boot
dut.custom_boot_pad := PlusArg("custom_boot_pin", width=1)
// Serialized TL
val sVal = p(SerialTLKey).get
require(sVal.axiMemOverSerialTLParams.isDefined)
require(sVal.isMemoryDevice)
val axiDomainParams = sVal.axiMemOverSerialTLParams.get
val memFreq = axiDomainParams.getMemFrequency(lazyDut.system)
withClockAndReset(clock, reset) {
val memOverSerialTLClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
memOverSerialTLClockBundle.clock := clock
memOverSerialTLClockBundle.reset := reset
val serial_bits = dut.serial_tl_pad.bits
dut.serial_tl_pad.clock := clock
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
lazyDut.system.serdesser.get,
serial_bits,
memOverSerialTLClockBundle,
reset)
io.success := SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), clock, reset)
// connect SimDRAM from the AXI port coming from the harness multi clock axi ram
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) =>
val memSize = sVal.memParams.size
val memBase = sVal.memParams.base
val lineSize = p(CacheBlockBytes)
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), memBase, edge.bundle)).suggestName("simdram")
mem.io.axi <> axi_port.bits
mem.io.clock := axi_port.clock
mem.io.reset := axi_port.reset
}
}
// JTAG
val jtag_wire = Wire(new JTAGIO)
jtag_wire.TDO.data := dut.jtag_pad.TDO
jtag_wire.TDO.driven := true.B
dut.jtag_pad.TCK := jtag_wire.TCK
dut.jtag_pad.TMS := jtag_wire.TMS
dut.jtag_pad.TDI := jtag_wire.TDI
val dtm_success = WireInit(false.B)
val jtag = Module(new SimJTAG(tickDelay=3)).connect(jtag_wire, clock, reset.asBool, ~(reset.asBool), dtm_success)
// UART
UARTAdapter.connect(Seq(dut.uart_pad))
}

View File

@@ -5,7 +5,7 @@ import chisel3.util._
import chisel3.experimental.{IntParam, BaseModule}
import freechips.rocketchip.amba.axi4._
import freechips.rocketchip.subsystem.BaseSubsystem
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper.{HasRegMap, RegField}
import freechips.rocketchip.tilelink._

View File

@@ -3,7 +3,7 @@ package chipyard.example
import chisel3._
import chisel3.util._
import freechips.rocketchip.subsystem.{BaseSubsystem, CacheBlockBytes}
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, IdRange}
import freechips.rocketchip.tilelink._

View File

@@ -1,6 +1,6 @@
package chipyard.example
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._

View File

@@ -2,7 +2,7 @@
import chisel3._
import chisel3.util._
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink.TLRegisterNode

View File

@@ -3,7 +3,7 @@ package chipyard.example
import chisel3._
import chisel3.util._
import freechips.rocketchip.config._
import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.diplomacy._

View File

@@ -5,7 +5,7 @@ import chisel3.util._
import dspblocks._
import dsptools.numbers._
import freechips.rocketchip.amba.axi4stream._
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink._

View File

@@ -8,7 +8,7 @@ import chisel3.util._
import dspblocks._
import dsptools.numbers._
import freechips.rocketchip.amba.axi4stream._
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.subsystem._

View File

@@ -8,7 +8,7 @@ import chisel3.util._
import dspblocks._
import dsptools.numbers._
import freechips.rocketchip.amba.axi4stream._
import freechips.rocketchip.config.{Parameters, Field, Config}
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.subsystem._

View File

@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import chisel3.experimental.{Analog, BaseModule, DataMirror, Direction}
import freechips.rocketchip.config.{Field, Config, Parameters}
import org.chipsalliance.cde.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike}
import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters}
import freechips.rocketchip.devices.debug._
@@ -22,8 +22,8 @@ import barstools.iocell.chisel._
import testchipip._
import chipyard._
import chipyard.clocking.{HasChipyardPRCI}
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO, ClockWithFreq}
import chipyard.clocking.{HasChipyardPRCI, ClockWithFreq}
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO}
import tracegen.{TraceGenSystemModuleImp}
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
@@ -154,22 +154,24 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
ports.map({ port =>
// DOC include start: HarnessClockInstantiatorEx
withClockAndReset(th.buildtopClock, th.buildtopReset) {
val memOverSerialTLClockBundle = p(HarnessClockInstantiatorKey).requestClockBundle("mem_over_serial_tl_clock", memFreq)
val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(
val memOverSerialTLClockBundle = th.harnessClockInstantiator.requestClockBundle("mem_over_serial_tl_clock", memFreq)
val serial_bits = port.bits
port.clock := th.buildtopClock
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
system.serdesser.get,
serial_bits,
memOverSerialTLClockBundle,
th.buildtopReset)
// DOC include end: HarnessClockInstantiatorEx
val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, th.buildtopClock, th.buildtopReset.asBool)
val success = SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), th.buildtopClock, th.buildtopReset.asBool)
when (success) { th.success := true.B }
// connect SimDRAM from the AXI port coming from the harness multi clock axi ram
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) =>
val memSize = sVal.memParams.size
val memBase = sVal.memParams.base
val lineSize = p(CacheBlockBytes)
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), edge.bundle)).suggestName("simdram")
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), memBase, edge.bundle)).suggestName("simdram")
mem.io.axi <> axi_port.bits
mem.io.clock := axi_port.clock
mem.io.reset := axi_port.reset
@@ -184,10 +186,12 @@ class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBind
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) =>
// TODO FIX: This currently makes each SimDRAM contain the entire memory space
val memSize = p(ExtMem).get.master.size
val memBase = p(ExtMem).get.master.base
val lineSize = p(CacheBlockBytes)
val clockFreq = p(MemoryBusKey).dtsFrequency.get
val mem = Module(new SimDRAM(memSize, lineSize, clockFreq, edge.bundle)).suggestName("simdram")
val mem = Module(new SimDRAM(memSize, lineSize, clockFreq, memBase, edge.bundle)).suggestName("simdram")
mem.io.axi <> port.bits
// Bug in Chisel implementation. See https://github.com/chipsalliance/chisel3/pull/1781
def Decoupled[T <: Data](irr: IrrevocableIO[T]): DecoupledIO[T] = {
@@ -252,7 +256,7 @@ class WithSimDebug extends OverrideHarnessBinder({
case d: ClockedDMIIO =>
val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B }
val dtm = Module(new SimDTM).connect(th.buildtopClock, th.buildtopReset.asBool, d, dtm_success)
val dtm = Module(new TestchipSimDTM).connect(th.buildtopClock, th.buildtopReset.asBool, d, dtm_success)
case j: JTAGChipIO =>
val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B }
@@ -262,7 +266,8 @@ class WithSimDebug extends OverrideHarnessBinder({
j.TCK := jtag_wire.TCK
j.TMS := jtag_wire.TMS
j.TDI := jtag_wire.TDI
val jtag = Module(new SimJTAG(tickDelay=3)).connect(jtag_wire, th.buildtopClock, th.buildtopReset.asBool, ~(th.buildtopReset.asBool), dtm_success)
val jtag = Module(new SimJTAG(tickDelay=3))
jtag.connect(jtag_wire, th.buildtopClock, th.buildtopReset.asBool, ~(th.buildtopReset.asBool), dtm_success)
}
}
})
@@ -294,27 +299,28 @@ class WithTiedOffDebug extends OverrideHarnessBinder({
})
class WithSerialAdapterTiedOff extends OverrideHarnessBinder({
class WithSerialTLTiedOff extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
ports.map({ port =>
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
withClockAndReset(th.buildtopClock, th.buildtopReset) {
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
SerialAdapter.tieoff(ram.module.io.tsi_ser)
}
val bits = port.bits
port.clock := false.B.asClock
port.bits.out.ready := false.B
port.bits.in.valid := false.B
port.bits.in.bits := DontCare
})
}
})
class WithSimSerial extends OverrideHarnessBinder({
class WithSimTSIOverSerialTL extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
ports.map({ port =>
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val bits = port.bits
port.clock := th.buildtopClock
withClockAndReset(th.buildtopClock, th.buildtopReset) {
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
val success = SerialAdapter.connectSimSerial(ram.module.io.tsi_ser, th.buildtopClock, th.buildtopReset.asBool)
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset)
val success = SimTSI.connect(Some(ram.module.io.tsi), th.buildtopClock, th.buildtopReset.asBool)
when (success) { th.success := true.B }
}
})
@@ -326,13 +332,14 @@ class WithUARTSerial extends OverrideHarnessBinder({
implicit val p = chipyard.iobinders.GetSystemParameters(system)
ports.map({ port =>
val freq = p(PeripheryBusKey).dtsFrequency.get
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val bits = port.bits
port.clock := th.buildtopClock
withClockAndReset(th.buildtopClock, th.buildtopReset) {
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset)
val uart_to_serial = Module(new UARTToSerial(freq, UARTParams(0)))
val serial_width_adapter = Module(new SerialWidthAdapter(
8, SerialAdapter.SERIAL_TSI_WIDTH))
ram.module.io.tsi_ser.flipConnect(serial_width_adapter.io.wide)
8, TSI.WIDTH))
ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide)
UARTAdapter.connect(Seq(uart_to_serial.io.uart), uart_to_serial.div)
serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial)
th.success := false.B
@@ -365,7 +372,8 @@ class WithCospike extends ComposeHarnessBinder({
mem0_size = p(ExtMem).map(_.master.size).getOrElse(BigInt(0)),
pmpregions = tiles.headOption.map(_.tileParams.core.nPMPs).getOrElse(0),
nharts = tiles.size,
bootrom = chipyardSystem.bootROM.map(_.module.contents.toArray.mkString(" ")).getOrElse("")
bootrom = chipyardSystem.bootROM.map(_.module.contents.toArray.mkString(" ")).getOrElse(""),
has_dtm = p(ExportDebug).protocols.contains(DMI) // assume that exposing clockeddmi means we will connect SimDTM
)
ports.map { p => p.traces.zipWithIndex.map(t => SpikeCosim(t._1, t._2, cfg)) }
}
@@ -385,8 +393,8 @@ class WithClockAndResetFromHarness extends OverrideHarnessBinder({
implicit val p = GetSystemParameters(system)
ports.map ({
case c: ClockWithFreq => {
th.setRefClockFreq(c.freqMHz)
c.clock := th.buildtopClock
val clock = th.harnessClockInstantiator.requestClockBundle(s"clock_${c.freqMHz}MHz", c.freqMHz * (1000 * 1000))
c.clock := clock.clock
}
case r: AsyncReset => r := th.buildtopReset.asAsyncReset
})

View File

@@ -0,0 +1,100 @@
package chipyard.harness
import chisel3._
import chisel3.util._
import chisel3.experimental.DoubleParam
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import freechips.rocketchip.diplomacy.{LazyModule}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.util.{ResetCatchAndSync}
import freechips.rocketchip.prci._
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders, HarnessClockInstantiatorKey}
import chipyard.iobinders.HasIOBinders
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
// HarnessClockInstantiators are classes which generate clocks that drive
// TestHarness simulation models and any Clock inputs to the ChipTop
trait HarnessClockInstantiator {
val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty
// request a clock bundle at a particular frequency
def requestClockBundle(name: String, freqRequested: Double): ClockBundle = {
if (_clockMap.contains(name)) {
require(freqRequested == _clockMap(name)._1,
s"Request clock freq = $freqRequested != previously requested ${_clockMap(name)._2} for requested clock $name")
_clockMap(name)._2
} else {
val clockBundle = Wire(new ClockBundle(ClockBundleParameters()))
_clockMap(name) = (freqRequested, clockBundle)
clockBundle
}
}
// refClock is the clock generated by TestDriver that is
// passed to the TestHarness as its implicit clock
def instantiateHarnessClocks(refClock: ClockBundle): Unit
}
class ClockSourceAtFreqMHz(val freqMHz: Double) extends BlackBox(Map(
"PERIOD" -> DoubleParam(1000/freqMHz)
)) with HasBlackBoxInline {
val io = IO(new ClockSourceIO)
val moduleName = this.getClass.getSimpleName
setInline(s"$moduleName.v",
s"""
|module $moduleName #(parameter PERIOD="") (
| input power,
| input gate,
| output clk);
| timeunit 1ns/1ps;
| reg clk_i = 1'b0;
| always #(PERIOD/2.0) clk_i = ~clk_i & (power & ~gate);
| assign clk = clk_i;
|endmodule
|""".stripMargin)
}
// The AbsoluteFreqHarnessClockInstantiator uses a Verilog blackbox to
// provide the precise requested frequency.
// This ClockInstantiator cannot be synthesized, run in Verilator, or run in FireSim
// It is useful for VCS/Xcelium-driven RTL simulations
class AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator {
def instantiateHarnessClocks(refClock: ClockBundle): Unit = {
val sinks = _clockMap.map({ case (name, (freq, bundle)) =>
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name))
}).toSeq
// connect wires to clock source
for (sinkParams <- sinks) {
val source = Module(new ClockSourceAtFreqMHz(sinkParams.take.get.freqMHz))
source.io.power := true.B
source.io.gate := false.B
_clockMap(sinkParams.name.get)._2.clock := source.io.clk
_clockMap(sinkParams.name.get)._2.reset := refClock.reset
}
}
}
class WithAbsoluteFreqHarnessClockInstantiator extends Config((site, here, up) => {
case HarnessClockInstantiatorKey => () => new AbsoluteFreqHarnessClockInstantiator
})
class AllClocksFromHarnessClockInstantiator extends HarnessClockInstantiator {
def instantiateHarnessClocks(refClock: ClockBundle): Unit = {
val freqs = _clockMap.map(_._2._1)
freqs.tail.foreach(t => require(t == freqs.head, s"Mismatching clocks $t != ${freqs.head}"))
for ((_, (_, bundle)) <- _clockMap) {
bundle.clock := refClock.clock
bundle.reset := refClock.reset
}
}
}
class WithAllClocksFromHarnessClockInstantiator extends Config((site, here, up) => {
case HarnessClockInstantiatorKey => () => new AllClocksFromHarnessClockInstantiator
})

View File

@@ -0,0 +1,64 @@
package chipyard.harness
import chisel3._
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import freechips.rocketchip.diplomacy.{LazyModule}
import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.util.{ResetCatchAndSync}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters}
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
import chipyard.iobinders.HasIOBinders
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
import chipyard.{ChipTop}
// -------------------------------
// Chipyard Test Harness
// -------------------------------
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz
case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]()
trait HasHarnessSignalReferences {
implicit val p: Parameters
val harnessClockInstantiator = p(HarnessClockInstantiatorKey)()
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
var refClockFreq: Double = p(DefaultClockFrequencyKey)
def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz }
def getRefClockFreq: Double = refClockFreq
def buildtopClock: Clock
def buildtopReset: Reset
def success: Bool
}
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
val io = IO(new Bundle {
val success = Output(Bool())
})
val buildtopClock = Wire(Clock())
val buildtopReset = Wire(Reset())
val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop")
val dut = Module(lazyDut.module)
io.success := false.B
val success = io.success
lazyDut match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
}
val refClkBundle = harnessClockInstantiator.requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
buildtopClock := refClkBundle.clock
buildtopReset := WireInit(refClkBundle.reset)
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := clock
implicitHarnessClockBundle.reset := reset
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
}

View File

@@ -6,7 +6,7 @@ package chipyard.stage.phases
import scala.util.Try
import scala.collection.mutable
import chipsalliance.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import chisel3.stage.phases.Elaborate
import firrtl.AnnotationSeq
import firrtl.annotations.{Annotation, NoTargetAnnotation}

View File

@@ -1,7 +1,7 @@
package chipyard.unittest
import chisel3._
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
class TestHarness(implicit val p: Parameters) extends Module {
val io = IO(new Bundle { val success = Output(Bool()) })

View File

@@ -1,6 +1,6 @@
package chipyard.unittest
import freechips.rocketchip.config.Parameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.util.{ElaborationArtefacts, PlusArgArtefacts}
class UnitTestSuite(implicit p: Parameters) extends freechips.rocketchip.unittest.UnitTestSuite {

View File

@@ -6,9 +6,9 @@ import chisel3._
import chisel3.experimental.annotate
import chisel3.util.experimental.BoringUtils
import freechips.rocketchip.config.{Field, Config, Parameters}
import org.chipsalliance.cde.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebugModuleImp}
import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebug}
import freechips.rocketchip.amba.axi4.{AXI4Bundle}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tile.{RocketTile}
@@ -30,7 +30,6 @@ import cva6.CVA6Tile
import boom.common.{BoomTile}
import barstools.iocell.chisel._
import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters, IOCellKey}
import chipyard.{HasHarnessSignalReferences}
import chipyard.harness._
object MainMemoryConsts {
@@ -68,15 +67,16 @@ class WithFireSimIOCellModels extends Config((site, here, up) => {
case IOCellKey => FireSimIOCellParams()
})
class WithSerialBridge extends OverrideHarnessBinder({
class WithTSIBridgeAndHarnessRAMOverSerialTL extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => {
ports.map { port =>
implicit val p = GetSystemParameters(system)
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val bits = port.bits
port.clock := th.buildtopClock
val ram = withClockAndReset(th.buildtopClock, th.buildtopReset) {
SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset)
}
SerialBridge(th.buildtopClock, ram.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.buildtopReset.asBool)
TSIBridge(th.buildtopClock, ram.module.io.tsi, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.buildtopReset.asBool)
}
Nil
}
@@ -125,16 +125,16 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({
axiClockBundle.clock := axiClock
axiClockBundle.reset := ResetCatchAndSync(axiClock, th.buildtopReset.asBool)
val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val serial_bits = port.bits
port.clock := th.buildtopClock
val harnessMultiClockAXIRAM = withClockAndReset(th.buildtopClock, th.buildtopReset) {
SerialAdapter.connectHarnessMultiClockAXIRAM(
TSIHarness.connectMultiClockAXIRAM(
system.serdesser.get,
serial_bits,
axiClockBundle,
th.buildtopReset)
}
SerialBridge(th.buildtopClock, harnessMultiClockAXIRAM.module.io.tsi_ser, Some(MainMemoryConsts.globalName), th.buildtopReset.asBool)
TSIBridge(th.buildtopClock, harnessMultiClockAXIRAM.module.io.tsi, Some(MainMemoryConsts.globalName), th.buildtopReset.asBool)
// connect SimAxiMem
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi4, edge) =>
@@ -232,7 +232,7 @@ class WithFireSimFAME5 extends ComposeIOBinder({
// Shorthand to register all of the provided bridges above
class WithDefaultFireSimBridges extends Config(
new WithSerialBridge ++
new WithTSIBridgeAndHarnessRAMOverSerialTL ++
new WithNICBridge ++
new WithUARTBridge ++
new WithBlockDeviceBridge ++
@@ -245,7 +245,7 @@ class WithDefaultFireSimBridges extends Config(
// Shorthand to register all of the provided mmio-only bridges above
class WithDefaultMMIOOnlyFireSimBridges extends Config(
new WithSerialBridge ++
new WithTSIBridgeAndHarnessRAMOverSerialTL ++
new WithUARTBridge ++
new WithBlockDeviceBridge ++
new WithFASEDBridge ++

View File

@@ -9,7 +9,7 @@ import chisel3.experimental.{IO}
import freechips.rocketchip.prci._
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
import freechips.rocketchip.config.{Field, Config, Parameters}
import org.chipsalliance.cde.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, InModuleBody, ValName}
import freechips.rocketchip.util.{ResetCatchAndSync, RecordMap}

View File

@@ -4,7 +4,7 @@ import java.io.File
import chisel3._
import chisel3.util.{log2Up}
import freechips.rocketchip.config.{Parameters, Config}
import org.chipsalliance.cde.config.{Parameters, Config}
import freechips.rocketchip.groundtest.TraceGenParams
import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
@@ -186,6 +186,22 @@ class FireSimRocketConfig extends Config(
new chipyard.RocketConfig)
// DOC include end: firesimconfig
class FireSimRocket1GiBDRAMConfig extends Config(
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 1L) ++
new FireSimRocketConfig)
class FireSimRocketMMIOOnly1GiBDRAMConfig extends Config(
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 1L) ++
new FireSimRocketMMIOOnlyConfig)
class FireSimRocket4GiBDRAMConfig extends Config(
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 4L) ++
new FireSimRocketConfig)
class FireSimRocketMMIOOnly4GiBDRAMConfig extends Config(
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 4L) ++
new FireSimRocketMMIOOnlyConfig)
class FireSimQuadRocketConfig extends Config(
new WithDefaultFireSimBridges ++
new WithDefaultMemModel ++

View File

@@ -2,7 +2,7 @@ package tracegen
import chisel3._
import chisel3.util.log2Ceil
import freechips.rocketchip.config.{Config, Parameters}
import org.chipsalliance.cde.config.{Config, Parameters}
import freechips.rocketchip.groundtest.{TraceGenParams, TraceGenTileAttachParams}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.system.BaseConfig

View File

@@ -1,9 +1,9 @@
package tracegen
import chisel3._
import freechips.rocketchip.config.{Field, Parameters}
import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, BufferParams}
import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple}
import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple, NullIntSyncSource, IntSyncXbar}
import freechips.rocketchip.groundtest.{DebugCombiner, TraceGenParams, GroundTestTile}
import freechips.rocketchip.subsystem._
import boom.lsu.BoomTraceGenTile
@@ -17,6 +17,7 @@ class TraceGenSystem(implicit p: Parameters) extends BaseSubsystem
case t: GroundTestTile => t.statusNode.makeSink()
case t: BoomTraceGenTile => t.statusNode.makeSink()
}
lazy val debugNode = IntSyncXbar() := NullIntSyncSource()
override lazy val module = new TraceGenSystemModuleImp(this)
}