Update README
[riscv-isa-sim.git] / riscv / dts.cc
1 // See LICENSE for license details.
2
3 #include "dts.h"
4 #include <iostream>
5 #include <sstream>
6 #include <signal.h>
7 #include <unistd.h>
8 #include <sys/wait.h>
9 #include <sys/types.h>
10
11 std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
12 std::vector<processor_t*> procs,
13 std::vector<std::pair<reg_t, mem_t*>> mems)
14 {
15 std::stringstream s;
16 s << std::dec <<
17 "/dts-v1/;\n"
18 "\n"
19 "/ {\n"
20 " #address-cells = <2>;\n"
21 " #size-cells = <2>;\n"
22 " compatible = \"ucbbar,spike-bare-dev\";\n"
23 " model = \"ucbbar,spike-bare\";\n"
24 " cpus {\n"
25 " #address-cells = <1>;\n"
26 " #size-cells = <0>;\n"
27 " timebase-frequency = <" << (cpu_hz/insns_per_rtc_tick) << ">;\n";
28 for (size_t i = 0; i < procs.size(); i++) {
29 s << " CPU" << i << ": cpu@" << i << " {\n"
30 " device_type = \"cpu\";\n"
31 " reg = <" << i << ">;\n"
32 " status = \"okay\";\n"
33 " compatible = \"riscv\";\n"
34 " riscv,isa = \"" << procs[i]->get_isa_string() << "\";\n"
35 " mmu-type = \"riscv," << (procs[i]->get_max_xlen() <= 32 ? "sv32" : "sv48") << "\";\n"
36 " clock-frequency = <" << cpu_hz << ">;\n"
37 " CPU" << i << "_intc: interrupt-controller {\n"
38 " #interrupt-cells = <1>;\n"
39 " interrupt-controller;\n"
40 " compatible = \"riscv,cpu-intc\";\n"
41 " };\n"
42 " };\n";
43 }
44 s << " };\n";
45 for (auto& m : mems) {
46 s << std::hex <<
47 " memory@" << m.first << " {\n"
48 " device_type = \"memory\";\n"
49 " reg = <0x" << (m.first >> 32) << " 0x" << (m.first & (uint32_t)-1) <<
50 " 0x" << (m.second->size() >> 32) << " 0x" << (m.second->size() & (uint32_t)-1) << ">;\n"
51 " };\n";
52 }
53 s << " soc {\n"
54 " #address-cells = <2>;\n"
55 " #size-cells = <2>;\n"
56 " compatible = \"ucbbar,spike-bare-soc\", \"simple-bus\";\n"
57 " ranges;\n"
58 " clint@" << CLINT_BASE << " {\n"
59 " compatible = \"riscv,clint0\";\n"
60 " interrupts-extended = <" << std::dec;
61 for (size_t i = 0; i < procs.size(); i++)
62 s << "&CPU" << i << "_intc 3 &CPU" << i << "_intc 7 ";
63 reg_t clintbs = CLINT_BASE;
64 reg_t clintsz = CLINT_SIZE;
65 s << std::hex << ">;\n"
66 " reg = <0x" << (clintbs >> 32) << " 0x" << (clintbs & (uint32_t)-1) <<
67 " 0x" << (clintsz >> 32) << " 0x" << (clintsz & (uint32_t)-1) << ">;\n"
68 " };\n"
69 " };\n"
70 " htif {\n"
71 " compatible = \"ucb,htif0\";\n"
72 " };\n"
73 "};\n";
74 return s.str();
75 }
76
77 std::string dts_compile(const std::string& dts)
78 {
79 // Convert the DTS to DTB
80 int dts_pipe[2];
81 pid_t dts_pid;
82
83 if (pipe(dts_pipe) != 0 || (dts_pid = fork()) < 0) {
84 std::cerr << "Failed to fork dts child: " << strerror(errno) << std::endl;
85 exit(1);
86 }
87
88 // Child process to output dts
89 if (dts_pid == 0) {
90 close(dts_pipe[0]);
91 int step, len = dts.length();
92 const char *buf = dts.c_str();
93 for (int done = 0; done < len; done += step) {
94 step = write(dts_pipe[1], buf+done, len-done);
95 if (step == -1) {
96 std::cerr << "Failed to write dts: " << strerror(errno) << std::endl;
97 exit(1);
98 }
99 }
100 close(dts_pipe[1]);
101 exit(0);
102 }
103
104 pid_t dtb_pid;
105 int dtb_pipe[2];
106 if (pipe(dtb_pipe) != 0 || (dtb_pid = fork()) < 0) {
107 std::cerr << "Failed to fork dtb child: " << strerror(errno) << std::endl;
108 exit(1);
109 }
110
111 // Child process to output dtb
112 if (dtb_pid == 0) {
113 dup2(dts_pipe[0], 0);
114 dup2(dtb_pipe[1], 1);
115 close(dts_pipe[0]);
116 close(dts_pipe[1]);
117 close(dtb_pipe[0]);
118 close(dtb_pipe[1]);
119 execl(DTC, DTC, "-O", "dtb", 0);
120 std::cerr << "Failed to run " DTC ": " << strerror(errno) << std::endl;
121 exit(1);
122 }
123
124 close(dts_pipe[1]);
125 close(dts_pipe[0]);
126 close(dtb_pipe[1]);
127
128 // Read-out dtb
129 std::stringstream dtb;
130
131 int got;
132 char buf[4096];
133 while ((got = read(dtb_pipe[0], buf, sizeof(buf))) > 0) {
134 dtb.write(buf, got);
135 }
136 if (got == -1) {
137 std::cerr << "Failed to read dtb: " << strerror(errno) << std::endl;
138 exit(1);
139 }
140 close(dtb_pipe[0]);
141
142 // Reap children
143 int status;
144 waitpid(dts_pid, &status, 0);
145 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
146 std::cerr << "Child dts process failed" << std::endl;
147 exit(1);
148 }
149 waitpid(dtb_pid, &status, 0);
150 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
151 std::cerr << "Child dtb process failed" << std::endl;
152 exit(1);
153 }
154
155 return dtb.str();
156 }