+++ /dev/null
-// See LICENSE for license details.
-
-#ifndef _RISCV_DEVICETREE_H
-#define _RISCV_DEVICETREE_H
-
-#include <stdint.h>
-#include <string.h>
-#include <string>
-#include <map>
-#include <vector>
-#include <arpa/inet.h>
-
-#define FDT_MAGIC 0xd00dfeedU
-#define FDT_VERSION 17
-#define FDT_COMP_VERSION 16
-#define FDT_BEGIN_NODE 1
-#define FDT_END_NODE 2
-#define FDT_PROP 3
-#define FDT_END 9
-
-struct fdt_header {
- uint32_t magic;
- uint32_t totalsize;
- uint32_t off_dt_struct;
- uint32_t off_dt_strings;
- uint32_t off_rsvmap;
- uint32_t version;
- uint32_t last_comp_version;
- uint32_t boot_cpuid_phys;
- uint32_t size_dt_strings;
- uint32_t size_dt_struct;
-};
-
-struct fdt_reserve_entry {
- uint64_t address;
- uint64_t size;
-};
-
-struct string_table {
- std::map<std::string, size_t> strings;
- std::vector<char> data;
-
- size_t add(std::string s) {
- if (!strings.count(s)) {
- strings[s] = data.size();
- data.insert(data.end(), s.begin(), s.end());
- data.push_back(0);
- }
- return strings[s];
- }
-};
-
-struct device_tree {
- device_tree() {
- memset(rsvmap, 0, sizeof(rsvmap));
- }
-
- void begin_node(std::string s) {
- std::vector<uint32_t> name = s2v(s);
- sblock.push_back(FDT_BEGIN_NODE);
- sblock.insert(sblock.end(), name.begin(), name.end());
- }
-
- void end_node() {
- sblock.push_back(FDT_END_NODE);
- }
-
- std::vector<char> finalize() {
- sblock.push_back(FDT_END);
-
- struct fdt_header h;
- h.size_dt_struct = sblock.size() * sizeof(sblock[0]);
- h.size_dt_strings = strings.data.size();
- h.magic = FDT_MAGIC;
- h.off_rsvmap = sizeof(h);
- h.off_dt_struct = h.off_rsvmap + sizeof(rsvmap);
- h.off_dt_strings = h.off_dt_struct + h.size_dt_struct;
- h.totalsize = h.off_dt_strings + h.size_dt_strings;
- h.version = FDT_VERSION;
- h.last_comp_version = FDT_COMP_VERSION;
- h.boot_cpuid_phys = 0;
-
- for (uint32_t* p = &h.magic; p < &h.magic + sizeof(h)/sizeof(uint32_t); p++)
- *p = htonl(*p);
- for (uint32_t& p : sblock)
- p = htonl(p);
-
- std::vector<char> res;
- res.insert(res.end(), (char*)&h, (char*)&h + sizeof(h));
- res.insert(res.end(), (char*)&rsvmap, (char*)&rsvmap + sizeof(rsvmap));
- res.insert(res.end(), (char*)&sblock[0],
- (char*)&sblock[0] + sblock.size() * sizeof(sblock[0]));
- res.insert(res.end(), strings.data.begin(), strings.data.end());
- return res;
- }
-
- void add_prop(std::string name, uint32_t data)
- {
- add_prop(name, std::vector<uint32_t>(1, data), sizeof(data));
- }
-
- void add_reg(std::vector<uint64_t> values)
- {
- std::vector<uint32_t> v;
- for (auto x : values) {
- v.push_back(x >> 32);
- v.push_back(x);
- }
- add_prop("reg", v, v.size() * sizeof(v[0]));
- }
-
- void add_prop(std::string name, std::string data)
- {
- add_prop(name, s2v(data), data.size()+1);
- }
-
- private:
- struct string_table strings;
- std::vector<uint32_t> sblock;
- struct fdt_reserve_entry rsvmap[1];
-
- std::vector<uint32_t> s2v(std::string data) {
- std::vector<char> v(data.begin(), data.end());
- do {
- v.push_back(0);
- } while (v.size() % 4);
-
- std::vector<uint32_t> words;
- for (size_t i = 0; i < v.size(); i += 4)
- words.push_back((v[i] << 24) | (v[i+1] << 16) | (v[i+2] << 8) | v[i+3]);
- return words;
- }
-
- void add_prop(std::string name, std::vector<uint32_t> data, size_t len) {
- sblock.push_back(FDT_PROP);
- sblock.push_back(len);
- sblock.push_back(strings.add(name));
- sblock.insert(sblock.end(), data.begin(), data.end());
- }
-};
-
-#endif
#include "sim.h"
#include "htif.h"
-#include "devicetree.h"
#include <map>
#include <iostream>
+#include <sstream>
#include <climits>
#include <cstdlib>
#include <cassert>
for (size_t i = 0; i < procs.size(); i++)
procs[i] = new processor_t(isa, this, i);
- make_device_tree();
+ make_config_string();
}
sim_t::~sim_t()
return bus.store(addr, len, bytes);
}
-void sim_t::make_device_tree()
+void sim_t::make_config_string()
{
- char buf[32];
- size_t max_devtree_size = procs.size() * 4096; // sloppy upper bound
- size_t cpu_size = NCSR * procs[0]->max_xlen / 8;
- reg_t cpu_addr = memsz + max_devtree_size;
-
- device_tree dt;
- dt.begin_node("");
- dt.add_prop("#address-cells", 2);
- dt.add_prop("#size-cells", 2);
- dt.add_prop("model", "Spike");
- dt.begin_node("memory@0");
- dt.add_prop("device_type", "memory");
- dt.add_reg({0, memsz});
- dt.end_node();
- dt.begin_node("cpus");
- dt.add_prop("#address-cells", 2);
- dt.add_prop("#size-cells", 2);
- for (size_t i = 0; i < procs.size(); i++) {
- sprintf(buf, "cpu@%" PRIx64, cpu_addr);
- dt.begin_node(buf);
- dt.add_prop("device_type", "cpu");
- dt.add_prop("compatible", "riscv");
- dt.add_prop("isa", procs[i]->isa_string);
- dt.add_reg({cpu_addr});
- dt.end_node();
-
- bus.add_device(cpu_addr, procs[i]);
- cpu_addr += cpu_size;
- }
- dt.end_node();
- dt.end_node();
-
- devicetree.reset(new rom_device_t(dt.finalize()));
- bus.add_device(memsz, devicetree.get());
+ size_t csr_size = NCSR * 16 /* RV128 */;
+ size_t device_tree_addr = memsz;
+ size_t cpu_addr = memsz + csr_size;
+
+ std::stringstream s;
+ s << std::hex <<
+ "platform {\n"
+ " vendor ucb;\n"
+ " arch spike;\n"
+ "};\n"
+ "ram {\n"
+ " 0 {\n"
+ " addr 0;\n"
+ " size 0x" << memsz << ";\n"
+ " };\n"
+ "};\n"
+ "core {\n";
+ for (size_t i = 0; i < procs.size(); i++) {
+ s <<
+ " " << i << " {\n"
+ " " << "0 {\n" << // hart 0 on core i
+ " isa " << procs[i]->isa_string << ";\n"
+ " addr 0x" << cpu_addr << ";\n"
+ " };\n"
+ " };\n";
+ bus.add_device(cpu_addr, procs[i]);
+ cpu_addr += csr_size;
+ }
+ s << "};\n";
+
+ std::string str = s.str();
+ std::vector<char> vec(str.begin(), str.end());
+ vec.push_back(0);
+ assert(vec.size() <= csr_size);
+ config_string.reset(new rom_device_t(vec));
+ bus.add_device(memsz, config_string.get());
}