Compare commits

...

2 Commits

Author SHA1 Message Date
4c7073657f Hello, World! 2026-03-09 17:12:28 +01:00
2252e1fa75 we can now execute crt0 2026-03-09 16:23:45 +01:00

View File

@@ -80,9 +80,9 @@ enum Op {
C_OR,
C_SD,
C_SDSP,
C_SLLI,
C_SRAI,
C_SRLI,
C_SLLI,
C_SUB,
C_SUBW,
C_SW,
@@ -103,6 +103,7 @@ enum Op {
LH,
LHU,
LR_D,
LR_W,
LUI,
LW,
LWU,
@@ -119,6 +120,7 @@ enum Op {
REMW,
SB,
SC_D,
SC_W,
SD,
SH,
SLL,
@@ -171,6 +173,7 @@ enum class Format {
I_SHIFT,
S,
B,
CB,
U,
J,
CI,
@@ -188,57 +191,109 @@ struct OpDef {
Format format;
};
static constexpr std::array<OpDef, 101> OP_TABLE = {{
{"???", Format::NONE}, {"add", Format::R},
{"addi", Format::I}, {"addiw", Format::I},
{"addw", Format::R}, {"amoswap.d", Format::R_ATOMIC},
{"and", Format::R}, {"andi", Format::I},
{"auipc", Format::U}, {"beq", Format::B},
{"bge", Format::B}, {"bgeu", Format::B},
{"blt", Format::B}, {"bltu", Format::B},
{"bne", Format::B}, {"c.add", Format::CR},
{"c.addi", Format::CI}, {"c.addiw", Format::CI},
{"c.addi16sp", Format::CI}, {"c.addi4spn", Format::CI},
{"c.addw", Format::CI}, {"c.and", Format::CR},
{"c.andi", Format::CI}, {"c.beqz", Format::B},
{"c.bnez", Format::B}, {"c.ebreak", Format::CR},
{"c.fldsp", Format::CSS}, {"c.j", Format::CJ},
{"c.jalr", Format::CR1}, {"c.jr", Format::CR1},
{"c.ld", Format::CL}, {"c.ldsp", Format::CL},
{"c.li", Format::CI}, {"c.lui", Format::CI},
{"c.lw", Format::CL}, {"c.mv", Format::CR},
{"c.or", Format::CR}, {"c.sd", Format::S},
{"c.sdsp", Format::CSS}, {"c.slli", Format::CI},
{"c.srai", Format::CI}, {"c.srli", Format::CI},
{"c.sub", Format::CR}, {"c.subw", Format::CR},
{"c.sw", Format::S}, {"c.swsp", Format::CSS},
{"c.xor", Format::CR}, {"div", Format::R},
{"divu", Format::R}, {"divuw", Format::R},
{"divw", Format::R}, {"ecall", Format::NONE},
{"fence", Format::NONE}, {"fence.tso", Format::NONE},
{"jal", Format::J}, {"jalr", Format::I},
{"lb", Format::I_LOAD}, {"lbu", Format::I_LOAD},
{"ld", Format::I_LOAD}, {"lh", Format::I_LOAD},
{"lhu", Format::I_LOAD}, {"lr.d", Format::R_ATOMIC_LR},
{"lui", Format::U}, {"lw", Format::I_LOAD},
{"lwu", Format::I_LOAD}, {"mul", Format::R},
{"mulh", Format::R}, {"mulhu", Format::R},
{"mulw", Format::R}, {"or", Format::R},
{"ori", Format::I}, {"pause", Format::NONE},
{"rem", Format::R}, {"remu", Format::R},
{"remuw", Format::R}, {"remw", Format::R},
{"sb", Format::S}, {"sc.d", Format::R_ATOMIC},
{"sd", Format::S}, {"sh", Format::S},
{"sll", Format::R}, {"slli", Format::I_SHIFT},
{"slliw", Format::I_SHIFT}, {"sllw", Format::R},
{"slt", Format::R}, {"slti", Format::I},
{"sltiu", Format::I}, {"sltu", Format::R},
{"sra", Format::R}, {"srai", Format::I_SHIFT},
{"sraiw", Format::I_SHIFT}, {"sraw", Format::R},
{"srl", Format::R}, {"srli", Format::I_SHIFT},
{"srliw", Format::I_SHIFT}, {"srlw", Format::R},
{"sub", Format::R}, {"subw", Format::R},
{"sw", Format::S}, {"xor", Format::R},
static constexpr std::array<OpDef, 103> OP_TABLE = {{
{"???", Format::NONE},
{"add", Format::R},
{"addi", Format::I},
{"addiw", Format::I},
{"addw", Format::R},
{"amoswap.d", Format::R_ATOMIC},
{"and", Format::R},
{"andi", Format::I},
{"auipc", Format::U},
{"beq", Format::B},
{"bge", Format::B},
{"bgeu", Format::B},
{"blt", Format::B},
{"bltu", Format::B},
{"bne", Format::B},
{"c.add", Format::CR},
{"c.addi", Format::CI},
{"c.addiw", Format::CI},
{"c.addi16sp", Format::CI},
{"c.addi4spn", Format::CI},
{"c.addw", Format::CR},
{"c.and", Format::CR},
{"c.andi", Format::CI},
{"c.beqz", Format::CB},
{"c.bnez", Format::CB},
{"c.ebreak", Format::NONE},
{"c.fldsp", Format::CSS},
{"c.j", Format::CJ},
{"c.jalr", Format::CR1},
{"c.jr", Format::CR1},
{"c.ld", Format::CL},
{"c.ldsp", Format::CL},
{"c.li", Format::CI},
{"c.lui", Format::CI},
{"c.lw", Format::CL},
{"c.mv", Format::CR},
{"c.or", Format::CR},
{"c.sd", Format::S},
{"c.sdsp", Format::CSS},
{"c.slli", Format::CI},
{"c.srai", Format::CI},
{"c.srli", Format::CI},
{"c.sub", Format::CR},
{"c.subw", Format::CR},
{"c.sw", Format::S},
{"c.swsp", Format::CSS},
{"c.xor", Format::CR},
{"div", Format::R},
{"divu", Format::R},
{"divuw", Format::R},
{"divw", Format::R},
{"ecall", Format::NONE},
{"fence", Format::NONE},
{"fence.tso", Format::NONE},
{"jal", Format::J},
{"jalr", Format::I},
{"lb", Format::I_LOAD},
{"lbu", Format::I_LOAD},
{"ld", Format::I_LOAD},
{"lh", Format::I_LOAD},
{"lhu", Format::I_LOAD},
{"lr.d", Format::R_ATOMIC_LR},
{"lr.w", Format::R_ATOMIC_LR},
{"lui", Format::U},
{"lw", Format::I_LOAD},
{"lwu", Format::I_LOAD},
{"mul", Format::R},
{"mulh", Format::R},
{"mulhu", Format::R},
{"mulw", Format::R},
{"or", Format::R},
{"ori", Format::I},
{"pause", Format::NONE},
{"rem", Format::R},
{"remu", Format::R},
{"remuw", Format::R},
{"remw", Format::R},
{"sb", Format::S},
{"sc.d", Format::R_ATOMIC},
{"sc.w", Format::R_ATOMIC},
{"sd", Format::S},
{"sh", Format::S},
{"sll", Format::R},
{"slli", Format::I_SHIFT},
{"slliw", Format::I_SHIFT},
{"sllw", Format::R},
{"slt", Format::R},
{"slti", Format::I},
{"sltiu", Format::I},
{"sltu", Format::R},
{"sra", Format::R},
{"srai", Format::I_SHIFT},
{"sraiw", Format::I_SHIFT},
{"sraw", Format::R},
{"srl", Format::R},
{"srli", Format::I_SHIFT},
{"srliw", Format::I_SHIFT},
{"srlw", Format::R},
{"sub", Format::R},
{"subw", Format::R},
{"sw", Format::S},
{"xor", Format::R},
{"xori", Format::I},
}};
@@ -334,6 +389,9 @@ public:
std::println("{} {}, {}, {}", def.mnemonic, REGS[ins.rs1], REGS[ins.rs2],
ins.imm);
break;
case Format::CB:
std::println("{} {}, {}", def.mnemonic, REGS[ins.rs1], ins.imm);
break;
case Format::J:
std::println("{} {}, {}", def.mnemonic, REGS[ins.rd], ins.imm);
break;
@@ -452,8 +510,10 @@ public:
}
}; break;
case Op::BGEU: {
std::println(stderr, "BGEU unimplemented");
exit(1);
if ((u64)m_regs[i.rs1] >= (u64)m_regs[i.rs2]) {
m_pc += i.imm;
continue;
}
}; break;
case Op::BLT: {
if (m_regs[i.rs1] < m_regs[i.rs2]) {
@@ -473,6 +533,95 @@ public:
continue;
}
}; break;
case Op::C_ADD: {
m_regs[i.rd] += m_regs[i.rs2];
}; break;
case Op::C_ADDI: {
m_regs[i.rd] += i.imm;
}; break;
case Op::C_ADDIW: {
m_regs[i.rd] = (i64)(i32)m_regs[i.rd] + i.imm;
}; break;
case Op::C_ADDI16SP: {
sp += i.imm;
}; break;
case Op::C_ADDI4SPN: {
m_regs[i.rd] = sp + i.imm;
}; break;
case Op::C_ADDW: {
m_regs[i.rd] = (i64)((i32)m_regs[i.rd] + (i32)m_regs[i.rs2]);
}; break;
case Op::C_AND: {
m_regs[i.rd] &= m_regs[i.rs2];
}; break;
case Op::C_ANDI: {
m_regs[i.rd] = m_regs[i.rs1] & i.imm;
}; break;
case Op::C_BEQZ: {
if (m_regs[i.rs1] == 0) {
m_pc += i.imm;
continue;
}
}; break;
case Op::C_BNEZ: {
if (m_regs[i.rs1] != 0) {
m_pc += i.imm;
continue;
}
}; break;
case Op::C_J: {
m_pc += i.imm;
continue;
}; break;
case Op::C_JALR: {
m_regs[1] = m_pc + 2;
m_pc = m_regs[i.rs1];
continue;
}; break;
case Op::C_JR: {
m_pc = m_regs[i.rs1];
continue;
}; break;
case Op::C_LD: {
u64 addr = m_regs[i.rs1] + i.imm;
m_regs[i.rd] = *(u64 *)&m_memory[addr];
}; break;
case Op::C_LDSP: {
u64 addr = sp + i.imm;
m_regs[i.rd] = *(u64 *)(&m_memory[addr]);
}; break;
case Op::C_LI: {
m_regs[i.rd] = i.imm;
}; break;
case Op::C_LUI: {
m_regs[i.rd] = (int64_t)(uint64_t)((int64_t)i.imm) << 12;
}; break;
case Op::C_LW: {
u64 addr = m_regs[i.rs1] + i.imm;
m_regs[i.rd] = *(u32 *)&m_memory[addr];
}; break;
case Op::C_MV: {
m_regs[i.rd] = m_regs[i.rs2];
}; break;
case Op::C_OR: {
m_regs[i.rd] |= m_regs[i.rs2];
}; break;
case Op::C_SDSP: {
u64 addr = sp + i.imm;
*(u64 *)(&m_memory[addr]) = m_regs[i.rs2];
}; break;
case Op::C_SLLI: {
m_regs[i.rd] = (i64)((u64)m_regs[i.rd] << i.imm);
}; break;
case Op::C_SRAI: {
m_regs[i.rd] >>= i.imm;
}; break;
case Op::C_SRLI: {
m_regs[i.rd] = (i64)((u64)m_regs[i.rd] >> i.imm);
}; break;
case Op::C_SUB: {
m_regs[i.rd] -= m_regs[i.rs2];
}; break;
case Op::DIV: {
if (m_regs[i.rs2] == 0) {
m_regs[i.rd] = -1;
@@ -480,10 +629,6 @@ public:
m_regs[i.rd] = m_regs[i.rs1] / m_regs[i.rs2];
}
}; break;
case Op::DIVU: {
std::println(stderr, "DIVU unimplemented");
exit(1);
}; break;
case Op::DIVUW: {
if (m_regs[i.rs2] == 0) {
m_regs[i.rd] = -1LL;
@@ -505,21 +650,38 @@ public:
case Op::ECALL: {
// https://jborza.com/post/2021-05-11-riscv-linux-syscalls/
switch (m_regs[17]) {
case 29: { // ioctl
u32 fd = m_regs[10];
u32 cmd = m_regs[11];
u64 arg = m_regs[12];
switch (cmd) {
case 0x5413: { // TIOCGWINSZ
m_regs[10] = -ENOTTY;
}; break;
default: {
std::println(stderr, "ioctl(fd={}, cmd={}, arg={}) unimplemented",
fd, cmd, arg);
exit(1);
}; break;
}
}; break;
case 63: { // read
if (m_regs[10] != 0) {
u32 fd = m_regs[10];
u64 buf = m_regs[11];
u64 count = m_regs[12];
if (fd != 0) {
std::println(stderr, "read syscall implemented only for stdin.");
exit(1);
}
u64 start = m_regs[11];
u64 count = m_regs[12];
u64 bytes_read = 0;
for (u64 i = 0; i < count; i++) {
char c;
if (!std::cin.get(c))
break;
m_memory[start + i] = (u8)c;
m_memory[buf + i] = (u8)c;
bytes_read++;
if (c == '\n')
break;
@@ -528,22 +690,58 @@ public:
m_regs[10] = bytes_read;
}; break;
case 64: { // write
if (m_regs[10] != 1) {
u32 fd = m_regs[10];
u64 buf = m_regs[11];
u64 count = m_regs[12];
if (fd != 1) {
std::println(stderr, "write syscall implemented only for stdout.");
exit(1);
}
u64 start = m_regs[11];
u64 end = m_regs[11] + m_regs[12];
for (u64 i = start; i < end; i++) {
u64 end = buf + count;
for (u64 i = buf; i < end; i++) {
std::cout.put(m_memory[i]);
}
m_regs[10] = count;
}; break;
case 93: { // exit
case 66: { // writev
u32 fd = m_regs[10];
u64 vec = m_regs[11];
u64 vlen = m_regs[12];
if (fd != 1) {
std::println(stderr, "writev syscall implemented only for stdout.");
exit(1);
}
u64 total_written = 0;
for (u64 i = 0; i < vlen; i++) {
u64 iov_entry = vec + i * 16;
u64 buf = *(u64 *)&m_memory[iov_entry];
u64 len = *(u64 *)&m_memory[iov_entry + 8];
for (u64 j = 0; j < len; j++) {
std::cout.put(m_memory[buf + j]);
}
total_written += len;
}
m_regs[10] = total_written;
} break;
case 93: // exit
case 94: { // exit_group
std::println("Program exited with code {}.", m_regs[10]);
return;
}; break;
case 96: { // set_tid_address
i64 tidptr = m_regs[10];
i32 tid = 123;
memcpy(&m_memory[tidptr], &tid, sizeof(tid));
m_regs[10] = tid;
}; break;
case 169: { // gettimeofday
i64 tv_addr = m_regs[10];
i64 tz_addr = m_regs[11];
@@ -590,20 +788,12 @@ public:
case Op::LH: {
m_regs[i.rd] = *(i16 *)&m_memory[m_regs[i.rs1] + i.imm];
}; break;
case Op::LHU: {
std::println(stderr, "LHU unimplemented");
exit(1);
}; break;
case Op::LUI: {
m_regs[i.rd] = (i64)(i32)(i.imm << 12);
}; break;
case Op::LW: {
m_regs[i.rd] = *(i32 *)&m_memory[m_regs[i.rs1] + i.imm];
}; break;
case Op::LWU: {
std::println(stderr, "LWU unimplemented");
exit(1);
}; break;
case Op::MUL: {
m_regs[i.rd] = m_regs[i.rs1] * m_regs[i.rs2];
}; break;
@@ -640,10 +830,6 @@ public:
case Op::OR: {
m_regs[i.rd] = m_regs[i.rs1] | m_regs[i.rs2];
}; break;
case Op::ORI: {
std::println(stderr, "ORI unimplemented");
exit(1);
}; break;
case Op::REM: {
if (m_regs[i.rs2] == 0) {
m_regs[i.rd] = m_regs[i.rs1];
@@ -665,15 +851,12 @@ public:
m_regs[i.rd] = (i32)((u32)m_regs[i.rs1] % (u32)m_regs[i.rs2]);
}
}; break;
case Op::REMW: {
std::println(stderr, "REMW unimplemented");
exit(1);
}; break;
case Op::SB: {
u64 addr = m_regs[i.rs1] + i.imm;
m_memory[addr] = m_regs[i.rs2];
}; break;
case Op::SD: {
case Op::SD:
case Op::C_SD: {
u64 addr = m_regs[i.rs1] + i.imm;
*(u64 *)(&m_memory[addr]) = m_regs[i.rs2];
}; break;
@@ -681,10 +864,6 @@ public:
u64 addr = m_regs[i.rs1] + i.imm;
*(u16 *)(&m_memory[addr]) = m_regs[i.rs2];
}; break;
case Op::SLL: {
std::println(stderr, "SLL unimplemented");
exit(1);
}; break;
case Op::SLLI: {
m_regs[i.rd] = m_regs[i.rs1] << i.shamt;
}; break;
@@ -698,20 +877,12 @@ public:
case Op::SLT: {
m_regs[i.rd] = (m_regs[i.rs1] < m_regs[i.rs2]) ? 1 : 0;
}; break;
case Op::SLTI: {
std::println(stderr, "SLTI unimplemented");
exit(1);
}; break;
case Op::SLTIU: {
m_regs[i.rd] = ((u64)m_regs[i.rs1] < (u64)(i64)i.imm) ? 1 : 0;
}; break;
case Op::SLTU: {
m_regs[i.rd] = ((u64)m_regs[i.rs1] < (u64)m_regs[i.rs2]) ? 1 : 0;
}; break;
case Op::SRA: {
std::println(stderr, "SRA unimplemented");
exit(1);
}; break;
case Op::SRAI: {
m_regs[i.rd] = (i64)m_regs[i.rs1] >> i.shamt;
}; break;
@@ -721,10 +892,6 @@ public:
case Op::SRAW: {
m_regs[i.rd] = ((i32)m_regs[i.rs1]) >> ((u32)m_regs[i.rs2] & 0b11111);
}; break;
case Op::SRL: {
std::println(stderr, "SRL unimplemented");
exit(1);
}; break;
case Op::SRLI: {
m_regs[i.rd] = (u64)m_regs[i.rs1] >> i.shamt;
}; break;
@@ -741,6 +908,7 @@ public:
case Op::SUBW: {
m_regs[i.rd] = (i32)(m_regs[i.rs1] - m_regs[i.rs2]);
}; break;
case Op::C_SW:
case Op::SW: {
u64 addr = m_regs[i.rs1] + i.imm;
*(u32 *)(&m_memory[addr]) = m_regs[i.rs2];
@@ -752,7 +920,7 @@ public:
m_regs[i.rd] = m_regs[i.rs1] ^ i.imm;
}; break;
default: {
std::println(stderr, "Unrecognized Op: {}", (u64)i.op);
std::println(stderr, "{} not implemented", OP_TABLE[i.op].mnemonic);
exit(1);
}; break;
}
@@ -885,16 +1053,17 @@ private:
i.imm = (i.imm << 22) >> 22;
i.op = Op::C_ADDI16SP;
} else {
i.imm = (((raw >> 12) & 0b1) << 17) | (((raw >> 2) & 0b11111) << 12);
i.imm = (i.imm << 14) >> 14;
i.imm = (((raw >> 12) & 0b1) << 5) | ((raw >> 2) & 0b11111);
i.imm = (i.imm << 26) >> 26;
i.op = Op::C_LUI;
}
}; break;
case 0b100: {
u8 funct2 = (raw >> 10) & 0b11;
if (funct2 == 0b11) {
i.rs1 = ((raw >> 7) & 0b111) + 8;
i.rd = i.rs1;
bool bit12 = (raw >> 12) & 0b1;
i.rs2 = ((raw >> 2) & 0b111) + 8;
@@ -1325,7 +1494,22 @@ private:
i.rs1 = (raw >> 15) & 0b11111;
i.rs2 = (raw >> 20) & 0b11111;
if (funct3 == 0b011) {
if (funct3 == 0b010) {
switch (funct7) {
case 0b00010: {
i.op = Op::LR_W;
}; break;
case 0b00011: {
i.op = Op::SC_W;
}; break;
default: {
std::println(stderr,
"0101111: funct3=010: unrecognized funct7: {:05b}",
funct7);
exit(1);
}; break;
}
} else if (funct3 == 0b011) {
switch (funct7) {
case 0b00001: {
i.op = Op::AMOSWAP_D;
@@ -1522,7 +1706,6 @@ int main(int argc, char *argv[]) {
exe_bytes.clear();
exe_bytes.shrink_to_fit();
r.disassemble_all();
std::println("END DISASSEMBLY");
r.execute();