P4C
The P4 Compiler
|
#include <instruction_memory.h>
Classes | |
struct | Use |
Public Member Functions | |
bool | alloc_always_run_instr (const IR::MAU::Table *tbl, Use &alloc, bitvec current_bv) |
bool | allocate_imem (const IR::MAU::Table *tbl, Use &alloc, PhvInfo &phv, bool gw_linked, ActionData::FormatType_t format_type, SplitAttachedInfo &sai) |
bool | find_row_and_color (bitvec current_bv, gress_t gress, int &row, int &color, bool &first_noop, bool has_unalloc_temp=false) |
const BFN::Alloc2Dbase< bitvec > & | imem_slot_inuse (gress_t gress) const |
virtual BFN::Alloc2Dbase< bitvec > & | imem_slot_inuse (gress_t gress)=0 |
const BFN::Alloc2Dbase< cstring > & | imem_use (gress_t gress) const |
virtual BFN::Alloc2Dbase< cstring > & | imem_use (gress_t gress)=0 |
bool | is_noop_slot (int row, int color) |
bool | shared_instr (const IR::MAU::Table *tbl, Use &alloc, bool gw_linked) |
void | update (const IR::MAU::Table *tbl) |
void | update (cstring name, const TableResourceAlloc *alloc, const IR::MAU::Table *tbl) |
void | update (cstring name, const TableResourceAlloc *alloc, gress_t gress) |
void | update (cstring name, const Use &alloc, gress_t gress) |
void | update_always_run (const Use &alloc, gress_t gress) |
Static Public Member Functions | |
static InstructionMemory * | create () |
Public Attributes | |
std::set< cstring > | atcam_updates |
std::map< const IR::MAU::ActionData *, const Use * > | shared_action_profiles |
const IMemSpec & | spec |
Static Public Attributes | |
static constexpr int | NOOP_COLOR = 0 |
static constexpr int | NOOP_ROW = 0 |
Protected Member Functions | |
InstructionMemory (const IMemSpec &s) | |
InstructionMemory (const InstructionMemory &)=delete | |
InstructionMemory & | operator= (const InstructionMemory &)=delete |
Algorithms for the allocation of the Instruction Memory. The Instruction Memory is defined in the uArch section 6.1.10.3 Action Instruction Memory.
The instruction memory is a 32 row x (PHV ALUs) per gress memory. Each action in P4 corresponds to a single RAM row in the IMEM. Each slot of a row corresponds to the instruction for that particular ALU. A noop instruction for an ALU is an all 0 encoded instruction. Thus an action in the P4 code coordinates to a single line in the instruction memory. For all PHVs that a particular action writes, the slots on that row will have the corresponding action, and for all PHVs that the particular action doesn't write, a noop, encoded as all 0s will let the PHV pass directly through. These instructions are called VLIW instructions, as one RAM line coordinates to hundreds of individual ALU instructions.
When a stage decides which actions to run, the RAM lines containing these actions are all ORed together to make a single instruction to be run by the ALUs. This is the root of action dependency. If two actions in the same packet operate on the same ALU, then their corresponding instruction opcodes will be ORed together, causing the instruction to be garbled and incorrect. (N.B. There is a possibility of removing action dependencies, if it is known that this ORing won't have any semantic change to the instruction)
Each instruction memory line has two colors. Two actions can be stored per RAM line as the actions on that RAM line can have a different color. This will only work if the intersection of the PHV writes for these actions are an empty set, as each individual ALU instruction can be marked a certain color.
Furthermore, actions can be shared across multiple tables, as long as the action opcodes are identical. The main corner case for this is a noop action, which usually appears in several tables. In both gresses, currently, the algorithm always reserves the first imem slot with the 0 color to be noop. Gateways that inhibit can potentially run an action as well, if the pfe for the imem is always defaulted on. Thus when the payload is all 0s, the instruction just runs a noop
bool InstructionMemory::shared_instr | ( | const IR::MAU::Table * | tbl, |
Use & | alloc, | ||
bool | gw_linked ) |
If two tables share an action profile, then the instruction memory location can be the exact same across both tables. However, the mem code for the instructions may need to differ.
Say for example, we had two tables {t1, t2} share an action profile that had the same 4 actions, {a1, a2, a3, a4 }. Four actions would require two bits of RAM line per entry. Let's say however, that one of the tables, with an action profile, i.e t2, is linked with a gateway. A gateway requires an action_instruction_adr_map_data entry as well, as the gateway goes through the hit pathway.
Thus in our example, t2 would require 5 instruction entries, and thus 3 bits of indirection, while t1 would only require 2 bits. Furthermore, if the gateway goes to row 0, then the an action encoding in t2 wouldn't fit within the 2 bits.
This function is to share the instruction memory line, while determining the correct memcode per action.