📄 main.cc
字号:
// A simple ROM module. It registers the following variables://// fileName name of the file that will be used to// initialize the content of the ROM.// size size of the memory bank in KB// must be a power of two.// readLatency latency of read accesses in nanoseconds.// (default: 150)// writeLatency latency of write attempts in nanoseconds// (default: 150)#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <assert.hh>#include <checkpoint.hh>#include <device.hh>#include <inttypes.hh>#include <module.hh>#include <serial.hh>#include <simarg.hh>#include <sulima.hh>#include "rom.hh"// Serialization information.SerialType<ROM> ROM::type( "ROM", "Basic ROM module.");// Runtime constructor.ROM::ROM(const SimArgs& args) : Module(args), Device(64), file_name(0), data(0){ if (args.length() > 2) throw Error("Too many arguments to \"sim::install ROM\"."); define("fileName", conf.file_name); define("size", conf.size); define("readLatency", conf.read_latency, 150); define("writeLatency", conf.write_latency, 150);}// Serialized constructor.ROM::ROM(Checkpoint& cp) : Module(cp), Device(64), file_name(extract_word(cp)), data(0){ define("fileName", conf.file_name, file_name); cp >> conf.size >> conf.read_latency >> conf.write_latency >> '\n'; define("size", conf.size); define("readLatency", conf.read_latency, conf.read_latency); define("writeLatency", conf.write_latency, conf.write_latency); reset(false);}// Destructor.ROM::~ROM(){ delete file_name; delete data;}// Module interface.voidROM::reset(bool warm){ struct stat stat_buf; if (!warm) { if (!is_power_of_two(conf.size)) throw Error("%#s: ROM size must be a power of two.", name()); UInt32 n = conf.size * KB; UInt64* buf = new UInt64[n/8]; memset(buf, 0, n); FILE* fp = fopen(conf.file_name, "rb"); if (!fp) { delete buf; throw FileError(conf.file_name); } /* fstat */ fstat(fileno(fp), &stat_buf); if ((UInt32) stat_buf.st_size > n) { throw Error("%#s: ROM size (%dkb) must be bigger" "than ROM filesize (%dkb).", name(), n / KB, stat_buf.st_size / KB); } fread(buf, 1, n, fp); if (ferror(fp)) { delete buf; fclose(fp); throw FileError(conf.file_name); } fclose(fp); // FIXME: only if host endianness is different for (UInt32 i = 0; i < n/8; i++) buf[i] = byte_swap(buf[i]); delete file_name; delete data; size = n; data = buf; file_name = copy(conf.file_name); read_latency = conf.read_latency; write_latency = conf.write_latency; freq = nanoseconds(1,1); }#if 0 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX for (int i = 0; i < 16*16; i += 16) { msg("%08x: " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x ", i * 16, data[i+0], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7], data[i+8], data[i+9], data[i+10], data[i+11], data[i+12], data[i+13], data[i+14], data[i+15]); }#endif // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}// Serialization interface.voidROM::checkpoint(Checkpoint& cp, bool parent) const{ ClockValue rl = nanoseconds(read_latency, freq); ClockValue wl = nanoseconds(write_latency, freq); if (parent) cp << type << ' ' << id << '\n'; cp << file_name << ' ' << size << ' ' << rl << ' ' << wl << '\n';}// Device access.ClockValueROM::read(UInt64 addr, UInt64* buf, int size){ assert(size > 0 && size <= 8); assert(!is_power_of_two(size) || (addr & (size - 1)) == 0); // Decode the address. Note that, as with real hardware, we simply ignore // irrelevant address lines (the hardware has no way of knowing where in // the address space it is currently mapped.) addr &= (ROM::size - 1);#if 0 // Fetch (size) bytes from (addr) to (buf). I'm using sizeof() instead of // explicit constants, as, if the minimum-width types aren't exactly the // right size, we have to give up on performance anyway. if (size == sizeof(UInt8)) *buf = *(UInt8 *)(data + addr); else if (size == sizeof(UInt16)) *buf = *(UInt16 *)(data + addr); else if (size == sizeof(UInt32)) *buf = *(UInt32 *)(data + addr); else if (size == sizeof(UInt64)) *buf = *(UInt64 *)(data + addr); else { // Forget about performance. memcpy(buf, data + addr, size); if (big_endian_host()) *buf >>= (sizeof(*buf) - size) * 8; }#else // taken from mips64/bus/read.cc if (size > 8) { UInt64* src = &data[addr / 8]; int i = 0; for (; i < size / 8; ++i) *buf++ = *src++; } else { UInt64 x = data[addr / 8]; unsigned offset = addr % 8; *buf = (big_endian_host()) ? x >> (offset * 8) : x >> (64 - (size + offset) * 8); }#endif // Compute the access latency. if (freq != bus->clock->freq) { read_latency = bus->clock->cycles(read_latency, freq); write_latency = bus->clock->cycles(write_latency, freq); freq = bus->clock->freq; } return read_latency * size; // assume an 8-bit ROM.}ClockValueROM::write(UInt64 addr, const UInt64 *, int size){ assert(size > 0 && size <= 8); assert(!is_power_of_two(size) || (addr & (size - 1)) == 0); msg("Write to ROM address %ld attempted.", addr); if (freq != bus->clock->freq) { read_latency = bus->clock->cycles(read_latency, freq); write_latency = bus->clock->cycles(write_latency, freq); freq = bus->clock->freq; } return bus_error(write_latency * size); // assume an 8-bit ROM.}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -