[Assembler] Allow the provision of a symbol resolution modifier functor
Currently just required in the special case of AUIPC symbol vs immediate
handling but might come handy later...
MODIFY
src/assembler/instruction.h
src/assembler/instruction.h
@@ -155,10 +155,17 @@ struct Imm : public Field {
* @param tokenIndex: Index within a list of decoded instruction tokens that corresponds to the immediate
* @param ranges: (ordered) list of ranges corresponding to fields of the immediate
* @param symbolType: Set if this immediate refers to a relative or absolute symbol.
+ * @param _symbolTransformer: Optional function used to process the immediate provided by a symbol value, before the
+ * immediate value is applied.
*/
Imm(unsigned _tokenIndex, unsigned _width, Repr _repr, const std::vector<ImmPart>& _parts,
- SymbolType _symbolType = SymbolType::None)
- : tokenIndex(_tokenIndex), parts(_parts), width(_width), repr(_repr), symbolType(_symbolType) {}
+ SymbolType _symbolType = SymbolType::None, const std::function<uint32_t(uint32_t)>& _symbolTransformer = {})
+ : tokenIndex(_tokenIndex),
+ parts(_parts),
+ width(_width),
+ repr(_repr),
+ symbolType(_symbolType),
+ symbolTransformer(_symbolTransformer) {}
std::optional<AssemblerTmp::Error> apply(const AssemblerTmp::TokenizedSrcLine& line, uint32_t& instruction,
FieldLinkRequest& linksWithSymbol) const override {
@@ -205,6 +212,10 @@ struct Imm : public Field {
adjustedValue -= address;
}
+ if (symbolTransformer) {
+ adjustedValue = symbolTransformer(adjustedValue);
+ }
+
for (const auto& part : parts) {
part.apply(adjustedValue, instruction);
}
@@ -242,6 +253,7 @@ struct Imm : public Field {
const unsigned width;
const Repr repr;
const SymbolType symbolType;
+ const std::function<uint32_t(uint32_t)> symbolTransformer;
};
template <typename ISA>

MODIFY
src/assembler/rv32i_assembler.cpp
src/assembler/rv32i_assembler.cpp
@@ -329,7 +329,20 @@ void RV32I_Assembler::enableExtI(RVInstrVec& instructions, RVPseudoInstrVec& pse
std::shared_ptr<RVInstr>(new RVInstr(Opcode("ecall", {OpPart(0b1110011, 0, 6), OpPart(0, 7, 31)}), {})));
instructions.push_back(UType("lui", 0b0110111));
- instructions.push_back(UType("auipc", 0b0010111));
+
+ /** @brief AUIPC requires special handling during symbol resolution as compared to if no symbol is provided to
+ * instruction.
+ * - If no symbol; the provided immediate will be placed in the upper 20 bits of the instruction
+ * - if symbol; the upper 20 bits of the provided resolved symbol will be placed in the upper 20 bits of the
+ * instruction. To facilitate these two capabilities, we provide a symbol modifier functor to adjust any provided
+ * symbol.
+ */
+ auto auipcSymbolModifier = [](uint32_t bareSymbol) { return bareSymbol >> 12; };
+ instructions.push_back(std::shared_ptr<RVInstr>(
+ new RVInstr(Opcode("auipc", {OpPart(0b0010111, 0, 6)}),
+ {std::make_shared<RVReg>(1, 7, 11),
+ std::make_shared<Imm>(2, 32, Imm::Repr::Hex, std::vector{ImmPart(0, 12, 31)},
+ Imm::SymbolType::Absolute, auipcSymbolModifier)})));
instructions.push_back(JType("jal", 0b1101111));

[Assembler] Allow the provision of a symbol resolution modifier functor

Currently just required in the special case of AUIPC symbol vs immediate
handling but might come handy later...