use super::amdgpu_instr_info::{
AmdgpuEncodingFormat, AmdgpuInstrDesc, AmdgpuInstrInfo, AmdgpuOpcode,
};
pub struct AmdgpuMCEncoder {
pub instr_info: AmdgpuInstrInfo,
output: Vec<u8>,
}
impl AmdgpuMCEncoder {
pub fn new() -> Self {
Self {
instr_info: AmdgpuInstrInfo::new(),
output: Vec::new(),
}
}
pub fn encode(&mut self, opcode: AmdgpuOpcode, reg_vals: &[u32]) -> Vec<u8> {
self.output.clear();
let Some(desc) = self.instr_info.get(opcode) else {
self.output.extend_from_slice(&[0xBF, 0x80, 0x00, 0x00]); return self.output.clone();
};
match desc.encoding_format {
AmdgpuEncodingFormat::SOP1 => self.encode_sop1(opcode, reg_vals),
AmdgpuEncodingFormat::SOP2 => self.encode_sop2(opcode, reg_vals),
AmdgpuEncodingFormat::SOPC => self.encode_sopc(opcode, reg_vals),
AmdgpuEncodingFormat::SOPK => self.encode_sopk(opcode, reg_vals),
AmdgpuEncodingFormat::SOPP => self.encode_sopp(opcode, reg_vals),
AmdgpuEncodingFormat::VOP1 => self.encode_vop1(opcode, reg_vals),
AmdgpuEncodingFormat::VOP2 => self.encode_vop2(opcode, reg_vals),
AmdgpuEncodingFormat::VOPC => self.encode_vopc(opcode, reg_vals),
AmdgpuEncodingFormat::VOP3 => self.encode_vop3(opcode, reg_vals),
AmdgpuEncodingFormat::VOP3P => self.encode_vop3p(opcode, reg_vals),
AmdgpuEncodingFormat::SMEM => self.encode_smem(opcode, reg_vals),
AmdgpuEncodingFormat::FLAT => self.encode_flat(opcode, reg_vals),
AmdgpuEncodingFormat::DS => self.encode_ds(opcode, reg_vals),
AmdgpuEncodingFormat::MIMG => self.encode_mimg(opcode, reg_vals),
AmdgpuEncodingFormat::EXP => self.encode_exp(opcode, reg_vals),
AmdgpuEncodingFormat::VINTRP => self.encode_vintrp(opcode, reg_vals),
}
self.output.clone()
}
fn encode_sop1(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.sop1_opcode(opcode);
let sdst = vals.get(0).copied().unwrap_or(0) & 0x7F;
let ssrc0 = vals.get(1).copied().unwrap_or(0) & 0x7F;
let word = enc_opcode | (sdst << 8) | (ssrc0 << 16);
self.emit32(word);
}
fn encode_sop2(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.sop2_opcode(opcode);
let sdst = vals.get(0).copied().unwrap_or(0) & 0x7F;
let ssrc0 = vals.get(1).copied().unwrap_or(0) & 0xFF;
let ssrc1 = vals.get(2).copied().unwrap_or(0) & 0xFF;
let word = enc_opcode | (sdst << 7) | (ssrc0 << 13) | (ssrc1 << 21);
self.emit32(word);
}
fn encode_sopc(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.sopc_opcode(opcode);
let ssrc0 = vals.get(0).copied().unwrap_or(0) & 0xFF;
let ssrc1 = vals.get(1).copied().unwrap_or(0) & 0xFF;
let word = enc_opcode | (ssrc0 << 13) | (ssrc1 << 21);
self.emit32(word);
}
fn encode_sopk(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.sopk_opcode(opcode);
let sdst = vals.get(0).copied().unwrap_or(0) & 0x1F;
let simm16 = vals.get(1).copied().unwrap_or(0) & 0xFFFF;
let word = enc_opcode | (sdst << 5) | (simm16 << 10);
self.emit32(word);
}
fn encode_sopp(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.sopp_opcode(opcode);
let simm16 = vals.get(0).copied().unwrap_or(0) & 0xFFFF;
let word = enc_opcode | (simm16 << 4);
self.emit32(word);
}
fn encode_vop1(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.vop1_opcode(opcode);
let vdst = vals.get(0).copied().unwrap_or(0) & 0xFF;
let src0 = vals.get(1).copied().unwrap_or(0) & 0xFF;
let word = enc_opcode | (vdst << 9) | (src0 << 17);
self.emit32(word);
}
fn encode_vop2(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.vop2_opcode(opcode);
let vdst = vals.get(0).copied().unwrap_or(0) & 0xFF;
let src0 = vals.get(1).copied().unwrap_or(0) & 0xFF;
let src1 = vals.get(2).copied().unwrap_or(0) & 0xFF;
let word = enc_opcode | (vdst << 6) | (src0 << 14) | (src1 << 22);
self.emit32(word);
}
fn encode_vopc(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.vopc_opcode(opcode);
let src0 = vals.get(0).copied().unwrap_or(0) & 0xFF;
let src1 = vals.get(1).copied().unwrap_or(0) & 0xFF;
let word = enc_opcode | (src0 << 14) | (src1 << 22);
self.emit32(word);
}
fn encode_vop3(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.vop3_opcode(opcode);
let vdst = vals.get(0).copied().unwrap_or(0) & 0xFF;
let sdst = vals.get(1).copied().unwrap_or(0) & 0x7F;
let src0 = vals.get(2).copied().unwrap_or(0) & 0x1FF;
let src1 = vals.get(3).copied().unwrap_or(0) & 0x1FF;
let src2 = vals.get(4).copied().unwrap_or(0) & 0x1FF;
let word0: u32 = enc_opcode | (vdst << 9) | (sdst << 17) | (1 << 25);
let word1: u32 = src0 | (src1 << 16) | (src2 << 24);
self.emit64(word0, word1);
}
fn encode_vop3p(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
self.encode_vop3(opcode, vals);
}
fn encode_smem(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.smem_opcode(opcode);
let sdst = vals.get(0).copied().unwrap_or(0) & 0x7F;
let sbase = vals.get(1).copied().unwrap_or(0) & 0x7F;
let offset = vals.get(2).copied().unwrap_or(0) & 0xFFFFF;
let word0: u32 = enc_opcode | (sdst << 8) | (sbase << 16);
let word1: u32 = offset;
self.emit64(word0, word1);
}
fn encode_flat(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.flat_opcode(opcode);
let vdst = vals.get(0).copied().unwrap_or(0) & 0xFF;
let addr = vals.get(1).copied().unwrap_or(0);
let data = vals.get(2).copied().unwrap_or(0);
let word0: u32 = enc_opcode | (vdst << 8);
let word1: u32 = addr;
self.emit64(word0, word1);
}
fn encode_ds(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.ds_opcode(opcode);
let addr = vals.get(0).copied().unwrap_or(0) & 0xFF;
let data0 = vals.get(1).copied().unwrap_or(0) & 0xFF;
let data1 = vals.get(2).copied().unwrap_or(0) & 0xFF;
let word0: u32 = enc_opcode | (addr << 16) | (data0 << 24);
let word1: u32 = data1;
self.emit64(word0, word1);
}
fn encode_mimg(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let enc_opcode = self.mimg_opcode(opcode);
let vdst = vals.get(0).copied().unwrap_or(0) & 0xFF;
let vaddr = vals.get(1).copied().unwrap_or(0) & 0xFF;
let dmask = vals.get(2).copied().unwrap_or(0xF) & 0xF;
let word0: u32 = enc_opcode | (vdst << 8) | (vaddr << 16);
let word1: u32 = dmask;
self.emit64(word0, word1);
}
fn encode_exp(&mut self, opcode: AmdgpuOpcode, vals: &[u32]) {
let target = self.exp_target(opcode);
let en_mask = vals.get(0).copied().unwrap_or(0xF) & 0xF;
let src0 = vals.get(1).copied().unwrap_or(0) & 0xFF;
let src1 = vals.get(2).copied().unwrap_or(0) & 0xFF;
let src2 = vals.get(3).copied().unwrap_or(0) & 0xFF;
let src3 = vals.get(4).copied().unwrap_or(0) & 0xFF;
let word0: u32 = target | (en_mask << 6) | (1 << 20); let word1: u32 = src0 | (src1 << 8) | (src2 << 16) | (src3 << 24);
self.emit64(word0, word1);
}
fn encode_vintrp(&mut self, _opcode: AmdgpuOpcode, _vals: &[u32]) {
self.emit32(0xD4000000);
}
fn sop1_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::SMovB32 => 0x03,
AmdgpuOpcode::SMovB64 => 0x04,
AmdgpuOpcode::SNotB32 => 0x0C,
AmdgpuOpcode::SWqmB32 => 0x10,
AmdgpuOpcode::SBrevB32 => 0x18,
AmdgpuOpcode::SAbsI32 => 0x24,
_ => 0x00,
}
}
fn sop2_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::SAddU32 => 0x00,
AmdgpuOpcode::SSubU32 => 0x01,
AmdgpuOpcode::SAndB32 => 0x0E,
AmdgpuOpcode::SOrB32 => 0x0F,
AmdgpuOpcode::SXorB32 => 0x10,
AmdgpuOpcode::SMulI32 => 0x12,
AmdgpuOpcode::SMinU32 => 0x17,
AmdgpuOpcode::SMaxU32 => 0x18,
_ => 0x00,
}
}
fn sopc_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::SCmpEqI32 => 0x00,
AmdgpuOpcode::SCmpLgI32 => 0x01,
AmdgpuOpcode::SCmpGtI32 => 0x02,
AmdgpuOpcode::SCmpEqU32 => 0x04,
_ => 0x00,
}
}
fn sopk_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::SMovkI32 => 0x00,
AmdgpuOpcode::SAddkI32 => 0x0F,
AmdgpuOpcode::SMulkI32 => 0x10,
_ => 0x00,
}
}
fn sopp_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::SNop => 0x00,
AmdgpuOpcode::SWaitcnt => 0x0C,
AmdgpuOpcode::SBranch => 0x02,
AmdgpuOpcode::SEndpgm => 0x01,
_ => 0x00,
}
}
fn vop1_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::VMovB32 => 0x01,
AmdgpuOpcode::VRcpF32 => 0x2E,
AmdgpuOpcode::VSqrtF32 => 0x33,
AmdgpuOpcode::VLogF32 => 0x35,
AmdgpuOpcode::VExpF32 => 0x36,
_ => 0x00,
}
}
fn vop2_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::VAddF32 => 0x03,
AmdgpuOpcode::VSubF32 => 0x04,
AmdgpuOpcode::VMulF32 => 0x08,
AmdgpuOpcode::VMinF32 => 0x0C,
AmdgpuOpcode::VMaxF32 => 0x0D,
AmdgpuOpcode::VAndB32 => 0x17,
AmdgpuOpcode::VOrB32 => 0x18,
AmdgpuOpcode::VXorB32 => 0x19,
_ => 0x00,
}
}
fn vopc_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::VCmpF32Eq => 0x02,
AmdgpuOpcode::VCmpF32Lt => 0x04,
AmdgpuOpcode::VCmpF32Gt => 0x06,
_ => 0x00,
}
}
fn vop3_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::VAddF32Vop3 => 0x01C3,
AmdgpuOpcode::VMulF32Vop3 => 0x01C8,
AmdgpuOpcode::VFmaF32 => 0x01CB,
AmdgpuOpcode::VAddF64 => 0x0280,
AmdgpuOpcode::VMadF32 => 0x01C9,
_ => 0x00,
}
}
fn smem_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::SLoadDword => 0x00,
AmdgpuOpcode::SLoadDwordX4 => 0x03,
AmdgpuOpcode::SStoreDword => 0x10,
_ => 0x00,
}
}
fn flat_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::FlatLoadDword => 0x10,
AmdgpuOpcode::FlatStoreDword => 0x18,
AmdgpuOpcode::GlobalLoadDword => 0x50,
AmdgpuOpcode::GlobalStoreDword => 0x58,
_ => 0x00,
}
}
fn ds_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::DsWriteB32 => 0x0D,
AmdgpuOpcode::DsReadB32 => 0x36,
AmdgpuOpcode::DsAddU32 => 0x2A,
_ => 0x00,
}
}
fn mimg_opcode(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::ImageLoad => 0x08,
AmdgpuOpcode::ImageStore => 0x18,
AmdgpuOpcode::ImageSample => 0x20,
_ => 0x00,
}
}
fn exp_target(&self, op: AmdgpuOpcode) -> u32 {
match op {
AmdgpuOpcode::ExpMrt0 => 0x00,
AmdgpuOpcode::ExpPos0 => 0x0C,
AmdgpuOpcode::ExpParam0 => 0x20,
AmdgpuOpcode::ExpNull => 0x09,
_ => 0x00,
}
}
fn emit32(&mut self, word: u32) {
self.output.extend_from_slice(&word.to_le_bytes());
}
fn emit64(&mut self, word0: u32, word1: u32) {
self.emit32(word0);
self.emit32(word1);
}
}
impl Default for AmdgpuMCEncoder {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GfxGeneration {
Gfx8,
Gfx8_1,
Gfx9,
Gfx906,
Gfx101,
Gfx103,
Gfx11,
}
impl GfxGeneration {
pub fn from_name(name: &str) -> Option<Self> {
match name.to_lowercase().as_str() {
"gfx800" | "gfx801" | "gfx802" | "gfx803" | "gfx804" | "gfx805" => Some(Self::Gfx8),
"gfx810" | "gfx811" | "gfx812" | "gfx813" => Some(Self::Gfx8_1),
"gfx900" | "gfx901" | "gfx902" | "gfx903" | "gfx904" | "gfx905" | "gfx909" => {
Some(Self::Gfx9)
}
"gfx906" | "gfx907" | "gfx908" => Some(Self::Gfx906),
"gfx1010" | "gfx1011" | "gfx1012" | "gfx1013" => Some(Self::Gfx101),
"gfx1030" | "gfx1031" | "gfx1032" | "gfx1033" | "gfx1034" | "gfx1035" => {
Some(Self::Gfx103)
}
"gfx1100" | "gfx1101" | "gfx1102" | "gfx1103" => Some(Self::Gfx11),
_ => None,
}
}
pub fn supports_dpp(&self) -> bool {
matches!(
self,
Self::Gfx8 | Self::Gfx8_1 | Self::Gfx9 | Self::Gfx906 | Self::Gfx101 | Self::Gfx103
)
}
pub fn supports_sdwa(&self) -> bool {
matches!(self, Self::Gfx8 | Self::Gfx8_1 | Self::Gfx9 | Self::Gfx906)
}
pub fn supports_vop3p(&self) -> bool {
matches!(
self,
Self::Gfx9 | Self::Gfx906 | Self::Gfx101 | Self::Gfx103 | Self::Gfx11
)
}
pub fn is_rdna(&self) -> bool {
matches!(self, Self::Gfx101 | Self::Gfx103 | Self::Gfx11)
}
pub fn is_gcn(&self) -> bool {
!self.is_rdna()
}
}
pub struct Vop3Encoder {
pub opcode: u16,
pub vdst: u8,
pub sdst: u8,
pub ssrc0: u16,
pub ssrc1: u8,
pub src0_mod: u8,
pub src1_mod: u8,
pub src2_mod: u8,
pub opsel: u8,
pub opsel_hi: u8,
pub clamp: bool,
pub omod: u8,
pub neg_lo: bool,
pub neg_hi: bool,
}
impl Default for Vop3Encoder {
fn default() -> Self {
Vop3Encoder {
opcode: 0,
vdst: 0,
sdst: 0,
ssrc0: 0,
ssrc1: 0,
src0_mod: 0,
src1_mod: 0,
src2_mod: 0,
opsel: 0,
opsel_hi: 0,
clamp: false,
omod: 0,
neg_lo: false,
neg_hi: false,
}
}
}
impl Vop3Encoder {
pub fn encode(&self) -> (u32, u32) {
let mut word0: u32 = 0;
word0 |= (self.opcode as u32) & 0x1FF; word0 |= ((self.vdst as u32) & 0xFF) << 9; word0 |= 1 << 25; word0 |= 1 << 31;
let mut word1: u32 = 0;
word1 |= (self.sdst as u32) & 0x7F; word1 |= (self.ssrc0 as u32 & 0x1FF) << 8; word1 |= (self.ssrc1 as u32 & 0xFF) << 17; if self.clamp {
word1 |= 1 << 26; }
word1 |= (self.omod as u32 & 0x3) << 27;
(word0, word1)
}
pub fn encode_extended(&self) -> (u32, u32) {
let mut word0: u32 = 0;
word0 |= (self.opcode as u32) & 0x1FF;
word0 |= ((self.vdst as u32) & 0xFF) << 9;
word0 |= ((self.opsel as u32) & 0x7) << 17; word0 |= ((self.opsel_hi as u32) & 0x3) << 21; if self.neg_lo {
word0 |= 1 << 23;
}
if self.neg_hi {
word0 |= 1 << 24;
}
word0 |= 1 << 25;
word0 |= 1 << 31;
let mut word1: u32 = 0;
word1 |= (self.sdst as u32) & 0x7F;
word1 |= (self.ssrc0 as u32 & 0x1FF) << 8;
word1 |= (self.ssrc1 as u32 & 0xFF) << 17;
word1 |= (self.src0_mod as u32 & 0x3) << 25;
word1 |= (self.src1_mod as u32 & 0x3) << 27;
word1 |= (self.src2_mod as u32 & 0x3) << 29;
if self.clamp {
word0 |= 1 << 26;
}
(word0, word1)
}
}
pub struct Vop3pEncoder {
pub opcode: u8,
pub vdst: u8,
pub sdst: u8,
pub ssrc0: u16,
pub ssrc1: u8,
pub opsel_hi: u8,
pub neg_lo: u8,
pub neg_hi: u8,
pub clamp: bool,
}
impl Default for Vop3pEncoder {
fn default() -> Self {
Vop3pEncoder {
opcode: 0,
vdst: 0,
sdst: 0,
ssrc0: 0,
ssrc1: 0,
opsel_hi: 0,
neg_lo: 0,
neg_hi: 0,
clamp: false,
}
}
}
impl Vop3pEncoder {
pub fn encode(&self) -> (u32, u32) {
let mut word0: u32 = 0;
word0 |= (self.opcode as u32) & 0x7F; word0 |= ((self.vdst as u32) & 0xFF) << 7; word0 |= ((self.opsel_hi as u32) & 0x3) << 15; word0 |= ((self.neg_lo as u32) & 0x7) << 17; word0 |= ((self.neg_hi as u32) & 0x7) << 20; if self.clamp {
word0 |= 1 << 23;
}
word0 |= 0x7F << 24; word0 |= 1 << 31;
let mut word1: u32 = 0;
word1 |= (self.sdst as u32) & 0x7F;
word1 |= (self.ssrc0 as u32 & 0x1FF) << 8;
word1 |= (self.ssrc1 as u32 & 0xFF) << 17;
(word0, word1)
}
pub fn encode_packed_f16(&self, op_sel: [bool; 4]) -> (u32, u32) {
let mut opsel = 0u8;
for (i, sel) in op_sel.iter().enumerate() {
if *sel {
opsel |= 1 << i;
}
}
let mut enc = Vop3pEncoder {
opsel_hi: opsel,
..*self
};
enc.encode()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DppCtrl {
QuadPerm(u8),
RowSl(u8),
RowSr(u8),
RowRl(u8),
RowRr(u8),
WaveSl(u8),
WaveSr(u8),
WaveRl(u8),
WaveRr(u8),
RowMirror,
RowHalfMirror,
Bcast15,
Bcast31,
}
impl DppCtrl {
pub fn encode(&self) -> u16 {
match self {
DppCtrl::QuadPerm(id) => 0x100 | ((id & 0x3) as u16),
DppCtrl::RowSl(n) => 0x110 | ((n & 0xF) as u16),
DppCtrl::RowSr(n) => 0x111 | ((n & 0xF) as u16),
DppCtrl::RowRl(n) => 0x114 | ((n & 0xF) as u16),
DppCtrl::RowRr(n) => 0x115 | ((n & 0xF) as u16),
DppCtrl::WaveSl(n) => 0x130 | ((n & 0xF) as u16),
DppCtrl::WaveSr(n) => 0x131 | ((n & 0xF) as u16),
DppCtrl::WaveRl(n) => 0x134 | ((n & 0xF) as u16),
DppCtrl::WaveRr(n) => 0x135 | ((n & 0xF) as u16),
DppCtrl::RowMirror => 0x140,
DppCtrl::RowHalfMirror => 0x141,
DppCtrl::Bcast15 => 0x142,
DppCtrl::Bcast31 => 0x143,
}
}
}
pub struct DppModifier {
pub ctrl: DppCtrl,
pub bank_mask: u8,
pub row_mask: u8,
pub bound_ctrl: bool,
}
impl DppModifier {
pub fn new(ctrl: DppCtrl) -> Self {
DppModifier {
ctrl,
bank_mask: 0xF,
row_mask: 0xF,
bound_ctrl: false,
}
}
pub fn encode(&self) -> u32 {
let mut dpp: u32 = 0;
dpp |= (self.ctrl.encode() as u32) & 0x1FF;
dpp |= ((self.bank_mask as u32) & 0xF) << 9;
dpp |= ((self.row_mask as u32) & 0xF) << 13;
if self.bound_ctrl {
dpp |= 1 << 17;
}
dpp
}
}
pub struct SdwaModifier {
pub dst_sel: SdwaSel,
pub dst_unused: SdwaUnused,
pub src0_sel: SdwaSel,
pub src0_sext: bool,
pub src0_neg: bool,
pub src0_abs: bool,
pub src1_sel: SdwaSel,
pub src1_sext: bool,
pub src1_neg: bool,
pub src1_abs: bool,
pub clamp: bool,
pub omod: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SdwaSel {
Byte0,
Byte1,
Byte2,
Byte3,
Word0,
Word1,
Dword,
}
impl SdwaSel {
pub fn encode(&self) -> u8 {
match self {
SdwaSel::Byte0 => 0,
SdwaSel::Byte1 => 1,
SdwaSel::Byte2 => 2,
SdwaSel::Byte3 => 3,
SdwaSel::Word0 => 4,
SdwaSel::Word1 => 5,
SdwaSel::Dword => 6,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SdwaUnused {
Preserve,
Zero,
Sext,
}
impl SdwaUnused {
pub fn encode(&self) -> u8 {
match self {
SdwaUnused::Preserve => 0,
SdwaUnused::Zero => 1,
SdwaUnused::Sext => 2,
}
}
}
impl Default for SdwaModifier {
fn default() -> Self {
SdwaModifier {
dst_sel: SdwaSel::Dword,
dst_unused: SdwaUnused::Preserve,
src0_sel: SdwaSel::Dword,
src0_sext: false,
src0_neg: false,
src0_abs: false,
src1_sel: SdwaSel::Dword,
src1_sext: false,
src1_neg: false,
src1_abs: false,
clamp: false,
omod: 0,
}
}
}
impl SdwaModifier {
pub fn encode(&self) -> u32 {
let mut sdwa: u32 = 0;
sdwa |= (self.dst_sel.encode() as u32) & 0x7;
sdwa |= ((self.dst_unused.encode() as u32) & 0x3) << 3;
if self.clamp {
sdwa |= 1 << 5;
}
sdwa |= ((self.src0_sel.encode() as u32) & 0x7) << 6;
if self.src0_sext {
sdwa |= 1 << 9;
}
if self.src0_neg {
sdwa |= 1 << 10;
}
if self.src0_abs {
sdwa |= 1 << 11;
}
sdwa |= ((self.src1_sel.encode() as u32) & 0x7) << 12;
if self.src1_sext {
sdwa |= 1 << 15;
}
if self.src1_neg {
sdwa |= 1 << 16;
}
if self.src1_abs {
sdwa |= 1 << 17;
}
sdwa |= (self.omod as u32 & 0x3) << 18;
sdwa
}
}
pub struct MubufEncoder {
pub opcode: u8,
pub vdata: u8,
pub vaddr: u8,
pub srsrc: u8,
pub soffset: u8,
pub offset: u16,
pub slc: bool, pub glc: bool, pub tfe: bool, pub idxen: bool, pub offen: bool, pub addr64: bool, pub lds: bool, }
impl Default for MubufEncoder {
fn default() -> Self {
MubufEncoder {
opcode: 0,
vdata: 0,
vaddr: 0,
srsrc: 0,
soffset: 0,
offset: 0,
slc: false,
glc: false,
tfe: false,
idxen: false,
offen: false,
addr64: false,
lds: false,
}
}
}
impl MubufEncoder {
pub fn encode(&self) -> (u32, u32) {
let mut word0: u32 = 0;
word0 |= (self.vdata as u32) & 0xFF; word0 |= ((self.opcode as u32) & 0x7F) << 8; word0 |= ((self.offset as u32) & 0xFFF) << 15; word0 |= ((self.soffset as u32) & 0x7) << 27;
let mut word1: u32 = 0;
word1 |= (self.srsrc as u32) & 0x1F; if self.lds {
word1 |= 1 << 5;
}
if self.glc {
word1 |= 1 << 6; }
if self.idxen {
word1 |= 1 << 7;
}
if self.offen {
word1 |= 1 << 8;
}
if self.addr64 {
word1 |= 1 << 9;
}
word1 |= ((self.vaddr as u32) & 0xFF) << 10; if self.slc {
word1 |= 1 << 18;
}
if self.tfe {
word1 |= 1 << 19;
}
(word0, word1)
}
}
pub struct MtbufEncoder {
pub opcode: u8,
pub vdata: u8,
pub vaddr: u8,
pub srsrc: u8,
pub soffset: u8,
pub offset: u16,
pub dfmt: u8, pub nfmt: u8, pub slc: bool,
pub glc: bool,
pub tfe: bool,
pub idxen: bool,
pub offen: bool,
pub addr64: bool,
}
impl Default for MtbufEncoder {
fn default() -> Self {
MtbufEncoder {
opcode: 0,
vdata: 0,
vaddr: 0,
srsrc: 0,
soffset: 0,
offset: 0,
dfmt: 0,
nfmt: 0,
slc: false,
glc: false,
tfe: false,
idxen: false,
offen: false,
addr64: false,
}
}
}
impl MtbufEncoder {
pub fn encode(&self) -> (u32, u32) {
let mut word0: u32 = 0;
word0 |= (self.vdata as u32) & 0xFF;
word0 |= ((self.opcode as u32) & 0xF) << 8;
word0 |= ((self.offset as u32) & 0xFFF) << 12;
word0 |= ((self.soffset as u32) & 0x7) << 24;
word0 |= ((self.dfmt as u32) & 0xF) << 16;
word0 |= ((self.nfmt as u32) & 0x7) << 20;
let mut word1: u32 = 0;
word1 |= (self.srsrc as u32) & 0x1F;
if self.glc {
word1 |= 1 << 6;
}
if self.idxen {
word1 |= 1 << 7;
}
if self.offen {
word1 |= 1 << 8;
}
if self.addr64 {
word1 |= 1 << 9;
}
word1 |= ((self.vaddr as u32) & 0xFF) << 10;
if self.slc {
word1 |= 1 << 18;
}
if self.tfe {
word1 |= 1 << 19;
}
(word0, word1)
}
}
pub struct MimgEncoder {
pub opcode: u8,
pub vdata: u8,
pub vaddr: u8,
pub srsrc: u8,
pub ssamp: u8,
pub dmask: u8,
pub unrm: bool,
pub glc: bool,
pub slc: bool,
pub tfe: bool,
pub da: bool, pub a16: bool, pub lwe: bool, pub r128: bool, pub dim: u8, }
impl Default for MimgEncoder {
fn default() -> Self {
MimgEncoder {
opcode: 0,
vdata: 0,
vaddr: 0,
srsrc: 0,
ssamp: 0,
dmask: 0xF,
unrm: false,
glc: false,
slc: false,
tfe: false,
da: false,
a16: false,
lwe: false,
r128: false,
dim: 0,
}
}
}
impl MimgEncoder {
pub fn encode(&self) -> (u32, u32) {
let mut word0: u32 = 0;
word0 |= (self.vdata as u32) & 0xFF;
word0 |= ((self.opcode as u32) & 0xFF) << 8;
word0 |= ((self.dmask as u32) & 0xF) << 16;
if self.unrm {
word0 |= 1 << 20;
}
if self.glc {
word0 |= 1 << 21;
}
if self.slc {
word0 |= 1 << 22;
}
if self.tfe {
word0 |= 1 << 23;
}
if self.da {
word0 |= 1 << 24;
}
let mut word1: u32 = 0;
word1 |= (self.srsrc as u32) & 0x1F;
word1 |= ((self.ssamp as u32) & 0xF) << 5;
if self.a16 {
word1 |= 1 << 9;
}
if self.lwe {
word1 |= 1 << 10;
}
if self.r128 {
word1 |= 1 << 11;
}
word1 |= ((self.dim as u32) & 0x7) << 12;
word1 |= ((self.vaddr as u32) & 0xFF) << 16;
(word0, word1)
}
}
pub struct ExpEncoder {
pub target: u8,
pub en_mask: u8,
pub compr: bool,
pub done: bool,
pub vm: bool,
pub vsrc0: u8,
pub vsrc1: u8,
pub vsrc2: u8,
pub vsrc3: u8,
}
impl Default for ExpEncoder {
fn default() -> Self {
ExpEncoder {
target: 0,
en_mask: 0xF,
compr: false,
done: false,
vm: false,
vsrc0: 0,
vsrc1: 0,
vsrc2: 0,
vsrc3: 0,
}
}
}
impl ExpEncoder {
pub fn encode(&self) -> (u32, u32) {
let mut word0: u32 = 0;
word0 |= (self.en_mask as u32) & 0xF;
word0 |= ((self.target as u32) & 0x3F) << 4;
if self.compr {
word0 |= 1 << 10;
}
word0 |= ((self.vsrc0 as u32) & 0xFF) << 16;
word0 |= ((self.vsrc1 as u32) & 0xFF) << 23;
if self.done {
word0 |= 1 << 30;
}
if self.vm {
word0 |= 1 << 31;
}
let mut word1: u32 = 0;
word1 |= ((self.vsrc2 as u32) & 0xFF) << 0;
word1 |= ((self.vsrc3 as u32) & 0xFF) << 7;
(word0, word1)
}
}
pub struct FlatEncoder {
pub opcode: u8,
pub vdst: u8,
pub vaddr: u8,
pub saddr: u8,
pub offset: u16,
pub glc: bool,
pub slc: bool,
pub segment: FlatSegment,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FlatSegment {
Global,
Scratch,
}
impl FlatSegment {
pub fn encode(&self) -> u8 {
match self {
FlatSegment::Global => 0,
FlatSegment::Scratch => 1,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_sop1() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::SMovB32, &[0, 1]);
assert_eq!(bytes.len(), 4);
assert_eq!(bytes[0], 0x03);
assert_eq!(bytes[1], 0x00); assert_eq!(bytes[2], 0x01); }
#[test]
fn test_encode_vop2() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::VAddF32, &[0, 1, 2]);
assert_eq!(bytes.len(), 4);
assert_eq!(bytes[0] & 0x3F, 0x03); }
#[test]
fn test_encode_sopp_nop() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::SNop, &[0]);
assert_eq!(bytes.len(), 4);
assert_eq!(bytes[0] & 0x0F, 0x00); }
#[test]
fn test_encode_smem() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::SLoadDword, &[0, 2, 0]);
assert_eq!(bytes.len(), 8); }
#[test]
fn test_encode_flat() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::GlobalLoadDword, &[5, 0x1000, 0]);
assert_eq!(bytes.len(), 8);
}
#[test]
fn test_encode_ds() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::DsWriteB32, &[0, 42, 0]);
assert_eq!(bytes.len(), 8);
}
#[test]
fn test_encode_unknown_opcode_graceful() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::SWqmB64, &[0, 0]);
assert_eq!(bytes.len(), 4);
}
#[test]
fn test_encode_vopc() {
let mut enc = AmdgpuMCEncoder::new();
let bytes = enc.encode(AmdgpuOpcode::VCmpF32Eq, &[0, 1]);
assert_eq!(bytes.len(), 4);
assert_eq!(bytes[0] & 0x3F, 0x02); }
#[test]
fn test_encode_all_formats_no_panic() {
let mut enc = AmdgpuMCEncoder::new();
enc.encode(AmdgpuOpcode::SMovB32, &[0, 0]); enc.encode(AmdgpuOpcode::SAddU32, &[0, 0, 0]); enc.encode(AmdgpuOpcode::SCmpEqI32, &[0, 0]); enc.encode(AmdgpuOpcode::SMovkI32, &[0, 0]); enc.encode(AmdgpuOpcode::SNop, &[0]); enc.encode(AmdgpuOpcode::VMovB32, &[0, 0]); enc.encode(AmdgpuOpcode::VAddF32, &[0, 0, 0]); enc.encode(AmdgpuOpcode::VCmpF32Eq, &[0, 0]); enc.encode(AmdgpuOpcode::VAddF32Vop3, &[0, 0, 0, 0, 0]); enc.encode(AmdgpuOpcode::SLoadDword, &[0, 0, 0]); enc.encode(AmdgpuOpcode::GlobalLoadDword, &[0, 0, 0]); enc.encode(AmdgpuOpcode::DsWriteB32, &[0, 0, 0]); enc.encode(AmdgpuOpcode::ImageSample, &[0, 0, 0]); enc.encode(AmdgpuOpcode::ExpMrt0, &[0, 0, 0, 0, 0]); }
}