OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [scripts/] [gen-instructions] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
#!/usr/bin/env python
2
 
3
# Copyright Jamie Iles, 2017
4
#
5
# This file is part of s80x86.
6
#
7
# s80x86 is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# s80x86 is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with s80x86.  If not, see .
19
 
20
import os
21
import pprint
22
import pystache
23
import struct
24
import yaml
25
 
26
from py8086sim.Cpu import RTLCPU, GPR, Flag
27
 
28
HERE = os.path.dirname(__file__)
29
INSTR_TEMPLATE = os.path.join(HERE, '..', 'documentation', 'instructions.templ')
30
 
31
pystache.defaults.DELIMITERS = (u'<%', u'%>')
32
 
33
with open(os.path.join(HERE, '..', 'documentation', 'instructions.yaml')) as instr:
34
    instructions = yaml.load(instr)
35
 
36
def has_modrm(operands):
37
    return any(map(lambda x: x != 'ES' and x.startswith('E'), operands))
38
 
39
def has_immediate(operands):
40
    return any(map(lambda x: x.startswith('I'), operands))
41
 
42
def has_mem_only(operands):
43
    return any(map(lambda x: x.startswith('M'), operands))
44
 
45
def to_raw_reg(gpr):
46
    if gpr >= GPR.AL:
47
        return int(gpr) - int(GPR.AL)
48
    return int(gpr)
49
 
50
def modrm(reg, encoding, cpu, timing_operands, rm_reg=None):
51
    reg = int(encoding.get('reg', reg))
52
    operands = encoding.get('operands', [])
53
 
54
    if timing_operands:
55
        for i, o in enumerate(operands):
56
            if o.startswith('E') and rm_reg:
57
                cpu.write_reg(GPR.values[rm_reg], timing_operands[i])
58
            elif o.startswith('E') and not rm_reg:
59
                cpu.write_reg(GPR.BX, 0x100)
60
                if o.endswith('b'):
61
                    cpu.write_mem8(cpu.read_reg(GPR.DS), 0x100, timing_operands[i])
62
                elif o.endswith('w'):
63
                    cpu.write_mem16(cpu.read_reg(GPR.DS), 0x100, timing_operands[i])
64
                else:
65
                    cpu.write_mem32(cpu.read_reg(GPR.DS), 0x100, timing_operands[i])
66
            elif o.startswith('G'):
67
                cpu.write_reg(GPR.values[reg], timing_operands[i])
68
 
69
    if rm_reg:
70
        return (3 << 6) | (to_raw_reg(reg) << 3) | to_raw_reg(rm_reg)
71
 
72
    return to_raw_reg(reg) << 3 | 7
73
 
74
def immediate(operands, timing_operands):
75
    imm_bytes = []
76
    for i, o in enumerate(operands):
77
        if o[0] not in 'IJ':
78
            continue
79
 
80
        v = 0
81
        if timing_operands:
82
            v = int(timing_operands[i])
83
 
84
        if o.endswith('b'):
85
            struct_fmt = '
86
        elif o.endswith('w'):
87
            struct_fmt = '
88
        else:
89
            struct_fmt = '
90
 
91
        packed = struct.pack(struct_fmt, v)
92
        for b in packed:
93
            imm_bytes.append(ord(b))
94
    return imm_bytes
95
 
96
def describe_operands(operands, timing_operands, E='memory'):
97
    names = []
98
 
99
    for o in operands:
100
        name = ''
101
 
102
        if o in GPR.names:
103
            names.append(o)
104
            continue
105
 
106
        for c in o:
107
            if c == 'E':
108
                name += E
109
            elif c == 'G':
110
                name += 'register'
111
            elif c == 'M':
112
                name += 'memory'
113
            elif c == 'I':
114
                name += 'immediate'
115
            elif c == 'J':
116
                name += 'displacement'
117
            elif c == 'O':
118
                name += 'moffset'
119
            elif c == 'w':
120
                name += '16'
121
            elif c == 'b':
122
                name += '8'
123
            elif c == 'p':
124
                name += '(seg:offset)'
125
            else:
126
                raise ValueError("Invalid operand type %s %c" % (o,c ))
127
 
128
        names.append(name)
129
 
130
    if timing_operands:
131
        return names, '(ex: ' + ' '.join(['0x{0:x}'.format(t) for t in timing_operands]) + ')'
132
 
133
    return names, None
134
 
135
def encode(encoding, cpu):
136
    cpu.reset()
137
 
138
    instr = [encoding['opcode']]
139
    operands = encoding.get('operands', [])
140
 
141
    timing_operands = encoding.get('timing_operands', [None])
142
 
143
    for timing in timing_operands:
144
        immed = immediate(operands, timing)
145
        if 'operands' in encoding and has_mem_only(operands):
146
            yield describe_operands(operands, timing), instr + [modrm(GPR.AX, encoding, cpu, timing)] + immed
147
        elif 'operands' in encoding and has_modrm(operands):
148
            gpr = GPR.BL if 'Eb' in operands else GPR.BX
149
            yield describe_operands(operands, timing, E='register'), instr + [modrm(GPR.AX, encoding, cpu, timing, rm_reg=gpr)] + immed
150
            yield describe_operands(operands, timing, E='memory'), instr + [modrm(GPR.AX, encoding, cpu, timing)] + immed
151
        else:
152
            yield describe_operands(operands, timing), instr + immed
153
 
154
def count_cycles(cpu, instr, note=None, skip=False):
155
    if skip:
156
        return '-'
157
 
158
    cpu.write_vector8(cpu.read_reg(GPR.CS),
159
                        cpu.read_reg(GPR.IP), instr)
160
    cpu.write_reg(GPR.CS, cpu.read_reg(GPR.CS))
161
    cpu.idle(256)
162
 
163
    count = cpu.time_step()
164
    if not note:
165
        return count
166
 
167
    return '{0} {1}'.format(count, note)
168
 
169
def describe_modrm(encoding):
170
    if 'reg' in encoding:
171
        return ' /{0}'.format(encoding['reg'])
172
    elif has_modrm(encoding.get('operands', [])):
173
        return ' /r'
174
    return ''
175
 
176
def describe_immediates(encoding):
177
    return ' ' + ', '.join(filter(lambda x: x[0] == 'I', encoding.get('operands', [])))
178
 
179
def setup(cpu, params):
180
    flags = 0
181
 
182
    for key, val in params.items():
183
        if key in GPR.names:
184
            cpu.write_reg(GPR.names[key], int(val))
185
        elif key in Flag.names and int(val) != 0:
186
            flags |= Flag.names[key]
187
 
188
    cpu.write_flags(flags)
189
 
190
definitions = []
191
for mnemonic in sorted(instructions.keys()):
192
    definition = instructions[mnemonic]
193
    encodings = []
194
 
195
    for encoding in definition['encodings']:
196
        cpu = RTLCPU('instructions')
197
 
198
        for operand_description, instr in encode(encoding, cpu):
199
            opcode = '{0:02x}'.format(encoding['opcode'])
200
            opcode += describe_modrm(encoding)
201
            opcode += describe_immediates(encoding)
202
 
203
            size = len(instr)
204
            # Optional immediate added to form EA
205
            if has_modrm(encoding.get('operands', [])):
206
                size = '{0}-{1}'.format(size, size + 2)
207
 
208
            prefix = []
209
            if 'use_prefix' in encoding:
210
                prefix = [int(encoding['use_prefix'])]
211
            if 'taken' in encoding:
212
                setup(cpu, encoding['taken'])
213
                taken = count_cycles(cpu, instr, note=encoding.get('note', ''))
214
                setup(cpu, encoding['not_taken'])
215
                not_taken = count_cycles(cpu, instr, note=encoding.get('note', ''))
216
                cycles = '{0} (taken) / {1} (not taken)'.format(taken, not_taken)
217
            elif 'base' in encoding:
218
                setup(cpu, encoding['base'])
219
                base = count_cycles(cpu, prefix + instr, note=encoding.get('note', ''))
220
                setup(cpu, encoding['next'])
221
                n = count_cycles(cpu, prefix + instr, note=encoding.get('note', ''))
222
                cycles = '{0} + (n-1)*{1}'.format(base, n-base)
223
            else:
224
                cycles = count_cycles(cpu, instr,
225
                                      note=encoding.get('note', ''),
226
                                      skip=encoding.get('notime', False))
227
 
228
            desc = mnemonic + ' ' + ', '.join(operand_description[0])
229
            if operand_description[1]:
230
                desc += ' ' + operand_description[1]
231
            encodings.append({
232
                'opcode': opcode,
233
                'mnemonic': desc,
234
                'cycles': cycles,
235
                'size': size
236
            })
237
 
238
        # Verilator uses a singleton for some things, make sure to gc the
239
        # cpu before creating a new one
240
        cpu = None
241
 
242
    idef = {
243
        'mnemonic': mnemonic.upper(),
244
        'encodings': encodings,
245
        'flags': definition.get('flags', {}),
246
        'notes': [],
247
    }
248
 
249
    for note in definition.get('notes', []):
250
        idef['notes'].append({'note': note})
251
 
252
    definitions.append(idef)
253
 
254
with open(INSTR_TEMPLATE) as template:
255
    print pystache.render(template.read(), { 'instructions': definitions })

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.