Commit 28b33fa0 authored by Lyude Paul's avatar Lyude Paul

wip: Add the start of full clause encoding

You read that right! This adds a (apparently incorrect? I'm not sure
what I've gotten wrong on this quite yet, but there are a couple bits
off on all of the results) partially complete clause encoder that
handles accumulating quad words of instructions, along with packing the
first constant into those quadwords. Next step is encoding the quad
words that contain the rest of the constants
parent a435811e
......@@ -33,7 +33,7 @@ import pprint
try:
import bitstring
from bitstring import BitArray, Bits
from bitstring import BitArray, Bits, BitStream
except Exception:
print("The bitstring module for python3 is needed to run this!", file=stderr)
import sys
......@@ -991,6 +991,8 @@ class Uniform:
class Instruction:
BIT_LENGTH = 78
class ImmediateCountError(ParsingException):
def __init__(self, token):
if token.read_type == ImmediateToken.ReadType.FULL32:
......@@ -1092,6 +1094,10 @@ class Instruction:
def stages(self):
return (self.fma, self.add)
def encode(self):
return ( self.add.encode()
+ self.fma.encode()
+ self.reg_file.encode(self))
class Clause:
class ClauseType(IntEnum):
......@@ -1296,7 +1302,6 @@ class Clause:
back_to_back=self.back_to_back,
unk0=0 # TODO
))
# return bitstring.pack('bool, uint:4=0, bool, uint:4=0
@property
def data_reg(self):
......@@ -1382,6 +1387,9 @@ class Clause:
Begin/finish building an instruction based off the the given tokens
"""
if len(self.instructions) > 8:
raise ParsingException("Clauses can only contain up to 8 instructions")
inst = self.__pending_inst
for i, src in enumerate(srcs):
if isinstance(src, RegisterToken):
......@@ -1429,9 +1437,239 @@ class Clause:
if dst:
self.__pending_writes[stage] = dst
def end(self):
if self.__pending_inst:
raise ParsingException('Incomplete instruction')
del self.__pending_inst
# Register writes for the last instruction go into the first's register
# file
first_inst = self.instructions[0]
for stage, write in self.__pending_writes.items():
if write:
first_inst.writes[stage] = \
first_inst.reg_file.add_reg_write(write.idx, stage)
del self.__pending_writes
for inst in self.instructions:
inst.reg_file.assign_reg_ports()
if inst.has_pending_immediates():
pending_slot = inst.reg_file.const_port
# The only slots that should be left are half filled slots that
# couldn't reuse a pre-existing slot
assert pending_slot.bitlen == 32
pending_slot.add_immediate(
ImmediateToken(0, ImmediateToken.ReadType.FULL32))
slot = ImmediateSlot(pending_slot.contents,
len(self.immediate_slots))
inst.resolve_immediates(self, slot)
self.immediate_slots.append(slot)
# TODO: Make sure we return whether or not the last format we used
# contained an inline immediate
@staticmethod
def _next_immediate_to_encode(cls, immediates):
if immediates:
return immediates.pop(0)
else:
return Bits(64)
def _encode_quadwords(self, immediates):
instructions = [i.encode() for i in self.instructions]
encoded = BitStream()
# Format 1
quadword = BitArray(128)
i0 = instructions.pop(0)
if instructions:
tag = 0b00101
elif immediates:
tag = 0b00001
else:
tag = 0b01001
quadword[0:45] = self.encode_header()
quadword[45:120] = i0[3:78]
quadword[120:125] = tag
quadword[125:128] = i0[0:3]
encoded.append(quadword)
if not instructions:
return encoded
# Format 2
quadword = BitArray(128)
i1 = instructions.pop(0)
i2 = instructions.pop(0) if instructions else None
if i2:
tag = 0b00100
elif immediates:
tag = 0b00000
else:
tag = 0b01000
if i2:
quadword[0:45] = i2[33:78]
quadword[45:120] = i1[3:78]
quadword[120:125] = tag
quadword[125:128] = i1[0:3]
encoded.append(quadword)
if not i2:
return encoded
# Format 3
quadword = BitArray(128)
i3 = instructions.pop(0) if instructions else None
used_fmt_3_2 = False
if not i3:
# Format 3.1
next_immediate = self._next_immediate_to_encode(immediates)
if immediates:
tag = 0b00000100
else:
tag = 0b01000100
quadword[0:3] = i2[0:3]
quadword[15:45] = i2[3:33]
quadword[60:120] = next_immediate[0:60]
quadword[120:128] = tag
elif instructions:
# Format 3.2
used_fmt_3_2 = True
next_immediate = self._next_immediate_to_encode(immediates)
tag = 0b10
quadword[0:15] = next_immediate[45:60]
quadword[15:45] = i2[3:33]
quadword[45:120] = i3[3:78]
quadword[120:122] = tag
quadword[122:125] = i3[0:3]
quadword[125:128] = i2[0:3]
else:
# Format 3.3
if immediates:
tag = 0b00000101
else:
tag = 0b01000101
quadword[0:3] = i2[0:3]
quadword[3:6] = i3[0:3]
quadword[15:45] = i2[3:33]
quadword[45:120] = i3[3:78]
quadword[120:128] = tag
encoded.append(quadword)
if not instructions:
return encoded, packed_immediate
# Format 4
quadword = BitArray(128)
i4 = instructions.pop(0)
i5 = instructions.pop(0) if instructions else None
if used_fmt_3_2:
# Format 4.1
if immediates:
tag = 0b00010
else:
tag = 0b01010
quadword[0:45] = next_immediate[0:45]
quadword[45:120] = i4[3:78]
quadword[120:125] = tag
quadword[125:128] = i4[0:3]
else:
# Format 4.2
tag = 0b01100
quadword[0:45] = i5[33:78]
quadword[45:120] = i4[3:78]
quadword[120:125] = tag
quadword[125:128] = i4[0:3]
encoded.append(quadword)
if not i5:
return encoded
# Format 5
quadword = BitArray(128)
i6 = instructions.pop(0) if instructions else None
if not i6:
# Format 5.1
next_immediate = self._next_immediate_to_encode(immediates)
if immediates:
tag = 0b01000110
else:
tag = 0b00000110
quadword[0:3] = i5[0:5]
quadword[15:45] = i5[3:33]
quadword[60:120] = next_immediate[0:60]
quadword[120:128] = tag
elif not instructions:
# Format 5.2
if immediates:
tag = 0b00000111
else:
tag = 0b01000111
quadword[0:3] = i5[0:3]
quadword[3:6] = i6[0:3]
quadword[15:45] = i5[3:33]
quadword[60:120] = i6[3:78]
quadword[120:128] = tag
else:
# Format 5.3
next_immediate = self._next_immediate_to_encode(immediates)
tag = 0b11
quadword[0:15] = next_immediate[45:60]
quadword[15:45] = i5[3:33]
quadword[45:120] = i6[3:78]
quadword[120:122] = tag
quadword[122:125] = i6[0:3]
quadword[125:128] = i5[0:3]
encoded.append(quadword)
if not instructions:
return encoded
# Format 6
quadword = BitArray(128)
i7 = instructions.pop(0)
if immediates:
tag = 0b00011
else:
tag = 0b01011
quadword[0:45] = next_immediate[0:45]
quadword[45:120] = i7[3:78]
quadword[120:125] = tag
quadword[125:128] = i7[0:3]
encoded.append(quadword)
return encoded
def encode(self):
encoded = BitString()
immediates = [s.encode_contents() for s in self.immediate_slots]
# TODO: FINISH IT.
return self._encode_quadwords(immediates)
def dump(self):
print('Clause #%d' % self.idx)
print('\tEncoded clause:')
for quadword in self.encode().cut(128):
print('\t\t%s' % ' '.join(w.hex for w in quadword.cut(32)))
print('\tHeader:')
print(f'\t\tEncoded: {self.encode_header().uint:#x} {self.encode_header().bin}')
print('\t\tType: %s' % self.clause_type.name)
......@@ -1461,19 +1699,25 @@ class Clause:
print('\tInstructions:')
for i in self.instructions:
print('\t\t%s' % i)
print('\t\t\t0x%x' % i.reg_file.encode(i).uint)
for stage in i.stages:
if hasattr(stage, 'encode'):
encoded = stage.encode()
if hasattr(encoded, 'uint'):
encoded_str_tg = hex(encoded.uint)
else:
encoded_str_tg = encoded
else:
encoded_str_tg = encoded
reg_file = i.reg_file.encode(i)
fma = i.fma.encode()
fma_encoded = isinstance(fma, Bits)
add = i.add.encode()
add_encoded = isinstance(add, Bits)
print('\t\t\tEncoded register file: 0x%x' % reg_file.uint)
if fma_encoded:
print('\t\t\tEncoded fma: 0x%x' % fma.uint)
else:
print('\t\t\tfma: %s' % fma)
print("\t\t\t%s" % encoded_str_tg)
if add_encoded:
print('\t\t\tEncoded add: 0x%x' % add.uint)
else:
print('\t\t\tadd: %s' % add)
if fma_encoded and add_encoded:
print('\t\t\tEncoded instruction: 0x%x' % i.encode().uint)
if self.immediate_slots:
print('\tImmediate slots:')
......@@ -1495,37 +1739,6 @@ class Clause:
for write in self.__pending_writes:
print('\t\t%s' % write)
def end(self):
if self.__pending_inst:
raise ParsingException('Incomplete instruction')
del self.__pending_inst
# Register writes for the last instruction go into the first's register
# file
first_inst = self.instructions[0]
for stage, write in self.__pending_writes.items():
if write:
first_inst.writes[stage] = \
first_inst.reg_file.add_reg_write(write.idx, stage)
del self.__pending_writes
for inst in self.instructions:
inst.reg_file.assign_reg_ports()
if inst.has_pending_immediates():
pending_slot = inst.reg_file.const_port
# The only slots that should be left are half filled slots that
# couldn't reuse a pre-existing slot
assert pending_slot.bitlen == 32
pending_slot.add_immediate(
ImmediateToken(0, ImmediateToken.ReadType.FULL32))
slot = ImmediateSlot(pending_slot.contents,
len(self.immediate_slots))
inst.resolve_immediates(self, slot)
self.immediate_slots.append(slot)
def __repr__(self):
return '<Clause #%d @ %d>' % (self.idx, id(self))
......@@ -1718,6 +1931,7 @@ if __name__ == '__main__':
try:
unexpected_eof = False
first_clause_dumped = False
clauses = []
try:
for i, l in itr:
......@@ -1736,8 +1950,7 @@ if __name__ == '__main__':
if l == '}':
clause.end()
if clauses:
prev = clauses[-1]
prev.next_clause_type = clause.clause_type
clauses[-1].next_clause_type = clause.clause_type
clauses.append(clause)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment