Merge remote-tracking branch 'origin/main' into use-fat-jar
This commit is contained in:
Submodule generators/boom updated: deae9f7046...679f358755
@@ -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 ®write : 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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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._
|
||||
|
||||
19
generators/chipyard/src/main/scala/ConfigFinder.scala
Normal file
19
generators/chipyard/src/main/scala/ConfigFinder.scala
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
/**
|
||||
|
||||
123
generators/chipyard/src/main/scala/clocking/ClockBinders.scala
Normal file
123
generators/chipyard/src/main/scala/clocking/ClockBinders.scala
Normal 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)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -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._
|
||||
|
||||
@@ -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._
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
generators/chipyard/src/main/scala/clocking/FakePLL.scala
Normal file
36
generators/chipyard/src/main/scala/clocking/FakePLL.scala
Normal 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))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}: _*)
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}: _*)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
38
generators/chipyard/src/main/scala/config/ChipConfigs.scala
Normal file
38
generators/chipyard/src/main/scala/config/ChipConfigs.scala
Normal 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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package chipyard
|
||||
|
||||
import freechips.rocketchip.config.{Config}
|
||||
import org.chipsalliance.cde.config.{Config}
|
||||
|
||||
// ---------------------
|
||||
// Heterogenous Configs
|
||||
|
||||
@@ -2,7 +2,7 @@ package chipyard
|
||||
|
||||
import chisel3._
|
||||
|
||||
import freechips.rocketchip.config.{Config}
|
||||
import org.chipsalliance.cde.config.{Config}
|
||||
|
||||
// ---------------------
|
||||
// Ibex Configs
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package chipyard
|
||||
|
||||
import freechips.rocketchip.config.{Config}
|
||||
import org.chipsalliance.cde.config.{Config}
|
||||
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package chipyard
|
||||
|
||||
import freechips.rocketchip.config.{Config}
|
||||
import org.chipsalliance.cde.config.{Config}
|
||||
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
|
||||
|
||||
// --------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ++
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
|
||||
@@ -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._
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
145
generators/chipyard/src/main/scala/example/FlatChipTop.scala
Normal file
145
generators/chipyard/src/main/scala/example/FlatChipTop.scala
Normal 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))
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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._
|
||||
|
||||
@@ -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._
|
||||
|
||||
|
||||
@@ -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._
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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._
|
||||
|
||||
@@ -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._
|
||||
|
||||
@@ -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._
|
||||
|
||||
@@ -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._
|
||||
|
||||
@@ -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
|
||||
})
|
||||
100
generators/chipyard/src/main/scala/harness/HarnessClocks.scala
Normal file
100
generators/chipyard/src/main/scala/harness/HarnessClocks.scala
Normal 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
|
||||
})
|
||||
64
generators/chipyard/src/main/scala/harness/TestHarness.scala
Normal file
64
generators/chipyard/src/main/scala/harness/TestHarness.scala
Normal 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)
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
@@ -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()) })
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Submodule generators/constellation updated: 4606ee19b7...e9f1c828ca
Submodule generators/cva6 updated: 6a6184f292...b2729b3b17
Submodule generators/fft-generator updated: a31bd038dd...be8ab768bd
@@ -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 ++
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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 ++
|
||||
|
||||
Submodule generators/gemmini updated: 686cb15dad...80e7376cf5
Submodule generators/hwacha updated: e1be8e2a41...d01ca1e7f8
Submodule generators/ibex updated: 626127f229...916fb7a6ff
Submodule generators/icenet updated: 90d52a6a84...ce1ec55c1f
Submodule generators/mempress updated: b9eaedc061...295ae0854a
Submodule generators/nvdla updated: 2b17011b26...7130a5c0f7
Submodule generators/riscv-sodor updated: 1b169845e3...92379541aa
Submodule generators/rocket-chip updated: f5ebf26b36...25e2c63567
Submodule generators/sha3 updated: 8c5d244303...1fa5ef8ae5
Submodule generators/sifive-blocks updated: 4273925fdd...534d3b74a0
Submodule generators/sifive-cache updated: 850e12154c...02e002b324
Submodule generators/testchipip updated: dead693f8f...ebf61569c5
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user