cpu: Generalize how register files are serialized.

Instead of explicitly serializing each type of register explicitly, and
using custom types, etc, store them as generic blocks of data. This lets
us get rid of the final use of TheISA::VecRegContainer and
TheISA::VecPredRegContainer.

Change-Id: I61dbd7825ffe35c41e1b7c8317590d06c21b4513
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/50252
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Gabe Black <gabe.black@gmail.com>
This commit is contained in:
Gabe Black
2021-09-11 00:20:41 -07:00
parent 32a206a2d0
commit 3d7d426fa5
3 changed files with 111 additions and 66 deletions

View File

@@ -92,7 +92,7 @@ board.set_se_binary_workload(
# Getting the pre-taken checkpoint from gem5-resources. This checkpoint
# was taken from running this gem5 configuration script,
# configs/example/gem5_library/checkpoints/riscv-hello-save-checkpoint.py
checkpoint_resource = Resource("riscv-hello-example-checkpoint")
checkpoint_resource = Resource("riscv-hello-example-checkpoint-v22-1")
# Now we restore the checkpoint by passing the path to the checkpoint to
# the Simulator object. The checkpoint_path could be a string containing

View File

@@ -210,43 +210,24 @@ ThreadContext::setRegFlat(const RegId &reg, RegVal val)
void
serialize(const ThreadContext &tc, CheckpointOut &cp)
{
// Cast away the const so we can get the non-const ISA ptr, which we then
// use to get the const register classes.
auto &nc_tc = const_cast<ThreadContext &>(tc);
const auto &regClasses = nc_tc.getIsaPtr()->regClasses();
for (const auto *reg_class: tc.getIsaPtr()->regClasses()) {
// MiscRegs are serialized elsewhere.
if (reg_class->type() == MiscRegClass)
continue;
const size_t numFloats = regClasses.at(FloatRegClass)->numRegs();
RegVal floatRegs[numFloats];
for (auto &id: *regClasses.at(FloatRegClass))
floatRegs[id.index()] = tc.getRegFlat(id);
// This is a bit ugly, but needed to maintain backwards
// compatibility.
arrayParamOut(cp, "floatRegs.i", floatRegs, numFloats);
const size_t reg_bytes = reg_class->regBytes();
const size_t reg_count = reg_class->numRegs();
const size_t array_bytes = reg_bytes * reg_count;
const size_t numVecs = regClasses.at(VecRegClass)->numRegs();
std::vector<TheISA::VecRegContainer> vecRegs(numVecs);
for (auto &id: *regClasses.at(VecRegClass))
tc.getRegFlat(id, &vecRegs[id.index()]);
SERIALIZE_CONTAINER(vecRegs);
uint8_t regs[array_bytes];
auto *reg_ptr = regs;
for (const auto &id: *reg_class) {
tc.getRegFlat(id, reg_ptr);
reg_ptr += reg_bytes;
}
const size_t numPreds = regClasses.at(VecPredRegClass)->numRegs();
std::vector<TheISA::VecPredRegContainer> vecPredRegs(numPreds);
for (auto &id: *regClasses.at(VecPredRegClass))
tc.getRegFlat(id, &vecPredRegs[id.index()]);
SERIALIZE_CONTAINER(vecPredRegs);
const size_t numInts = regClasses.at(IntRegClass)->numRegs();
RegVal intRegs[numInts];
for (auto &id: *regClasses.at(IntRegClass))
intRegs[id.index()] = tc.getRegFlat(id);
SERIALIZE_ARRAY(intRegs, numInts);
const size_t numCcs = regClasses.at(CCRegClass)->numRegs();
if (numCcs) {
RegVal ccRegs[numCcs];
for (auto &id: *regClasses.at(CCRegClass))
ccRegs[id.index()] = tc.getRegFlat(id);
SERIALIZE_ARRAY(ccRegs, numCcs);
arrayParamOut(cp, std::string("regs.") + reg_class->name(), regs,
array_bytes);
}
tc.pcState().serialize(cp);
@@ -257,40 +238,24 @@ serialize(const ThreadContext &tc, CheckpointOut &cp)
void
unserialize(ThreadContext &tc, CheckpointIn &cp)
{
const auto &regClasses = tc.getIsaPtr()->regClasses();
for (const auto *reg_class: tc.getIsaPtr()->regClasses()) {
// MiscRegs are serialized elsewhere.
if (reg_class->type() == MiscRegClass)
continue;
const size_t numFloats = regClasses.at(FloatRegClass)->numRegs();
RegVal floatRegs[numFloats];
// This is a bit ugly, but needed to maintain backwards
// compatibility.
arrayParamIn(cp, "floatRegs.i", floatRegs, numFloats);
for (auto &id: *regClasses.at(FloatRegClass))
tc.setRegFlat(id, floatRegs[id.index()]);
const size_t reg_bytes = reg_class->regBytes();
const size_t reg_count = reg_class->numRegs();
const size_t array_bytes = reg_bytes * reg_count;
const size_t numVecs = regClasses.at(VecRegClass)->numRegs();
std::vector<TheISA::VecRegContainer> vecRegs(numVecs);
UNSERIALIZE_CONTAINER(vecRegs);
for (auto &id: *regClasses.at(VecRegClass))
tc.setRegFlat(id, &vecRegs[id.index()]);
uint8_t regs[array_bytes];
arrayParamIn(cp, std::string("regs.") + reg_class->name(), regs,
array_bytes);
const size_t numPreds = regClasses.at(VecPredRegClass)->numRegs();
std::vector<TheISA::VecPredRegContainer> vecPredRegs(numPreds);
UNSERIALIZE_CONTAINER(vecPredRegs);
for (auto &id: *regClasses.at(VecPredRegClass))
tc.setRegFlat(id, &vecPredRegs[id.index()]);
const size_t numInts = regClasses.at(IntRegClass)->numRegs();
RegVal intRegs[numInts];
UNSERIALIZE_ARRAY(intRegs, numInts);
for (auto &id: *regClasses.at(IntRegClass))
tc.setRegFlat(id, intRegs[id.index()]);
const size_t numCcs = regClasses.at(CCRegClass)->numRegs();
if (numCcs) {
RegVal ccRegs[numCcs];
UNSERIALIZE_ARRAY(ccRegs, numCcs);
for (auto &id: *regClasses.at(CCRegClass))
tc.setRegFlat(id, ccRegs[id.index()]);
auto *reg_ptr = regs;
for (const auto &id: *reg_class) {
tc.setRegFlat(id, reg_ptr);
reg_ptr += reg_bytes;
}
}
std::unique_ptr<PCStateBase> pc_state(tc.pcState().clone());

View File

@@ -0,0 +1,80 @@
# Rename register files to their new systematic names.
def upgrader(cpt):
is_arm = cpt.get('root', 'isa', fallback='') == 'arm'
import re
is_cpu = lambda sec: 'intRegs' in cpt[sec]
cpu_sections = filter(is_cpu, cpt.sections())
for sec in cpu_sections:
items = cpt[sec]
# Almost all registers are 64 bits, except vectors and predicate
# vectors in ARM.
regval_bits = 64
arm_vec_bits = 2048
byte_bits = 8
byte_mask = (0x1 << byte_bits) - 1
# If there's vecRegs, create regs.vector_element from it.
vec_regs = items.get('vecRegs')
if vec_regs is not None:
reg_vals = vec_regs.split()
if is_arm:
full_bits = arm_vec_bits
else:
full_bits = regval_bits
reg_vals = ['0']
elem_bits = 32
elem_mask = (0x1 << elem_bits) - 1
bytes = []
for full in reg_vals:
full = int(full)
for idx in range(full_bits // elem_bits):
# Extract one element.
elem = full & elem_mask
full = full >> elem_bits
# Treat the element as a RegVal value, even if it's
# fewer bits in the vector registers.
for chunk in range(regval_bits // byte_bits):
bytes.append(f'{elem & byte_mask}')
elem = elem >> byte_bits
items['regs.vector_element'] = ' '.join(bytes)
name_map = {
'floatRegs.i': 'regs.floating_point',
'vecRegs': 'regs.vector',
'vecPredRegs': 'regs.vector_predicate',
'intRegs': 'regs.integer',
'ccRegs': 'regs.condition_code',
}
for old, new in name_map.items():
if old in items:
if is_arm and old in ('vecRegs', 'vecPredRegs'):
reg_bits = 2048
else:
reg_bits = regval_bits
reg_vals = items[old].split()
if not is_arm and old in ('vecRegs', 'vecPredRegs'):
reg_vals = ['0']
bytes = []
for reg in reg_vals:
reg = int(reg)
for chunk in range(reg_bits // byte_bits):
bytes.append(f'{reg & byte_mask}')
reg = reg >> byte_bits
items[new] = ' '.join(bytes)
del items[old]
items.setdefault('regs.condition_code', '')
legacy_version = 16