add disk
This commit is contained in:
parent
2e7ab57cc1
commit
2b423a40ed
@ -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
|
||||
|
||||
|
||||
36
src/block_device.cpp
Normal file
36
src/block_device.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "block_device.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
|
||||
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<char*>(data), block_size);
|
||||
}
|
||||
|
||||
void FileDisk::write(const uint8_t* data, uint16_t block)
|
||||
{
|
||||
m_file.seekg(block * block_size);
|
||||
m_file.write(reinterpret_cast<const char*>(data), block_size);
|
||||
}
|
||||
66
src/block_device.hpp
Normal file
66
src/block_device.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <vector>
|
||||
|
||||
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<uint8_t> 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;
|
||||
};
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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<char>(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);
|
||||
|
||||
|
||||
54
src/main.cpp
54
src/main.cpp
@ -1,44 +1,32 @@
|
||||
#include "block_device.hpp"
|
||||
#include "builder.hpp"
|
||||
#include "io_device.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <SDL2/SDL_main.h>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <print>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
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<uint8_t, 65536>();
|
||||
|
||||
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)
|
||||
|
||||
22
src/vm.cpp
22
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 ">.<";
|
||||
}
|
||||
|
||||
23
src/vm.hpp
23
src/vm.hpp
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "block_device.hpp"
|
||||
#include "io_device.hpp"
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user