auto scroll
This commit is contained in:
parent
25f7c12e97
commit
c1c8bcf0b3
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
MAKEFLAGS += -j16
|
MAKEFLAGS += -j16
|
||||||
|
|
||||||
CXXFLAGS := -std=c++23 -Wall -Wextra -pedantic-errors -fsanitize=address
|
CXXFLAGS := -std=c++23 -Wall -Wextra -pedantic-errors -fsanitize=address -g -ggdb
|
||||||
LDFLAGS :=
|
LDFLAGS :=
|
||||||
|
|
||||||
CXXFLAGS += $(shell pkgconf sdl2 --cflags)
|
CXXFLAGS += $(shell pkgconf sdl2 --cflags)
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
|
||||||
|
|
||||||
const fl_zero 0x1
|
const fl_zero 1 << 0
|
||||||
const fl_eq 0x2
|
const fl_eq 1 << 1
|
||||||
const fl_be 0x4
|
const fl_be 1 << 2
|
||||||
const fl_lt 0x8
|
const fl_ab 1 << 3
|
||||||
const fl_err 0xa
|
const fl_lt 1 << 4
|
||||||
|
const fl_gt 1 << 5
|
||||||
|
const fl_err 1 << 6
|
||||||
|
|
||||||
const vcd_base 0x2000
|
const vcd_base 0x2000
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ key_press_int:
|
|||||||
|
|
||||||
mov [rsp], r1
|
mov [rsp], r1
|
||||||
add rsp, 2
|
add rsp, 2
|
||||||
call print_u16
|
call term_putc
|
||||||
sub rsp, 2
|
sub rsp, 2
|
||||||
|
|
||||||
jmp .leave
|
jmp .leave
|
||||||
@ -81,7 +83,9 @@ key_press_int:
|
|||||||
.leave:
|
.leave:
|
||||||
reti
|
reti
|
||||||
|
|
||||||
|
|
||||||
const term_width 20
|
const term_width 20
|
||||||
|
const term_height 12
|
||||||
|
|
||||||
term_y:
|
term_y:
|
||||||
dw 0
|
dw 0
|
||||||
@ -95,23 +99,112 @@ term_putc:
|
|||||||
|
|
||||||
mov r1, [rbp-6]
|
mov r1, [rbp-6]
|
||||||
|
|
||||||
mov r0, [counter]
|
cmp r1, '\n'
|
||||||
add r0, vcd_base
|
mov r0, rfl
|
||||||
|
and r0, fl_eq
|
||||||
|
jnz r0, .next_row
|
||||||
|
|
||||||
cmp r1, ' '
|
cmp r1, ' '
|
||||||
mov r2, rfl
|
mov r0, rfl
|
||||||
and r2, fl_eq
|
and r0, fl_eq
|
||||||
jnz r2, .incr
|
jnz r0, .next_col
|
||||||
|
|
||||||
|
cmp r1, '\0'
|
||||||
|
mov r0, rfl
|
||||||
|
and r0, fl_eq
|
||||||
|
jnz r0, .next_col
|
||||||
|
|
||||||
|
mov r0, [term_y]
|
||||||
|
mul r0, term_width
|
||||||
|
add r0, vcd_base
|
||||||
|
mov r2, [term_x]
|
||||||
|
add r0, r2
|
||||||
mov byte [r0], r1
|
mov byte [r0], r1
|
||||||
.incr:
|
|
||||||
mov r0, [counter]
|
.next_col:
|
||||||
add r0, 1
|
mov r2, [term_x]
|
||||||
mov [counter], r0
|
add r2, 1
|
||||||
|
mov [term_x], r2
|
||||||
|
cmp r2, term_width
|
||||||
|
mov r0, rfl
|
||||||
|
and r0, fl_lt
|
||||||
|
jnz r0, .leave
|
||||||
|
|
||||||
|
.next_row:
|
||||||
|
mov r0, 0
|
||||||
|
mov [term_x], r0
|
||||||
|
|
||||||
|
mov r2, [term_y]
|
||||||
|
add r2, 1
|
||||||
|
cmp r2, term_height
|
||||||
|
mov r0, rfl
|
||||||
|
and r0, fl_lt
|
||||||
|
jnz r0, .increment_y
|
||||||
|
|
||||||
|
call term_scroll
|
||||||
|
jmp .leave
|
||||||
|
|
||||||
|
.increment_y:
|
||||||
|
mov [term_y], r2
|
||||||
|
|
||||||
.leave:
|
.leave:
|
||||||
mov rsp, rbp
|
mov rsp, rbp
|
||||||
sub rsp, 2
|
sub rsp, 2
|
||||||
mov rbp, [rsp]
|
mov rbp, [rsp]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
term_scroll:
|
||||||
|
mov r1, 0 ; row
|
||||||
|
jmp .l1_cond
|
||||||
|
.l1_body:
|
||||||
|
mov r2, 0 ; col
|
||||||
|
jmp .l2_cond
|
||||||
|
.l2_body:
|
||||||
|
mov r0, term_width
|
||||||
|
mul r0, r1
|
||||||
|
add r0, r2
|
||||||
|
mov r4, byte [vcd_base + term_width + r0]
|
||||||
|
mov byte [vcd_base + r0], r4
|
||||||
|
|
||||||
|
add r2, 1
|
||||||
|
.l2_cond:
|
||||||
|
cmp r2, term_width
|
||||||
|
mov r0, rfl
|
||||||
|
and r0, fl_lt
|
||||||
|
jnz r0, .l2_body
|
||||||
|
|
||||||
|
add r1, 1
|
||||||
|
.l1_cond:
|
||||||
|
cmp r1, term_height - 1
|
||||||
|
mov r0, rfl
|
||||||
|
and r0, fl_lt
|
||||||
|
jnz r0, .l1_body
|
||||||
|
|
||||||
|
mov r2, 0
|
||||||
|
jmp .l3_cond
|
||||||
|
.l3_body:
|
||||||
|
mov r0, ' '
|
||||||
|
mov byte [vcd_base + (term_height - 1) * term_width + r2], r0
|
||||||
|
|
||||||
|
add r2, 1
|
||||||
|
.l3_cond:
|
||||||
|
cmp r2, term_width
|
||||||
|
mov r0, rfl
|
||||||
|
and r0, fl_lt
|
||||||
|
jnz r0, .l3_body
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print_u16:
|
print_u16:
|
||||||
mov [rsp], rbp
|
mov [rsp], rbp
|
||||||
add rsp, 2
|
add rsp, 2
|
||||||
|
|||||||
52
programs/term.txt
Normal file
52
programs/term.txt
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
const term_width: u16 = 20;
|
||||||
|
const term_height: u16 = 12;
|
||||||
|
|
||||||
|
static term_x: u16 = 0;
|
||||||
|
static term_y: u16 = 0;
|
||||||
|
|
||||||
|
static vcd: *u16 = 0x2000;
|
||||||
|
|
||||||
|
fn term_putc(ch: u16)
|
||||||
|
{
|
||||||
|
if (ch == '\n')
|
||||||
|
continue 'next_line;
|
||||||
|
|
||||||
|
if (ch == '\0')
|
||||||
|
continue 'next_col;
|
||||||
|
if (ch == ' ')
|
||||||
|
continue 'next_col;
|
||||||
|
|
||||||
|
vcd[term_y * term_width + term_x] = ch;
|
||||||
|
|
||||||
|
'next_col:
|
||||||
|
term_x += 1;
|
||||||
|
if (term_x < term_width)
|
||||||
|
return
|
||||||
|
|
||||||
|
'next_line:
|
||||||
|
term_x = 0;
|
||||||
|
|
||||||
|
if (term_y + 1 >= term_height) {
|
||||||
|
term_scroll();
|
||||||
|
} else {
|
||||||
|
term_y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_scroll()
|
||||||
|
{
|
||||||
|
for row: u16 in 0..term_height - 1 {
|
||||||
|
for col: u16 in 0..term_width {
|
||||||
|
|
||||||
|
vcd[row * term_width + col]
|
||||||
|
= vcd[(row + 1) * term_width + col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for col: u16 in 0..term_width {
|
||||||
|
vcd[(term_height - 1) * term_width + col] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: syntax=rust
|
||||||
|
|
||||||
@ -245,6 +245,8 @@ enum class Mnemonic {
|
|||||||
add,
|
add,
|
||||||
sub,
|
sub,
|
||||||
rsub,
|
rsub,
|
||||||
|
mul,
|
||||||
|
imul,
|
||||||
call,
|
call,
|
||||||
ret,
|
ret,
|
||||||
reti,
|
reti,
|
||||||
@ -276,6 +278,8 @@ static const auto mnemonic_map
|
|||||||
{ "add", M::add },
|
{ "add", M::add },
|
||||||
{ "sub", M::sub },
|
{ "sub", M::sub },
|
||||||
{ "rsub", M::rsub },
|
{ "rsub", M::rsub },
|
||||||
|
{ "mul", M::mul },
|
||||||
|
{ "imul", M::imul },
|
||||||
{ "call", M::call },
|
{ "call", M::call },
|
||||||
{ "ret", M::ret },
|
{ "ret", M::ret },
|
||||||
{ "reti", M::reti },
|
{ "reti", M::reti },
|
||||||
@ -459,7 +463,9 @@ void Assembler::assemble_line(const Line& line)
|
|||||||
case M::rshr:
|
case M::rshr:
|
||||||
case M::add:
|
case M::add:
|
||||||
case M::sub:
|
case M::sub:
|
||||||
case M::rsub: {
|
case M::rsub:
|
||||||
|
case M::mul:
|
||||||
|
case M::imul: {
|
||||||
auto dst = std::unique_ptr<EvaledOperand> {};
|
auto dst = std::unique_ptr<EvaledOperand> {};
|
||||||
auto op1_store = std::unique_ptr<EvaledOperand> {};
|
auto op1_store = std::unique_ptr<EvaledOperand> {};
|
||||||
auto op2 = std::unique_ptr<EvaledOperand> {};
|
auto op2 = std::unique_ptr<EvaledOperand> {};
|
||||||
@ -519,6 +525,12 @@ void Assembler::assemble_line(const Line& line)
|
|||||||
case Mnemonic::rsub:
|
case Mnemonic::rsub:
|
||||||
l.rsub_reg(dst->as_reg(), op1->as_reg(), op2->as_reg());
|
l.rsub_reg(dst->as_reg(), op1->as_reg(), op2->as_reg());
|
||||||
break;
|
break;
|
||||||
|
case M::mul:
|
||||||
|
l.mul_reg(dst->as_reg(), op1->as_reg(), op2->as_reg());
|
||||||
|
break;
|
||||||
|
case M::imul:
|
||||||
|
l.imul_reg(dst->as_reg(), op1->as_reg(), op2->as_reg());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false && "unhandled");
|
assert(false && "unhandled");
|
||||||
}
|
}
|
||||||
@ -554,6 +566,12 @@ void Assembler::assemble_line(const Line& line)
|
|||||||
case Mnemonic::rsub:
|
case Mnemonic::rsub:
|
||||||
l.rsub_imm(dst->as_reg(), op1->as_reg(), op2->as_imm());
|
l.rsub_imm(dst->as_reg(), op1->as_reg(), op2->as_imm());
|
||||||
break;
|
break;
|
||||||
|
case M::mul:
|
||||||
|
l.mul_imm(dst->as_reg(), op1->as_reg(), op2->as_imm());
|
||||||
|
break;
|
||||||
|
case M::imul:
|
||||||
|
l.imul_imm(dst->as_reg(), op1->as_reg(), op2->as_imm());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false && "unhandled");
|
assert(false && "unhandled");
|
||||||
}
|
}
|
||||||
@ -672,6 +690,9 @@ auto Assembler::eval_operand(const Expr& expr) -> std::unique_ptr<EvaledOperand>
|
|||||||
return eval_operand_mem(*expr.as_unary());
|
return eval_operand_mem(*expr.as_unary());
|
||||||
case Expr::Ty::MemByte: {
|
case Expr::Ty::MemByte: {
|
||||||
auto evaled = eval_operand_mem(*expr.as_unary());
|
auto evaled = eval_operand_mem(*expr.as_unary());
|
||||||
|
if (not evaled)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
switch (evaled->ty) {
|
switch (evaled->ty) {
|
||||||
case EOT::MemWordImm:
|
case EOT::MemWordImm:
|
||||||
evaled->ty = EOT::MemByteImm;
|
evaled->ty = EOT::MemByteImm;
|
||||||
@ -695,7 +716,10 @@ auto Assembler::eval_operand(const Expr& expr) -> std::unique_ptr<EvaledOperand>
|
|||||||
case Expr::Ty::Shl:
|
case Expr::Ty::Shl:
|
||||||
case Expr::Ty::Shr:
|
case Expr::Ty::Shr:
|
||||||
case Expr::Ty::Add:
|
case Expr::Ty::Add:
|
||||||
case Expr::Ty::Sub: {
|
case Expr::Ty::Sub:
|
||||||
|
case Expr::Ty::Mul:
|
||||||
|
case Expr::Ty::Div:
|
||||||
|
case Expr::Ty::Mod: {
|
||||||
return eval_operand_to_imm(expr);
|
return eval_operand_to_imm(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -715,7 +739,10 @@ auto Assembler::eval_operand_mem(const Expr& expr)
|
|||||||
case Expr::Ty::Xor:
|
case Expr::Ty::Xor:
|
||||||
case Expr::Ty::And:
|
case Expr::Ty::And:
|
||||||
case Expr::Ty::Shl:
|
case Expr::Ty::Shl:
|
||||||
case Expr::Ty::Shr: {
|
case Expr::Ty::Shr:
|
||||||
|
case Expr::Ty::Mul:
|
||||||
|
case Expr::Ty::Div:
|
||||||
|
case Expr::Ty::Mod: {
|
||||||
auto op = eval_operand_to_imm(expr);
|
auto op = eval_operand_to_imm(expr);
|
||||||
if (not op)
|
if (not op)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -822,7 +849,9 @@ auto Assembler::eval_operand_to_imm(const Expr& expr)
|
|||||||
return std::make_unique<EO>(loc, EOT::Imm, *result);
|
return std::make_unique<EO>(loc, EOT::Imm, *result);
|
||||||
}
|
}
|
||||||
case Expr::Ty::Reg:
|
case Expr::Ty::Reg:
|
||||||
|
if (not m_second_pass) {
|
||||||
error(loc, "registers cannot be part of an expression");
|
error(loc, "registers cannot be part of an expression");
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
case Expr::Ty::Int:
|
case Expr::Ty::Int:
|
||||||
return std::make_unique<EO>(
|
return std::make_unique<EO>(
|
||||||
@ -843,7 +872,10 @@ auto Assembler::eval_operand_to_imm(const Expr& expr)
|
|||||||
case Expr::Ty::Shl:
|
case Expr::Ty::Shl:
|
||||||
case Expr::Ty::Shr:
|
case Expr::Ty::Shr:
|
||||||
case Expr::Ty::Add:
|
case Expr::Ty::Add:
|
||||||
case Expr::Ty::Sub: {
|
case Expr::Ty::Sub:
|
||||||
|
case Expr::Ty::Mul:
|
||||||
|
case Expr::Ty::Div:
|
||||||
|
case Expr::Ty::Mod: {
|
||||||
auto& [left_expr, right_expr] = expr.as_binary();
|
auto& [left_expr, right_expr] = expr.as_binary();
|
||||||
auto left = eval_operand_to_imm(*left_expr);
|
auto left = eval_operand_to_imm(*left_expr);
|
||||||
if (not left)
|
if (not left)
|
||||||
@ -886,15 +918,12 @@ auto Assembler::binary_op(Expr::Ty exprTy, uint16_t left, uint16_t right)
|
|||||||
return (uint16_t)((int16_t)left + (int16_t)right);
|
return (uint16_t)((int16_t)left + (int16_t)right);
|
||||||
case Expr::Ty::Sub:
|
case Expr::Ty::Sub:
|
||||||
return (uint16_t)((int16_t)left - (int16_t)right);
|
return (uint16_t)((int16_t)left - (int16_t)right);
|
||||||
|
case Expr::Ty::Mul:
|
||||||
// taken from vc3
|
return (uint16_t)((int16_t)left * (int16_t)right);
|
||||||
// case Expr::Ty::Mul:
|
case Expr::Ty::Div:
|
||||||
// return (uint16_t)((int16_t)left * (int16_t)right);
|
return (uint16_t)((int16_t)left / (int16_t)right);
|
||||||
// case Expr::Ty::Div:
|
case Expr::Ty::Mod:
|
||||||
// return (uint16_t)((int16_t)left / (int16_t)right);
|
return (uint16_t)((int16_t)left % (int16_t)right);
|
||||||
// case Expr::Ty::Mod:
|
|
||||||
// return (uint16_t)((int16_t)left % (int16_t)right);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false && "unhandled");
|
assert(false && "unhandled");
|
||||||
}
|
}
|
||||||
@ -1087,13 +1116,16 @@ auto Parser::parse_binary(int prec) -> std::unique_ptr<Expr>
|
|||||||
using Op = std::tuple<TT, T, int>;
|
using Op = std::tuple<TT, T, int>;
|
||||||
|
|
||||||
constexpr auto ops = std::array {
|
constexpr auto ops = std::array {
|
||||||
Op { TT::Pipe, T::Or, 5 },
|
Op { TT::Pipe, T::Or, 6 },
|
||||||
Op { TT::Hat, T::Xor, 4 },
|
Op { TT::Hat, T::Xor, 5 },
|
||||||
Op { TT::Ampersand, T::And, 3 },
|
Op { TT::Ampersand, T::And, 4 },
|
||||||
Op { TT::LtLt, T::Shl, 2 },
|
Op { TT::LtLt, T::Shl, 3 },
|
||||||
Op { TT::GtGt, T::Shr, 2 },
|
Op { TT::GtGt, T::Shr, 3 },
|
||||||
Op { TT::Plus, T::Add, 1 },
|
Op { TT::Plus, T::Add, 2 },
|
||||||
Op { TT::Minus, T::Sub, 1 },
|
Op { TT::Minus, T::Sub, 2 },
|
||||||
|
Op { TT::Aster, T::Mul, 1 },
|
||||||
|
Op { TT::Slash, T::Div, 1 },
|
||||||
|
Op { TT::Perc, T::Mod, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (prec == 0) {
|
if (prec == 0) {
|
||||||
|
|||||||
@ -44,6 +44,9 @@ namespace asmer {
|
|||||||
Shr,
|
Shr,
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
};
|
};
|
||||||
|
|
||||||
using Ptr = std::unique_ptr<Expr>;
|
using Ptr = std::unique_ptr<Expr>;
|
||||||
|
|||||||
129
src/builder.cpp
129
src/builder.cpp
@ -1,3 +1,4 @@
|
|||||||
|
#define DEFINE_BINARY_INSTRUCTIONS
|
||||||
#include "builder.hpp"
|
#include "builder.hpp"
|
||||||
#include "vm.hpp"
|
#include "vm.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -235,125 +236,21 @@ void Builder::cmp_imm(Reg op1, uint16_t op2)
|
|||||||
i.build(*this);
|
i.build(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::or_reg(Reg dst, Reg op1, Reg op2)
|
#define X(NAME, OP) \
|
||||||
{
|
void Builder::NAME##_reg(Reg dst, Reg op1, Reg op2) \
|
||||||
LOG;
|
{ \
|
||||||
binary_reg(dst, op1, op2, Op::Or);
|
LOG; \
|
||||||
|
binary_reg(dst, op1, op2, Op::OP); \
|
||||||
|
} \
|
||||||
|
void Builder::NAME##_imm(Reg dst, Reg op1, uint16_t op2) \
|
||||||
|
{ \
|
||||||
|
LOG; \
|
||||||
|
binary_imm(dst, op1, op2, Op::OP); \
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::and_reg(Reg dst, Reg op1, Reg op2)
|
BINARY_INSTRUCTIONS
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::And);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::xor_reg(Reg dst, Reg op1, Reg op2)
|
#undef X
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::Xor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::shl_reg(Reg dst, Reg op1, Reg op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::Shl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::rshl_reg(Reg dst, Reg op1, Reg op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::RShl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::shr_reg(Reg dst, Reg op1, Reg op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::Shr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::rshr_reg(Reg dst, Reg op1, Reg op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::RShr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::add_reg(Reg dst, Reg op1, Reg op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::Add);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::sub_reg(Reg dst, Reg op1, Reg op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::Sub);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::rsub_reg(Reg dst, Reg op1, Reg op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_reg(dst, op1, op2, Op::RSub);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::or_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::Xor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::and_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::And);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::xor_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::Xor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::shl_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::Shl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::rshl_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::RShl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::shr_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::Shr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::rshr_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::RShr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::add_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::Add);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::sub_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::Sub);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::rsub_imm(Reg dst, Reg op1, uint16_t op2)
|
|
||||||
{
|
|
||||||
LOG;
|
|
||||||
binary_imm(dst, op1, op2, Op::RSub);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::binary_reg(Reg dst, Reg op1, Reg op2, Op op)
|
void Builder::binary_reg(Reg dst, Reg op1, Reg op2, Op op)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,6 +4,20 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <print>
|
#include <print>
|
||||||
|
|
||||||
|
#define BINARY_INSTRUCTIONS \
|
||||||
|
X(or, Or) \
|
||||||
|
X(and, And) \
|
||||||
|
X(xor, Xor) \
|
||||||
|
X(shl, Shl) \
|
||||||
|
X(rshl, RShl) \
|
||||||
|
X(shr, Shr) \
|
||||||
|
X(rshr, RShr) \
|
||||||
|
X(add, Add) \
|
||||||
|
X(sub, Sub) \
|
||||||
|
X(rsub, RSub) \
|
||||||
|
X(mul, Mul) \
|
||||||
|
X(imul, IMul)
|
||||||
|
|
||||||
namespace vc5::tools {
|
namespace vc5::tools {
|
||||||
|
|
||||||
using namespace vc5;
|
using namespace vc5;
|
||||||
@ -33,26 +47,15 @@ public:
|
|||||||
void stb_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 and_reg(Reg dst, Reg op1, Reg op2);
|
#define X(NAME, OP) \
|
||||||
void xor_reg(Reg dst, Reg op1, Reg op2);
|
void NAME##_reg(Reg dst, Reg op1, Reg op2); \
|
||||||
void shl_reg(Reg dst, Reg op1, Reg op2);
|
void NAME##_imm(Reg dst, Reg op1, uint16_t op2);
|
||||||
void rshl_reg(Reg dst, Reg op1, Reg op2);
|
|
||||||
void shr_reg(Reg dst, Reg op1, Reg op2);
|
BINARY_INSTRUCTIONS
|
||||||
void rshr_reg(Reg dst, Reg op1, Reg op2);
|
|
||||||
void add_reg(Reg dst, Reg op1, Reg op2);
|
#undef X
|
||||||
void sub_reg(Reg dst, Reg op1, Reg op2);
|
|
||||||
void rsub_reg(Reg dst, Reg op1, Reg op2);
|
|
||||||
void or_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void and_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void xor_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void shl_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void rshl_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void shr_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void rshr_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void add_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void sub_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void rsub_imm(Reg dst, Reg op1, uint16_t op2);
|
|
||||||
void call_reg(Reg op1);
|
void call_reg(Reg op1);
|
||||||
void call_imm(uint16_t op1);
|
void call_imm(uint16_t op1);
|
||||||
void ret();
|
void ret();
|
||||||
@ -103,3 +106,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DEFINE_BINARY_INSTRUCTIONS
|
||||||
|
#undef BINARY_INSTRUCTIONS
|
||||||
|
#endif
|
||||||
|
|||||||
@ -131,7 +131,7 @@ auto Scanner::next() -> Tok
|
|||||||
}
|
}
|
||||||
return tok(TT::Gt, loc);
|
return tok(TT::Gt, loc);
|
||||||
}
|
}
|
||||||
if (test_in("\n()[].,:|^+-!")) {
|
if (test_in("\n()[].,:|^+-*/%!")) {
|
||||||
auto ty = static_cast<TT>(current());
|
auto ty = static_cast<TT>(current());
|
||||||
step();
|
step();
|
||||||
return tok(ty, loc);
|
return tok(ty, loc);
|
||||||
|
|||||||
@ -54,6 +54,9 @@ struct Tok {
|
|||||||
Ampersand = '&',
|
Ampersand = '&',
|
||||||
Plus = '+',
|
Plus = '+',
|
||||||
Minus = '-',
|
Minus = '-',
|
||||||
|
Aster = '*',
|
||||||
|
Slash = '/',
|
||||||
|
Perc = '%',
|
||||||
Exclam = '!',
|
Exclam = '!',
|
||||||
Lt = '<',
|
Lt = '<',
|
||||||
Gt = '>',
|
Gt = '>',
|
||||||
|
|||||||
35
src/vm.cpp
35
src/vm.cpp
@ -411,11 +411,21 @@ int VM::run_instruction()
|
|||||||
} else {
|
} else {
|
||||||
*m_rfl &= (uint16_t)~(1u << std::to_underlying(Flag::Be));
|
*m_rfl &= (uint16_t)~(1u << std::to_underlying(Flag::Be));
|
||||||
}
|
}
|
||||||
|
if (op1 > op2) {
|
||||||
|
*m_rfl |= 1u << std::to_underlying(Flag::Ab);
|
||||||
|
} else {
|
||||||
|
*m_rfl &= (uint16_t)~(1u << std::to_underlying(Flag::Ab));
|
||||||
|
}
|
||||||
if ((int16_t)op1 < (int16_t)op2) {
|
if ((int16_t)op1 < (int16_t)op2) {
|
||||||
*m_rfl |= 1u << std::to_underlying(Flag::Lt);
|
*m_rfl |= 1u << std::to_underlying(Flag::Lt);
|
||||||
} else {
|
} else {
|
||||||
*m_rfl &= (uint16_t)~(1u << std::to_underlying(Flag::Lt));
|
*m_rfl &= (uint16_t)~(1u << std::to_underlying(Flag::Lt));
|
||||||
}
|
}
|
||||||
|
if ((int16_t)op1 > (int16_t)op2) {
|
||||||
|
*m_rfl |= 1u << std::to_underlying(Flag::Gt);
|
||||||
|
} else {
|
||||||
|
*m_rfl &= (uint16_t)~(1u << std::to_underlying(Flag::Gt));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::Or:
|
case Op::Or:
|
||||||
@ -427,13 +437,18 @@ int VM::run_instruction()
|
|||||||
case Op::RShr:
|
case Op::RShr:
|
||||||
case Op::Add:
|
case Op::Add:
|
||||||
case Op::Sub:
|
case Op::Sub:
|
||||||
case Op::RSub: {
|
case Op::RSub:
|
||||||
|
case Op::Mul:
|
||||||
|
case Op::IMul: {
|
||||||
auto op1 = ins.op1();
|
auto op1 = ins.op1();
|
||||||
auto op2 = ins.op2_or_imm();
|
auto op2 = ins.op2_or_imm();
|
||||||
auto dst_reg = ins.dst_reg();
|
auto dst_reg = ins.dst_reg();
|
||||||
|
|
||||||
uint16_t* dst = &m_regs[std::to_underlying(dst_reg)];
|
uint16_t* dst = &m_regs[std::to_underlying(dst_reg)];
|
||||||
|
|
||||||
|
auto as_u16 = [](auto v) { return static_cast<uint16_t>(v); };
|
||||||
|
auto as_i16 = [](auto v) { return static_cast<int16_t>(v); };
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Op::Or:
|
case Op::Or:
|
||||||
*dst = op1 | op2;
|
*dst = op1 | op2;
|
||||||
@ -445,16 +460,16 @@ int VM::run_instruction()
|
|||||||
*dst = op1 & op2;
|
*dst = op1 & op2;
|
||||||
break;
|
break;
|
||||||
case Op::Shl:
|
case Op::Shl:
|
||||||
*dst = static_cast<uint16_t>(op1 << op2);
|
*dst = as_u16(op1 << op2);
|
||||||
break;
|
break;
|
||||||
case Op::RShl:
|
case Op::RShl:
|
||||||
*dst = static_cast<uint16_t>(op2 << op1);
|
*dst = as_u16(op2 << op1);
|
||||||
break;
|
break;
|
||||||
case Op::Shr:
|
case Op::Shr:
|
||||||
*dst = static_cast<uint16_t>(op1 >> op2);
|
*dst = as_u16(op1 >> op2);
|
||||||
break;
|
break;
|
||||||
case Op::RShr:
|
case Op::RShr:
|
||||||
*dst = static_cast<uint16_t>(op2 >> op1);
|
*dst = as_u16(op2 >> op1);
|
||||||
break;
|
break;
|
||||||
case Op::Add:
|
case Op::Add:
|
||||||
*dst = op1 + op2;
|
*dst = op1 + op2;
|
||||||
@ -465,6 +480,12 @@ int VM::run_instruction()
|
|||||||
case Op::RSub:
|
case Op::RSub:
|
||||||
*dst = op2 - op1;
|
*dst = op2 - op1;
|
||||||
break;
|
break;
|
||||||
|
case Op::Mul:
|
||||||
|
*dst = op1 * op2;
|
||||||
|
break;
|
||||||
|
case Op::IMul:
|
||||||
|
*dst = as_u16(as_i16(op1) * as_i16(op2));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -647,6 +668,10 @@ auto vc5::op_str(Op op) -> std::string_view
|
|||||||
return "Sub";
|
return "Sub";
|
||||||
case Op::RSub:
|
case Op::RSub:
|
||||||
return "RSub";
|
return "RSub";
|
||||||
|
case Op::Mul:
|
||||||
|
return "Mul";
|
||||||
|
case Op::IMul:
|
||||||
|
return "IMul";
|
||||||
case Op::Call:
|
case Op::Call:
|
||||||
return "Call";
|
return "Call";
|
||||||
case Op::Ret:
|
case Op::Ret:
|
||||||
|
|||||||
@ -33,6 +33,8 @@ enum class Op : uint16_t {
|
|||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
RSub,
|
RSub,
|
||||||
|
Mul,
|
||||||
|
IMul,
|
||||||
|
|
||||||
Call,
|
Call,
|
||||||
Ret,
|
Ret,
|
||||||
@ -82,8 +84,10 @@ enum class Flag : uint16_t {
|
|||||||
Zero = 0,
|
Zero = 0,
|
||||||
Eq = 1,
|
Eq = 1,
|
||||||
Be = 2,
|
Be = 2,
|
||||||
Lt = 3,
|
Ab = 3,
|
||||||
Err = 4,
|
Lt = 4,
|
||||||
|
Gt = 5,
|
||||||
|
Err = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VcdDescript {
|
struct VcdDescript {
|
||||||
|
|||||||
@ -8,12 +8,17 @@ if exists("b:current_syntax")
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
syn keyword Keyword const align db dw
|
syn keyword Keyword const align db dw
|
||||||
syn keyword Keyword nop hlt jmp jnz mov cmp or and xor shl rshl shr rshr add sub rsub
|
syn keyword Keyword nop hlt jmp jnz mov cmp
|
||||||
|
syn keyword Keyword or and xor shl rshl shr rshr add sub rsub mul imul
|
||||||
syn keyword Keyword call ret reti lkbd lvcd dskr dskw
|
syn keyword Keyword call ret reti lkbd lvcd dskr dskw
|
||||||
|
syn keyword Type byte word
|
||||||
syn keyword Operator r0 r1 r2 r3 r4 r5 rbp rsp rfl rip
|
syn keyword Operator r0 r1 r2 r3 r4 r5 rbp rsp rfl rip
|
||||||
|
|
||||||
syn match Operator '+'
|
syn match Operator '+'
|
||||||
syn match Operator '-'
|
syn match Operator '-'
|
||||||
|
syn match Operator '*'
|
||||||
|
syn match Operator '/'
|
||||||
|
syn match Operator '%'
|
||||||
syn match Operator '='
|
syn match Operator '='
|
||||||
syn match Operator '<'
|
syn match Operator '<'
|
||||||
syn match Operator '>'
|
syn match Operator '>'
|
||||||
@ -21,7 +26,6 @@ syn match Operator '|'
|
|||||||
syn match Operator '^'
|
syn match Operator '^'
|
||||||
syn match Operator '&'
|
syn match Operator '&'
|
||||||
|
|
||||||
|
|
||||||
syn match Number '0'
|
syn match Number '0'
|
||||||
syn match Number '[1-9][0-9]*'
|
syn match Number '[1-9][0-9]*'
|
||||||
syn match Number '0b[01]*'
|
syn match Number '0b[01]*'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user