summaryrefslogtreecommitdiff
path: root/parse-opcodes
blob: a2302d4ef1c08fe25d2d8a4e9324741d9fb01865 (plain)
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/python

import math
import sys
import tokenize

match = {}
mask = {}

args = {}
args['ra'] = (24,20)
args['rb'] = (19,15)
args['rc'] = (4,0)
args['rd'] = (9,5)
args['imm27'] = (26,0)
args['imm20'] = (19,0)
args['imm'] = (11,0)
args['shamt'] = (10,5)
args['shamtw'] = (9,5)

def binary(n, digits=0):
	rep = bin(n)[2:]
	return rep if digits == 0 else ('0' * (digits - len(rep))) + rep

def make_disasm_table(match,mask):
	print '/* Automatically generated by parse-opcodes */'
	for name,match in match.iteritems():
		name2 = name.upper().replace('.','_')
		print '#define MATCH_%s %s' % (name2, hex(match))
		print '#define  MASK_%s %s' % (name2, hex(mask[name]))

def make_switch(match,mask):
	opcode_base = 25
	opcode_size = 7
	funct_base = 12
	funct_size = 3

	opcode_mask = ((1<<(opcode_base+opcode_size))-(1<<opcode_base))
	funct_mask = ((1<<(funct_base+funct_size))-(1<<funct_base))

	print '/* Automatically generated by parse-opcodes */'
	print 'switch((insn.bits >> 0x%x) & 0x%x)' % (opcode_base,(1<<opcode_size)-1)
	print '{'

	for opc in range(0,1<<opcode_size):
		has_some_instruction = 0
		for name in match.iterkeys():
			if ((opc << opcode_base) & mask[name]) == (match[name] & mask[name] & opcode_mask):
				has_some_instruction = 1
		if not has_some_instruction: continue

		print '  case 0x%x:' % opc
		print '  {'
		done = 0
		for name in match.iterkeys():
			name2 = name.replace('.','_')
			# case 0: opcode fully describes insn
			if ((opc << opcode_base) & mask[name]) == match[name] and (opcode_mask & mask[name]) == mask[name]:
				print '    #include "insns/%s.h"' % name2
				done = 1
				break

		if not done:
			print '    switch((insn.bits >> 0x%x) & 0x%x)' % (funct_base,(1<<funct_size)-1)
			print '    {'
			for funct in range(0,1<<funct_size):
				has_some_instruction = 0
				for name in match.iterkeys():
					if (opc << opcode_base | funct << funct_base) == (match[name] & (opcode_mask | funct_mask)):
						has_some_instruction = 1
				if not has_some_instruction: continue
				print '      case 0x%x:' % funct
				print '      {'
				done = 0
				for name in match.iterkeys():
					name2 = name.replace('.','_')
					# case 1: opcode + funct code completely describe insn
					if ((opc << opcode_base | funct << funct_base) & mask[name]) == match[name] and ((opcode_mask | funct_mask) & mask[name]) == mask[name]:
						print '        #include "insns/%s.h"' % name2
						print '        break;'
						done = 1
						break
				if not done:
					for name in match.iterkeys():
						name2 = name.replace('.','_')
						# case 2: general case: opcode + funct incompletely describe insn
						if (opc << opcode_base | funct << funct_base) == (match[name] & (opcode_mask | funct_mask)):
							print '        if((insn.bits & 0x%x) == 0x%x)' % (mask[name],match[name])
							print '        {'
							print '          #include "insns/%s.h"' % name2
							print '          break;'
							print '        }'
					print '        #include "insns/unimp.h"'
				print '      }'
			print '      default:'
			print '      {'
			print '        #include "insns/unimp.h"'
			print '      }'
			print '    }'
		print '    break;'
		print '  }'
	print '  default:'
	print '  {'
	print '    #include "insns/unimp.h"'
	print '  }'
	print '}'

for line in sys.stdin:
	line = line.partition('#')
	tokens = line[0].split()
	
	if len(tokens) == 0:
		continue
	assert len(tokens) >= 2

	name = tokens[0]
	mymatch = 0
	mymask = 0
	cover = 0

	for token in tokens[1:len(tokens)]:
		if len(token.split('=')) == 2:
			tmp = token.split('=')
			val = int(tmp[1],0)
			if len(tmp[0].split('..')) == 2:
				tmp = tmp[0].split('..')
				hi = int(tmp[0])
				lo = int(tmp[1])
				if hi <= lo:
					sys.exit("%s: bad range %d..%d" % (name,hi,lo))
			else:
				hi = lo = int(tmp[0])
			if val >= (1 << (hi-lo+1)):
				sys.exit("%s: bad value %d for range %d..%d" % (name,val,hi,lo))
			mymatch = mymatch | (val << lo)
			mymask = mymask | ((1<<(hi+1))-(1<<lo))
			if cover & ((1<<(hi+1))-(1<<lo)):
				sys.exit("%s: overspecified" % name)
			cover = cover | ((1<<(hi+1))-(1<<lo))
		elif token in args:
			if cover & ((1<<(args[token][0]+1))-(1<<args[token][1])):
				sys.exit("%s: overspecified" % name)
			cover = cover | ((1<<(args[token][0]+1))-(1<<args[token][1]))
		else:
			sys.exit("%s: unknown token %s" % (name,token));
	
	if cover != 0xFFFFFFFF:
		sys.exit("%s: not all bits are covered" % name)

	for name2,match2 in match.iteritems():
		if (match2 & mymask) == mymatch:
			sys.exit("%s and %s overlap" % (name,name2));

	mask[name] = mymask;
	match[name] = mymatch;

if sys.argv[1] == '-tex':
	make_latex_table(opcodes, ['Instructions encoded by opcode field','Instructions encoded by funct field when opcode = %(opcode)d'], ['opcodes','opcode%(opcode)d'])
elif sys.argv[1] == '-disasm':
	make_disasm_table(match,mask)
elif sys.argv[1] == '-switch':
	make_switch(match,mask)
else:
	assert 0