Merge remote-tracking branch 'upstream/main' into graphics

This commit is contained in:
Hansung Kim
2023-07-22 14:45:48 -07:00
175 changed files with 5277 additions and 4019 deletions

View File

@@ -1,13 +1,44 @@
#include <cstdint>
#include <vector>
#include <string>
#include <riscv/sim.h>
#include <riscv/mmu.h>
#include <riscv/encoding.h>
#include <vpi_user.h>
#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)
#define CLINT_SIZE (0x10000)
#define UART_BASE (0x54000000)
#define UART_SIZE (0x1000)
#define PLIC_BASE (0xc000000)
#define PLIC_SIZE (0x4000000)
#define COSPIKE_PRINTF(...) { \
printf(__VA_ARGS__); \
fprintf(stderr, __VA_ARGS__); \
}
typedef struct system_info_t {
std::string isa;
@@ -16,14 +47,37 @@ typedef struct system_info_t {
uint64_t mem0_size;
int nharts;
std::vector<char> bootrom;
std::string priv;
};
class read_override_device_t : public abstract_device_t {
public:
read_override_device_t(std::string n, reg_t sz) : was_read_from(false), size(sz), name(n) { };
virtual bool load(reg_t addr, size_t len, uint8_t* bytes) override {
if (addr + len > size) return false;
COSPIKE_PRINTF("Read from device %s at %lx\n", name.c_str(), addr);
was_read_from = true;
return true;
}
virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) override {
COSPIKE_PRINTF("Store to device %s at %lx\n", name.c_str(), addr);
return (addr + len <= size);
}
bool was_read_from;
private:
reg_t size;
std::string name;
};
system_info_t* info = NULL;
sim_t* sim = NULL;
bool cospike_debug;
reg_t tohost_addr = 0;
reg_t fromhost_addr = 0;
reg_t cospike_timeout = 0;
std::set<reg_t> magic_addrs;
cfg_t* cfg;
std::vector<std::shared_ptr<read_override_device_t>> read_override_devices;
static std::vector<std::pair<reg_t, mem_t*>> make_mems(const std::vector<mem_cfg_t> &layout)
{
@@ -35,14 +89,16 @@ static std::vector<std::pair<reg_t, mem_t*>> make_mems(const std::vector<mem_cfg
return mems;
}
extern "C" void cospike_set_sysinfo(char* isa, int pmpregions,
extern "C" void cospike_set_sysinfo(char* isa, char* priv, int pmpregions,
long long int mem0_base, long long int mem0_size,
int nharts,
char* bootrom
) {
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->priv = std::string(priv);
info->pmpregions = pmpregions;
info->mem0_base = mem0_base;
info->mem0_size = mem0_size;
@@ -64,11 +120,13 @@ 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) {
printf("Configuring spike cosim\n");
if (unlikely(!sim)) {
COSPIKE_PRINTF("Configuring spike cosim\n");
std::vector<mem_cfg_t> mem_cfg;
std::vector<size_t> hartids;
mem_cfg.push_back(mem_cfg_t(info->mem0_base, info->mem0_size));
@@ -78,7 +136,7 @@ extern "C" void cospike_cosim(long long int cycle,
cfg = new cfg_t(std::make_pair(0, 0),
nullptr,
info->isa.c_str(),
"MSU",
info->priv.c_str(),
"vlen:128,elen:64",
false,
endianness_little,
@@ -91,34 +149,48 @@ extern "C" void cospike_cosim(long long int cycle,
std::vector<std::pair<reg_t, mem_t*>> mems = make_mems(cfg->mem_layout());
rom_device_t *boot_rom = new rom_device_t(info->bootrom);
mem_t *boot_addr_reg = new mem_t(0x1000);
size_t default_boot_rom_size = 0x10000;
size_t default_boot_rom_addr = 0x10000;
assert(info->bootrom.size() < default_boot_rom_size);
info->bootrom.resize(default_boot_rom_size);
std::shared_ptr<rom_device_t> boot_rom = std::make_shared<rom_device_t>(info->bootrom);
std::shared_ptr<mem_t> boot_addr_reg = std::make_shared<mem_t>(0x1000);
uint64_t default_boot_addr = 0x80000000;
boot_addr_reg->store(0, 8, (const uint8_t*)(&default_boot_addr));
boot_addr_reg.get()->store(0, 8, (const uint8_t*)(&default_boot_addr));
// Don't actually build a clint
mem_t* clint_mem = new mem_t(CLINT_SIZE);
std::shared_ptr<read_override_device_t> clint = std::make_shared<read_override_device_t>("clint", CLINT_SIZE);
std::shared_ptr<read_override_device_t> uart = std::make_shared<read_override_device_t>("uart", UART_SIZE);
std::shared_ptr<read_override_device_t> plic = std::make_shared<read_override_device_t>("plic", PLIC_SIZE);
std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices;
read_override_devices.push_back(clint);
read_override_devices.push_back(uart);
read_override_devices.push_back(plic);
std::vector<std::pair<reg_t, std::shared_ptr<abstract_device_t>>> devices;
// The device map is hardcoded here for now
plugin_devices.push_back(std::pair(0x4000, boot_addr_reg));
plugin_devices.push_back(std::pair(0x10000, boot_rom));
plugin_devices.push_back(std::pair(CLINT_BASE, clint_mem));
devices.push_back(std::pair(0x4000, boot_addr_reg));
devices.push_back(std::pair(default_boot_rom_addr, boot_rom));
devices.push_back(std::pair(CLINT_BASE, clint));
devices.push_back(std::pair(UART_BASE, uart));
devices.push_back(std::pair(PLIC_BASE, plic));
s_vpi_vlog_info vinfo;
if (!vpi_get_vlog_info(&vinfo))
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") {
in_permissive = true;
} else if (arg == "+permissive-off") {
in_permissive = false;
} else if (arg == "+cospike_debug") {
} else if (arg == "+cospike_debug" || arg == "+cospike-debug") {
cospike_debug = true;
} else if (arg.find("+cospike-timeout=") == 0) {
cospike_timeout = strtoull(arg.substr(17).c_str(), 0, 10);
} else if (!in_permissive) {
htif_args.push_back(arg);
}
@@ -136,14 +208,17 @@ extern "C" void cospike_cosim(long long int cycle,
.support_impebreak = true
};
printf("%s\n", info->isa.c_str());
COSPIKE_PRINTF("isa string: %s\n", info->isa.c_str());
COSPIKE_PRINTF("htif args: ");
for (int i = 0; i < htif_args.size(); i++) {
printf("%s\n", htif_args[i].c_str());
COSPIKE_PRINTF("%s", htif_args[i].c_str());
}
COSPIKE_PRINTF("\n");
std::vector<const device_factory_t*> plugin_device_factories;
sim = new sim_t(cfg, false,
mems,
plugin_devices,
plugin_device_factories,
htif_args,
dm_config,
nullptr,
@@ -152,107 +227,274 @@ extern "C" void cospike_cosim(long long int cycle,
false,
nullptr
);
for (auto &it : devices)
sim->add_device(it.first, it.second);
#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;
COSPIKE_PRINTF("Matching spike memory initial state for region %lx-%lx\n", base, base + size);
if (!temp_mem_bus.store(base, size, pair.second.data)) {
COSPIKE_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++) {
// Use our own reset vector
sim->get_core(hartid)->get_state()->pc = 0x10040;
// Set MMU to support up to sv39, as our normal hw configs do
sim->get_core(hartid)->set_impl(IMPL_MMU_SV48, false);
sim->get_core(hartid)->set_impl(IMPL_MMU_SV57, false);
// HACKS: Our processor's don't implement zicntr fully, they don't provide time
sim->get_core(hartid)->get_state()->csrmap.erase(CSR_TIME);
}
sim->set_debug(cospike_debug);
printf("Setting up htif for spike cosim\n");
sim->set_histogram(true);
sim->set_procs_debug(cospike_debug);
COSPIKE_PRINTF("Setting up htif for spike cosim\n");
((htif_t*)sim)->start();
printf("Spike cosim started\n");
COSPIKE_PRINTF("Spike cosim started\n");
tohost_addr = ((htif_t*)sim)->get_tohost_addr();
fromhost_addr = ((htif_t*)sim)->get_fromhost_addr();
printf("Tohost : %lx\n", tohost_addr);
printf("Fromhost: %lx\n", fromhost_addr);
COSPIKE_PRINTF("Tohost : %lx\n", tohost_addr);
COSPIKE_PRINTF("Fromhost: %lx\n", fromhost_addr);
COSPIKE_PRINTF("BootROM base : %lx\n", default_boot_rom_addr);
COSPIKE_PRINTF("BootROM size : %lx\n", boot_rom->contents().size());
COSPIKE_PRINTF("Memory base : %lx\n", info->mem0_base);
COSPIKE_PRINTF("Memory size : %lx\n", info->mem0_size);
}
if (priv & 0x4) { // debug
return;
}
if (cospike_timeout && cycle > cospike_timeout) {
if (sim) {
COSPIKE_PRINTF("Cospike reached timeout cycles = %ld, terminating\n", cospike_timeout);
delete sim;
}
exit(0);
}
processor_t* p = sim->get_core(hartid);
state_t* s = p->get_state();
#ifdef COSPIKE_DTM
if (dtm && dtm->loadarch_done && !spike_loadarch_done) {
COSPIKE_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) {
COSPIKE_PRINTF("VLEN mismatch loadarch: $d != spike: $d\n", ls.VLEN, p->VU.VLEN);
abort();
}
if (ls.ELEN != p->VU.ELEN) {
COSPIKE_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 stip_interrupt = interrupt_cause == 0x5;
bool mtip_interrupt = interrupt_cause == 0x7;
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) {
COSPIKE_PRINTF("%d interrupt %lx\n", cycle, cause);
if (ssip_interrupt || stip_interrupt) {
// do nothing
} else if (msip_interrupt) {
s->mip->backdoor_write_with_mask(MIP_MSIP, MIP_MSIP);
} else if (mtip_interrupt) {
s->mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP);
} else if (debug_interrupt) {
return;
} else {
printf("Unknown interrupt %lx\n", interrupt_cause);
COSPIKE_PRINTF("Unknown interrupt %lx\n", interrupt_cause);
abort();
}
}
if (raise_exception)
printf("%d exception %lx\n", cycle, cause);
COSPIKE_PRINTF("%d exception %lx\n", cycle, cause);
if (valid) {
printf("%d Cosim: %lx", cycle, iaddr);
if (has_wdata) {
printf(" %lx", wdata);
}
printf("\n");
p->clear_waiting_for_interrupt();
COSPIKE_PRINTF("%d Cosim: %lx", cycle, iaddr);
// if (has_wdata) {
// COSPIKE_PRINTF(" s: %lx", wdata);
// }
COSPIKE_PRINTF("\n");
}
if (valid || raise_interrupt || raise_exception)
if (valid || raise_interrupt || raise_exception) {
p->clear_waiting_for_interrupt();
for (auto& e : read_override_devices) e.get()->was_read_from = false;
p->step(1);
if (unlikely(cospike_debug)) {
COSPIKE_PRINTF("spike pc is %lx\n", s->pc);
COSPIKE_PRINTF("spike mstatus is %lx\n", s->mstatus->read());
COSPIKE_PRINTF("spike mip is %lx\n", s->mip->read());
COSPIKE_PRINTF("spike mie is %lx\n", s->mie->read());
COSPIKE_PRINTF("spike wfi state is %d\n", p->is_waiting_for_interrupt());
}
}
if (valid) {
if (valid && !raise_exception) {
if (s_pc != iaddr) {
printf("%d PC mismatch %lx != %lx\n", cycle, s_pc, iaddr);
COSPIKE_PRINTF("%d PC mismatch spike %llx != DUT %llx\n", cycle, s_pc, iaddr);
if (unlikely(cospike_debug)) {
COSPIKE_PRINTF("spike mstatus is %lx\n", s->mstatus->read());
COSPIKE_PRINTF("spike mcause is %lx\n", s->mcause->read());
COSPIKE_PRINTF("spike mtval is %lx\n" , s->mtval->read());
COSPIKE_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);
}
if ((waddr == CLINT_BASE + 0x4000 + 4*hartid)) {
s->mip->backdoor_write_with_mask(MIP_MTIP, 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)) {
COSPIKE_PRINTF("Probable magic mem %lx\n", w_data);
magic_addrs.insert(w_data);
}
}
if (has_wdata) {
auto& log = s->log_reg_write;
auto& mem_read = s->log_mem_read;
bool scalar_wb = false;
bool vector_wb = false;
uint32_t vector_cnt = 0;
for (auto &regwrite : log) {
//TODO: scaling to multi issue reads?
reg_t mem_read_addr = mem_read.empty() ? 0 : std::get<0>(mem_read[0]);
for (auto regwrite : log) {
int rd = regwrite.first >> 4;
int type = regwrite.first & 0xf;
// 0 => int
// 1 => fp
// 2 => vec
// 3 => vec hint
// 4 => csr
if ((rd != 0 && type == 0) || type == 1) {
// Override reads from some CSRs
uint64_t csr_addr = (insn >> 20) & 0xfff;
bool csr_read = (insn & 0x7f) == 0x73;
if (csr_read) printf("CSR read %lx\n", csr_addr);
if (csr_read && (
(csr_addr == 0x301) || // misa
(csr_addr == 0xf13) || // mimpid
(csr_addr == 0xf12) || // marchid
(csr_addr == 0xf11) || // mvendorid
(csr_addr == 0xb00) || // mcycle
(csr_addr == 0xb02) || // minstret
(csr_addr >= 0x3b0 && csr_addr <= 0x3ef) // pmpaddr
)) {
printf("CSR override\n");
s->XPR.write(rd, wdata);
} else if (!mem_read.empty() && ((magic_addrs.count(mem_read_addr) ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr) ||
(CLINT_BASE <= mem_read_addr && mem_read_addr < (CLINT_BASE + CLINT_SIZE))
))) {
// Don't check reads from tohost, reads from magic memory, or reads from clint
// Technically this could be buggy because log_mem_read only reports vaddrs, but
// no software ever should access tohost/fromhost/clint with vaddrs anyways
printf("Read override %lx\n", mem_read_addr);
s->XPR.write(rd, wdata);
} else if (wdata != regwrite.second.v[0]) {
printf("%d wdata mismatch reg %d %lx != %lx\n", cycle, rd, regwrite.second.v[0], wdata);
exit(1);
}
}
int rd = regwrite.first >> 4;
int type = regwrite.first & 0xf;
// 0 => int
// 1 => fp
// 2 => vec
// 3 => vec hint
// 4 => csr
bool device_read = false;
for (auto& e : read_override_devices) if (e.get()->was_read_from) device_read = true;
bool lr_read = ((insn & MASK_LR_D) == MATCH_LR_D) || ((insn & MASK_LR_W) == MATCH_LR_W);
bool sc_read = ((insn & MASK_SC_D) == MATCH_SC_D) || ((insn & MASK_SC_W) == MATCH_SC_W);
bool ignore_read = sc_read || (!mem_read.empty() &&
(magic_addrs.count(mem_read_addr) ||
device_read ||
lr_read ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr)));
// 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)
COSPIKE_PRINTF("CSR read %lx\n", csr_addr);
if (csr_read && ((csr_addr == 0x301) || // misa
(csr_addr == 0x306) || // mcounteren
(csr_addr == 0xf13) || // mimpid
(csr_addr == 0xf12) || // marchid
(csr_addr == 0xf11) || // mvendorid
(csr_addr == 0xb00) || // mcycle
(csr_addr == 0xb02) || // minstret
(csr_addr == 0xc00) || // cycle
(csr_addr == 0xc01) || // time
(csr_addr == 0xc02) || // instret
(csr_addr >= 0x7a0 && csr_addr <= 0x7aa) || // debug trigger registers
(csr_addr >= 0x3b0 && csr_addr <= 0x3ef) // pmpaddr
)) {
COSPIKE_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
COSPIKE_PRINTF("Read override %lx = %lx\n", mem_read_addr, wdata);
s->XPR.write(rd, wdata);
} else if (wdata != regwrite.second.v[0]) {
COSPIKE_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) {
// COSPIKE_PRINTF("Scalar wdata behavior divergence between spike and DUT\n");
// exit(-1);
// }
}
}
}
// }

View File

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

View File

@@ -2,13 +2,22 @@
#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>
#include "testchip_tsi.h"
extern testchip_tsi_t* tsi;
#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,
@@ -80,10 +89,11 @@ public:
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(const char* fname);
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; }
@@ -109,6 +119,7 @@ public:
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,
@@ -324,7 +335,7 @@ extern "C" void spike_tile(int hartid, char* isa,
}
}
if (loadmem_file != "" && tcm_size > 0)
simif->loadmem(loadmem_file.c_str());
simif->loadmem(tcm_base, loadmem_file.c_str());
p->reset();
p->get_state()->pc = reset_vector;
@@ -334,14 +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 (!simif->htif && tsi) {
simif->htif = (htif_t*) tsi;
}
#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);
@@ -350,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) {
@@ -439,6 +459,7 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
std::vector<size_t>(),
false,
0),
accessed_tofrom_host(false),
icache_ways(icache_ways),
icache_sets(icache_sets),
dcache_ways(dcache_ways),
@@ -504,6 +525,12 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
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) {
for (auto& r: cacheables) {
if (addr >= r.base && addr < r.base + r.size) {
@@ -544,6 +571,12 @@ 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;
@@ -579,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);
}
@@ -605,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;
@@ -911,6 +947,13 @@ 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;
@@ -936,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;
@@ -1009,30 +1054,28 @@ bool chipyard_simif_t::tcm_d(uint64_t* data) {
return true;
}
#define parse_nibble(c) ((c) >= 'a' ? (c)-'a'+10 : (c)-'0')
void chipyard_simif_t::loadmem(const char* fname) {
std::ifstream in(fname);
std::string line;
if (!in.is_open()) {
printf("SpikeTile couldn't open loadmem file %s\n", fname);
abort();
}
size_t fsize = 0;
size_t start = 0;
while (std::getline(in, line)) {
for (ssize_t i = line.length()-2, j = 0; i >= 0; i -= 2, j++) {
char byte = (parse_nibble(line[i]) << 4) | parse_nibble(line[i+1]);
ssize_t addr = (start + j) % tcm_size;
tcm[addr] = (uint8_t)byte;
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);
}
start += line.length()/2;
fsize += line.length()/2;
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);
if (fsize > tcm_size) {
fprintf(stderr, "Loadmem file is too large\n");
abort();
}
}
reg_t entry;
load_elf(fname, &loadmem_memif, &entry);
}
bool insn_should_fence(uint64_t bits) {
@@ -1060,33 +1103,31 @@ void spike_thread_main(void* arg)
// if (insn_should_fence(last_bits) && !simif->stq_empty()) {
// host->switch_to();
// }
uint64_t old_minstret = state->minstret->read();
proc->step(1);
tile->max_insns--;
if (proc->is_waiting_for_interrupt()) {
if (simif->fast_clint) {
// uint64_t mip = state->mip->read();
// uint64_t mie = state->mie->read();
//printf("Setting MTIP %x %x %x %x %lx\n", simif->cycle, old_minstret, mip, mie,
// state->pc);
state->mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP);
tile->max_insns = tile->max_insns <= 1 ? 0 : 1;
} else {
//printf("SpikeTile in WFI\n");
tile->max_insns = 0;
}
}
if (tile->max_insns % 100 == 0) {
uint64_t old_minstret = state->minstret->read();
uint64_t tohost_addr = simif->htif ? simif->htif->get_tohost_addr() : 0;
uint64_t fromhost_addr = simif->htif ? simif->htif->get_fromhost_addr() : 0;
auto& mem_read = state->log_mem_read;
reg_t mem_read_addr = mem_read.empty() ? 0 : std::get<0>(mem_read[0]);
if ((old_minstret == state->minstret->read()) ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr)) {
tile->max_insns == 0;
if (state->debug_mode) {
// TODO: Fix. This needs to apply the same hack as rocket-chip...
// JALRs in debug mode should flush the ICache.
// There is no API to determine if a JALR was executed, so hack the
// pc of the JALR in the debug rom here instead.
if (state->pc == 0x838) {
simif->flush_icache();
}
}
// If we get stuck in WFI, or we start polling tohost/fromhost, switch to host thread
if ((old_minstret == state->minstret->read()) || simif->accessed_tofrom_host) {
tile->max_insns = 0;
}
state->mcycle->write(simif->cycle);
}
}

View File

@@ -1,5 +1,6 @@
import "DPI-C" function void cospike_set_sysinfo(
input string isa,
input string priv,
input int pmpregions,
input longint mem0_base,
input longint mem0_size,
@@ -16,12 +17,14 @@ 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
);
module SpikeCosim #(
parameter ISA,
parameter PRIV,
parameter PMPREGIONS,
parameter MEM0_BASE,
parameter MEM0_SIZE,
@@ -42,6 +45,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,11 +54,12 @@ 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
cospike_set_sysinfo(ISA, PMPREGIONS, MEM0_BASE, MEM0_SIZE, NHARTS, BOOTROM);
cospike_set_sysinfo(ISA, PRIV, PMPREGIONS, MEM0_BASE, MEM0_SIZE, NHARTS, BOOTROM);
end;
always @(posedge clock) begin
@@ -62,12 +67,12 @@ module SpikeCosim #(
if (trace_0_valid || trace_0_exception || trace_0_cause) begin
cospike_cosim(cycle, hartid, trace_0_has_wdata, trace_0_valid, trace_0_iaddr,
trace_0_insn, trace_0_exception, trace_0_interrupt, trace_0_cause,
trace_0_wdata);
trace_0_wdata, trace_0_priv);
end
if (trace_1_valid || trace_1_exception || trace_1_cause) begin
cospike_cosim(cycle, hartid, trace_1_has_wdata, trace_1_valid, trace_1_iaddr,
trace_1_insn, trace_1_exception, trace_1_interrupt, trace_1_cause,
trace_1_wdata);
trace_1_wdata, trace_1_priv);
end
end
end

View File

@@ -14,15 +14,18 @@ import testchipip.TileTraceIO
case class SpikeCosimConfig(
isa: String,
priv: String,
pmpregions: Int,
mem0_base: BigInt,
mem0_size: BigInt,
nharts: Int,
bootrom: String
bootrom: String,
has_dtm: Boolean
)
class SpikeCosim(cfg: SpikeCosimConfig) extends BlackBox(Map(
"ISA" -> StringParam(cfg.isa),
"PRIV" -> StringParam(cfg.priv),
"PMPREGIONS" -> IntParam(cfg.pmpregions),
"MEM0_BASE" -> IntParam(cfg.mem0_base),
"MEM0_SIZE" -> IntParam(cfg.mem0_size),
@@ -32,6 +35,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 +50,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,25 +69,23 @@ 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) {
cosim.io.trace(i).valid := trace.insns(i).valid
val insn = trace.trace.insns(i)
cosim.io.trace(i).valid := insn.valid
val signed = Wire(SInt(64.W))
signed := trace.insns(i).iaddr.asSInt
signed := insn.iaddr.asSInt
cosim.io.trace(i).iaddr := signed.asUInt
cosim.io.trace(i).insn := trace.insns(i).insn
cosim.io.trace(i).exception := trace.insns(i).exception
cosim.io.trace(i).interrupt := trace.insns(i).interrupt
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).insn := insn.insn
cosim.io.trace(i).exception := insn.exception
cosim.io.trace(i).interrupt := insn.interrupt
cosim.io.trace(i).cause := insn.cause
cosim.io.trace(i).has_wdata := insn.wdata.isDefined.B
cosim.io.trace(i).wdata := insn.wdata.getOrElse(0.U)
cosim.io.trace(i).priv := insn.priv
}
}
}

View File

@@ -13,10 +13,11 @@ import freechips.rocketchip.devices.tilelink._
// DOC include start: DigitalTop
class DigitalTop(implicit p: Parameters) extends ChipyardSystem
with testchipip.CanHavePeripheryUARTTSI // Enables optional UART-based TSI transport
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.CanHaveBankedScratchpad // Enables optionally adding a banked scratchpad
with testchipip.CanHavePeripheryBlockDevice // Enables optionally adding the block device
with testchipip.CanHavePeripheryTLSerial // Enables optionally adding the backing memory and serial adapter
with sifive.blocks.devices.i2c.HasPeripheryI2C // Enables optionally adding the sifive I2C

View File

@@ -1,96 +0,0 @@
package chipyard
import chisel3._
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}
import chipyard.iobinders.HasIOBinders
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
import chipyard.HarnessClockInstantiatorKey
// 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 = {
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
}
// The DividerOnlyHarnessClockInstantiator uses synthesizable clock divisors
// to approximate frequency ratios between the requested clocks
class DividerOnlyHarnessClockInstantiator extends HarnessClockInstantiator {
// connect all clock wires specified to a divider only PLL
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
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
}
}
}
// 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 ClockSourceAtFreq(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
})

View File

@@ -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}
@@ -304,6 +303,15 @@ class WithSerialTLIOCells extends OverrideIOBinder({
}).getOrElse((Nil, Nil))
})
class WithSerialTLPunchthrough extends OverrideIOBinder({
(system: CanHavePeripheryTLSerial) => system.serial_tl.map({ s =>
val sys = system.asInstanceOf[BaseSubsystem]
val port = IO(s.getWrappedValue.cloneType)
port <> s.getWrappedValue
(Seq(port), Nil)
}).getOrElse((Nil, Nil))
})
class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({
(system: CanHaveMasterAXI4MemPort) => {
implicit val p: Parameters = GetSystemParameters(system)
@@ -412,6 +420,15 @@ class WithCustomBootPin extends OverrideIOBinder({
}).getOrElse((Nil, Nil))
})
class WithUARTTSIPunchthrough extends OverrideIOBinder({
(system: CanHavePeripheryUARTTSI) => system.uart_tsi.map({ p =>
val sys = system.asInstanceOf[BaseSubsystem]
val uart_tsi = IO(new UARTTSIIO(p.uartParams))
uart_tsi <> p
(Seq(uart_tsi), Nil)
}).getOrElse((Nil, Nil))
})
class WithTLMemPunchthrough extends OverrideIOBinder({
(system: CanHaveMasterTLMemPort) => {
val io_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.mem_tl)).suggestName("tl_slave")

View File

@@ -7,6 +7,7 @@ import chisel3.experimental.{IntParam, StringParam, IO}
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._
@@ -61,6 +62,7 @@ case class SpikeCoreParams() extends CoreParams {
val useBitManipCrypto = false
val useCryptoNIST = false
val useCryptoSM = false
val useConditionalZero = false
override def vLen = 128
override def vMemDataBits = 128
@@ -189,7 +191,8 @@ class SpikeBlackBox(
readonly_uncacheable_regions: String,
executable_regions: String,
tcm_base: BigInt,
tcm_size: BigInt) extends BlackBox(Map(
tcm_size: BigInt,
use_dtm: Boolean) extends BlackBox(Map(
"HARTID" -> IntParam(hartId),
"ISA" -> StringParam(isa),
"PMPREGIONS" -> IntParam(pmpregions),
@@ -302,7 +305,11 @@ class SpikeBlackBox(
})
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) {
@@ -326,13 +333,18 @@ 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,
outer.spikeTileParams.tcmParams.map(_.base).getOrElse(0),
outer.spikeTileParams.tcmParams.map(_.size).getOrElse(0)
outer.spikeTileParams.tcmParams.map(_.size).getOrElse(0),
useDTM
))
spike.io.clock := clock.asBool
val cycle = RegInit(0.U(64.W))
@@ -421,7 +433,7 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
spike.io.mmio.a.ready := mmio_tl.a.ready
mmio_tl.a.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 })
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)

View File

@@ -1,63 +0,0 @@
package chipyard
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}
// -------------------------------
// 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](() => new DividerOnlyHarnessClockInstantiator)
trait HasHarnessSignalReferences {
implicit val p: Parameters
val harnessClockInstantiator = p(HarnessClockInstantiatorKey)()
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
var refClockFreq: Double = p(DefaultClockFrequencyKey)
def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz }
def getRefClockFreq: Double = refClockFreq
def buildtopClock: Clock
def buildtopReset: Reset
def success: Bool
}
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
val io = IO(new Bundle {
val success = Output(Bool())
})
val buildtopClock = Wire(Clock())
val buildtopReset = Wire(Reset())
val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop")
val dut = Module(lazyDut.module)
io.success := false.B
val success = io.success
lazyDut match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
}
val refClkBundle = harnessClockInstantiator.requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
buildtopClock := refClkBundle.clock
buildtopReset := WireInit(refClkBundle.reset)
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
implicitHarnessClockBundle.clock := clock
implicitHarnessClockBundle.reset := reset
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
}

View File

@@ -13,53 +13,11 @@ class ClockWithFreq(val freqMHz: Double) extends Bundle {
val clock = Clock()
}
// This uses synthesizable clock divisors to approximate frequency rations
// between the requested clocks. This is currently the defualt clock generator "model",
// as it can be used in VCS/Xcelium/Verilator/FireSim
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)
}
}
})
// 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 verilator or firesim
// Note: This will not simulate properly with firesim
class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
// Connect the implicit clock
@@ -80,9 +38,9 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
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() }
clockDivider.tlNode := system.prci_ctrl_domain { TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := system.prci_ctrl_bus.get }
clockSelector.tlNode := system.prci_ctrl_domain { TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := system.prci_ctrl_bus.get }
pllCtrl.tlNode := system.prci_ctrl_domain { TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := system.prci_ctrl_bus.get }
system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode
@@ -100,7 +58,7 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
pllCtrlSink := pllCtrl.ctrlNode
InModuleBody {
val clock_wire = Wire(Input(new ClockWithFreq(80)))
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))
@@ -125,3 +83,43 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
}
}
})
// 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) =>
require(m.take.isDefined, s"""Clock ${m.name.get} has no requested frequency
|Clocks: ${edge.sink.members.map(_.name.get)}""".stripMargin)
val freq = m.take.get.freqMHz
val clock_io = IO(Input(new ClockWithFreq(freq))).suggestName(s"clock_${m.name.get}")
b.clock := clock_io.clock
b.reset := reset_io
clock_io
}.toSeq
((clock_ios :+ reset_io), Nil)
}
}
})

View File

@@ -23,10 +23,9 @@ object ClockGroupCombiner {
case object ClockGroupCombinerKey extends Field[Seq[(String, ClockSinkParameters => Boolean)]](Nil)
// All clock groups with a name containing any substring in names will be combined into a single clock group
class WithClockGroupsCombinedByName(grouped_name: String, names: String*) extends Config((site, here, up) => {
case ClockGroupCombinerKey => {
val combiner: ClockSinkParameters => Boolean = { m => names.map(n => m.name.get.contains(n)).reduce(_||_) }
up(ClockGroupCombinerKey) ++ Seq((grouped_name, combiner))
class WithClockGroupsCombinedByName(groups: (String, Seq[String], Seq[String])*) extends Config((site, here, up) => {
case ClockGroupCombinerKey => groups.map { case (grouped_name, matched_names, unmatched_names) =>
(grouped_name, (m: ClockSinkParameters) => matched_names.exists(n => m.name.get.contains(n)) && !unmatched_names.exists(n => m.name.get.contains(n)))
}
})
@@ -49,9 +48,14 @@ class ClockGroupCombiner(implicit p: Parameters, v: ValName) extends LazyModule
val name = combiners(i)._1
i = i + 1
require(g.size >= 1)
require(g.forall(_.take.get == g.head.take.get))
(grouped ++ Seq(ClockSinkParameters(take = g.head.take, name = Some(name))), r)
val takes = g.map(_.take).flatten
require(takes.distinct.size <= 1,
s"Clock group $name has non-homogeneous requested ClockParameters $takes")
require(takes.size > 0,
s"Clock group $name has no inheritable frequencies")
(grouped ++ Seq(ClockSinkParameters(take = takes.headOption, name = Some(name))), r)
}
ClockGroupSinkParameters(
name = u.name,
members = grouped ++ rest

View File

@@ -60,23 +60,23 @@ object ClockGroupNamePrefixer {
* The default if all functions return None.
*/
object ClockGroupFrequencySpecifier {
def apply(
assigners: Seq[(String) => Option[Double]],
defaultFreq: Double)(
implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = {
def apply(assigners: Seq[(String) => Option[Double]])(
implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = {
def lookupFrequencyForName(clock: ClockSinkParameters): ClockSinkParameters = {
require(clock.name.nonEmpty, "All clocks in clock group must have an assigned name")
val clockFreq = assigners.foldLeft(defaultFreq)(
(currentFreq, candidateFunc) => candidateFunc(clock.name.get).getOrElse(currentFreq))
clock.copy(take = clock.take match {
case Some(cp) =>
println(s"Clock ${clock.name.get}: using diplomatically specified frequency of ${cp.freqMHz}.")
Some(cp)
case None => Some(ClockParameters(clockFreq))
})
}
def lookupFrequencyForName(clock: ClockSinkParameters): ClockSinkParameters = clock.copy(take = clock.take match {
case Some(cp) =>
println(s"Clock ${clock.name.get}: using diplomatically specified frequency of ${cp.freqMHz}.")
Some(cp)
case None => {
val freqs = assigners.map { f => f(clock.name.get) }.flatten
if (freqs.size > 0) {
println(s"Clock ${clock.name.get}: using specified frequency of ${freqs.last}")
Some(ClockParameters(freqs.last))
} else {
None
}
}
})
LazyModule(new ClockGroupParameterModifier(sinkFn = { s => s.copy(members = s.members.map(lookupFrequencyForName)) })).node
}

View File

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

View File

@@ -14,15 +14,17 @@ import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.prci._
import testchipip.{TLTileResetCtrl}
import chipyard.{DefaultClockFrequencyKey}
import testchipip.{TLTileResetCtrl, ClockGroupFakeResetSynchronizer}
case class ChipyardPRCIControlParams(
slaveWhere: TLBusWrapperLocation = CBUS,
baseAddress: BigInt = 0x100000,
enableTileClockGating: Boolean = true,
enableTileResetSetting: Boolean = true
)
enableTileResetSetting: Boolean = true,
enableResetSynchronizers: Boolean = true // this should only be disabled to work around verilator async-reset initialization problems
) {
def generatePRCIXBar = enableTileClockGating || enableTileResetSetting
}
case object ChipyardPRCIControlKey extends Field[ChipyardPRCIControlParams](ChipyardPRCIControlParams())
@@ -37,6 +39,13 @@ trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesTiles =>
val prci_ctrl_domain = LazyModule(new ClockSinkDomain(name=Some("chipyard-prci-control")))
prci_ctrl_domain.clockNode := tlbus.fixedClockNode
val prci_ctrl_bus = Option.when(prciParams.generatePRCIXBar) { prci_ctrl_domain { TLXbar() } }
prci_ctrl_bus.foreach(xbar => tlbus.coupleTo("prci_ctrl") { (xbar
:= TLFIFOFixer(TLFIFOFixer.all)
:= TLBuffer()
:= _)
})
// Aggregate all the clock groups into a single node
val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node
val allClockGroupsNode = ClockGroupEphemeralNode()
@@ -70,21 +79,47 @@ trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesTiles =>
// 5. Add reset control registers to the tiles (if desired)
// The final clock group here contains physically distinct clock domains, which some PRCI node in a
// diplomatic IOBinder should drive
val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey))
val clockGroupCombiner = ClockGroupCombiner()
val resetSynchronizer = ClockGroupResetSynchronizer()
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() }
val resetSynchronizer = prci_ctrl_domain {
if (prciParams.enableResetSynchronizers) ClockGroupResetSynchronizer() else ClockGroupFakeResetSynchronizer()
}
val tileClockGater = Option.when(prciParams.enableTileClockGating) { prci_ctrl_domain {
val clock_gater = LazyModule(new TileClockGater(prciParams.baseAddress + 0x00000, tlbus.beatBytes))
clock_gater.tlNode := TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := prci_ctrl_bus.get
clock_gater
} }
val tileResetSetter = Option.when(prciParams.enableTileResetSetting) { prci_ctrl_domain {
val reset_setter = LazyModule(new TileResetSetter(prciParams.baseAddress + 0x10000, tlbus.beatBytes,
tile_prci_domains.map(_.tile_reset_domain.clockNode.portParams(0).name.get), Nil))
reset_setter.tlNode := TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := prci_ctrl_bus.get
reset_setter
} }
if (!prciParams.enableResetSynchronizers) {
println(Console.RED + s"""
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
WARNING:
DISABLING THE RESET SYNCHRONIZERS RESULTS IN
A BROKEN DESIGN THAT WILL NOT BEHAVE
PROPERLY AS ASIC OR FPGA.
THESE SHOULD ONLY BE DISABLED TO WORK AROUND
LIMITATIONS IN ASYNC RESET INITIALIZATION IN
RTL SIMULATORS, NAMELY VERILATOR.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
""" + Console.RESET)
}
(aggregator
:= frequencySpecifier
:= clockGroupCombiner
:= resetSynchronizer
:= tileClockGater
:= tileResetSetter
:= tileClockGater.map(_.clockNode).getOrElse(ClockGroupEphemeralNode()(ValName("temp")))
:= tileResetSetter.map(_.clockNode).getOrElse(ClockGroupEphemeralNode()(ValName("temp")))
:= allClockGroupsNode)
}

View File

@@ -26,20 +26,26 @@ class TLClockDivider(address: BigInt, beatBytes: Int, divBits: Int = 8)(implicit
val sinks = clockNode.out.head._1.member.elements.toSeq
require (sources.size == sinks.size)
val nSinks = sinks.size
// The implicit clock of this module is the clock of the tilelink bus
// busReset is sync'd to that clock, and will be asserted longer than the
// resets coming in through the clockNode, since the busReset is derived from
// the clockNode resets in downstream PRCI nodes
val busReset = reset
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))
}
val reg = 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
}
val divider = Module(new testchipip.ClockDivideOrPass(divBits, depth = 3, genClockGate = p(ClockGateImpl)))
divider.io.clockIn := sources(i).clock
// busReset is expected to be high for a long time, since reset will take a while to propagate
// to the TL bus. While reset is propagating, make sure we propagate a fast, undivided clock
// by setting divisor=0. The divisor signal into the ClockDividerOrPass is synchronized internally
divider.io.divisor := Mux(busReset.asBool, 0.U, reg.io.q)
divider.io.resetAsync := ResetStretcher(sources(i).clock, asyncReset, 20).asAsyncReset
sinks(i)._2.clock := divider.io.clockOut
// Note this is not synchronized to the output clock, which takes time to appear
// so this is still asyncreset

View File

@@ -13,23 +13,6 @@ 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() },

View File

@@ -46,10 +46,3 @@ class TileClockGater(address: BigInt, beatBytes: Int)(implicit p: Parameters, va
}
}
object TileClockGater {
def apply(address: BigInt, tlbus: TLBusWrapper)(implicit p: Parameters, v: ValName) = {
val gater = LazyModule(new TileClockGater(address, tlbus.beatBytes))
tlbus.toVariableWidthSlave(Some("clock-gater")) { gater.tlNode := TLBuffer() }
gater.clockNode
}
}

View File

@@ -62,12 +62,3 @@ class TileResetSetter(address: BigInt, beatBytes: Int, tileNames: Seq[String], i
}
}
}
object TileResetSetter {
def apply(address: BigInt, tlbus: TLBusWrapper, tileNames: Seq[String], initResetHarts: Seq[Int])(implicit p: Parameters, v: ValName) = {
val setter = LazyModule(new TileResetSetter(address, tlbus.beatBytes, tileNames, initResetHarts))
tlbus.toVariableWidthSlave(Some("tile-reset-setter")) { setter.tlNode := TLBuffer() }
setter.clockNode
}
}

View File

@@ -12,50 +12,58 @@ import org.chipsalliance.cde.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.WithSimUARTToUARTTSI ++ // connect a SimUART to the UART-TSI port
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
// IOCells are generated for "Chip-like" IOs
new chipyard.iobinders.WithSerialTLIOCells ++
new chipyard.iobinders.WithDebugIOCells ++
new chipyard.iobinders.WithUARTIOCells ++
new chipyard.iobinders.WithGPIOCells ++
new chipyard.iobinders.WithSPIIOCells ++
new chipyard.iobinders.WithExtInterruptIOCells ++
new chipyard.iobinders.WithCustomBootPin ++
// The "punchthrough" IOBInders below don't generate IOCells, as these interfaces shouldn't really be mapped to ASIC IO
// Instead, they directly pass through the DigitalTop ports to ports in the ChipTop
new chipyard.iobinders.WithAXI4MemPunchthrough ++
new chipyard.iobinders.WithAXI4MMIOPunchthrough ++
new chipyard.iobinders.WithTLMemPunchthrough ++
new chipyard.iobinders.WithL2FBusAXI4Punchthrough ++
new chipyard.iobinders.WithBlockDeviceIOPunchthrough ++
new chipyard.iobinders.WithNICIOPunchthrough ++
new chipyard.iobinders.WithSerialTLIOCells ++
new chipyard.iobinders.WithDebugIOCells ++
new chipyard.iobinders.WithUARTIOCells ++
new chipyard.iobinders.WithGPIOCells ++
new chipyard.iobinders.WithSPIIOCells ++
new chipyard.iobinders.WithTraceIOPunchthrough ++
new chipyard.iobinders.WithExtInterruptIOCells ++
new chipyard.iobinders.WithCustomBootPin ++
new chipyard.iobinders.WithUARTTSIPunchthrough ++
// Default behavior is to use a divider-only clock-generator
// This works in VCS, Verilator, and FireSim/
// This should get replaced with a PLL-like config instead
new chipyard.clocking.WithDividerOnlyClockGenerator ++
// By default, punch out IOs to the Harness
new chipyard.clocking.WithPassthroughClockGenerator ++
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("sbus", "mbus", "pbus", "fbus", "cbus", "implicit"), Seq("tile"))) ++
new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus
new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus
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.WithSerialTLClientIdBits(4) ++ // support up to 1 << 4 simultaneous requests from serialTL port
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 freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ // Default 1 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)

View File

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

View File

@@ -13,7 +13,7 @@ class CVA6Config extends Config(
new chipyard.config.AbstractConfig)
class dmiCVA6Config extends Config(
new chipyard.harness.WithSerialAdapterTiedOff ++ // Tie off the serial port, override default instantiation of SimSerial
new chipyard.harness.WithSerialTLTiedOff ++ // Tie off the serial-tilelink port
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new cva6.WithNCVA6Cores(1) ++ // single CVA6 core
new chipyard.config.AbstractConfig)

View File

@@ -2,43 +2,106 @@ package chipyard
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.subsystem.{MBUS, SBUS}
import testchipip.{OBUS}
// A simple config demonstrating how to set up a basic chip in Chipyard
class ChipLikeQuadRocketConfig extends Config(
class ChipLikeRocketConfig extends Config(
//==================================
// Set up TestHarness
//==================================
new chipyard.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute frequencies for simulations in the harness
// NOTE: This only simulates properly in VCS
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute frequencies for simulations in the harness
// NOTE: This only simulates properly in VCS
new chipyard.harness.WithSimAXIMemOverSerialTL ++ // Attach SimDRAM to serial-tl port
//==================================
// 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)
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // 1 RocketTile
//==================================
// 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 testchipip.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 buses
//==================================
new testchipip.WithOffchipBusClient(MBUS) ++
new testchipip.WithOffchipBus ++
//==================================
// Set up clock./reset
//==================================
new chipyard.clocking.WithPLLSelectorDividerClockGenerator ++ // Use a PLL-based clock selector/divider generator structure
// Create two clock groups, uncore and fbus, in addition to the tile clock groups
new chipyard.clocking.WithClockGroupsCombinedByName("uncore", "implicit", "sbus", "mbus", "cbus", "system_bus") ++
new chipyard.clocking.WithClockGroupsCombinedByName("fbus", "fbus", "pbus") ++
// Set up the crossings
new chipyard.config.WithFbusToSbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between SBUS and FBUS
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 testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS
// Create the uncore clock group
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("implicit", "sbus", "mbus", "cbus", "system_bus", "fbus", "pbus"), Nil)) ++
new chipyard.config.AbstractConfig)
// A simple config demonstrating a "bringup prototype" to bringup the ChipLikeRocketconfig
class ChipBringupHostConfig extends Config(
//=============================
// Set up TestHarness for standalone-sim
//=============================
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // Generate absolute frequencies
new chipyard.harness.WithSerialTLTiedOff ++ // when doing standalone sim, tie off the serial-tl port
new chipyard.harness.WithSimTSIToUARTTSI ++ // Attach SimTSI-over-UART to the UART-TSI port
new chipyard.iobinders.WithSerialTLPunchthrough ++ // Don't generate IOCells for the serial TL (this design maps to FPGA)
//=============================
// Setup the SerialTL side on the bringup device
//=============================
new testchipip.WithSerialTLWidth(4) ++ // match width with the chip
new testchipip.WithSerialTLMem(base = 0x0, size = 0x80000000L, // accessible memory of the chip that doesn't come from the tethered host
idBits = 4, isMainMemory = false) ++ // This assumes off-chip mem starts at 0x8000_0000
new testchipip.WithSerialTLClockDirection(provideClockFreqMHz = Some(75)) ++ // bringup board drives the clock for the serial-tl receiver on the chip, use 75MHz clock
//============================
// Setup bus topology on the bringup system
//============================
new testchipip.WithOffchipBusClient(SBUS, // offchip bus hangs off the SBUS
blockRange = AddressSet.misaligned(0x80000000L, (BigInt(1) << 30) * 4)) ++ // offchip bus should not see the main memory of the testchip, since that can be accessed directly
new testchipip.WithOffchipBus ++ // offchip bus
//=============================
// Set up memory on the bringup system
//=============================
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 4L) ++ // match what the chip believes the max size should be
//=============================
// Generate the TSI-over-UART side of the bringup system
//=============================
new testchipip.WithUARTTSIClient(initBaudRate = BigInt(921600)) ++ // nonstandard baud rate to improve performance
//=============================
// Set up clocks of the bringup system
//=============================
new chipyard.clocking.WithPassthroughClockGenerator ++ // pass all the clocks through, since this isn't a chip
new chipyard.config.WithFrontBusFrequency(75.0) ++ // run all buses of this system at 75 MHz
new chipyard.config.WithMemoryBusFrequency(75.0) ++
new chipyard.config.WithPeripheryBusFrequency(75.0) ++
// Base is the no-cores config
new chipyard.NoCoresConfig)
class TetheredChipLikeRocketConfig extends Config(
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute freqs for sims in the harness
new chipyard.harness.WithMultiChipSerialTL(0, 1) ++ // connect the serial-tl ports of the chips together
new chipyard.harness.WithMultiChip(0, new ChipLikeRocketConfig) ++
new chipyard.harness.WithMultiChip(1, new ChipBringupHostConfig))
// Verilator does not initialize some of the async-reset reset-synchronizer
// flops properly, so this config disables them.
// This config should only be used for verilator simulations
class VerilatorCITetheredChipLikeRocketConfig extends Config(
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute freqs for sims in the harness
new chipyard.harness.WithMultiChipSerialTL(0, 1) ++ // connect the serial-tl ports of the chips together
new chipyard.harness.WithMultiChip(0, new chipyard.config.WithNoResetSynchronizers ++ new ChipLikeRocketConfig) ++
new chipyard.harness.WithMultiChip(1, new ChipBringupHostConfig))

View File

@@ -61,7 +61,6 @@ class LargeNVDLARocketConfig extends Config(
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
new chipyard.example.WithStreamingFIR ++ // use top with tilelink-controlled streaming FIR
new freechips.rocketchip.subsystem.WithNBigCores(1) ++

View File

@@ -68,9 +68,9 @@ class MultiNoCConfig extends Config(
"serial-tl" -> 0),
outNodeMapping = ListMap(
"error" -> 1, "l2[0]" -> 2, "pbus" -> 3, "plic" -> 4,
"clint" -> 5, "dmInner" -> 6, "bootrom" -> 7, "tileClockGater" -> 8, "tileResetSetter" -> 9)),
"clint" -> 5, "dmInner" -> 6, "bootrom" -> 7, "clock" -> 8)),
NoCParams(
topology = TerminalRouter(BidirectionalLine(10)),
topology = TerminalRouter(BidirectionalLine(9)),
channelParamGen = (a, b) => UserChannelParams(Seq.fill(5) { UserVirtualChannelParams(4) }),
routingRelation = NonblockingVirtualSubnetworksRouting(TerminalRouterRouting(BidirectionalLineRouting()), 5, 1))
)) ++

View File

@@ -4,6 +4,15 @@ import org.chipsalliance.cde.config.{Config}
// A empty config with no cores. Useful for testing
class NoCoresConfig extends Config(
new testchipip.WithNoBootAddrReg ++
new testchipip.WithNoCustomBootPin ++
new chipyard.config.WithNoCLINT ++
new chipyard.config.WithNoBootROM ++
new chipyard.config.WithBroadcastManager ++
new chipyard.config.WithNoUART ++
new chipyard.config.WithNoTileClockGaters ++
new chipyard.config.WithNoTileResetSetters ++
new chipyard.config.WithNoBusErrorDevices ++
new chipyard.config.WithNoDebug ++
new chipyard.config.WithNoPLIC ++
new chipyard.config.AbstractConfig)

View File

@@ -2,6 +2,7 @@ package chipyard
import org.chipsalliance.cde.config.{Config}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
import freechips.rocketchip.subsystem.{MBUS}
// ---------------------------------------------------------
// Configs which add non-default peripheral devices or ports
@@ -58,20 +59,37 @@ 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)
// DOC include end: DmiRocket
class ManyPeripheralsRocketConfig extends Config(
new testchipip.WithBlockDevice ++ // add block-device module to peripherybus
new testchipip.WithOffchipBusClient(MBUS) ++ // OBUS provides backing memory to the MBUS
new testchipip.WithOffchipBus ++ // OBUS must exist for serial-tl to master off-chip memory
new testchipip.WithSerialTLMem(isMainMemory=true) ++ // set lbwif memory base to DRAM_BASE, use as main memory
new chipyard.harness.WithSimSPIFlashModel(true) ++ // add the SPI flash model in the harness (read-only)
new chipyard.harness.WithSimBlockDevice ++ // drive block-device IOs with SimBlockDevice
new chipyard.config.WithSPIFlash ++ // add the SPI flash controller
new freechips.rocketchip.subsystem.WithDefaultMMIOPort ++ // add default external master port
new freechips.rocketchip.subsystem.WithDefaultSlavePort ++ // add default external slave port
new testchipip.WithBlockDevice ++ // add block-device module to peripherybus
new testchipip.WithSerialTLMem(isMainMemory=true) ++ // set lbwif memory base to DRAM_BASE, use as main memory
new freechips.rocketchip.subsystem.WithNoMemPort ++ // remove AXI4 backing memory
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
class QuadChannelRocketConfig extends Config(
new freechips.rocketchip.subsystem.WithNMemoryChannels(4) ++ // 4 AXI4 channels
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
class UARTTSIRocketConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++
new testchipip.WithUARTTSIClient ++
new chipyard.config.WithMemoryBusFrequency(10) ++
new chipyard.config.WithFrontBusFrequency(10) ++
new chipyard.config.WithPeripheryBusFrequency(10) ++
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core
new chipyard.config.AbstractConfig)

View File

@@ -29,14 +29,6 @@ class RocketGPUConfig extends Config(
new freechips.rocketchip.subsystem.WithNCustomSmallCores(2) ++ // multiple rocket-core
new chipyard.config.AbstractConfig)
class UARTTSIRocketConfig extends Config(
new chipyard.harness.WithUARTSerial ++
new chipyard.config.WithNoUART ++
new chipyard.config.WithMemoryBusFrequency(10) ++
new chipyard.config.WithPeripheryBusFrequency(10) ++
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core
new chipyard.config.AbstractConfig)
class SimAXIRocketConfig extends Config(
new chipyard.harness.WithSimAXIMem ++ // drive the master AXI4 memory with a SimAXIMem, a 1-cycle magic memory, instead of default SimDRAM
new freechips.rocketchip.subsystem.WithNBigCores(1) ++

View File

@@ -0,0 +1,32 @@
package chipyard
import org.chipsalliance.cde.config.{Config}
//-----------------
// Shuttle Configs
//-----------------
class ShuttleConfig extends Config(
new shuttle.common.WithNShuttleCores ++ // 1x dual-issue shuttle core
new chipyard.config.AbstractConfig)
class ShuttleCosimConfig extends Config(
new chipyard.harness.WithCospike ++ // attach spike-cosim
new chipyard.config.WithTraceIO ++ // enable trace-io for cosim
new shuttle.common.WithShuttleDebugROB ++ // enable shuttle debug ROB for cosim
new shuttle.common.WithNShuttleCores ++
new chipyard.config.AbstractConfig)
class dmiShuttleCosimConfig extends Config(
new chipyard.harness.WithSerialTLTiedOff ++ // don't attach anything to serial-tl
new chipyard.harness.WithCospike ++ // attach spike-cosim
new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port
new chipyard.config.WithTraceIO ++ // enable traceio for cosim
new shuttle.common.WithShuttleDebugROB ++ // enable shuttle debug ROB for cosim
new shuttle.common.WithNShuttleCores ++
new chipyard.config.AbstractConfig)
class GemminiShuttleConfig extends Config(
new gemmini.DefaultGemminiConfig ++ // use Gemmini systolic array GEMM accel
new shuttle.common.WithNShuttleCores ++
new chipyard.config.AbstractConfig)

View File

@@ -8,7 +8,6 @@ class Sodor1StageConfig extends Config(
// Create a Sodor 1-stage core
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage1Factory) ++
new testchipip.WithSerialTLWidth(32) ++
new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++
@@ -18,7 +17,6 @@ class Sodor2StageConfig extends Config(
// Create a Sodor 2-stage core
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage2Factory) ++
new testchipip.WithSerialTLWidth(32) ++
new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++
@@ -28,7 +26,6 @@ class Sodor3StageConfig extends Config(
// Create a Sodor 1-stage core with two ports
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 2)) ++
new testchipip.WithSerialTLWidth(32) ++
new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++
@@ -38,7 +35,6 @@ class Sodor3StageSinglePortConfig extends Config(
// Create a Sodor 3-stage core with one ports (instruction and data memory access controlled by arbiter)
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 1)) ++
new testchipip.WithSerialTLWidth(32) ++
new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++
@@ -48,7 +44,6 @@ class Sodor5StageConfig extends Config(
// Create a Sodor 5-stage core
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage5Factory) ++
new testchipip.WithSerialTLWidth(32) ++
new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++
@@ -58,7 +53,6 @@ class SodorUCodeConfig extends Config(
// Construct a Sodor microcode-based single-bus core
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.UCodeFactory) ++
new testchipip.WithSerialTLWidth(32) ++
new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++

View File

@@ -10,6 +10,11 @@ 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) ++
@@ -22,13 +27,17 @@ class SpikeFastUARTConfig extends Config(
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 ++
@@ -38,7 +47,6 @@ class SpikeUltraFastDevicesConfig 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) ++

View File

@@ -4,21 +4,24 @@ 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.clocking.WithDividerOnlyClockGenerator ++
new chipyard.clocking.WithPassthroughClockGenerator ++
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("sbus", "implicit"), Nil)) ++
new chipyard.config.WithTracegenSystem ++
new chipyard.config.WithNoSubsystemDrivenClocks ++
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++
new chipyard.config.WithMemoryBusFrequency(100.0) ++
new chipyard.config.WithPeripheryBusFrequency(100.0) ++
new chipyard.config.WithMemoryBusFrequency(1000.0) ++
new chipyard.config.WithSystemBusFrequency(1000.0) ++
new chipyard.config.WithPeripheryBusFrequency(1000.0) ++
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
new freechips.rocketchip.groundtest.GroundTestBaseConfig)
class TraceGenConfig extends Config(
new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++
new AbstractTraceGenConfig)

View File

@@ -14,7 +14,6 @@ import freechips.rocketchip.tilelink.{HasTLBusParams}
import chipyard._
import chipyard.clocking._
// The default RocketChip BaseSubsystem drives its diplomatic clock graph
// with the implicit clocks of Subsystem. Don't do that, instead we extend
// the diplomacy graph upwards into the ChipTop, where we connect it to
@@ -37,14 +36,6 @@ class WithTileFrequency(fMHz: Double, hartId: Option[Int] = None) extends ClockN
},
fMHz)
class WithPeripheryBusFrequencyAsDefault extends Config((site, here, up) => {
case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get.toDouble / (1000 * 1000))
})
class WithSystemBusFrequencyAsDefault extends Config((site, here, up) => {
case DefaultClockFrequencyKey => (site(SystemBusKey).dtsFrequency.get.toDouble / (1000 * 1000))
})
class BusFrequencyAssignment[T <: HasTLBusParams](re: Regex, key: Field[T]) extends Config((site, here, up) => {
case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++
Seq((cName: String) => site(key).dtsFrequency.flatMap { f =>
@@ -116,17 +107,14 @@ class WithControlBusFrequency(freqMHz: Double) extends Config((site, here, up) =
class WithRationalMemoryBusCrossing extends WithSbusToMbusCrossingType(RationalCrossing(Symmetric))
class WithAsynchrousMemoryBusCrossing extends WithSbusToMbusCrossingType(AsynchronousCrossing())
class WithTestChipBusFreqs extends Config(
// Frequency specifications
new chipyard.config.WithTileFrequency(1600.0) ++ // Matches the maximum frequency of U540
new chipyard.config.WithSystemBusFrequency(800.0) ++ // Put the system bus at a lower freq, representative of ncore working at a lower frequency than the tiles. Same freq as U540
new chipyard.config.WithMemoryBusFrequency(1000.0) ++ // 2x the U540 freq (appropriate for a 128b Mbus)
new chipyard.config.WithPeripheryBusFrequency(800.0) ++ // Match the sbus and pbus frequency
new chipyard.config.WithSystemBusFrequencyAsDefault ++ // All unspecified clock frequencies, notably the implicit clock, will use the sbus freq (800 MHz)
// 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 boom.common.WithRationalBoomTiles ++ // Add rational crossings between BoomTile and uncore
new testchipip.WithAsynchronousSerialSlaveCrossing // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS
)
class WithNoTileClockGaters extends Config((site, here, up) => {
case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey).copy(enableTileClockGating = false)
})
class WithNoTileResetSetters extends Config((site, here, up) => {
case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey).copy(enableTileResetSetting = false)
})
class WithNoResetSynchronizers extends Config((site, here, up) => {
case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey).copy(enableResetSynchronizers = false)
})

View File

@@ -5,8 +5,9 @@ import chisel3._
import chisel3.util.{log2Up}
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.devices.tilelink.{BootROMLocated, PLICKey, CLINTKey}
import freechips.rocketchip.devices.debug.{Debug, ExportDebug, DebugModuleKey, DMI, JtagDTMKey, JtagDTMConfig}
import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
import freechips.rocketchip.stage.phases.TargetDirKey
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tile.{XLen}
@@ -14,53 +15,125 @@ import freechips.rocketchip.tile.{XLen}
import sifive.blocks.devices.gpio._
import sifive.blocks.devices.uart._
import sifive.blocks.devices.spi._
import sifive.blocks.devices.i2c._
import testchipip._
import chipyard.{ExtTLMem}
// Set the bootrom to the Chipyard bootrom
class WithBootROM extends Config((site, here, up) => {
/**
* Config fragment for adding a BootROM to the SoC
*
* @param address the address of the BootROM device
* @param size the size of the BootROM
* @param hang the power-on reset vector, i.e. the program counter will be set to this value on reset
* @param contentFileName the path to the BootROM image
*/
class WithBootROM(address: BigInt = 0x10000, size: Int = 0x10000, hang: BigInt = 0x10040) extends Config((site, here, up) => {
case BootROMLocated(x) => up(BootROMLocated(x), site)
.map(_.copy(contentFileName = s"${site(TargetDirKey)}/bootrom.rv${site(XLen)}.img"))
.map(_.copy(
address = address,
size = size,
hang = hang,
contentFileName = s"${site(TargetDirKey)}/bootrom.rv${site(XLen)}.img"
))
})
// DOC include start: gpio config fragment
class WithGPIO extends Config((site, here, up) => {
case PeripheryGPIOKey => Seq(
GPIOParams(address = 0x10012000, width = 4, includeIOF = false))
/**
* Config fragment for adding a GPIO peripheral device to the SoC
*
* @param address the address of the GPIO device
* @param width the number of pins of the GPIO device
*/
class WithGPIO(address: BigInt = 0x10010000, width: Int = 4) extends Config ((site, here, up) => {
case PeripheryGPIOKey => up(PeripheryGPIOKey) ++ Seq(
GPIOParams(address = address, width = width, includeIOF = false))
})
// DOC include end: gpio config fragment
class WithUART(baudrate: BigInt = 115200) extends Config((site, here, up) => {
case PeripheryUARTKey => Seq(
UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256, initBaudRate = baudrate))
})
/**
* Config fragment for removing all UART peripheral devices from the SoC
*/
class WithNoUART extends Config((site, here, up) => {
case PeripheryUARTKey => Nil
})
/**
* Config fragment for adding a UART peripheral device to the SoC
*
* @param address the address of the UART device
* @param baudrate the baudrate of the UART device
*/
class WithUART(baudrate: BigInt = 115200, address: BigInt = 0x10020000) extends Config ((site, here, up) => {
case PeripheryUARTKey => up(PeripheryUARTKey) ++ Seq(
UARTParams(address = address, nTxEntries = 256, nRxEntries = 256, initBaudRate = baudrate))
})
class WithUARTFIFOEntries(txEntries: Int, rxEntries: Int) extends Config((site, here, up) => {
case PeripheryUARTKey => up(PeripheryUARTKey).map(_.copy(nTxEntries = txEntries, nRxEntries = rxEntries))
})
class WithSPIFlash(size: BigInt = 0x10000000) extends Config((site, here, up) => {
// Note: the default size matches freedom with the addresses below
case PeripherySPIFlashKey => Seq(
SPIFlashParams(rAddress = 0x10040000, fAddress = 0x20000000, fSize = size))
class WithUARTInitBaudRate(baudrate: BigInt = 115200) extends Config ((site, here, up) => {
case PeripheryUARTKey => up(PeripheryUARTKey).map(_.copy(initBaudRate=baudrate))
})
class WithDMIDTM extends Config((site, here, up) => {
case ExportDebug => up(ExportDebug, site).copy(protocols = Set(DMI))
/**
* Config fragment for adding a SPI peripheral device with Execute-in-Place capability to the SoC
*
* @param address the address of the SPI controller
* @param fAddress the address of the Execute-in-Place (XIP) region of the SPI flash memory
* @param size the size of the Execute-in-Place (XIP) region of the SPI flash memory
*/
class WithSPIFlash(size: BigInt = 0x10000000, address: BigInt = 0x10030000, fAddress: BigInt = 0x20000000) extends Config((site, here, up) => {
// Note: the default size matches freedom with the addresses below
case PeripherySPIFlashKey => up(PeripherySPIFlashKey) ++ Seq(
SPIFlashParams(rAddress = address, fAddress = fAddress, fSize = size))
})
/**
* Config fragment for adding a SPI peripheral device to the SoC
*
* @param address the address of the SPI controller
*/
class WithSPI(address: BigInt = 0x10031000) extends Config((site, here, up) => {
case PeripherySPIKey => up(PeripherySPIKey) ++ Seq(
SPIParams(rAddress = address))
})
/**
* Config fragment for adding a I2C peripheral device to the SoC
*
* @param address the address of the I2C controller
*/
class WithI2C(address: BigInt = 0x10040000) extends Config((site, here, up) => {
case PeripheryI2CKey => up(PeripheryI2CKey) ++ Seq(
I2CParams(address = address, controlXType = AsynchronousCrossing(), intXType = AsynchronousCrossing())
)
})
class WithNoDebug extends Config((site, here, up) => {
case DebugModuleKey => None
})
class WithTLSerialLocation(masterWhere: TLBusWrapperLocation, slaveWhere: TLBusWrapperLocation) extends Config((site, here, up) => {
case SerialTLAttachKey => up(SerialTLAttachKey, site).copy(masterWhere = masterWhere, slaveWhere = slaveWhere)
class WithDMIDTM extends Config((site, here, up) => {
case ExportDebug => up(ExportDebug, site).copy(protocols = Set(DMI))
})
/**
* Config fragment for adding a JTAG Debug Module to the SoC
*
* @param idcodeVersion the version of the JTAG protocol the Debug Module supports
* @param partNum the part number of the Debug Module
* @param manufId the 11-bit JEDEC Designer ID of the chip manufacturer
* @param debugIdleCycles the number of cycles the Debug Module waits before responding to a request
*/
class WithJTAGDTMKey(idcodeVersion: Int = 2, partNum: Int = 0x000, manufId: Int = 0x489, debugIdleCycles: Int = 5) extends Config((site, here, up) => {
case JtagDTMKey => new JtagDTMConfig (
idcodeVersion = idcodeVersion,
idcodePartNum = partNum,
idcodeManufId = manufId,
debugIdleCycles = debugIdleCycles)
})
class WithTLBackingMemory extends Config((site, here, up) => {
@@ -68,18 +141,6 @@ class WithTLBackingMemory extends Config((site, here, up) => {
case ExtTLMem => up(ExtMem, site) // enable TL backing memory
})
class WithSerialTLBackingMemory extends Config((site, here, up) => {
case ExtMem => None
case SerialTLKey => up(SerialTLKey, site).map { k => k.copy(
memParams = {
val memPortParams = up(ExtMem, site).get
require(memPortParams.nMemoryChannels == 1)
memPortParams.master
},
isMemoryDevice = true
)}
})
class WithExtMemIdBits(n: Int) extends Config((site, here, up) => {
case ExtMem => up(ExtMem, site).map(x => x.copy(master = x.master.copy(idBits = n)))
})
@@ -87,3 +148,23 @@ 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))
})
class WithNoCLINT extends Config((site, here, up) => {
case CLINTKey => None
})
class WithNoBootROM extends Config((site, here, up) => {
case BootROMLocated(_) => None
})
class WithNoBusErrorDevices extends Config((site, here, up) => {
case SystemBusKey => up(SystemBusKey).copy(errorDevice = None)
case ControlBusKey => up(ControlBusKey).copy(errorDevice = None)
case PeripheryBusKey => up(PeripheryBusKey).copy(errorDevice = None)
case MemoryBusKey => up(MemoryBusKey).copy(errorDevice = None)
case FrontBusKey => up(FrontBusKey).copy(errorDevice = None)
})

View File

@@ -9,7 +9,10 @@ import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams
import boom.common.{BoomTileAttachParams}
import cva6.{CVA6TileAttachParams}
import sodor.common.{SodorTileAttachParams}
import ibex.{IbexTileAttachParams}
import testchipip._
import barf.{TilePrefetchingMasterPortParams}
class WithL2TLBs(entries: Int) extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map {
@@ -79,3 +82,17 @@ class WithRocketDCacheScratchpad extends Config((site, here, up) => {
}
})
class WithTilePrefetchers extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map {
case tp: RocketTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy(
master = TilePrefetchingMasterPortParams(tp.tileParams.hartId, tp.crossingParams.master)))
case tp: BoomTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy(
master = TilePrefetchingMasterPortParams(tp.tileParams.hartId, tp.crossingParams.master)))
case tp: SodorTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy(
master = TilePrefetchingMasterPortParams(tp.tileParams.hartId, tp.crossingParams.master)))
case tp: IbexTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy(
master = TilePrefetchingMasterPortParams(tp.tileParams.hartId, tp.crossingParams.master)))
case tp: CVA6TileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy(
master = TilePrefetchingMasterPortParams(tp.tileParams.hartId, tp.crossingParams.master)))
}
})

View File

@@ -7,6 +7,7 @@ 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

View File

@@ -7,7 +7,7 @@ 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 freechips.rocketchip.tilelink.{TLBuffer, TLFragmenter}
import chipyard.{BuildSystem, DigitalTop}
import chipyard.clocking._
import chipyard.iobinders.{IOCellKey, JTAGChipIO}
@@ -33,9 +33,9 @@ class FlatChipTop(implicit p: Parameters) extends LazyModule {
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() }
tlbus.coupleTo("clock-div-ctrl") { clockDivider.tlNode := TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := TLBuffer() := _ }
tlbus.coupleTo("clock-sel-ctrl") { clockSelector.tlNode := TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := TLBuffer() := _ }
tlbus.coupleTo("pll-ctrl") { pllCtrl.tlNode := TLFragmenter(tlbus.beatBytes, tlbus.blockBytes) := TLBuffer() := _ }
system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode

View File

@@ -11,8 +11,8 @@ import freechips.rocketchip.util.{PlusArg}
import freechips.rocketchip.subsystem.{CacheBlockBytes}
import freechips.rocketchip.devices.debug.{SimJTAG}
import freechips.rocketchip.jtag.{JTAGIO}
import testchipip.{SerialTLKey, SerialAdapter, UARTAdapter, SimDRAM}
import chipyard.{BuildTop}
import testchipip.{SerialTLKey, UARTAdapter, SimDRAM, TSIHarness, SimTSI}
import chipyard.harness.{BuildTop}
// A "flat" TestHarness that doesn't use IOBinders
// use with caution.
@@ -40,28 +40,27 @@ class FlatTestHarness(implicit val p: Parameters) extends Module {
// Serialized TL
val sVal = p(SerialTLKey).get
require(sVal.axiMemOverSerialTLParams.isDefined)
require(sVal.isMemoryDevice)
val axiDomainParams = sVal.axiMemOverSerialTLParams.get
val serialTLManagerParams = sVal.serialTLManagerParams.get
val axiDomainParams = serialTLManagerParams.axiMemOverSerialTLParams.get
require(serialTLManagerParams.isMemoryDevice)
val memFreq = axiDomainParams.getMemFrequency(lazyDut.system)
withClockAndReset(clock, reset) {
val memOverSerialTLClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
memOverSerialTLClockBundle.clock := clock
memOverSerialTLClockBundle.reset := reset
val serial_bits = SerialAdapter.asyncQueue(dut.serial_tl_pad, clock, reset)
val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(
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,
clock,
reset)
io.success := SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, clock, 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
(harnessMultiClockAXIRAM.mem_axi4.get zip harnessMultiClockAXIRAM.memNode.get.edges.in).map { case (axi_port, edge) =>
val memSize = serialTLManagerParams.memParams.size
val memBase = serialTLManagerParams.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

View File

@@ -165,17 +165,17 @@ trait CanHavePeripheryGCD { this: BaseSubsystem =>
case Some(params) => {
if (params.useAXI4) {
val gcd = LazyModule(new GCDAXI4(params, pbus.beatBytes)(p))
pbus.toSlave(Some(portName)) {
pbus.coupleTo(portName) {
gcd.node :=
AXI4Buffer () :=
TLToAXI4 () :=
// toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needsx
TLFragmenter(pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true)
TLFragmenter(pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true) := _
}
Some(gcd)
} else {
val gcd = LazyModule(new GCDTL(params, pbus.beatBytes)(p))
pbus.toVariableWidthSlave(Some(portName)) { gcd.node }
pbus.coupleTo(portName) { gcd.node := TLFragmenter(pbus.beatBytes, pbus.blockBytes) := _ }
Some(gcd)
}
}

View File

@@ -62,7 +62,7 @@ trait CanHavePeripheryInitZero { this: BaseSubsystem =>
p(InitZeroKey) .map { k =>
val initZero = LazyModule(new InitZero()(p))
fbus.fromPort(Some("init-zero"))() := initZero.node
fbus.coupleFrom("init-zero") { _ := initZero.node }
}
}

View File

@@ -67,6 +67,7 @@ case class MyCoreParams(
val useCryptoNIST: Boolean = false
val useCryptoSM: Boolean = false
val traceHasWdata: Boolean = false
val useConditionalZero = false
}
// DOC include start: CanAttachTile

View File

@@ -203,7 +203,7 @@ trait CanHavePeripheryStreamingFIR extends BaseSubsystem {
genOut = FixedPoint(8.W, 3.BP),
coeffs = Seq(1.F(0.BP), 2.F(0.BP), 3.F(0.BP)),
params = params))
pbus.toVariableWidthSlave(Some("streamingFIR")) { streamingFIR.mem.get := TLFIFOFixer() }
pbus.coupleTo("streamingFIR") { streamingFIR.mem.get := TLFIFOFixer() := TLFragmenter(pbus.beatBytes, pbus.blockBytes) := _ }
Some(streamingFIR)
}
case None => None

View File

@@ -132,7 +132,7 @@ trait CanHavePeripheryStreamingPassthrough { this: BaseSubsystem =>
val passthrough = p(StreamingPassthroughKey) match {
case Some(params) => {
val streamingPassthroughChain = LazyModule(new TLStreamingPassthroughChain(params, UInt(32.W)))
pbus.toVariableWidthSlave(Some("streamingPassthrough")) { streamingPassthroughChain.mem.get := TLFIFOFixer() }
pbus.coupleTo("streamingPassthrough") { streamingPassthroughChain.mem.get := TLFIFOFixer() := TLFragmenter(pbus.beatBytes, pbus.blockBytes) := _ }
Some(streamingPassthroughChain)
}
case None => None

View File

@@ -30,12 +30,10 @@ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvon
import scala.reflect.{ClassTag}
case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Unit]](
Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Unit]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => ())
)
case object HarnessBinders extends Field[HarnessBinderMap](HarnessBinderMapDefault)
object ApplyHarnessBinders {
def apply(th: HasHarnessSignalReferences, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = {
def apply(th: HasHarnessInstantiators, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = {
val pm = portMap.withDefaultValue(Nil)
p(HarnessBinders).foreach { case (s, f) =>
f(sys, th, pm(s))
@@ -45,29 +43,25 @@ object ApplyHarnessBinders {
}
// The ClassTags here are necessary to overcome issues arising from type erasure
class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Unit) => (T, S, Seq[U]) => Unit)(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => {
class HarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](composer: ((T, S, Seq[U]) => Unit) => (T, S, Seq[U]) => Unit)(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => {
case HarnessBinders => up(HarnessBinders, site) + (systemTag.runtimeClass.toString ->
((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
((t: Any, th: HasHarnessInstantiators, ports: Seq[Data]) => {
val pts = ports.collect({case p: U => p})
require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${portTag}")
val upfn = up(HarnessBinders, site)(systemTag.runtimeClass.toString)
th match {
case th: S =>
t match {
case system: T => composer(upfn)(system, th, pts)
case _ =>
}
(th, t) match {
case (th: S, system: T) => composer(upfn)(system, th, pts)
case _ =>
}
})
)
})
class OverrideHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Unit)
class OverrideHarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](fn: => (T, S, Seq[U]) => Unit)
(implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U])
extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => fn)
class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Unit)
class ComposeHarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](fn: => (T, S, Seq[U]) => Unit)
(implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U])
extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => (t, th, p) => {
upfn(t, th, p)
@@ -76,104 +70,98 @@ class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: =>
class WithGPIOTiedOff extends OverrideHarnessBinder({
(system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => {
(system: HasPeripheryGPIOModuleImp, th: HasHarnessInstantiators, ports: Seq[Analog]) => {
ports.foreach { _ <> AnalogConst(0) }
}
})
// DOC include start: WithUARTAdapter
class WithUARTAdapter extends OverrideHarnessBinder({
(system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => {
(system: HasPeripheryUARTModuleImp, th: HasHarnessInstantiators, ports: Seq[UARTPortIO]) => {
UARTAdapter.connect(ports)(system.p)
}
})
// DOC include end: WithUARTAdapter
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => {
SimSPIFlashModel.connect(ports, th.buildtopReset, rdOnly)(system.p)
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessInstantiators, ports: Seq[SPIChipIO]) => {
SimSPIFlashModel.connect(ports, th.harnessBinderReset, rdOnly)(system.p)
}
})
class WithSimBlockDevice extends OverrideHarnessBinder({
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
(system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
implicit val p: Parameters = GetSystemParameters(system)
ports.map { b => SimBlockDevice.connect(b.clock, th.buildtopReset.asBool, Some(b.bits)) }
ports.map { b => SimBlockDevice.connect(b.clock, th.harnessBinderReset.asBool, Some(b.bits)) }
}
})
class WithBlockDeviceModel extends OverrideHarnessBinder({
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
(system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
implicit val p: Parameters = GetSystemParameters(system)
ports.map { b => withClockAndReset(b.clock, th.buildtopReset) { BlockDeviceModel.connect(Some(b.bits)) } }
ports.map { b => BlockDeviceModel.connect(Some(b.bits)) }
}
})
class WithLoopbackNIC extends OverrideHarnessBinder({
(system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
(system: CanHavePeripheryIceNIC, th: HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => {
implicit val p: Parameters = GetSystemParameters(system)
ports.map { n =>
withClockAndReset(n.clock, th.buildtopReset) {
NicLoopback.connect(Some(n.bits), p(NICKey))
}
}
ports.map { n => NicLoopback.connect(Some(n.bits), p(NICKey)) }
}
})
class WithSimNetwork extends OverrideHarnessBinder({
(system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
(system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => {
implicit val p: Parameters = GetSystemParameters(system)
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.buildtopReset.asBool) }
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessBinderReset.asBool) }
}
})
class WithSimAXIMem extends OverrideHarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
(system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) =>
val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p))
withClockAndReset(port.clock, port.reset) {
Module(mem.module).suggestName("mem")
}
Module(mem.module).suggestName("mem")
mem.io_axi4.head <> port.bits
}
}
})
class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
p(SerialTLKey).map({ sVal =>
require(sVal.axiMemOverSerialTLParams.isDefined)
val axiDomainParams = sVal.axiMemOverSerialTLParams.get
require(sVal.isMemoryDevice)
val serialTLManagerParams = sVal.serialTLManagerParams.get
val axiDomainParams = serialTLManagerParams.axiMemOverSerialTLParams.get
require(serialTLManagerParams.isMemoryDevice)
val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations])
ports.map({ port =>
// DOC include start: HarnessClockInstantiatorEx
withClockAndReset(th.buildtopClock, th.buildtopReset) {
val memOverSerialTLClockBundle = th.harnessClockInstantiator.requestClockBundle("mem_over_serial_tl_clock", memFreq)
val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(
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)
when (success) { th.success := true.B }
val memOverSerialTLClock = th.harnessClockInstantiator.requestClockHz("mem_over_serial_tl_clock", memFreq)
val serial_bits = port.bits
port.clock := th.harnessBinderClock
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
system.serdesser.get,
serial_bits,
memOverSerialTLClock,
th.harnessBinderReset)
// DOC include end: HarnessClockInstantiatorEx
val success = SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), th.harnessBinderClock, th.harnessBinderReset.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 lineSize = p(CacheBlockBytes)
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), edge.bundle)).suggestName("simdram")
mem.io.axi <> axi_port.bits
mem.io.clock := axi_port.clock
mem.io.reset := axi_port.reset
}
// connect SimDRAM from the AXI port coming from the harness multi clock axi ram
(harnessMultiClockAXIRAM.mem_axi4.get zip harnessMultiClockAXIRAM.memNode.get.edges.in).map { case (axi_port, edge) =>
val memSize = serialTLManagerParams.memParams.size
val memBase = serialTLManagerParams.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
}
})
})
@@ -181,13 +169,15 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
})
class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
(system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, 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] = {
@@ -214,7 +204,7 @@ class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBind
})
class WithSimAXIMMIO extends OverrideHarnessBinder({
(system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
(system: CanHaveMasterAXI4MMIOPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
(ports zip system.mmioAXI4Node.edges.in).map { case (port, edge) =>
val mmio_mem = LazyModule(new SimAXIMem(edge, size = p(ExtBus).get.size)(p))
@@ -227,13 +217,13 @@ class WithSimAXIMMIO extends OverrideHarnessBinder({
})
class WithTieOffInterrupts extends OverrideHarnessBinder({
(system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => {
(system: HasExtInterruptsModuleImp, th: HasHarnessInstantiators, ports: Seq[UInt]) => {
ports.foreach { _ := 0.U }
}
})
class WithTieOffL2FBusAXI extends OverrideHarnessBinder({
(system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => {
(system: CanHaveSlaveAXI4Port, th: HasHarnessInstantiators, ports: Seq[ClockedIO[AXI4Bundle]]) => {
ports.foreach({ p =>
p.bits := DontCare
p.bits.aw.valid := false.B
@@ -246,13 +236,13 @@ class WithTieOffL2FBusAXI extends OverrideHarnessBinder({
})
class WithSimDebug extends OverrideHarnessBinder({
(system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
(system: HasPeripheryDebug, th: HasHarnessInstantiators, ports: Seq[Data]) => {
implicit val p: Parameters = GetSystemParameters(system)
ports.map {
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.harnessBinderClock, th.harnessBinderReset.asBool, d, dtm_success)
case j: JTAGChipIO =>
val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B }
@@ -262,13 +252,14 @@ 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.harnessBinderClock, th.harnessBinderReset.asBool, ~(th.harnessBinderReset.asBool), dtm_success)
}
}
})
class WithTiedOffDebug extends OverrideHarnessBinder({
(system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
(system: HasPeripheryDebug, th: HasHarnessInstantiators, ports: Seq[Data]) => {
ports.map {
case j: JTAGChipIO =>
j.TCK := true.B.asClock
@@ -294,78 +285,93 @@ class WithTiedOffDebug extends OverrideHarnessBinder({
})
class WithSerialAdapterTiedOff extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
class WithSerialTLTiedOff extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, 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
if (DataMirror.directionOf(port.clock) == Direction.Input) {
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({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
class WithSimTSIOverSerialTL extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, 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)
val success = SerialAdapter.connectSimSerial(ram.module.io.tsi_ser, th.buildtopClock, th.buildtopReset.asBool)
when (success) { th.success := true.B }
}
val bits = port.bits
port.clock := th.harnessBinderClock
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset)
val success = SimTSI.connect(Some(ram.module.io.tsi), th.harnessBinderClock, th.harnessBinderReset.asBool)
when (success) { th.success := true.B }
})
}
})
class WithUARTSerial extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
class WithSimUARTToUARTTSI extends OverrideHarnessBinder({
(system: CanHavePeripheryUARTTSI, th: HasHarnessInstantiators, ports: Seq[UARTTSIIO]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
require(ports.size <= 1)
ports.map { port => {
UARTAdapter.connect(Seq(port.uart),
baudrate=port.uartParams.initBaudRate,
clockFrequency=th.getHarnessBinderClockFreqHz.toInt,
forcePty=true)
assert(!port.dropped)
}}
}
})
class WithSimTSIToUARTTSI extends OverrideHarnessBinder({
(system: CanHavePeripheryUARTTSI, th: HasHarnessInstantiators, ports: Seq[UARTTSIIO]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
require(ports.size <= 1)
ports.map({ port =>
val freq = p(PeripheryBusKey).dtsFrequency.get
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
withClockAndReset(th.buildtopClock, th.buildtopReset) {
val ram = SerialAdapter.connectHarnessRAM(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)
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
}
val freq = th.getHarnessBinderClockFreqHz.toInt
val uart_to_serial = Module(new UARTToSerial(freq, port.uartParams))
val serial_width_adapter = Module(new SerialWidthAdapter(8, TSI.WIDTH))
val success = SimTSI.connect(Some(TSIIO(serial_width_adapter.io.wide)), th.harnessBinderClock, th.harnessBinderReset)
when (success) { th.success := true.B }
assert(!uart_to_serial.io.dropped)
serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial)
uart_to_serial.io.uart.rxd := port.uart.txd
port.uart.rxd := uart_to_serial.io.uart.txd
})
}
})
class WithTraceGenSuccess extends OverrideHarnessBinder({
(system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => {
(system: TraceGenSystemModuleImp, th: HasHarnessInstantiators, ports: Seq[Bool]) => {
ports.map { p => when (p) { th.success := true.B } }
}
})
class WithSimDromajoBridge extends ComposeHarnessBinder({
(system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => {
(system: CanHaveTraceIOModuleImp, th: HasHarnessInstantiators, ports: Seq[TraceOutputTop]) => {
ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) }
}
})
class WithCospike extends ComposeHarnessBinder({
(system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => {
(system: CanHaveTraceIOModuleImp, th: HasHarnessInstantiators, ports: Seq[TraceOutputTop]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
val chipyardSystem = system.asInstanceOf[ChipyardSystemModule[_]].outer.asInstanceOf[ChipyardSystem]
val tiles = chipyardSystem.tiles
val cfg = SpikeCosimConfig(
isa = tiles.headOption.map(_.isaDTS).getOrElse(""),
priv = tiles.headOption.map(t => if (t.usingUser) "MSU" else if (t.usingSupervisor) "MS" else "M").getOrElse(""),
mem0_base = p(ExtMem).map(_.master.base).getOrElse(BigInt(0)),
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)) }
}
@@ -373,7 +379,7 @@ class WithCospike extends ComposeHarnessBinder({
class WithCustomBootPinPlusArg extends OverrideHarnessBinder({
(system: CanHavePeripheryCustomBootPin, th: HasHarnessSignalReferences, ports: Seq[Bool]) => {
(system: CanHavePeripheryCustomBootPin, th: HasHarnessInstantiators, ports: Seq[Bool]) => {
val pin = PlusArg("custom_boot_pin", width=1)
ports.foreach(_ := pin)
}
@@ -381,14 +387,15 @@ class WithCustomBootPinPlusArg extends OverrideHarnessBinder({
class WithClockAndResetFromHarness extends OverrideHarnessBinder({
(system: HasChipyardPRCI, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
(system: HasChipyardPRCI, th: HasHarnessInstantiators, ports: Seq[Data]) => {
implicit val p = GetSystemParameters(system)
val clocks = ports.collect { case c: ClockWithFreq => c }
ports.map ({
case c: ClockWithFreq => {
th.setRefClockFreq(c.freqMHz)
c.clock := th.buildtopClock
val clock = th.harnessClockInstantiator.requestClockMHz(s"clock_${c.freqMHz.toInt}MHz", c.freqMHz)
c.clock := clock
}
case r: AsyncReset => r := th.buildtopReset.asAsyncReset
case r: AsyncReset => r := th.referenceReset.asAsyncReset
})
}
})

View File

@@ -0,0 +1,100 @@
package chipyard.harness
import chisel3._
import chisel3.util._
import chisel3.experimental.DoubleParam
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import freechips.rocketchip.diplomacy.{LazyModule}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.util.{ResetCatchAndSync}
import freechips.rocketchip.prci._
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders, HarnessClockInstantiatorKey}
import chipyard.iobinders.HasIOBinders
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
// HarnessClockInstantiators are classes which generate clocks that drive
// TestHarness simulation models and any Clock inputs to the ChipTop
trait HarnessClockInstantiator {
val clockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty
// request a clock at a particular frequency
def requestClockHz(name: String, freqHzRequested: Double): Clock = {
if (clockMap.contains(name)) {
require(freqHzRequested == clockMap(name)._1,
s"Request clock freq = $freqHzRequested != previously requested ${clockMap(name)._2} for requested clock $name")
clockMap(name)._2
} else {
val clock = Wire(Clock())
clockMap(name) = (freqHzRequested, clock)
clock
}
}
def requestClockMHz(name: String, freqMHzRequested: Double): Clock = {
requestClockHz(name, freqMHzRequested * (1000 * 1000))
}
// refClock is the clock generated by TestDriver that is
// passed to the TestHarness as its implicit clock
def instantiateHarnessClocks(refClock: Clock, refClockFreqMHz: Double): 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 or run in FireSim
// It is useful for RTL simulations
class AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator {
def instantiateHarnessClocks(refClock: Clock, refClockFreqMHz: Double): Unit = {
// connect wires to clock source
for ((name, (freqHz, clock)) <- clockMap) {
val source = Module(new ClockSourceAtFreqMHz(freqHz / (1000 * 1000)))
source.io.power := true.B
source.io.gate := false.B
clock := source.io.clk
}
}
}
class WithAbsoluteFreqHarnessClockInstantiator extends Config((site, here, up) => {
case HarnessClockInstantiatorKey => () => new AbsoluteFreqHarnessClockInstantiator
})
class AllClocksFromHarnessClockInstantiator extends HarnessClockInstantiator {
def instantiateHarnessClocks(refClock: Clock, refClockFreqMHz: Double): Unit = {
val freqs = clockMap.map(_._2._1)
freqs.tail.foreach(t => require(t == freqs.head, s"Mismatching clocks $t != ${freqs.head}"))
for ((name, (freq, clock)) <- clockMap) {
val freqMHz = freq / (1000 * 1000)
require(freqMHz == refClockFreqMHz,
s"AllClocksFromHarnessClockInstantiator has reference ${refClockFreqMHz.toInt} MHz attempting to drive clock $name which requires $freqMHz MHz")
clock := refClock
}
}
}
class WithAllClocksFromHarnessClockInstantiator extends Config((site, here, up) => {
case HarnessClockInstantiatorKey => () => new AllClocksFromHarnessClockInstantiator
})

View File

@@ -0,0 +1,101 @@
package chipyard.harness
import chisel3._
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.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters}
import freechips.rocketchip.stage.phases.TargetDirKey
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
import chipyard.iobinders.HasIOBinders
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
import chipyard.{ChipTop}
// -------------------------------
// Chipyard Test Harness
// -------------------------------
case object MultiChipNChips extends Field[Option[Int]](None) // None means ignore MultiChipParams
case class MultiChipParameters(chipId: Int) extends Field[Parameters]
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]()
case object HarnessBinderClockFrequencyKey extends Field[Double](100.0) // MHz
case object MultiChipIdx extends Field[Int](0)
class WithMultiChip(id: Int, p: Parameters) extends Config((site, here, up) => {
case MultiChipParameters(`id`) => p
case MultiChipNChips => Some(up(MultiChipNChips).getOrElse(0) max (id + 1))
})
class WithHomogeneousMultiChip(n: Int, p: Parameters, idStart: Int = 0) extends Config((site, here, up) => {
case MultiChipParameters(id) => if (id >= idStart && id < idStart + n) p else up(MultiChipParameters(id))
case MultiChipNChips => Some(up(MultiChipNChips).getOrElse(0) max (idStart + n))
})
class WithHarnessBinderClockFreqMHz(freqMHz: Double) extends Config((site, here, up) => {
case HarnessBinderClockFrequencyKey => freqMHz
})
// A TestHarness mixing this in will
// - use the HarnessClockInstantiator clock provide
trait HasHarnessInstantiators {
implicit val p: Parameters
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
private val harnessBinderClockFreq: Double = p(HarnessBinderClockFrequencyKey)
def getHarnessBinderClockFreqHz: Double = harnessBinderClockFreq * 1000000
def getHarnessBinderClockFreqMHz: Double = harnessBinderClockFreq
// buildtopClock takes the refClockFreq, and drives the harnessbinders
val harnessBinderClock = Wire(Clock())
val harnessBinderReset = Wire(Reset())
// classes which inherit this trait should provide the below definitions
def referenceClockFreqMHz: Double
def referenceClock: Clock
def referenceReset: Reset
def success: Bool
// This can be accessed to get new clocks from the harness
val harnessClockInstantiator = p(HarnessClockInstantiatorKey)()
val supportsMultiChip: Boolean = false
private val chipParameters = p(MultiChipNChips) match {
case Some(n) => (0 until n).map { i => p(MultiChipParameters(i)).alterPartial {
case TargetDirKey => p(TargetDirKey) // hacky fix
case MultiChipIdx => i
}}
case None => Seq(p)
}
// This shold be called last to build the ChipTops
def instantiateChipTops(): Seq[LazyModule] = {
require(p(MultiChipNChips).isEmpty || supportsMultiChip,
s"Selected Harness does not support multi-chip")
val lazyDuts = chipParameters.zipWithIndex.map { case (q,i) =>
LazyModule(q(BuildTop)(q)).suggestName(s"chiptop$i")
}
val duts = lazyDuts.map(l => Module(l.module))
withClockAndReset (harnessBinderClock, harnessBinderReset) {
lazyDuts.zipWithIndex.foreach {
case (d: HasIOBinders, i: Int) => ApplyHarnessBinders(this, d.lazySystem, d.portMap)(chipParameters(i))
case _ =>
}
ApplyMultiHarnessBinders(this, lazyDuts)
}
val harnessBinderClk = harnessClockInstantiator.requestClockMHz("harnessbinder_clock", getHarnessBinderClockFreqMHz)
println(s"Harness binder clock is $harnessBinderClockFreq")
harnessBinderClock := harnessBinderClk
harnessBinderReset := ResetCatchAndSync(harnessBinderClk, referenceReset.asBool)
harnessClockInstantiator.instantiateHarnessClocks(referenceClock, referenceClockFreqMHz)
lazyDuts
}
}

View File

@@ -0,0 +1,78 @@
package chipyard.harness
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike}
import freechips.rocketchip.devices.debug._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.util._
import testchipip._
import chipyard._
import chipyard.clocking.{HasChipyardPRCI, ClockWithFreq}
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO, HasIOBinders}
import scala.reflect.{ClassTag}
case class MultiHarnessBinders(c0: Int, c1: Int) extends Field[MultiHarnessBinderMap](MultiHarnessBinderMapDefault)
class MultiHarnessBinder[T0, T1, S <: HasHarnessInstantiators, U0 <: Data, U1 <: Data]
(chip0: Int, chip1: Int, fn: => (T0, T1, S, Seq[U0], Seq[U1]) => Unit)
(implicit tag0: ClassTag[T0], tag1: ClassTag[T1], thtag: ClassTag[S], ptag0: ClassTag[U0], ptag1: ClassTag[U1])
extends Config((site, here, up) => {
// Override any HarnessBinders for chip0/chip1
case MultiChipParameters(`chip0`) => new Config(
new OverrideHarnessBinder[T0, S, U0]((system: T0, th: S, ports: Seq[U0]) => Nil) ++
up(MultiChipParameters(chip0))
)
case MultiChipParameters(`chip1`) => new Config(
new OverrideHarnessBinder[T1, S, U1]((system: T1, th: S, ports: Seq[U1]) => Nil) ++
up(MultiChipParameters(chip1))
)
// Set the multiharnessbinder key
case MultiHarnessBinders(`chip0`, `chip1`) => up(MultiHarnessBinders(chip0, chip1)) +
((tag0.runtimeClass.toString, tag1.runtimeClass.toString) ->
((c0: Any, c1: Any, th: HasHarnessInstantiators, ports0: Seq[Data], ports1: Seq[Data]) => {
val pts0 = ports0.map(_.asInstanceOf[U0])
val pts1 = ports1.map(_.asInstanceOf[U1])
require(pts0.size == pts1.size)
(c0, c1, th) match {
case (c0: T0, c1: T1, th: S) => fn(c0, c1, th, pts0, pts1)
case _ =>
}
})
)
})
object ApplyMultiHarnessBinders {
def apply(th: HasHarnessInstantiators, chips: Seq[LazyModule])(implicit p: Parameters): Unit = {
Seq.tabulate(chips.size, chips.size) { case (i, j) => if (i != j) {
(chips(i), chips(j)) match {
case (l0: HasIOBinders, l1: HasIOBinders) => p(MultiHarnessBinders(i, j)).foreach {
case ((s0, s1), f) => {
f(l0.lazySystem , l1.lazySystem , th, l0.portMap(s0), l1.portMap(s1))
f(l0.lazySystem.module, l1.lazySystem.module, th, l0.portMap(s0), l1.portMap(s1))
}
}
case _ =>
}
}}
}
}
class WithMultiChipSerialTL(chip0: Int, chip1: Int) extends MultiHarnessBinder(chip0, chip1, (
(system0: CanHavePeripheryTLSerial, system1: CanHavePeripheryTLSerial,
th: HasHarnessInstantiators,
ports0: Seq[ClockedIO[SerialIO]], ports1: Seq[ClockedIO[SerialIO]]
) => {
require(ports0.size == ports1.size)
(ports0 zip ports1).map { case (l, r) =>
l.clock <> r.clock
require(l.bits.w == r.bits.w)
l.bits.flipConnect(r.bits)
}
}
))

View File

@@ -0,0 +1,38 @@
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
// -------------------------------
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessInstantiators {
val io = IO(new Bundle {
val success = Output(Bool())
})
val success = WireInit(false.B)
io.success := success
override val supportsMultiChip = true
// By default, the chipyard makefile sets the TestHarness implicit clock to be 1GHz
// This clock shouldn't be used by this TestHarness however, as most users
// will use the AbsoluteFreqHarnessClockInstantiator, which generates clocks
// in verilog blackboxes
def referenceClockFreqMHz = 1000.0
def referenceClock = clock
def referenceReset = reset
val lazyDuts = instantiateChipTops()
}

View File

@@ -0,0 +1,17 @@
package chipyard
import chisel3._
import scala.collection.immutable.ListMap
package object harness
{
type HarnessBinderFunction = (Any, HasHarnessInstantiators, Seq[Data]) => Unit
type HarnessBinderMap = Map[String, HarnessBinderFunction]
def HarnessBinderMapDefault: HarnessBinderMap = (new ListMap[String, HarnessBinderFunction])
.withDefaultValue((t: Any, th: HasHarnessInstantiators, d: Seq[Data]) => ())
type MultiHarnessBinderFunction = (Any, Any, HasHarnessInstantiators, Seq[Data], Seq[Data]) => Unit
type MultiHarnessBinderMap = Map[(String, String), MultiHarnessBinderFunction]
def MultiHarnessBinderMapDefault: MultiHarnessBinderMap = (new ListMap[(String, String), MultiHarnessBinderFunction])
.withDefaultValue((_: Any, _: Any, _: HasHarnessInstantiators, _: Seq[Data], _: Seq[Data]) => ())
}

View File

@@ -0,0 +1,90 @@
// See LICENSE for license details
package chipyard.upf
import scala.collection.mutable.{ListBuffer}
import scalax.collection.mutable.{Graph}
import scalax.collection.GraphPredef._, scalax.collection.GraphEdge._
import chipyard.harness.{TestHarness}
import freechips.rocketchip.diplomacy.{LazyModule}
object ChipTopUPF {
def default: UPFFunc.UPFFunction = {
case top: LazyModule => {
val modulesList = getLazyModules(top)
val pdList = createPowerDomains(modulesList)
val g = connectPDHierarchy(pdList)
traverseGraph(g, UPFGenerator.generateUPF)
}
}
def getLazyModules(top: LazyModule): ListBuffer[LazyModule] = {
var i = 0
var result = new ListBuffer[LazyModule]()
result.append(top)
while (i < result.length) {
val lazyMod = result(i)
for (child <- lazyMod.getChildren) {
result.append(child)
}
i += 1
}
return result
}
def createPowerDomains(modulesList: ListBuffer[LazyModule]): ListBuffer[PowerDomain] = {
var pdList = ListBuffer[PowerDomain]()
for (pdInput <- UPFInputs.upfInfo) {
val pd = new PowerDomain(name=pdInput.name, modules=getPDModules(pdInput, modulesList),
isTop=pdInput.isTop, isGated=pdInput.isGated,
highVoltage=pdInput.highVoltage, lowVoltage=pdInput.lowVoltage)
pdList.append(pd)
}
return pdList
}
def getPDModules(pdInput: PowerDomainInput, modulesList: ListBuffer[LazyModule]): ListBuffer[LazyModule] = {
var pdModules = ListBuffer[LazyModule]()
for (moduleName <- pdInput.moduleList) {
var module = modulesList.filter(_.module.name == moduleName)
if (module.length == 1) { // filter returns a collection
pdModules.append(module(0))
} else {
module = modulesList.filter(_.module.instanceName == moduleName)
if (module.length == 1) {
pdModules.append(module(0))
} else {
module = modulesList.filter(_.module.pathName == moduleName)
if (module.length == 1) {
pdModules.append(module(0))
} else {
throw new Exception(s"PowerDomainInput module list doesn't exist in design.")
}
}
}
}
return pdModules
}
def connectPDHierarchy(pdList: ListBuffer[PowerDomain]): Graph[PowerDomain, DiEdge] = {
var g = Graph[PowerDomain, DiEdge]()
for (pd <- pdList) {
val pdInput = UPFInputs.upfInfo.filter(_.name == pd.name)(0)
val childPDs = pdList.filter(x => pdInput.childrenPDs.contains(x.name))
for (childPD <- childPDs) {
g += (pd ~> childPD) // directed edge from pd to childPD
}
}
return g
}
def traverseGraph(g: Graph[PowerDomain, DiEdge], action: (PowerDomain, Graph[PowerDomain, DiEdge]) => Unit): Unit = {
for (node <- g.nodes.filter(_.diPredecessors.isEmpty)) { // all nodes without parents
g.outerNodeTraverser(node).foreach(pd => action(pd, g))
}
}
}
case object ChipTopUPFAspect extends UPFAspect[chipyard.harness.TestHarness](ChipTopUPF.default)

View File

@@ -0,0 +1,24 @@
// See LICENSE for license details
package chipyard.upf
import chisel3.aop.{Aspect}
import firrtl.{AnnotationSeq}
import chipyard.harness.{TestHarness}
import freechips.rocketchip.stage.phases.{TargetDirKey}
import freechips.rocketchip.diplomacy.{LazyModule}
abstract class UPFAspect[T <: TestHarness](upf: UPFFunc.UPFFunction) extends Aspect[T] {
final override def toAnnotation(top: T): AnnotationSeq = {
UPFFunc.UPFPath = top.p(TargetDirKey) + "/upf"
require(top.lazyDuts.length == 1) // currently only supports 1 chiptop
upf(top.lazyDuts.head)
AnnotationSeq(Seq()) // noop
}
}
object UPFFunc {
type UPFFunction = PartialFunction[LazyModule, Unit]
var UPFPath = "" // output dir path
}

View File

@@ -0,0 +1,264 @@
// See LICENSE for license details
package chipyard.upf
import java.io.{FileWriter}
import java.nio.file.{Paths, Files}
import scala.collection.mutable.{ListBuffer}
import scalax.collection.mutable.{Graph}
import scalax.collection.GraphPredef._, scalax.collection.GraphEdge._
import freechips.rocketchip.diplomacy.{LazyModule}
case class PowerDomain (val name: String, val modules: ListBuffer[LazyModule],
val isTop: Boolean, val isGated: Boolean,
val highVoltage: Double, val lowVoltage: Double) {
val mainVoltage = isGated match {
case true => highVoltage // gated nets should have access to high voltage rail (since they are being gated to optimize power)
case false => lowVoltage // currently assuming non-gated nets are on low voltage rail
}
}
object UPFGenerator {
def generateUPF(pd: PowerDomain, g: Graph[PowerDomain, DiEdge]): Unit = {
val node = g.get(pd)
val children = node.diSuccessors.map(x => x.toOuter).toList
val pdList = g.nodes.map(x => x.toOuter).toList
val filePath = UPFFunc.UPFPath
val fileName = s"${pd.name}.upf"
writeFile(filePath, fileName, createMessage(pd, children, pdList))
}
def createMessage(pd: PowerDomain, children: List[PowerDomain], pdList: List[PowerDomain]): String = {
var message = ""
message += loadUPF(pd, children)
message += createPowerDomains(pd)
message += createSupplyPorts(pd)
message += createSupplyNets(pd)
message += connectSupplies(pd)
message += setDomainNets(pd)
message += createPowerSwitches(pd)
message += createPowerStateTable(pd, getPorts(pd, children))
message += createLevelShifters(pd, pdList)
return message
}
def writeFile(filePath: String, fileName: String, message: String): Unit = {
if (!Files.exists(Paths.get(filePath))) {
Files.createDirectories(Paths.get(filePath))
}
val fw = new FileWriter(s"${filePath}/${fileName}", false)
fw.write(message)
fw.close()
}
def getPorts(pd: PowerDomain, children: List[PowerDomain]): ListBuffer[String] = {
var portsList = ListBuffer[String]()
portsList += "VDDH"
portsList += "VDDL"
if (pd.isGated) {
portsList += s"VDD_${pd.name}"
}
for (child <- children) {
if (child.isGated) {
portsList += s"VDD_${child.name}"
}
}
return portsList
}
def loadUPF(pd: PowerDomain, children: List[PowerDomain]): String = {
var message = "##### Set Scope and Load UPF #####\n"
var subMessage = s"set_scope /${pd.modules(0).module.name}\n" //
children.foreach{
child => {
subMessage += s"load_upf ${child.name}.upf -scope ${child.modules(0).module.name}\n"
}
}
message += subMessage
message += "\n"
return message
}
def createPowerDomains(pd: PowerDomain): String = {
var message = "##### Create Power Domains #####\n"
var subMessage = ""
pd.isTop match {
case true => subMessage += s"create_power_domain ${pd.name} -include_scope\n"
case false => {
subMessage += s"create_power_domain ${pd.name} -elements { "
for (module <- pd.modules) {
subMessage += s"${module.module.name} "
}
subMessage += "}\n"
}
}
message += subMessage
message += "\n"
return message
}
def createSupplyPorts(pd: PowerDomain): String = {
if (!pd.isTop) {
return ""
}
var message = "##### Create Supply Ports #####\n"
var subMessage = pd.isTop match {
case true => {
s"create_supply_port VDDH -direction in -domain ${pd.name}\n" +
s"create_supply_port VDDL -direction in -domain ${pd.name}\n" +
s"create_supply_port VSS -direction in -domain ${pd.name}\n"
}
case false => ""
}
message += subMessage
message += "\n"
return message
}
def createSupplyNets(pd: PowerDomain): String = {
var message = "##### Create Supply Nets #####\n"
var subMessage = pd.isTop match {
case true => {
s"create_supply_net VDDH -domain ${pd.name}\n" +
s"create_supply_net VDDL -domain ${pd.name}\n" +
s"create_supply_net VSS -domain ${pd.name}\n"
}
case false => {
s"create_supply_net VDDH -domain ${pd.name} -reuse\n" +
s"create_supply_net VDDL -domain ${pd.name} -reuse\n" +
s"create_supply_net VSS -domain ${pd.name} -reuse\n"
}
}
if (pd.isGated) {
subMessage += s"create_supply_net VDD_${pd.name} -domain ${pd.name}\n"
}
message += subMessage
message += "\n"
return message
}
def connectSupplies(pd: PowerDomain): String = {
var message = "##### Connect Supply Nets and Ports #####\n"
var subMessage = "connect_supply_net VDDH -ports VDDH\n" +
"connect_supply_net VDDL -ports VDDL\n" +
"connect_supply_net VSS -ports VSS\n"
message += subMessage
message += "\n"
return message
}
def setDomainNets(pd: PowerDomain): String = {
var message = "##### Set Domain Supply Nets #####\n"
var subMessage = pd.isGated match {
case true => s"set_domain_supply_net ${pd.name} -primary_power_net VDD_${pd.name} -primary_ground_net VSS\n"
case false => s"set_domain_supply_net ${pd.name} -primary_power_net VDDL -primary_ground_net VSS\n"
}
message += subMessage
message += "\n"
return message
}
def createPowerSwitches(pd: PowerDomain): String = {
if (!pd.isGated) {
return ""
}
var message = "##### Power Switches #####\n"
var subMessage = pd.isGated match {
case true => s"""create_power_switch sw_${pd.name} -domain ${pd.name} -input_supply_port "psw_VDDH VDDH" """ +
s"""-output_supply_port "psw_VDD_${pd.name} VDD_${pd.name}" """ +
s"""-control_port "psw_${pd.name}_en ${pd.modules(0).module.name}/${pd.modules(0).module.name}_en" """ +
s"""-on_state "psw_${pd.name}_ON psw_VDDH { !psw_${pd.name}_en }"""" + "\n"
case false => ""
}
message += subMessage
message += "\n"
return message
}
def createPowerStateTable(pd: PowerDomain, portsList: ListBuffer[String]): String = {
if (!pd.isTop) {
return ""
}
var message = "##### Power State Table #####\n"
var portStates = ""
var createPST = "create_pst pst_table -supplies { "
for (port <- portsList) {
createPST += s"${port} "
if (port == "VDDH") {
portStates += s"add_port_state ${port} -state { HighVoltage ${pd.highVoltage} }\n"
} else if (port == "VDDL") {
portStates += s"add_port_state ${port} -state { LowVoltage ${pd.lowVoltage} }\n"
} else { // gated
portStates += s"add_port_state ${port} -state { HighVoltage ${pd.highVoltage } -state { ${port}_OFF off }\n"
}
}
portStates += "\n"
createPST += "}\n\n"
var pstStates = ""
for (state <- UPFInputs.states.keys) {
val stateVal = getStateVal(pd, state)
pstStates += s"add_pst_state ${state} -pst pst_table -state { "
for (port <- portsList) {
if (port == "VDDH") {
pstStates += s"HighVoltage "
} else if (port == "VDDL") {
pstStates += s"LowVoltage "
} else { // gated
stateVal match {
case 0 => pstStates += s"${port}_OFF "
case 1 => pstStates += s"HighVoltage "
}
}
}
pstStates += "}\n"
}
message += portStates
message += createPST
message += pstStates
message += "\n"
return message
}
def getStateVal(pd: PowerDomain, state: String): Int = {
val stateVals = UPFInputs.states(state).split(",").map(_.trim.toInt)
val index = UPFInputs.domains.indexOf(pd.name)
return stateVals(index)
}
// current strategy: for each power domain, create level shifters for outputs going to all other pds
// not creating level shifters for inputs since every pd will already shift its outputs
// creating level shifters going to every other pd since not sure how to check if there is communication or not between any 2
def createLevelShifters(pd: PowerDomain, pdList: List[PowerDomain]): String = {
var message = "##### Level Shifters #####\n"
for (pd2 <- pdList) {
if (pd != pd2) {
val voltage1 = pd.mainVoltage
val voltage2 = pd2.mainVoltage
var subMessage = voltage1 match {
case x if x < voltage2 => {
s"set_level_shifter LtoH_${pd.name}_to_${pd2.name} " +
s"-domain ${pd.name} " +
"-applies_to outputs " +
"rule low_to_high " +
"-location self\n"
}
case y if y > voltage2 => {
s"set_level_shifter HtoL_${pd.name}_to_${pd2.name} " +
s"-domain ${pd.name} " +
"-applies_to outputs " +
"rule high_to_low " +
"-location self\n"
}
case _ => ""
}
message += subMessage
}
}
message += "\n"
return message
}
}

View File

@@ -0,0 +1,54 @@
// See LICENSE for license details
package chipyard.upf
// outputs are dumped in vlsi/generated-src/upf
object UPFInputs {
/**
* UPF info
* each PowerDomainInput represents a desired power domain
* each input will contain all the necessary info to describe a power domain in UPF, including hierarchy
*/
val upfInfo = List(
PowerDomainInput(name="PD_top", isTop=true, moduleList=List("DigitalTop"),
parentPD="", childrenPDs=List("PD_RocketTile1", "PD_RocketTile2"),
isGated=false, highVoltage=3.9, lowVoltage=3.4),
PowerDomainInput(name="PD_RocketTile1", isTop=false, moduleList=List("tile_prci_domain"),
parentPD="PD_top", childrenPDs=List(),
isGated=false, highVoltage=3.9, lowVoltage=3.1),
PowerDomainInput(name="PD_RocketTile2", isTop=false, moduleList=List("tile_prci_domain_1"),
parentPD="PD_top", childrenPDs=List(),
isGated=false, highVoltage=3.9, lowVoltage=3.2),
)
/**
* PST info
* experimental Power State Table input, used to gate power domains based on specified power states
* place names of all power domains to be gated in the domains list
* states will map different keywords (arbitrary strings) to a binary on or off (1 or 0) to form a power state
* order of domains in list corresponds to order of values in each states mapping
*/
val domains = List("PD_top", "PD_RocketTile1", "PD_RocketTile2")
val states = Map(
"ON" -> "1, 1, 1",
"OFF" -> "0, 0, 0"
)
}
/**
* Representation of a power domain used to generate UPF.
*
* @param name name of the power domain.
* @param isTop if the power domain is the top level or not.
* @param moduleList refers to all the Verilog modules belonging to this power domain. Can be module name, instance name, or full path name.
* @param parentPD the name of the parent power domain to this one.
* @param childrenPDs names of all the children power domains to this one.
* @param isGated if the power domain is gated or not.
* @param highVoltage voltage value of the high voltage rail (currently, gated nets have access to high voltage since they are optimized to save power).
* @param lowVoltage voltage value of the low voltage rail (currently, non-gated nets default to the low voltage rail).
*/
case class PowerDomainInput(name: String, isTop: Boolean, moduleList: List[String],
parentPD: String, childrenPDs: List[String],
isGated: Boolean, highVoltage: Double, lowVoltage: Double)

View File

@@ -4,6 +4,7 @@ package firesim.firesim
import chisel3._
import chisel3.experimental.annotate
import chisel3.experimental.{DataMirror, Direction}
import chisel3.util.experimental.BoringUtils
import org.chipsalliance.cde.config.{Field, Config, Parameters}
@@ -30,12 +31,12 @@ import cva6.CVA6Tile
import boom.common.{BoomTile}
import barstools.iocell.chisel._
import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters, IOCellKey}
import chipyard.{HasHarnessSignalReferences}
import chipyard._
import chipyard.harness._
object MainMemoryConsts {
val regionNamePrefix = "MainMemory"
def globalName = s"${regionNamePrefix}_${NodeIdx()}"
def globalName()(implicit p: Parameters) = s"${regionNamePrefix}_${p(MultiChipIdx)}"
}
trait Unsupported {
@@ -68,15 +69,14 @@ 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 ram = withClockAndReset(th.buildtopClock, th.buildtopReset) {
SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
}
SerialBridge(th.buildtopClock, ram.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.buildtopReset.asBool)
val bits = port.bits
port.clock := th.harnessBinderClock
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset)
TSIBridge(th.harnessBinderClock, ram.module.io.tsi, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.harnessBinderReset.asBool)
}
Nil
}
@@ -97,13 +97,13 @@ class WithUARTBridge extends OverrideHarnessBinder({
val pbusClockNode = system.outer.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(PBUS).fixedClockNode
val pbusClock = pbusClockNode.in.head._1.clock
BoringUtils.bore(pbusClock, Seq(uartSyncClock))
ports.map { p => UARTBridge(uartSyncClock, p, th.buildtopReset.asBool)(system.p) }; Nil
ports.map { p => UARTBridge(uartSyncClock, p, th.harnessBinderReset.asBool)(system.p) }; Nil
})
class WithBlockDeviceBridge extends OverrideHarnessBinder({
(system: CanHavePeripheryBlockDevice, th: FireSim, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
implicit val p: Parameters = GetSystemParameters(system)
ports.map { b => BlockDevBridge(b.clock, b.bits, th.buildtopReset.asBool) }
ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessBinderReset.asBool) }
Nil
}
})
@@ -113,31 +113,25 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({
implicit val p = GetSystemParameters(system)
p(SerialTLKey).map({ sVal =>
require(sVal.axiMemOverSerialTLParams.isDefined)
val axiDomainParams = sVal.axiMemOverSerialTLParams.get
require(sVal.isMemoryDevice)
val serialTLManagerParams = sVal.serialTLManagerParams.get
val axiDomainParams = serialTLManagerParams.axiMemOverSerialTLParams.get
require(serialTLManagerParams.isMemoryDevice)
val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations])
ports.map({ port =>
val axiClock = p(ClockBridgeInstantiatorKey).requestClock("mem_over_serial_tl_clock", memFreq)
val axiClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
axiClockBundle.clock := axiClock
axiClockBundle.reset := ResetCatchAndSync(axiClock, th.buildtopReset.asBool)
val axiClock = th.harnessClockInstantiator.requestClockHz("mem_over_serial_tl_clock", memFreq)
val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
val harnessMultiClockAXIRAM = withClockAndReset(th.buildtopClock, th.buildtopReset) {
SerialAdapter.connectHarnessMultiClockAXIRAM(
system.serdesser.get,
serial_bits,
axiClockBundle,
th.buildtopReset)
}
SerialBridge(th.buildtopClock, harnessMultiClockAXIRAM.module.io.tsi_ser, Some(MainMemoryConsts.globalName), th.buildtopReset.asBool)
val serial_bits = port.bits
port.clock := th.harnessBinderClock
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
system.serdesser.get,
serial_bits,
axiClock,
ResetCatchAndSync(axiClock, th.harnessBinderReset.asBool))
TSIBridge(th.harnessBinderClock, harnessMultiClockAXIRAM.module.io.tsi, Some(MainMemoryConsts.globalName), th.harnessBinderReset.asBool)
// connect SimAxiMem
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi4, edge) =>
(harnessMultiClockAXIRAM.mem_axi4.get zip harnessMultiClockAXIRAM.memNode.get.edges.in).map { case (axi4, edge) =>
val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth,
axi4.bits.ar.bits.addr.getWidth,
axi4.bits.ar.bits.id.getWidth)
@@ -192,7 +186,7 @@ class WithDromajoBridge extends ComposeHarnessBinder({
class WithTraceGenBridge extends OverrideHarnessBinder({
(system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) =>
ports.map { p => GroundTestBridge(th.buildtopClock, p)(system.p) }; Nil
ports.map { p => GroundTestBridge(th.harnessBinderClock, p)(system.p) }; Nil
})
class WithFireSimMultiCycleRegfile extends ComposeIOBinder({
@@ -232,7 +226,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 +239,7 @@ class WithDefaultFireSimBridges extends Config(
// Shorthand to register all of the provided mmio-only bridges above
class WithDefaultMMIOOnlyFireSimBridges extends Config(
new WithSerialBridge ++
new WithTSIBridgeAndHarnessRAMOverSerialTL ++
new WithUARTBridge ++
new WithBlockDeviceBridge ++
new WithFASEDBridge ++

View File

@@ -20,258 +20,76 @@ import chipyard.harness._
import chipyard.iobinders._
import chipyard.clocking._
// Determines the number of times to instantiate the DUT in the harness.
// Subsumes legacy supernode support
case object NumNodes extends Field[Int](1)
class WithNumNodes(n: Int) extends Config((pname, site, here) => {
case NumNodes => n
})
// Hacky: Set before each node is generated. Ideally we'd give IO binders
// accesses to the the Harness's parameters instance. We could then alter that.
object NodeIdx {
private var idx = 0
def increment(): Unit = {idx = idx + 1 }
def apply(): Int = idx
}
/**
* Specifies DUT clocks for the rational clock bridge
*
* @param allClocks Seq. of RationalClocks that want a clock
*
* @param baseClockName Name of domain that the allClocks is rational to
*
* @param baseFreqRequested Freq. for the reference domain in Hz
*/
case class BuildTopClockParameters(allClocks: Seq[RationalClock], baseClockName: String, baseFreqRequested: Double)
/**
* Under FireSim's current multiclock implementation there can be only a
* single clock bridge. This requires, therefore, that it be instantiated in
* the harness and reused across all supernode instances. This class attempts to
* memoize its instantiation such that it can be referenced from within a ClockScheme function.
*/
class ClockBridgeInstantiator {
private val _harnessClockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty
class FireSimClockBridgeInstantiator extends HarnessClockInstantiator {
// connect all clock wires specified to the RationalClockBridge
def instantiateHarnessClocks(refClock: Clock, refClockFreqMHz: Double): Unit = {
val sinks = clockMap.map({ case (name, (freq, bundle)) =>
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name))
}).toSeq
// Assumes that the supernode implementation results in duplicated clocks
// (i.e. only 1 set of clocks is generated for all BuildTop designs)
private var _buildTopClockParams: Option[BuildTopClockParameters] = None
private val _buildTopClockMap: LinkedHashMap[String, (RationalClock, Clock)] = LinkedHashMap.empty
private var _buildTopClockRecord: Option[RecordMap[Clock]] = None
val pllConfig = new SimplePllConfiguration("firesimRationalClockBridge", sinks)
pllConfig.emitSummaries()
/**
* Request a clock at a particular frequency
*
* @param name An identifier for the associated clock domain
*
* @param freqRequested Freq. for the domain in Hz
*/
def requestClock(name: String, freqRequested: Double): Clock = {
val clkWire = Wire(new Clock)
_harnessClockMap(name) = (freqRequested, clkWire)
clkWire
}
/**
* Get a RecordMap of clocks for a set of input RationalClocks. Used to drive
* the design elaborated by buildtop
*
* @param clockMapParameters Defines the set of required clocks
*/
def requestClockRecordMap(clockMapParameters: BuildTopClockParameters): RecordMap[Clock] = {
if (_buildTopClockParams.isDefined) {
require(_buildTopClockParams.get == clockMapParameters, "Must request same set of clocks on repeated invocations.")
} else {
val clockRecord = Wire(RecordMap(clockMapParameters.allClocks.map { c => (c.name, Clock()) }:_*))
// Build up the mutable structures describing the clocks for the dut
_buildTopClockParams = Some(clockMapParameters)
_buildTopClockRecord = Some(clockRecord)
for (clock <- clockMapParameters.allClocks) {
val clockWire = Wire(new Clock)
_buildTopClockMap(clock.name) = (clock, clockWire)
clockRecord(clock.name).get := clockWire
var instantiatedClocks = LinkedHashMap[Int, (Clock, Seq[String])]()
// connect wires to clock source
def findOrInstantiate(freqMHz: Int, name: String): Clock = {
if (!instantiatedClocks.contains(freqMHz)) {
val clock = Wire(Clock())
instantiatedClocks(freqMHz) = (clock, Seq(name))
} else {
instantiatedClocks(freqMHz) = (instantiatedClocks(freqMHz)._1, instantiatedClocks(freqMHz)._2 :+ name)
}
instantiatedClocks(freqMHz)._1
}
for ((name, (freq, clock)) <- clockMap) {
val freqMHz = (freq / (1000 * 1000)).toInt
clock := findOrInstantiate(freqMHz, name)
}
_buildTopClockRecord.get
}
// The undivided reference clock as calculated by pllConfig must be instantiated
findOrInstantiate(pllConfig.referenceFreqMHz.toInt, "reference")
/**
* Connect all clocks requested to ClockBridge
*/
def instantiateFireSimClockBridge: Unit = {
require(_buildTopClockParams.isDefined, "Must have rational clocks to assign to")
val BuildTopClockParameters(allClocks, refRatClockName, refRatClockFreq) = _buildTopClockParams.get
require(_buildTopClockMap.exists(_._1 == refRatClockName),
s"Provided base-clock name for rational clocks, ${refRatClockName}, doesn't match a name within specified rational clocks." +
"Available clocks:\n " + _buildTopClockMap.map(_._1).mkString("\n "))
// Simplify the RationalClocks ratio's
val refRatClock = _buildTopClockMap.find(_._1 == refRatClockName).get._2._1
val simpleRatClocks = _buildTopClockMap.map { t =>
val ratClock = t._2._1
ratClock.copy(
multiplier = ratClock.multiplier * refRatClock.divisor,
divisor = ratClock.divisor * refRatClock.multiplier).simplify
}
// Determine all the clock dividers (harness + rational clocks)
// Note: Requires that the BuildTop reference frequency is requested with proper freq.
val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(refRatClockName))
val harSinkParams = _harnessClockMap.map { case (name, (freq, bundle)) =>
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))),name=Some(name))
val ratClocks = instantiatedClocks.map { case (freqMHz, (clock, names)) =>
(RationalClock(names.mkString(","), 1, pllConfig.referenceFreqMHz.toInt / freqMHz), clock)
}.toSeq
val allSinkParams = harSinkParams :+ refRatSinkParams
// Use PLL config to determine overall div's
val pllConfig = new SimplePllConfiguration("firesimOverallClockBridge", allSinkParams)
pllConfig.emitSummaries
// Adjust all BuildTop RationalClocks with the div determined by the PLL
val refRatDiv = pllConfig.sinkDividerMap(refRatSinkParams)
val adjRefRatClocks = simpleRatClocks.map { clock =>
clock.copy(divisor = clock.divisor * refRatDiv).simplify
}
// Convert harness clocks to RationalClocks
val harRatClocks = harSinkParams.map { case ClockSinkParameters(_, _, _, _, clkParamsOpt, nameOpt) =>
RationalClock(nameOpt.get, 1, pllConfig.referenceFreqMHz.toInt / clkParamsOpt.get.freqMHz.toInt)
}
val allAdjRatClks = adjRefRatClocks ++ harRatClocks
// Removes clocks that have the same frequency before instantiating the
// clock bridge to avoid unnecessary BUFGCE use.
val allDistinctRatClocks = allAdjRatClks.foldLeft(Seq(RationalClock(pllConfig.referenceSinkParams.name.get, 1, 1))) {
case (list, candidate) => if (list.exists { clock => clock.equalFrequency(candidate) }) list else list :+ candidate
}
val clockBridge = Module(new RationalClockBridge(allDistinctRatClocks))
val cbVecTuples = allDistinctRatClocks.zip(clockBridge.io.clocks)
// Connect all clocks (harness + BuildTop clocks)
for (clock <- allAdjRatClks) {
val (_, cbClockField) = cbVecTuples.find(_._1.equalFrequency(clock)).get
_buildTopClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField }
_harnessClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField }
val clockBridge = Module(new RationalClockBridge(ratClocks.map(_._1)))
(clockBridge.io.clocks zip ratClocks).foreach { case (clk, rat) =>
rat._2 := clk
}
}
}
case object ClockBridgeInstantiatorKey extends Field[ClockBridgeInstantiator](new ClockBridgeInstantiator)
case object FireSimBaseClockNameKey extends Field[String]("implicit_clock")
class ClocksWithSinkParams(val params: Seq[ClockSinkParameters]) extends Bundle {
val clocks = Vec(params.size, Clock())
}
class WithFireSimSimpleClocks extends OverrideLazyIOBinder({
(system: HasChipyardPRCI) => {
implicit val p = GetSystemParameters(system)
// Figure out what provides this in the chipyard scheme
implicit val valName = ValName("FireSimClocking")
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 inputClockSource = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
system.allClockGroupsNode := inputClockSource
InModuleBody {
val (clockGroupBundle, clockGroupEdge) = inputClockSource.out.head
val reset_io = IO(Input(AsyncReset())).suggestName("async_reset")
val input_clocks = IO(Input(new ClocksWithSinkParams(clockGroupEdge.sink.members)))
.suggestName("clocks")
(clockGroupBundle.member.data zip input_clocks.clocks).foreach { case (clockBundle, inputClock) =>
clockBundle.clock := inputClock
clockBundle.reset := reset_io
}
(Seq(reset_io, input_clocks), Nil)
}
}
})
class WithFireSimHarnessClockBinder extends OverrideHarnessBinder({
(system: HasChipyardPRCI, th: FireSim, ports: Seq[Data]) => {
implicit val p = th.p
ports.map ({
case c: ClocksWithSinkParams => {
val pllConfig = new SimplePllConfiguration("firesimBuildTopClockGenerator", c.params)
pllConfig.emitSummaries
th.setRefClockFreq(pllConfig.referenceFreqMHz)
val rationalClockSpecs = for ((sinkP, division) <- pllConfig.sinkDividerMap) yield {
RationalClock(sinkP.name.get, 1, division)
}
val input_clocks: RecordMap[Clock] = p(ClockBridgeInstantiatorKey).requestClockRecordMap(
BuildTopClockParameters(
rationalClockSpecs.toSeq,
p(FireSimBaseClockNameKey),
pllConfig.referenceFreqMHz * (1000 * 1000)))
(c.clocks zip c.params) map ({ case (clock, param) =>
clock := input_clocks(param.name.get).get
})
}
case r: Reset => r := th.buildtopReset.asAsyncReset
})
}
})
class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences {
class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessInstantiators {
require(harnessClockInstantiator.isInstanceOf[FireSimClockBridgeInstantiator])
freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary())
val buildtopClock = Wire(Clock())
val buildtopReset = WireInit(false.B)
// The peek-poke bridge must still be instantiated even though it's
// functionally unused. This will be removed in a future PR.
val dummy = WireInit(false.B)
val peekPokeBridge = PeekPokeBridge(buildtopClock, dummy)
val peekPokeBridge = PeekPokeBridge(harnessBinderClock, dummy)
val resetBridge = Module(new ResetPulseBridge(ResetPulseBridgeParameters()))
// In effect, the bridge counts the length of the reset in terms of this clock.
resetBridge.io.clock := buildtopClock
buildtopReset := resetBridge.io.reset
// Ensures FireSim-synthesized assertions and instrumentation is disabled
// while buildtopReset is asserted. This ensures assertions do not fire at
// time zero in the event their local reset is delayed (typically because it
// has been pipelined)
midas.targetutils.GlobalResetCondition(buildtopReset)
resetBridge.io.clock := harnessBinderClock
def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B }
def referenceClockFreqMHz = 0.0
def referenceClock = false.B.asClock // unused
def referenceReset = resetBridge.io.reset
def success = { require(false, "success should not be used in Firesim"); false.B }
// Instantiate multiple instances of the DUT to implement supernode
for (i <- 0 until p(NumNodes)) {
// It's not a RC bump without some hacks...
// Copy the AsyncClockGroupsKey to generate a fresh node on each
// instantiation of the dut, otherwise the initial instance will be
// reused across each node
import freechips.rocketchip.subsystem.AsyncClockGroupsKey
val lazyModule = LazyModule(p(BuildTop)(p))
val module = Module(lazyModule.module)
override val supportsMultiChip = true
lazyModule match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
}
NodeIdx.increment()
}
instantiateChipTops()
buildtopClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge
// Ensures FireSim-synthesized assertions and instrumentation is disabled
// while resetBridge.io.reset is asserted. This ensures assertions do not fire at
// time zero in the event their local reset is delayed (typically because it
// has been pipelined)
midas.targetutils.GlobalResetCondition(resetBridge.io.reset)
}

View File

@@ -18,6 +18,7 @@ import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams}
import scala.math.{min, max}
import chipyard.clocking.{ChipyardPRCIControlKey}
import chipyard.harness.{HarnessClockInstantiatorKey}
import icenet._
import firesim.bridges._
@@ -43,6 +44,11 @@ class WithoutClockGating extends Config((site, here, up) => {
case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey, site).copy(enableTileClockGating = false)
})
// Use the firesim clock bridge instantiator. this is required
class WithFireSimHarnessClockBridgeInstantiator extends Config((site, here, up) => {
case HarnessClockInstantiatorKey => () => new FireSimClockBridgeInstantiator
})
// Testing configurations
// This enables printfs used in testing
class WithScalaTestFeatures extends Config((site, here, up) => {
@@ -63,9 +69,11 @@ class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small")
// Minimal set of FireSim-related design tweaks - notably discludes FASED, TraceIO, and the BlockDevice
class WithMinimalFireSimDesignTweaks extends Config(
// Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset
new WithFireSimHarnessClockBinder ++
new WithFireSimSimpleClocks ++
// Required*: Punch all clocks to FireSim's harness clock instantiator
new WithFireSimHarnessClockBridgeInstantiator ++
new chipyard.harness.WithHarnessBinderClockFreqMHz(1000.0) ++
new chipyard.harness.WithClockAndResetFromHarness ++
new chipyard.clocking.WithPassthroughClockGenerator ++
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
new WithBootROM ++
// Required: Existing FAME-1 transform cannot handle black-box clock gates
@@ -84,7 +92,7 @@ class WithFireSimDesignTweaks extends Config(
// Optional: reduce the width of the Serial TL interface
new testchipip.WithSerialTLWidth(4) ++
// Required*: Scale default baud rate with periphery bus frequency
new chipyard.config.WithUART(BigInt(3686400L)) ++
new chipyard.config.WithUARTInitBaudRate(BigInt(3686400L)) ++
// Optional: Adds IO to attach tracerV bridges
new chipyard.config.WithTraceIO ++
// Optional: Request 16 GiB of target-DRAM by default (can safely request up to 32 GiB on F1)
@@ -95,11 +103,15 @@ class WithFireSimDesignTweaks extends Config(
// Tweaks to modify target clock frequencies / crossings to legacy firesim defaults
class WithFireSimHighPerfClocking extends Config(
// Create clock group for uncore that does not include mbus
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("sbus", "pbus", "fbus", "cbus", "implicit"), Nil)) ++
// Optional: This sets the default frequency for all buses in the system to 3.2 GHz
// (since unspecified bus frequencies will use the pbus frequency)
// This frequency selection matches FireSim's legacy selection and is required
// to support 200Gb NIC performance. You may select a smaller value.
new chipyard.config.WithPeripheryBusFrequency(3200.0) ++
new chipyard.config.WithSystemBusFrequency(3200.0) ++
new chipyard.config.WithFrontBusFrequency(3200.0) ++
// Optional: These three configs put the DRAM memory system in it's own clock domain.
// Removing the first config will result in the FASED timing model running
// at the pbus freq (above, 3.2 GHz), which is outside the range of valid DDR3 speedgrades.
@@ -116,25 +128,17 @@ class WithFireSimConfigTweaks extends Config(
// Using some other frequency will require runnings the FASED runtime configuration generator
// to generate faithful DDR3 timing values.
new chipyard.config.WithSystemBusFrequency(1000.0) ++
new chipyard.config.WithSystemBusFrequencyAsDefault ++ // All unspecified clock frequencies, notably the implicit clock, will use the sbus freq (1000 MHz)
// Explicitly set PBUS + MBUS to 1000 MHz, since they will be driven to 100 MHz by default because of assignments in the Chisel
new chipyard.config.WithPeripheryBusFrequency(1000.0) ++
new chipyard.config.WithMemoryBusFrequency(1000.0) ++
new WithFireSimDesignTweaks
)
// Tweak more representative of testchip configs
class WithFireSimTestChipConfigTweaks extends Config(
new chipyard.config.WithTestChipBusFreqs ++
new WithFireSimDesignTweaks
)
// Tweaks to use minimal design tweaks
// Need to use initramfs to use linux (no block device)
class WithMinimalFireSimHighPerfConfigTweaks extends Config(
new WithFireSimHighPerfClocking ++
new freechips.rocketchip.subsystem.WithNoMemPort ++
new testchipip.WithBackingScratchpad ++
new testchipip.WithMbusScratchpad ++
new WithMinimalFireSimDesignTweaks
)
@@ -144,7 +148,7 @@ class WithMinimalFireSimHighPerfConfigTweaks extends Config(
class WithMinimalAndBlockDeviceFireSimHighPerfConfigTweaks extends Config(
new WithFireSimHighPerfClocking ++
new freechips.rocketchip.subsystem.WithNoMemPort ++ // removes mem port for FASEDBridge to match against
new testchipip.WithBackingScratchpad ++ // adds backing scratchpad for memory to replace FASED model
new testchipip.WithMbusScratchpad ++ // adds backing scratchpad for memory to replace FASED model
new testchipip.WithBlockDevice(true) ++ // add in block device
new WithMinimalFireSimDesignTweaks
)
@@ -164,6 +168,23 @@ class WithFireSimHighPerfConfigTweaks extends Config(
new WithFireSimDesignTweaks
)
// Tweak more representative of testchip configs
class WithFireSimTestChipConfigTweaks extends Config(
// Frequency specifications
new chipyard.config.WithTileFrequency(1000.0) ++ // Realistic tile frequency for a test chip
new chipyard.config.WithSystemBusFrequency(500.0) ++ // Realistic system bus frequency
new chipyard.config.WithMemoryBusFrequency(1000.0) ++ // Needs to be 1000 MHz to model DDR performance accurately
new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Match the sbus and pbus frequency
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("sbus", "pbus", "fbus", "cbus", "implicit"), Seq("tile"))) ++
// 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 boom.common.WithRationalBoomTiles ++ // Add rational crossings between BoomTile and uncore
new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS
new WithFireSimDesignTweaks
)
/*******************************************************************************
* Full TARGET_CONFIG configurations. These set parameters of the target being
* simulated.
@@ -186,6 +207,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 ++
@@ -204,7 +241,7 @@ class FireSimSmallSystemConfig extends Config(
new freechips.rocketchip.subsystem.WithExtMemSize(1 << 28) ++
new testchipip.WithDefaultSerialTL ++
new testchipip.WithBlockDevice ++
new chipyard.config.WithUART ++
new chipyard.config.WithUARTInitBaudRate(BigInt(3686400L)) ++
new freechips.rocketchip.subsystem.WithInclusiveCache(nWays = 2, capacityKB = 64) ++
new chipyard.RocketConfig)
@@ -251,9 +288,10 @@ class FireSimLeanGemminiPrintfRocketConfig extends Config(
// Supernode Configurations, base off chipyard's RocketConfig
//**********************************************************************************
class SupernodeFireSimRocketConfig extends Config(
new WithNumNodes(4) ++
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 8L) ++ // 8 GB
new FireSimRocketConfig)
new WithFireSimHarnessClockBridgeInstantiator ++
new chipyard.harness.WithHomogeneousMultiChip(n=4, new Config(
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 8L) ++ // 8GB DRAM per node
new FireSimRocketConfig)))
//**********************************************************************************
//* CVA6 Configurations
@@ -291,7 +329,7 @@ class FireSim16LargeBoomConfig extends Config(
class FireSimNoMemPortConfig extends Config(
new WithDefaultFireSimBridges ++
new freechips.rocketchip.subsystem.WithNoMemPort ++
new testchipip.WithBackingScratchpad ++
new testchipip.WithMbusScratchpad ++
new WithFireSimConfigTweaks ++
new chipyard.RocketConfig)

1
generators/shuttle Submodule

Submodule generators/shuttle added at 3c15591a9e