-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathrbgen.rb
More file actions
147 lines (118 loc) · 3.64 KB
/
rbgen.rb
File metadata and controls
147 lines (118 loc) · 3.64 KB
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# This file contains the ruby code generator for mipsgen.
#
# See scripts/mipsgen.rb for the caller of this code.
# See disasm/js/mipsdis.js for the disassembler that hosts the generated code.
# See docs/rbgen.md for more info.
# The argument list for calling ruby decode_xxx functions.
$rbargs = "pc, op";
def rb_generate_comment_header
puts <<HERE
# This file contains autogenerated routines for dispatching and disassembling
# MIPS opcodes.
#
# The code has been generated by mipsgen.
#
# See scripts/mipsgen.rb for the code generator framework.
# See codegen/rbgen.rb for ruby specific information.
HERE
end
# Builds the format string used by snprintf in the generated decoder function.
# The metadata for this is in tables/asm_format.txt and tables/field_format.txt.
def rb_build_format_string(mne, tokens, field_format)
fmt_a = []
tokens.each{|t|
if (field_format.include?(t))
fmt_a << field_format[t][0]
else
fmt_a << t
end
}
fmt_s = mne
if (!fmt_a.empty?)
fmt_s += ' ' + fmt_a.join
end
return '"' + fmt_s + '"'
end
# Builds the arguments for the format string built by rb_build_format_string.
def rb_build_args(mne, tokens, field_format)
args_a = []
tokens.each{|t|
if (field_format.include?(t))
pc = field_format[t][1]
field_args = pc ? "pc,op" : "op"
args_a << "get#{t}(#{field_args})"
end
}
return args_a
end
# Builds the error checks required for a decoder.
# Every opcode has its bitmask checked against a comparison value.
# Some opcodes (cl, jalr) require extra checking.
# The metadata for this is in tables/opcode_bits.txt
def rb_build_error_checks(mne, bitmasks)
mask = bitmasks[mne]['mask']
value = bitmasks[mne]['value']
has_reserved = bitmasks[mne]['reserved']
checks = []
if (has_reserved)
checks << "check_opcode(op, #{mask}, #{value})"
end
if (mne =~ /^cl/)
checks << 'check_cl(getrt(op), getrd(op))'
end
if (mne =~ /^jalr/)
checks << "check_jalr(getrs(op), getrd(op))"
end
return checks
end
# Emits the generated decoder to stdout.
def rb_emit_decoder(mne, checks, fmt, args)
spargs = [fmt] + args
puts "def decode_#{mne}(#{$rbargs})"
if (!checks.empty?)
puts " if (!(#{checks.join("&&")}))"
puts " return 'illegal'"
puts " end"
puts ""
end
puts " return sprintf(#{spargs.join(',')})"
puts "end"
puts ""
end
# Generates all decoders.
def rb_generate_decoders(asm_format, field_format, bitmasks)
asm_format.each{|k,toks|
fmt = rb_build_format_string(k, toks, field_format)
args = rb_build_args(k, toks, field_format)
checks = rb_build_error_checks(k, bitmasks)
rb_emit_decoder(k, checks, fmt, args)
}
end
# Generates a dispatch function.
def rb_gen_switch(name, field, groups)
puts "def decode_#{name}(#{$rbargs})"
puts " case (get#{field}(op))"
groups.each{|grp,vals|
puts " when #{vals.join(',')}"
puts " return decode_#{grp}(#{$rbargs});"
}
puts " end"
puts "end"
puts ""
end
# Generates all dispatch functions.
def rb_generate_switches(tables)
tables.each{|k, v|
rb_gen_switch(k, v['field'], v['groups'])
}
end
# Entry point for ruby code generation.
def rb_generate(gen_info)
asm_format = gen_info['asm_format']
field_format = gen_info['field_format']
bitmasks = gen_info['bitmasks']
tables = gen_info['dispatch_tables']
rb_generate_comment_header()
rb_generate_decoders(asm_format, field_format, bitmasks)
rb_generate_switches(tables)
end