Skip to content

Commit 7b235ce

Browse files
committed
Added PUTS instruction
1 parent 349a0c2 commit 7b235ce

4 files changed

Lines changed: 59 additions & 33 deletions

File tree

spec/machine_spec.cr

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,23 @@ describe StackVM::Machine do
189189
machine.stack_read_value(Float32).should eq 50
190190
end
191191

192+
it "runs PUTS" do
193+
io = IO::Memory.new
194+
195+
machine = Machine.new(64, output: io)
196+
machine.flash Assembler::Utils.convert_opcodes EXE{
197+
LOADI, BYTE, 0_u8,
198+
LOADI, BYTE, 1_u8,
199+
LOADI, BYTE, 2_u8,
200+
LOADI, BYTE, 3_u8,
201+
PUTS, DWORD,
202+
HALT
203+
}
204+
machine.start
205+
206+
io.to_s.should eq "Bytes[0, 1, 2, 3]\n"
207+
end
208+
192209
end
193210

194211
end

src/stackvm.cr

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,12 @@ module StackVM
1111

1212
# Compile the above program to bytes
1313
binary = Assembler::Utils.convert_opcodes EXE{
14+
LOADI, BYTE, 0_u8,
15+
LOADI, BYTE, 1_u8,
16+
LOADI, BYTE, 2_u8,
17+
LOADI, BYTE, 3_u8,
1418

15-
# 64 bit signed int
16-
LOADI, QWORD, 25_u64,
17-
LOADI, QWORD, 25_u64,
18-
ADD | M_B,
19-
20-
# 32 bit signed int
21-
LOADI, DWORD, 25_u32,
22-
LOADI, DWORD, 25_u32,
23-
ADD,
24-
25-
# 64 bit unsigned int
26-
LOADI, QWORD, 25_u64,
27-
LOADI, QWORD, 25_u64,
28-
ADD | M_B | M_S,
29-
30-
# 32 bit unsigned int
31-
LOADI, DWORD, -1.to_u32,
32-
LOADI, DWORD, 25_u32,
33-
ADD | M_S,
34-
35-
# 64 bit float
36-
LOADI, QWORD, 25_f64,
37-
LOADI, QWORD, 25_f64,
38-
ADD | M_B | M_T,
39-
40-
# 32 bit float
41-
LOADI, DWORD, 25_f32,
42-
LOADI, DWORD, 25_f32,
43-
ADD | M_T,
19+
PUTS, DWORD,
4420

4521
HALT
4622
}

src/stackvm/machine/debugger.cr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ module StackVM::Machine::Utils
5050
rescue e : Exception
5151
@output.puts "An exception happened:"
5252
@output.puts e
53+
@output.puts e.backtrace.join "\n"
5354
end
5455
end
5556
end

src/stackvm/machine/machine.cr

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ module StackVM::Machine
1212
property instruction : Instruction
1313
property executable_size : UInt64
1414

15-
def initialize(memory_size = DEFAULT_MEMORY_SIZE)
15+
property input : IO
16+
property output : IO
17+
property error : IO
18+
19+
def initialize(memory_size = DEFAULT_MEMORY_SIZE, @input = STDIN, @output = STDOUT, @error = STDERR)
1620
@regs = Slice(UInt64).new(20, 0_u64)
1721
@memory = Slice(UInt8).new(memory_size, 0_u8)
1822
@instruction = Instruction.new 0b00000000_00110000_u16
@@ -123,6 +127,10 @@ module StackVM::Machine
123127
return op_exp
124128
when OP::LOADI
125129
return op_loadi
130+
when OP::NOP
131+
return false
132+
when OP::PUTS
133+
return op_puts
126134
when OP::HALT
127135
return op_halt
128136
else
@@ -256,6 +264,11 @@ module StackVM::Machine
256264
value
257265
end
258266

267+
# Reads *amount* of bytes from the stack
268+
def stack_read_bytes(amount)
269+
memory_read @regs[Reg::SP] - amount, amount
270+
end
271+
259272
# Pops a *type* value from the stack
260273
def stack_read_value(type : Number.class)
261274
memory_read_value @regs[Reg::SP] - sizeof(typeof(type)), type
@@ -505,16 +518,35 @@ module StackVM::Machine
505518

506519
# Decodes the amount of bytes that are being pushed
507520
type = memory_read(@regs[Reg::IP] + 2, 2)
508-
type = Pointer(UInt32).new type.to_unsafe.address
509-
amount_of_bytes = type[0]
521+
amount_of_bytes = IO::ByteFormat::LittleEndian.decode UInt16, type
510522

511-
# Reads *type* bytes
523+
# Reads *amount_of_bytes* bytes
512524
value = memory_read(@regs[Reg::IP] + 6, amount_of_bytes)
513525
stack_push value
514526

515527
return false
516528
end
517529

530+
# Executes a PUTS instruction
531+
#
532+
# ```
533+
# LOADI BYTE 25
534+
# LOADI BYTE 50
535+
# PUTS WORD # => prints [25, 50]
536+
# ```
537+
def op_puts
538+
539+
# Decodes the amount of bytes that are being read
540+
type = memory_read(@regs[Reg::IP] + 2, 2)
541+
amount_of_bytes = IO::ByteFormat::LittleEndian.decode UInt16, type
542+
543+
# Reads *amount_of_bytes* bytes
544+
value = stack_read_bytes amount_of_bytes
545+
@output.puts value
546+
547+
return false
548+
end
549+
518550
# Executes a HALT instruction
519551
#
520552
# ```

0 commit comments

Comments
 (0)