diff --git a/programs/echo_keyboard.txt b/programs/echo_keyboard.txt index 05dab56..678db00 100644 --- a/programs/echo_keyboard.txt +++ b/programs/echo_keyboard.txt @@ -3,19 +3,30 @@ %define KBD_CODE 0x1ffe %define VCD 0x2000 -%define FL_EQ 1 << 1 +%define FL_EQ 0x2 +%define FL_EQ 0x4 %define KBD_FLAG_IS_RELEASE 0x1 mov rsp, 0x1000 mov rbp, rsp - ; setup vcd + mov r0, 512 + mov r1, 1 + dskr r0, r1 + + ; setup video character display (VCD) + ; descriptor table structure: + ; [addr + 0] memory map base mov r0, VCD mov [0x700], r0 lvcd 0x700 - ; setup kbd + ; setup keyboard (KBD) + ; descriptor table structure: + ; [addr + 0] status address + ; [addr + 2] keycode address + ; [addr + 4] keyboard interrupt handler mov r0, KBD_STATUS mov [0x702], r0 mov r0, KBD_CODE @@ -24,7 +35,7 @@ mov [0x706], r0 lkbd 0x702 - ; init counter + ; character counter mov r0, 0 mov [0x600], r0 @@ -50,10 +61,31 @@ key_press_int: mov r0, [0x600] add r0, r0, 1 mov [0x600], r0 - .leave: reti +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 + +.not_letter: + + +61 >= 61 ; vim: syntax=nasm diff --git a/src/block_device.cpp b/src/block_device.cpp new file mode 100644 index 0000000..3bf9a82 --- /dev/null +++ b/src/block_device.cpp @@ -0,0 +1,36 @@ +#include "block_device.hpp" +#include +#include +#include +#include + +using namespace vc5; + +void MemoryDisk::read(uint8_t* data, uint16_t block) +{ + std::memcpy(data, &m_data[block * block_size], block_size); +} + +void MemoryDisk::write(const uint8_t* data, uint16_t block) +{ + std::memcpy(&m_data[block * block_size], data, block_size); +} + +auto FileDisk::block_count() -> uint16_t +{ + m_file.seekg(0, std::ios_base::end); + std::streamsize location = m_file.tellg(); + return location / block_size & 0xffff; +} + +void FileDisk::read(uint8_t* data, uint16_t block) +{ + m_file.seekg(block * block_size); + m_file.read(reinterpret_cast(data), block_size); +} + +void FileDisk::write(const uint8_t* data, uint16_t block) +{ + m_file.seekg(block * block_size); + m_file.write(reinterpret_cast(data), block_size); +} diff --git a/src/block_device.hpp b/src/block_device.hpp new file mode 100644 index 0000000..9809143 --- /dev/null +++ b/src/block_device.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace vc5 { + +namespace fs = std::filesystem; + +class BlockDevice { +public: + virtual ~BlockDevice() = default; + + static constexpr uint16_t block_size = 512; + + virtual auto block_count() -> uint16_t = 0; + + virtual void read(uint8_t* data, uint16_t block) = 0; + virtual void write(const uint8_t* data, uint16_t block) = 0; +}; + +class MemoryDisk final : public BlockDevice { +public: + explicit MemoryDisk(uint16_t block_count) + : m_data(block_size * block_count, 0) + , m_block_count(block_count) + { + } + + auto block_count() -> uint16_t override + { + return m_block_count; + } + + void read(uint8_t* data, uint16_t block) override; + void write(const uint8_t* data, uint16_t block) override; + + auto data() -> uint8_t* + { + return m_data.data(); + } + +private: + std::vector m_data; + uint16_t m_block_count; +}; + +class FileDisk final : public BlockDevice { +public: + explicit FileDisk(fs::path file_path) + : m_file(file_path, std::ios_base::binary) + { + } + + auto block_count() -> uint16_t override; + void read(uint8_t* data, uint16_t block) override; + void write(const uint8_t* data, uint16_t block) override; + +private: + std::fstream m_file; +}; + +} diff --git a/src/builder.cpp b/src/builder.cpp index 3bfbf08..00d5f5a 100644 --- a/src/builder.cpp +++ b/src/builder.cpp @@ -361,3 +361,19 @@ void Builder::lkbd_imm(uint16_t op1) i.imm(op1); i.build(*this); } + +void Builder::dskr(Reg dst, Reg op1) +{ + auto i = InsBuilder(Op::DSKR); + i.dst_reg(dst); + i.op1_reg(op1); + i.build(*this); +} + +void Builder::dskw(Reg dst, Reg op1) +{ + auto i = InsBuilder(Op::DSKW); + i.dst_reg(dst); + i.op1_reg(op1); + i.build(*this); +} diff --git a/src/builder.hpp b/src/builder.hpp index 9135844..2ecc4be 100644 --- a/src/builder.hpp +++ b/src/builder.hpp @@ -58,6 +58,8 @@ public: void lvcd_imm(uint16_t op1); void lkbd_reg(Reg op1); void lkbd_imm(uint16_t op1); + void dskr(Reg dst, Reg op1); + void dskw(Reg dst, Reg op1); uint16_t ip() const { diff --git a/src/io_device.cpp b/src/io_device.cpp index cebfa8c..c9b83f8 100644 --- a/src/io_device.cpp +++ b/src/io_device.cpp @@ -113,8 +113,6 @@ auto IoDevice::set_char(uint16_t offset, uint8_t value) { auto lock = std::lock_guard(mx); - std::println("char = '{}' or '{}'", static_cast(value), value); - SDL_Color* buffer; int pitch; int res = SDL_LockTexture(m_texture, NULL, (void**)&buffer, &pitch); @@ -161,7 +159,7 @@ auto IoDevice::set_char(uint16_t offset, uint8_t value) } SDL_UnlockTexture(m_texture); - SDL_RenderCopy(m_renderer, m_texture, NULL, NULL); + SDL_RenderCopy(m_renderer, m_texture, nullptr, nullptr); SDL_RenderPresent(m_renderer); diff --git a/src/main.cpp b/src/main.cpp index 9e2da60..a4c1613 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,44 +1,32 @@ +#include "block_device.hpp" #include "builder.hpp" #include "io_device.hpp" #include "vm.hpp" #include -#include -#include -#include -#include -#include #include #include -#include -#include using namespace std::chrono_literals; using namespace vc5; -using R = Reg; +using namespace vc5::regs; int main() { auto device = IoDevice::create().value(); + device->set_title("vc5"); - constexpr R r0 = R::R0; - constexpr R r1 = R::R1; - constexpr R r2 = R::R2; - constexpr R r3 = R::R3; - constexpr R r4 = R::R4; - constexpr R r5 = R::R5; - constexpr R rbp = R::Rbp; - constexpr R rsp = R::Rsp; - constexpr R rfl = R::Rfl; - constexpr R rip = R::Rip; + auto disk = MemoryDisk(128); - auto program = std::array(); - - auto l = Builder(program.data()); + auto l = Builder(disk.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); @@ -70,7 +58,7 @@ int main() l.load_word_imm(r1, 0x1ffe); l.cmp_imm(r1, 44); l.mov_reg(r2, rfl); - l.and_imm(r2, r2, 1 << std::to_underlying(Flag::Eq)); + 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); @@ -90,28 +78,8 @@ int main() l.set_ip(to_set_key_press_int_leave + 2); l.push(key_press_int_leave); - auto vm = VM(*device); - vm.load(0, program.data(), program.size()); - - device->set_title("vc5"); - + auto vm = VM(*device, disk); vm.run(); - - std::println("--- regs ---"); - std::println("r0\t{}", vm.reg(r0)); - std::println("r1\t{}", vm.reg(r1)); - std::println("r2\t{}", vm.reg(r2)); - std::println("r3\t{}", vm.reg(r3)); - std::println("r4\t{}", vm.reg(r4)); - std::println("r5\t{}", vm.reg(r5)); - std::println("rbp\t{}", vm.reg(rbp)); - std::println("rsp\t{}", vm.reg(rsp)); - std::println("rfl\t{}", vm.reg(rfl)); - std::println("rip\t{}", vm.reg(rip)); - std::println("--- mem ---"); - for (uint16_t i = 0; i < 32; i += 2) { - std::println("{: 4x}\t{}", i, vm.word(i)); - } } extern "C" const char* __asan_default_options(void) diff --git a/src/vm.cpp b/src/vm.cpp index 80c494e..edc3404 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -18,6 +18,11 @@ void VM::load(uint16_t offset, const uint8_t* data, size_t data_size) int VM::run() { + constexpr uint16_t bootloader_size = 512; + for (uint16_t i = 0; i * m_disk->block_size < bootloader_size; ++i) { + m_disk->read(&m_mem[i * m_disk->block_size], i); + } + m_on = true; while (m_on) { if (not m_halted) { @@ -405,6 +410,19 @@ int VM::run_instruction() .int_handler = word(op1 + 4), }; m_kbd_loaded = true; + break; + } + case Op::DSKR: { + auto addr = ins.dst(); + auto block = ins.op1(); + m_disk->read(&m_mem[addr], block); + break; + } + case Op::DSKW: { + auto addr = ins.op1(); + auto block = ins.dst(); + m_disk->write(&m_mem[addr], block); + break; } } @@ -532,6 +550,10 @@ const char* vc5::op_str(Op op) return "LVCD"; case Op::LKBD: return "LKBD"; + case Op::DSKR: + return "DSKR"; + case Op::DSKW: + return "DSKW"; } return ">.<"; } diff --git a/src/vm.hpp b/src/vm.hpp index ca763fe..c1f5900 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -1,5 +1,6 @@ #pragma once +#include "block_device.hpp" #include "io_device.hpp" #include #include @@ -38,6 +39,11 @@ enum class Op : uint16_t { LVCD, // load keyboard LKBD, + + // disk read + DSKR, + // disk write + DSKW, }; const char* op_str(Op op); @@ -55,6 +61,19 @@ enum class Reg : uint16_t { Rip = 9, }; +namespace regs { + constexpr Reg r0 = Reg::R0; + constexpr Reg r1 = Reg::R1; + constexpr Reg r2 = Reg::R2; + constexpr Reg r3 = Reg::R3; + constexpr Reg r4 = Reg::R4; + constexpr Reg r5 = Reg::R5; + constexpr Reg rbp = Reg::Rbp; + constexpr Reg rsp = Reg::Rsp; + constexpr Reg rfl = Reg::Rfl; + constexpr Reg rip = Reg::Rip; +} + enum class Flag : uint16_t { Zero = 0, Eq = 1, @@ -85,8 +104,9 @@ enum class KbdStatusFlag : uint16_t { class VM { public: - VM(IoDevice& device) + VM(IoDevice& device, BlockDevice& disk) : m_device(&device) + , m_disk(&disk) { } @@ -119,6 +139,7 @@ private: uint16_t* m_rip = &m_regs[std::to_underlying(Reg::Rip)]; IoDevice* m_device; + BlockDevice* m_disk; bool m_on = true; bool m_halted = false;