summaryrefslogtreecommitdiff
path: root/asm.rb
blob: 80bbd67172fe7f60f0cd2511330fce9de8f28c80 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/usr/bin/ruby -w

OPCODES = {
  "acc="  => 0x000,
  "load"  => 0x100,
  "store" => 0x200,
  "ifeq"  => 0x300,
  "jmp"   => 0x400,
  "++acc" => 0xf01,
  "--acc" => 0xf02,
  "++idx" => 0xf04,
  "--idx" => 0xf08,
  "swap"  => 0xf10,
  "idx"   => 0xf20,
  "tx"    => 0xf40,
  "halt"  => 0xf80,
  }

Line = Struct.new(:opcode, :refs, :code)

$labels = {}
$code = []
ARGF.each_line() do | line |
  line.chomp!()
  line.sub!(/^.*\/\/\s*/, "")
  next unless line =~ /\S/
  op = 0x000
  refs = []
  line.scan(/\S+/).each() do | word |
    if word =~ /^0(\d+)$/
      op |= $1.to_i(8)
    elsif word =~ /^-0(\d+)$/
      op |= 0x100 - $1.to_i(8)
    elsif word =~ /^(\d+)$/
      op |= $1.to_i(10)
    elsif word =~ /^-(\d+)$/
      op |= 0x100 - $1.to_i(10)
    elsif word =~ /^0x([0-9a-f]+)$/i
      op |= $1.to_i(16)
    elsif word =~ /^-0x([0-9a-f]+)$/i
      op |= 0x100 - $1.to_i(16)
    elsif OPCODES.key?(word)
      op |= OPCODES[word]
    elsif word =~ /^(.+):$/
      $labels[$1] = $code.size()
    else
      refs << word
    end
  end
  $code << Line.new(op, refs, line)
end

$code.each_with_index() do | line, i |
  op = line.opcode
  line.refs.each() do | ref |
    if $labels.key?(ref)
      target = $labels[ref] - (i + 1)
      target += 0x100 if target < 0
      op |= target
    else
      throw "I don't understand #{ref.inspect()}"
    end
  end
  $stdout.write("#{op.to_s(16).rjust(3, "0")} // #{line.code}\n")
end