Skip to content

Instantly share code, notes, and snippets.

@icebreaker icebreaker/fibo.asm
Last active Nov 14, 2015

Embed
What would you like to do?
A small "experimental" VM written in Ruby.
;
; Prints first N from the Fibonacci sequence.
;
read_n:
mov dx, 78
prc dx
mov dx, 58
prc dx
rdr dx
cmp dx, 0
je read_n
mov cx, 0
mov ax, 0
mov bx, 1
loop:
prr bx
push bx
add bx, ax
pop ax
add cx, 1
cmp cx, dx
jne loop
;
; Prints a NxM matrix of 'X's
;
read_x:
mov ax, 88
prc ax
mov ax, 58
prc ax
rdr ax
cmp ax, 0
je read_x
read_y:
mov bx, 89
prc bx
mov bx, 58
prc bx
rdr bx
cmp bx, 0
je read_y
mov cx, 0
mov dx, 0
draw_y:
push dx
draw_x:
mov dx, 88
prc dx
mov dx, 32
prc dx
add cx, 1
cmp cx, ax
jne draw_x
mov dx, 10
prc dx
xor cx, cx
pop dx
add dx, 1
cmp dx, bx
jne draw_y
push ax
mov ax, 10
prc ax
pop ax
#!/usr/bin/env ruby
class VM
REG_0 = 0x00
REG_1 = 0x01
REG_2 = 0x02
REG_3 = 0x03
REG_4 = 0x04
REG_N = 0x05
OP_NOP = 0x00
OP_PUSH = 0x01
OP_POP = 0x02
OP_LDR = 0x03
OP_MOV = 0x04
OP_ADD = 0x05
OP_SUB = 0x06
OP_CMP = 0x07
OP_JNE = 0x08
OP_JE = 0x09
OP_JMP = 0x10
OP_XOR = 0x11
OP_RDR = 0x12
OP_PRR = 0x13
OP_PRC = 0x14
OP_RDC = 0x15
attr_reader :registers
def initialize
@registers = [].fill(0x00, 0x00, REG_N)
@stack = []
end
def eval(bytecode)
i = 0
c = 0
l = bytecode.length - 3
while i <= l
case bytecode[i+0] # op
when OP_NOP # nop
# nop
when OP_PUSH # push r1
@stack.push(@registers[bytecode[i+1]])
when OP_POP # pop r1
@registers[bytecode[i+1]] = @stack.pop
when OP_LDR # ldr r1, 10
@registers[bytecode[i+1]] = bytecode[i+2]
when OP_MOV # mov r1, r2
@registers[bytecode[i+1]] = @registers[bytecode[i+2]]
when OP_ADD # add r1, r2
@registers[bytecode[i+1]] += @registers[bytecode[i+2]]
when OP_SUB # sub r1, r2
@registers[bytecode[i+1]] -= @registers[bytecode[i+2]]
when OP_CMP # cmp r1, r2
c = ((@registers[bytecode[i+1]] == @registers[bytecode[i+2]]) ? 1 : 0)
when OP_JNE # jne addr
i = bytecode[i+1] if c == 0
when OP_JE # je addr
i = bytecode[i+1] if c == 1
when OP_JMP # jmp addr
i = bytecode[i+1]
when OP_XOR # xor r1, r2
@registers[bytecode[i+1]] ^= @registers[bytecode[i+2]]
when OP_RDR # rdr r1
@registers[bytecode[i+1]] = STDIN.gets.chomp.to_i
when OP_PRR # prr r1
STDOUT.puts(@registers[bytecode[i+1]])
when OP_PRC # prc r1
STDOUT.putc(@registers[bytecode[i+1]])
when OP_RDC # rdc r1
@registers[bytecode[i+1]] = STDIN.getc.ord
else
raise ArgumentError, "Unsupported opcode: #{bytecode[i]}"
end
i += 3
end
end
end
class ASM
attr_reader :source, :bytecode
def initialize(source)
@source = source
@bytecode = []
compile!
end
private
REGS = {
'ax' => VM::REG_1,
'bx' => VM::REG_2,
'cx' => VM::REG_3,
'dx' => VM::REG_4
}
OPS = {
'nop' => VM::OP_NOP,
'push' => VM::OP_PUSH,
'pop' => VM::OP_POP,
'ldr' => VM::OP_LDR,
'mov' => VM::OP_MOV,
'add' => VM::OP_ADD,
'sub' => VM::OP_SUB,
'cmp' => VM::OP_CMP,
'jne' => VM::OP_JNE,
'je' => VM::OP_JE,
'jmp' => VM::OP_JMP,
'xor' => VM::OP_XOR,
'rdr' => VM::OP_RDR,
'prr' => VM::OP_PRR,
'prc' => VM::OP_PRC,
'rdc' => VM::OP_RDC
}
def compile!
labels = {}
@source.split("\n").each_with_index do |line, index|
line.strip!
next if line.length == 0 or line[0] == ';'
if line =~ /^(.*?)\s+(.*?)(\s*,\s*(.*?))?$/
op = OPS[$1.downcase]
raise ArgumentError, "Invalid operator: #{$1} on line #{index+1}" unless op
if $4
r1 = REGS[$2.downcase]
raise ArgumentError, "Invalid register: #{$2} on line #{index+1}" unless r1
if $4[1] == 'x'
r2 = REGS[$4.downcase]
raise ArgumentError, "Invalid register: #{$4} on line #{index+1}" unless r2
else
r2 = VM::REG_0
@bytecode += [VM::OP_LDR, r2, $4.to_i]
end
else
case op
when VM::OP_JNE, VM::OP_JE, VM::OP_JMP
r1 = labels[$2.downcase]
raise ArgumentError, "Invalid label: #{$2} on line #{index+1}" unless r1
else
r1 = REGS[$2.downcase]
raise ArgumentError, "Invalid register: #{$2} on line #{index+1}" unless r1
end
r2 = VM::OP_NOP
end
@bytecode += [op, r1, r2]
elsif line =~ /^(.*?):$/
labels[$1.strip] = @bytecode.length - 3
else
raise ArgumentError, "Invalid syntax: #{line} on line #{index + 1}"
end
end
end
end
if ARGV.size > 0
VM.new.eval(ASM.new(File.read(ARGV[0])).bytecode)
else
STDOUT.puts "usage: %s file.asm" % File.basename(__FILE__)
end
@texrg

This comment has been minimized.

Copy link

texrg commented Nov 14, 2015

This is interpreter.Is possible to create assembler?
convertassembler code to normal code for linux 32? http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html

creating working ELF binary from scratch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.