functions
This commit is contained in:
parent
eab5a313ab
commit
8cb0ac6070
@ -61,91 +61,98 @@ key_press_int:
|
|||||||
cmp r1, 44 ; spacebar
|
cmp r1, 44 ; spacebar
|
||||||
mov r2, rfl
|
mov r2, rfl
|
||||||
and r2, fl_eq
|
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
|
jnz r2, .print_space
|
||||||
add r1, 61 ; scancode letter -> ascii
|
add r1, 61 ; scancode letter -> ascii
|
||||||
mov [rsp], r0
|
|
||||||
|
mov [rsp], r1
|
||||||
add rsp, 2
|
add rsp, 2
|
||||||
call print_char
|
;call print_char
|
||||||
|
call print_u16
|
||||||
|
sub rsp, 2
|
||||||
|
|
||||||
jmp .leave
|
jmp .leave
|
||||||
.print_space:
|
.print_space:
|
||||||
mov r0, ' '
|
mov r1, ' '
|
||||||
mov [rsp], r0
|
|
||||||
|
mov [rsp], r1
|
||||||
add rsp, 2
|
add rsp, 2
|
||||||
call print_char
|
call print_char
|
||||||
|
sub rsp, 2
|
||||||
|
|
||||||
.leave:
|
.leave:
|
||||||
reti
|
reti
|
||||||
|
|
||||||
print_char:
|
print_char:
|
||||||
mov [rsp], rbp
|
mov [rsp], rbp
|
||||||
mov rbp, rsp
|
|
||||||
add rsp, 2
|
add rsp, 2
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
mov r1, [rbp-6]
|
mov r1, [rbp-6]
|
||||||
|
|
||||||
|
mov r0, [counter]
|
||||||
add r0, vcd_base
|
add r0, vcd_base
|
||||||
mov r1, [kbd_code]
|
|
||||||
cmp r1, ' '
|
cmp r1, ' '
|
||||||
mov r2, rfl
|
mov r2, rfl
|
||||||
and r2, fl_eq
|
and r2, fl_eq
|
||||||
jnz r2, .incr
|
jnz r2, .incr
|
||||||
add r1, 61
|
|
||||||
mov byte [r0], r1
|
mov byte [r0], r1
|
||||||
.incr:
|
.incr:
|
||||||
mov r0, [counter]
|
mov r0, [counter]
|
||||||
add r0, 1
|
add r0, 1
|
||||||
mov [counter], r0
|
mov [counter], r0
|
||||||
.leave:
|
.leave:
|
||||||
|
mov rsp, rbp
|
||||||
sub rsp, 2
|
sub rsp, 2
|
||||||
mov rbp, [rsp]
|
mov rbp, [rsp]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;print_int:
|
print_u16:
|
||||||
; mov [rsp], rbp
|
mov [rsp], rbp
|
||||||
; add rsp, 2
|
add rsp, 2
|
||||||
; mov rbp, rsp
|
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
|
|
||||||
|
|
||||||
|
mov r1, [rbp-6] ; value to print
|
||||||
|
mov r4, 0 ; place index
|
||||||
|
|
||||||
;scancode_to_char:
|
jmp .digits_cond
|
||||||
; cmp r1, 61
|
.digits_body:
|
||||||
;
|
mov r2, .places
|
||||||
; mov r2, rfl
|
add r2, r4
|
||||||
; and r2, r2, FL_LT
|
mov r2, [r2] ; place
|
||||||
; jnz .not_letter
|
|
||||||
;
|
mov r3, 0 ; place occurences
|
||||||
; ; if r1 > 86 { goto .not_letter }
|
jmp .place_cond
|
||||||
; cmp r1, 86
|
.place_body:
|
||||||
; mov r2, rfl
|
add r3, 1
|
||||||
; xor r2, 0xffff
|
sub r1, r2
|
||||||
; and r2, r2, FL_EQ | FL_LT
|
.place_cond:
|
||||||
;
|
cmp r2, r1
|
||||||
;
|
mov r0, rfl
|
||||||
; mov r4, rfl
|
and r0, fl_eq | fl_lt
|
||||||
; and r4, r4, FL_EQ
|
jnz r0, .place_body
|
||||||
; shr r4, r4, 2
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -406,24 +406,24 @@ void Assembler::assemble_line(const Line& line)
|
|||||||
l.mov_imm(dst->as_reg(), src->as_imm());
|
l.mov_imm(dst->as_reg(), src->as_imm());
|
||||||
} else if (dst_ty == Reg and src_ty == MemWordReg) {
|
} else if (dst_ty == Reg and src_ty == MemWordReg) {
|
||||||
auto [reg, offset] = src->as_reg_imm_pair();
|
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) {
|
} 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) {
|
} else if (dst_ty == MemWordReg and src_ty == Reg) {
|
||||||
auto [reg, offset] = dst->as_reg_imm_pair();
|
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) {
|
} 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) {
|
} else if (dst_ty == Reg and src_ty == MemByteReg) {
|
||||||
auto [reg, offset] = src->as_reg_imm_pair();
|
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) {
|
} 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) {
|
} else if (dst_ty == MemByteReg and src_ty == Reg) {
|
||||||
auto [reg, offset] = dst->as_reg_imm_pair();
|
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) {
|
} 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 {
|
} else {
|
||||||
operation_not_supported();
|
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)
|
auto Assembler::define_sym(std::string ident, uint16_t value)
|
||||||
-> std::expected<void, std::string>
|
-> std::expected<void, std::string>
|
||||||
{
|
{
|
||||||
std::println("define_sym(\"{}\", {})", ident, value);
|
|
||||||
|
|
||||||
if (m_syms.contains(ident)) {
|
if (m_syms.contains(ident)) {
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
std::format("symbol \"{}\" already defined", ident));
|
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)
|
auto Assembler::get_sym(const std::string& ident)
|
||||||
-> std::expected<uint16_t, std::string>
|
-> std::expected<uint16_t, std::string>
|
||||||
{
|
{
|
||||||
std::println(" get_sym(\"{}\")", ident);
|
|
||||||
|
|
||||||
if (not m_syms.contains(ident)) {
|
if (not m_syms.contains(ident)) {
|
||||||
return std::unexpected(std::format("symbol \"{}\" not defined", ident));
|
return std::unexpected(std::format("symbol \"{}\" not defined", ident));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,77 +141,77 @@ void Builder::mov_imm(Reg dst, uint16_t imm)
|
|||||||
i.build(*this);
|
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;
|
LOG;
|
||||||
auto i = InsBuilder(Op::LoadWord);
|
auto i = InsBuilder(Op::LdW);
|
||||||
i.dst_reg(dst);
|
i.dst_reg(dst);
|
||||||
i.op1_reg(addr);
|
i.op1_reg(addr);
|
||||||
i.imm_without_flag(offset);
|
i.imm_without_flag(offset);
|
||||||
i.build(*this);
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::load_word_imm(Reg dst, uint16_t addr)
|
void Builder::ldw_imm(Reg dst, uint16_t addr)
|
||||||
{
|
{
|
||||||
LOG;
|
LOG;
|
||||||
auto i = InsBuilder(Op::LoadWord);
|
auto i = InsBuilder(Op::LdW);
|
||||||
i.dst_reg(dst);
|
i.dst_reg(dst);
|
||||||
i.imm(addr);
|
i.imm(addr);
|
||||||
i.build(*this);
|
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;
|
LOG;
|
||||||
auto i = InsBuilder(Op::StoreWord);
|
auto i = InsBuilder(Op::StW);
|
||||||
i.dst_reg(dst);
|
i.dst_reg(dst);
|
||||||
i.imm_without_flag(offset);
|
i.imm_without_flag(offset);
|
||||||
i.op2_reg(op2);
|
i.op2_reg(op2);
|
||||||
i.build(*this);
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::store_word_imm(uint16_t dst, Reg op2)
|
void Builder::stw_imm(uint16_t dst, Reg op2)
|
||||||
{
|
{
|
||||||
LOG;
|
LOG;
|
||||||
auto i = InsBuilder(Op::StoreWord);
|
auto i = InsBuilder(Op::StW);
|
||||||
i.imm(dst);
|
i.imm(dst);
|
||||||
i.op2_reg(op2);
|
i.op2_reg(op2);
|
||||||
i.build(*this);
|
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;
|
LOG;
|
||||||
auto i = InsBuilder(Op::LoadByte);
|
auto i = InsBuilder(Op::LdB);
|
||||||
i.dst_reg(dst);
|
i.dst_reg(dst);
|
||||||
i.op1_reg(addr);
|
i.op1_reg(addr);
|
||||||
i.imm_without_flag(offset);
|
i.imm_without_flag(offset);
|
||||||
i.build(*this);
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::load_byte_imm(Reg dst, uint16_t addr)
|
void Builder::ldb_imm(Reg dst, uint16_t addr)
|
||||||
{
|
{
|
||||||
LOG;
|
LOG;
|
||||||
auto i = InsBuilder(Op::LoadByte);
|
auto i = InsBuilder(Op::LdB);
|
||||||
i.dst_reg(dst);
|
i.dst_reg(dst);
|
||||||
i.imm(addr);
|
i.imm(addr);
|
||||||
i.build(*this);
|
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;
|
LOG;
|
||||||
auto i = InsBuilder(Op::StoreByte);
|
auto i = InsBuilder(Op::StB);
|
||||||
i.dst_reg(dst);
|
i.dst_reg(dst);
|
||||||
i.imm_without_flag(offset);
|
i.imm_without_flag(offset);
|
||||||
i.op2_reg(op2);
|
i.op2_reg(op2);
|
||||||
i.build(*this);
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::store_byte_imm(uint16_t dst, Reg op2)
|
void Builder::stb_imm(uint16_t dst, Reg op2)
|
||||||
{
|
{
|
||||||
LOG;
|
LOG;
|
||||||
auto i = InsBuilder(Op::StoreByte);
|
auto i = InsBuilder(Op::StB);
|
||||||
i.imm(dst);
|
i.imm(dst);
|
||||||
i.op2_reg(op2);
|
i.op2_reg(op2);
|
||||||
i.build(*this);
|
i.build(*this);
|
||||||
|
|||||||
@ -23,14 +23,14 @@ public:
|
|||||||
void jnz_imm(Reg op1, uint16_t op2);
|
void jnz_imm(Reg op1, uint16_t op2);
|
||||||
void mov_reg(Reg dst, Reg src);
|
void mov_reg(Reg dst, Reg src);
|
||||||
void mov_imm(Reg dst, uint16_t imm);
|
void mov_imm(Reg dst, uint16_t imm);
|
||||||
void load_word_reg(Reg dst, Reg addr, uint16_t offset);
|
void ldw_reg(Reg dst, Reg addr, uint16_t offset);
|
||||||
void load_word_imm(Reg dst, uint16_t addr);
|
void ldw_imm(Reg dst, uint16_t addr);
|
||||||
void store_word_reg(Reg dst, uint16_t offset, Reg op2);
|
void stw_reg(Reg dst, uint16_t offset, Reg op2);
|
||||||
void store_word_imm(uint16_t dst, Reg op2);
|
void stw_imm(uint16_t dst, Reg op2);
|
||||||
void load_byte_reg(Reg dst, Reg addr, uint16_t offset);
|
void ldb_reg(Reg dst, Reg addr, uint16_t offset);
|
||||||
void load_byte_imm(Reg dst, uint16_t addr);
|
void ldb_imm(Reg dst, uint16_t addr);
|
||||||
void store_byte_reg(Reg dst, uint16_t offset, Reg op2);
|
void stb_reg(Reg dst, uint16_t offset, Reg op2);
|
||||||
void store_byte_imm(uint16_t dst, Reg op2);
|
void stb_imm(uint16_t dst, Reg op2);
|
||||||
void cmp_reg(Reg op1, Reg op2);
|
void cmp_reg(Reg op1, Reg op2);
|
||||||
void cmp_imm(Reg op1, uint16_t op2);
|
void cmp_imm(Reg op1, uint16_t op2);
|
||||||
void or_reg(Reg dst, Reg op1, Reg op2);
|
void or_reg(Reg dst, Reg op1, Reg op2);
|
||||||
|
|||||||
@ -26,6 +26,11 @@ constexpr uint64_t char_data(uint8_t ch)
|
|||||||
case '2': return 0x003C66060C18307E;
|
case '2': return 0x003C66060C18307E;
|
||||||
case '3': return 0x003C66060C06663C;
|
case '3': return 0x003C66060C06663C;
|
||||||
case '4': return 0x000C1C3C6C7E0C0C;
|
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 'A': return 0x00187E66667E6666;
|
||||||
case 'B': return 0x00787E667C667E7C;
|
case 'B': return 0x00787E667C667E7C;
|
||||||
@ -173,7 +178,7 @@ auto IoDevice::poll_event() -> std::unique_ptr<IoEvent>
|
|||||||
std::lock_guard lock(mx);
|
std::lock_guard lock(mx);
|
||||||
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
if (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
return std::make_unique<IoEvent>(
|
return std::make_unique<IoEvent>(
|
||||||
|
|||||||
61
src/vm.cpp
61
src/vm.cpp
@ -273,13 +273,13 @@ struct InsReader {
|
|||||||
int VM::run_instruction()
|
int VM::run_instruction()
|
||||||
{
|
{
|
||||||
auto ip = *m_rip;
|
auto ip = *m_rip;
|
||||||
if (ip > 0x400)
|
if (ip >= 0x400)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
auto ins = InsReader(*this);
|
auto ins = InsReader(*this);
|
||||||
auto op = static_cast<Op>(ins.to_u16() & 0b11'1111);
|
auto op = static_cast<Op>(ins.to_u16() & 0b11'1111);
|
||||||
std::println(
|
std::println(
|
||||||
" [{: 2x}]: 0x{:04x} {: <9} {:04b} {:04b} {:04b} {:04b} {:04x}",
|
" [{: >2x}]: 0x{:04x} {: <6} {:04b} {:04b} {:04b} {:04b} {:04x}",
|
||||||
ip,
|
ip,
|
||||||
ins.to_u16(),
|
ins.to_u16(),
|
||||||
op_str(op),
|
op_str(op),
|
||||||
@ -293,10 +293,36 @@ int VM::run_instruction()
|
|||||||
case Op::Nop:
|
case Op::Nop:
|
||||||
break;
|
break;
|
||||||
case Op::Hlt:
|
case Op::Hlt:
|
||||||
|
if (not m_interrupts_enabled) {
|
||||||
|
std::println("warning: halted without interrupts enabled");
|
||||||
|
}
|
||||||
m_halted = true;
|
m_halted = true;
|
||||||
break;
|
break;
|
||||||
case Op::Jmp: {
|
case Op::Jmp: {
|
||||||
auto op1 = ins.op1_or_imm();
|
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>(reg)),
|
||||||
|
this->reg(static_cast<Reg>(reg)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
*m_rip = op1;
|
*m_rip = op1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -315,7 +341,7 @@ int VM::run_instruction()
|
|||||||
set_reg(dst, src);
|
set_reg(dst, src);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::LoadWord: {
|
case Op::LdW: {
|
||||||
auto addr = ins.mem_addr(ins.op1(), eat_word());
|
auto addr = ins.mem_addr(ins.op1(), eat_word());
|
||||||
|
|
||||||
if ((addr & 0b1) != 0) {
|
if ((addr & 0b1) != 0) {
|
||||||
@ -331,7 +357,7 @@ int VM::run_instruction()
|
|||||||
set_reg(reg, word(addr));
|
set_reg(reg, word(addr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::StoreWord: {
|
case Op::StW: {
|
||||||
auto addr = ins.mem_addr(ins.dst(), eat_word());
|
auto addr = ins.mem_addr(ins.dst(), eat_word());
|
||||||
|
|
||||||
if ((addr & 0b1) != 0) {
|
if ((addr & 0b1) != 0) {
|
||||||
@ -353,14 +379,14 @@ int VM::run_instruction()
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::LoadByte: {
|
case Op::LdB: {
|
||||||
auto addr = ins.mem_addr(ins.op1(), eat_word());
|
auto addr = ins.mem_addr(ins.op1(), eat_word());
|
||||||
auto reg = ins.dst_reg();
|
auto reg = ins.dst_reg();
|
||||||
|
|
||||||
set_reg(reg, byte(addr));
|
set_reg(reg, byte(addr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::StoreByte: {
|
case Op::StB: {
|
||||||
auto addr = ins.mem_addr(ins.dst(), eat_word());
|
auto addr = ins.mem_addr(ins.dst(), eat_word());
|
||||||
auto src = ins.op2();
|
auto src = ins.op2();
|
||||||
|
|
||||||
@ -448,9 +474,9 @@ int VM::run_instruction()
|
|||||||
case Op::Call: {
|
case Op::Call: {
|
||||||
auto op1 = ins.op1_or_imm();
|
auto op1 = ins.op1_or_imm();
|
||||||
|
|
||||||
auto return_addr = word(*m_rip);
|
auto return_addr = *m_rip;
|
||||||
set_word(*m_rsp, return_addr);
|
set_word(*m_rsp, return_addr);
|
||||||
*m_rsp -= 2;
|
*m_rsp += 2;
|
||||||
|
|
||||||
*m_rip = op1;
|
*m_rip = op1;
|
||||||
break;
|
break;
|
||||||
@ -464,7 +490,6 @@ int VM::run_instruction()
|
|||||||
case Op::RetI: {
|
case Op::RetI: {
|
||||||
*m_rsp -= 2;
|
*m_rsp -= 2;
|
||||||
auto return_addr = word(*m_rsp);
|
auto return_addr = word(*m_rsp);
|
||||||
|
|
||||||
*m_rip = return_addr;
|
*m_rip = return_addr;
|
||||||
|
|
||||||
m_interrupts_enabled = true;
|
m_interrupts_enabled = true;
|
||||||
@ -579,7 +604,7 @@ void VM::interrupt(uint16_t handler_addr)
|
|||||||
m_interrupts_enabled = false;
|
m_interrupts_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* vc5::op_str(Op op)
|
auto vc5::op_str(Op op) -> std::string_view
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Op::Nop:
|
case Op::Nop:
|
||||||
@ -592,14 +617,14 @@ const char* vc5::op_str(Op op)
|
|||||||
return "Jnz";
|
return "Jnz";
|
||||||
case Op::Mov:
|
case Op::Mov:
|
||||||
return "Mov";
|
return "Mov";
|
||||||
case Op::LoadWord:
|
case Op::LdW:
|
||||||
return "LoadWord";
|
return "LdW";
|
||||||
case Op::StoreWord:
|
case Op::StW:
|
||||||
return "StoreWord";
|
return "StW";
|
||||||
case Op::LoadByte:
|
case Op::LdB:
|
||||||
return "LoadByte";
|
return "LdB";
|
||||||
case Op::StoreByte:
|
case Op::StB:
|
||||||
return "StoreByte";
|
return "StB";
|
||||||
case Op::Cmp:
|
case Op::Cmp:
|
||||||
return "Cmp";
|
return "Cmp";
|
||||||
case Op::Or:
|
case Op::Or:
|
||||||
|
|||||||
11
src/vm.hpp
11
src/vm.hpp
@ -7,6 +7,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace vc5 {
|
namespace vc5 {
|
||||||
@ -17,10 +18,10 @@ enum class Op : uint16_t {
|
|||||||
Jmp,
|
Jmp,
|
||||||
Jnz,
|
Jnz,
|
||||||
Mov,
|
Mov,
|
||||||
LoadWord,
|
LdW,
|
||||||
StoreWord,
|
StW,
|
||||||
LoadByte,
|
LdB,
|
||||||
StoreByte,
|
StB,
|
||||||
Cmp,
|
Cmp,
|
||||||
Or,
|
Or,
|
||||||
And,
|
And,
|
||||||
@ -49,7 +50,7 @@ enum class Op : uint16_t {
|
|||||||
DSKW,
|
DSKW,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* op_str(Op op);
|
auto op_str(Op op) -> std::string_view;
|
||||||
|
|
||||||
enum class Reg : uint16_t {
|
enum class Reg : uint16_t {
|
||||||
R0 = 0,
|
R0 = 0,
|
||||||
|
|||||||
105
src/vm_main.cpp
105
src/vm_main.cpp
@ -4,6 +4,7 @@
|
|||||||
#include "vm.hpp"
|
#include "vm.hpp"
|
||||||
#include <SDL2/SDL_main.h>
|
#include <SDL2/SDL_main.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -11,118 +12,20 @@ using namespace std::chrono_literals;
|
|||||||
|
|
||||||
using namespace vc5;
|
using namespace vc5;
|
||||||
|
|
||||||
static void make_program(uint8_t* data);
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
auto device = IoDevice::create().value();
|
auto device = IoDevice::create().value();
|
||||||
device->set_title("vc5");
|
device->set_title("vc5");
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc > 2) {
|
||||||
auto disk = MemoryDisk(128);
|
std::println("error: no boot disk (file name) specified");
|
||||||
|
return EXIT_FAILURE;
|
||||||
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 disk = FileDisk(argv[1]);
|
||||||
|
|
||||||
auto memory_disk = MemoryDisk(128);
|
|
||||||
make_program(memory_disk.data());
|
|
||||||
|
|
||||||
auto file_block = std::vector<uint8_t>(BlockDevice::block_size);
|
|
||||||
disk.read(file_block.data(), 0);
|
|
||||||
|
|
||||||
auto memory_block = std::vector<uint8_t>(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);
|
auto vm = VM(*device, disk);
|
||||||
vm.run();
|
vm.run();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void make_program(uint8_t* data)
|
|
||||||
{
|
|
||||||
using namespace vc5::regs;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" const char* __asan_default_options(void)
|
extern "C" const char* __asan_default_options(void)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user