diff --git a/programs/boot.vc5asm b/programs/boot.vc5asm index 338e7b8..8986577 100644 --- a/programs/boot.vc5asm +++ b/programs/boot.vc5asm @@ -61,91 +61,98 @@ key_press_int: cmp r1, 44 ; spacebar mov r2, rfl and r2, fl_eq -; jnz r2, .incr -; add r1, 61 -; mov byte [r0], r1 -;.incr: -; mov r0, [counter] -; add r0, 1 -; mov [counter], r0 - jnz r2, .print_space add r1, 61 ; scancode letter -> ascii - mov [rsp], r0 + + mov [rsp], r1 add rsp, 2 - call print_char + ;call print_char + call print_u16 + sub rsp, 2 + jmp .leave .print_space: - mov r0, ' ' - mov [rsp], r0 + mov r1, ' ' + + mov [rsp], r1 add rsp, 2 call print_char + sub rsp, 2 + .leave: reti print_char: mov [rsp], rbp - mov rbp, rsp add rsp, 2 + mov rbp, rsp mov r1, [rbp-6] + mov r0, [counter] add r0, vcd_base - mov r1, [kbd_code] cmp r1, ' ' mov r2, rfl and r2, fl_eq jnz r2, .incr - add r1, 61 mov byte [r0], r1 .incr: mov r0, [counter] add r0, 1 mov [counter], r0 .leave: + mov rsp, rbp sub rsp, 2 mov rbp, [rsp] ret -;print_int: -; mov [rsp], rbp -; add rsp, 2 -; mov rbp, rsp -; add rsp, rsp, 2 -; -; mov r1, [rbp-2] -; -; mov r2, 10000 -; mov r3, 0 -; jmp .c_10000 -;.b_10000: -; add r3, 1 -; sub r1, r2 -;.c_10000: -; cmp r2, r1 -; mov r0, rfl -; and r0, fl_eq | fl_lt -; jnz r0, .b_10000 -; add r3, 48 +print_u16: + mov [rsp], rbp + add rsp, 2 + mov rbp, rsp + mov r1, [rbp-6] ; value to print + mov r4, 0 ; place index -;scancode_to_char: -; cmp r1, 61 -; -; mov r2, rfl -; and r2, r2, FL_LT -; jnz .not_letter -; -; ; if r1 > 86 { goto .not_letter } -; cmp r1, 86 -; mov r2, rfl -; xor r2, 0xffff -; and r2, r2, FL_EQ | FL_LT -; -; -; mov r4, rfl -; and r4, r4, FL_EQ -; shr r4, r4, 2 + jmp .digits_cond +.digits_body: + mov r2, .places + add r2, r4 + mov r2, [r2] ; place + + mov r3, 0 ; place occurences + jmp .place_cond +.place_body: + add r3, 1 + sub r1, r2 +.place_cond: + cmp r2, r1 + mov r0, rfl + and r0, fl_eq | fl_lt + jnz r0, .place_body + + mov r0, r3 + add r0, 48 + mov [rsp], r0 + add rsp, 2 + call print_char + sub rsp, 2 + + add r4, 2 +.digits_cond: + cmp r4, 10 + mov r0, rfl + and r0, fl_lt + jnz r0, .digits_body + +.leave: + mov rsp, rbp + sub rsp, 2 + mov rbp, [rsp] + ret + +.places: + dw 10000, 1000, 100, 10, 1 diff --git a/src/assembler.cpp b/src/assembler.cpp index 7a61e5a..0ee0e6b 100644 --- a/src/assembler.cpp +++ b/src/assembler.cpp @@ -406,24 +406,24 @@ void Assembler::assemble_line(const Line& line) l.mov_imm(dst->as_reg(), src->as_imm()); } else if (dst_ty == Reg and src_ty == MemWordReg) { auto [reg, offset] = src->as_reg_imm_pair(); - l.load_word_reg(dst->as_reg(), reg, offset); + l.ldw_reg(dst->as_reg(), reg, offset); } else if (dst_ty == Reg and src_ty == MemWordImm) { - l.load_word_imm(dst->as_reg(), src->as_imm()); + l.ldw_imm(dst->as_reg(), src->as_imm()); } else if (dst_ty == MemWordReg and src_ty == Reg) { auto [reg, offset] = dst->as_reg_imm_pair(); - l.store_word_reg(reg, offset, src->as_reg()); + l.stw_reg(reg, offset, src->as_reg()); } else if (dst_ty == MemWordImm and src_ty == Reg) { - l.store_word_imm(dst->as_imm(), src->as_reg()); + l.stw_imm(dst->as_imm(), src->as_reg()); } else if (dst_ty == Reg and src_ty == MemByteReg) { auto [reg, offset] = src->as_reg_imm_pair(); - l.load_byte_reg(dst->as_reg(), reg, offset); + l.ldb_reg(dst->as_reg(), reg, offset); } else if (dst_ty == Reg and src_ty == MemByteImm) { - l.load_byte_imm(dst->as_reg(), src->as_imm()); + l.ldb_imm(dst->as_reg(), src->as_imm()); } else if (dst_ty == MemByteReg and src_ty == Reg) { auto [reg, offset] = dst->as_reg_imm_pair(); - l.store_byte_reg(reg, offset, src->as_reg()); + l.stb_reg(reg, offset, src->as_reg()); } else if (dst_ty == MemByteImm and src_ty == Reg) { - l.store_byte_imm(dst->as_imm(), src->as_reg()); + l.stb_imm(dst->as_imm(), src->as_reg()); } else { operation_not_supported(); } @@ -912,8 +912,6 @@ bool Assembler::arg_count_wrong(const Line& ins, size_t count) auto Assembler::define_sym(std::string ident, uint16_t value) -> std::expected { - std::println("define_sym(\"{}\", {})", ident, value); - if (m_syms.contains(ident)) { return std::unexpected( std::format("symbol \"{}\" already defined", ident)); @@ -926,8 +924,6 @@ auto Assembler::define_sym(std::string ident, uint16_t value) auto Assembler::get_sym(const std::string& ident) -> std::expected { - std::println(" get_sym(\"{}\")", ident); - if (not m_syms.contains(ident)) { return std::unexpected(std::format("symbol \"{}\" not defined", ident)); } diff --git a/src/builder.cpp b/src/builder.cpp index 872591d..c7d8c21 100644 --- a/src/builder.cpp +++ b/src/builder.cpp @@ -141,77 +141,77 @@ void Builder::mov_imm(Reg dst, uint16_t imm) i.build(*this); } -void Builder::load_word_reg(Reg dst, Reg addr, uint16_t offset) +void Builder::ldw_reg(Reg dst, Reg addr, uint16_t offset) { LOG; - auto i = InsBuilder(Op::LoadWord); + auto i = InsBuilder(Op::LdW); i.dst_reg(dst); i.op1_reg(addr); i.imm_without_flag(offset); i.build(*this); } -void Builder::load_word_imm(Reg dst, uint16_t addr) +void Builder::ldw_imm(Reg dst, uint16_t addr) { LOG; - auto i = InsBuilder(Op::LoadWord); + auto i = InsBuilder(Op::LdW); i.dst_reg(dst); i.imm(addr); i.build(*this); } -void Builder::store_word_reg(Reg dst, uint16_t offset, Reg op2) +void Builder::stw_reg(Reg dst, uint16_t offset, Reg op2) { LOG; - auto i = InsBuilder(Op::StoreWord); + auto i = InsBuilder(Op::StW); i.dst_reg(dst); i.imm_without_flag(offset); i.op2_reg(op2); i.build(*this); } -void Builder::store_word_imm(uint16_t dst, Reg op2) +void Builder::stw_imm(uint16_t dst, Reg op2) { LOG; - auto i = InsBuilder(Op::StoreWord); + auto i = InsBuilder(Op::StW); i.imm(dst); i.op2_reg(op2); i.build(*this); } -void Builder::load_byte_reg(Reg dst, Reg addr, uint16_t offset) +void Builder::ldb_reg(Reg dst, Reg addr, uint16_t offset) { LOG; - auto i = InsBuilder(Op::LoadByte); + auto i = InsBuilder(Op::LdB); i.dst_reg(dst); i.op1_reg(addr); i.imm_without_flag(offset); i.build(*this); } -void Builder::load_byte_imm(Reg dst, uint16_t addr) +void Builder::ldb_imm(Reg dst, uint16_t addr) { LOG; - auto i = InsBuilder(Op::LoadByte); + auto i = InsBuilder(Op::LdB); i.dst_reg(dst); i.imm(addr); i.build(*this); } -void Builder::store_byte_reg(Reg dst, uint16_t offset, Reg op2) +void Builder::stb_reg(Reg dst, uint16_t offset, Reg op2) { LOG; - auto i = InsBuilder(Op::StoreByte); + auto i = InsBuilder(Op::StB); i.dst_reg(dst); i.imm_without_flag(offset); i.op2_reg(op2); i.build(*this); } -void Builder::store_byte_imm(uint16_t dst, Reg op2) +void Builder::stb_imm(uint16_t dst, Reg op2) { LOG; - auto i = InsBuilder(Op::StoreByte); + auto i = InsBuilder(Op::StB); i.imm(dst); i.op2_reg(op2); i.build(*this); diff --git a/src/builder.hpp b/src/builder.hpp index 92c7c5c..842c0a5 100644 --- a/src/builder.hpp +++ b/src/builder.hpp @@ -23,14 +23,14 @@ public: void jnz_imm(Reg op1, uint16_t op2); void mov_reg(Reg dst, Reg src); void mov_imm(Reg dst, uint16_t imm); - void load_word_reg(Reg dst, Reg addr, uint16_t offset); - void load_word_imm(Reg dst, uint16_t addr); - void store_word_reg(Reg dst, uint16_t offset, Reg op2); - void store_word_imm(uint16_t dst, Reg op2); - void load_byte_reg(Reg dst, Reg addr, uint16_t offset); - void load_byte_imm(Reg dst, uint16_t addr); - void store_byte_reg(Reg dst, uint16_t offset, Reg op2); - void store_byte_imm(uint16_t dst, Reg op2); + void ldw_reg(Reg dst, Reg addr, uint16_t offset); + void ldw_imm(Reg dst, uint16_t addr); + void stw_reg(Reg dst, uint16_t offset, Reg op2); + void stw_imm(uint16_t dst, Reg op2); + void ldb_reg(Reg dst, Reg addr, uint16_t offset); + void ldb_imm(Reg dst, uint16_t addr); + void stb_reg(Reg dst, uint16_t offset, Reg op2); + void stb_imm(uint16_t dst, Reg op2); void cmp_reg(Reg op1, Reg op2); void cmp_imm(Reg op1, uint16_t op2); void or_reg(Reg dst, Reg op1, Reg op2); diff --git a/src/io_device.cpp b/src/io_device.cpp index 63dbbe3..c789cb9 100644 --- a/src/io_device.cpp +++ b/src/io_device.cpp @@ -26,6 +26,11 @@ constexpr uint64_t char_data(uint8_t ch) case '2': return 0x003C66060C18307E; case '3': return 0x003C66060C06663C; case '4': return 0x000C1C3C6C7E0C0C; + case '5': return 0x007E607C0606663C; + case '6': return 0x003C66607C66663C; + case '7': return 0x007F63060C181818; + case '8': return 0x003C66663C66663C; + case '9': return 0x003C66663E06663C; case 'A': return 0x00187E66667E6666; case 'B': return 0x00787E667C667E7C; @@ -173,7 +178,7 @@ auto IoDevice::poll_event() -> std::unique_ptr std::lock_guard lock(mx); SDL_Event event; - if (SDL_PollEvent(&event)) { + while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: return std::make_unique( diff --git a/src/vm.cpp b/src/vm.cpp index e6fd4cb..c4a1c9a 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -273,13 +273,13 @@ struct InsReader { int VM::run_instruction() { auto ip = *m_rip; - if (ip > 0x400) + if (ip >= 0x400) return -1; auto ins = InsReader(*this); auto op = static_cast(ins.to_u16() & 0b11'1111); std::println( - " [{: 2x}]: 0x{:04x} {: <9} {:04b} {:04b} {:04b} {:04b} {:04x}", + " [{: >2x}]: 0x{:04x} {: <6} {:04b} {:04b} {:04b} {:04b} {:04x}", ip, ins.to_u16(), op_str(op), @@ -293,10 +293,36 @@ int VM::run_instruction() case Op::Nop: break; case Op::Hlt: + if (not m_interrupts_enabled) { + std::println("warning: halted without interrupts enabled"); + } m_halted = true; break; case Op::Jmp: { auto op1 = ins.op1_or_imm(); + + if (op1 == 1) { + for (uint16_t reg = 0; reg < 10; ++reg) { + constexpr auto reg_strs = std::array { + "r0"sv, + "r1"sv, + "r2"sv, + "r3"sv, + "r4"sv, + "r5"sv, + "rbp"sv, + "rsp"sv, + "rfl"sv, + "rip"sv, + }; + std::println(" {: <3} | {:04x} {: 5}", + reg_strs[reg], + this->reg(static_cast(reg)), + this->reg(static_cast(reg))); + } + break; + } + *m_rip = op1; break; } @@ -315,7 +341,7 @@ int VM::run_instruction() set_reg(dst, src); break; } - case Op::LoadWord: { + case Op::LdW: { auto addr = ins.mem_addr(ins.op1(), eat_word()); if ((addr & 0b1) != 0) { @@ -331,7 +357,7 @@ int VM::run_instruction() set_reg(reg, word(addr)); break; } - case Op::StoreWord: { + case Op::StW: { auto addr = ins.mem_addr(ins.dst(), eat_word()); if ((addr & 0b1) != 0) { @@ -353,14 +379,14 @@ int VM::run_instruction() break; } - case Op::LoadByte: { + case Op::LdB: { auto addr = ins.mem_addr(ins.op1(), eat_word()); auto reg = ins.dst_reg(); set_reg(reg, byte(addr)); break; } - case Op::StoreByte: { + case Op::StB: { auto addr = ins.mem_addr(ins.dst(), eat_word()); auto src = ins.op2(); @@ -448,9 +474,9 @@ int VM::run_instruction() case Op::Call: { auto op1 = ins.op1_or_imm(); - auto return_addr = word(*m_rip); + auto return_addr = *m_rip; set_word(*m_rsp, return_addr); - *m_rsp -= 2; + *m_rsp += 2; *m_rip = op1; break; @@ -464,7 +490,6 @@ int VM::run_instruction() case Op::RetI: { *m_rsp -= 2; auto return_addr = word(*m_rsp); - *m_rip = return_addr; m_interrupts_enabled = true; @@ -579,7 +604,7 @@ void VM::interrupt(uint16_t handler_addr) m_interrupts_enabled = false; } -const char* vc5::op_str(Op op) +auto vc5::op_str(Op op) -> std::string_view { switch (op) { case Op::Nop: @@ -592,14 +617,14 @@ const char* vc5::op_str(Op op) return "Jnz"; case Op::Mov: return "Mov"; - case Op::LoadWord: - return "LoadWord"; - case Op::StoreWord: - return "StoreWord"; - case Op::LoadByte: - return "LoadByte"; - case Op::StoreByte: - return "StoreByte"; + case Op::LdW: + return "LdW"; + case Op::StW: + return "StW"; + case Op::LdB: + return "LdB"; + case Op::StB: + return "StB"; case Op::Cmp: return "Cmp"; case Op::Or: diff --git a/src/vm.hpp b/src/vm.hpp index ebc68fb..3ad7508 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include namespace vc5 { @@ -17,10 +18,10 @@ enum class Op : uint16_t { Jmp, Jnz, Mov, - LoadWord, - StoreWord, - LoadByte, - StoreByte, + LdW, + StW, + LdB, + StB, Cmp, Or, And, @@ -49,7 +50,7 @@ enum class Op : uint16_t { DSKW, }; -const char* op_str(Op op); +auto op_str(Op op) -> std::string_view; enum class Reg : uint16_t { R0 = 0, diff --git a/src/vm_main.cpp b/src/vm_main.cpp index ca1167f..a2e4b5d 100644 --- a/src/vm_main.cpp +++ b/src/vm_main.cpp @@ -4,6 +4,7 @@ #include "vm.hpp" #include #include +#include #include #include @@ -11,118 +12,20 @@ using namespace std::chrono_literals; using namespace vc5; -static void make_program(uint8_t* data); - int main(int argc, char** argv) { auto device = IoDevice::create().value(); device->set_title("vc5"); - if (argc < 2) { - auto disk = MemoryDisk(128); - - make_program(disk.data()); - - std::println("memory disk"); - for (size_t i = 0; i < 128; i += 4) { - std::println("{:02x} {:02x} {:02x} {:02x}", - disk.data()[i], - disk.data()[i + 1], - disk.data()[i + 2], - disk.data()[i + 3]); - } - - auto vm = VM(*device, disk); - vm.run(); - } else { - auto disk = FileDisk(argv[1]); - - auto memory_disk = MemoryDisk(128); - make_program(memory_disk.data()); - - auto file_block = std::vector(BlockDevice::block_size); - disk.read(file_block.data(), 0); - - auto memory_block = std::vector(BlockDevice::block_size); - memory_disk.read(memory_block.data(), 0); - - std::println("file disk"); - for (size_t i = 0; i < 128; i += 4) { - std::println("{:02x} {:02x} {:02x} {:02x}", - file_block[i], - file_block[i + 1], - file_block[i + 2], - file_block[i + 3]); - } - - auto vm = VM(*device, disk); - vm.run(); + if (argc > 2) { + std::println("error: no boot disk (file name) specified"); + return EXIT_FAILURE; } -} -void make_program(uint8_t* data) -{ - using namespace vc5::regs; + auto disk = FileDisk(argv[1]); - auto l = tools::Builder(data); - - l.mov_imm(rsp, 0x1000); - l.mov_reg(rbp, rsp); - - l.mov_imm(r0, 512); - l.mov_imm(r1, 1); - l.dskr(r0, r1); - - l.mov_imm(r0, 0x2000); - l.store_word_imm(0x700, r0); - l.lvcd_imm(0x700); - - l.mov_imm(r0, 0x1ffc); - l.store_word_imm(0x702, r0); - l.mov_imm(r0, 0x1ffe); - l.store_word_imm(0x704, r0); - auto to_set_key_press_int = l.ip(); - l.mov_imm(r0, 0); - l.store_word_imm(0x706, r0); - l.lkbd_imm(0x702); - - l.mov_imm(r0, 0); - l.store_word_imm(0x600, r0); - - auto main_loop = l.ip(); - l.hlt(); - l.jmp_imm(main_loop); - - auto key_press_int = l.ip(); - l.load_word_imm(r0, 0x1ffc); - l.and_imm(r0, r0, 1); - auto to_set_key_press_int_leave = l.ip(); - l.jnz_imm(r0, 0); - - l.load_word_imm(r0, 0x600); - l.add_imm(r0, r0, 0x2000); - l.load_word_imm(r1, 0x1ffe); - l.cmp_imm(r1, 44); - l.mov_reg(r2, rfl); - l.and_imm(r2, r2, 2); - auto to_set_key_press_incr = l.ip(); - l.jnz_imm(r2, 0); - l.add_imm(r1, r1, 61); - l.store_byte_reg(r0, 0, r1); - auto key_press_incr = l.ip(); - l.load_word_imm(r0, 0x600); - l.add_imm(r0, r0, 1); - l.store_word_imm(0x600, r0); - - auto key_press_int_leave = l.ip(); - l.reti(); - - l.set_ip(to_set_key_press_int + 2); - l.push(key_press_int); - l.set_ip(to_set_key_press_incr + 2); - l.push(key_press_incr); - l.set_ip(to_set_key_press_int_leave + 2); - l.push(key_press_int_leave); + auto vm = VM(*device, disk); + vm.run(); } extern "C" const char* __asan_default_options(void)