From 8e542d4fc8d5e883d2e920ef412e439a92e91b44 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 7 Jun 2018 14:49:41 +0530 Subject: [PATCH] arch-power: Fix fixed-point logical instructions This fixes the following logical instructions: * Extend Sign Byte (extsb[.]) * Extend Sign Halfword (extsh[.]) * Count Leading Zeros Word (cntlzw[.]) * Compare Bytes (cmpb) This also fixes disassembly generation for all of the above. Change-Id: I98873edf24db606d8de481aa18bcb809ad38d296 Signed-off-by: Sandipan Das --- src/arch/power/insts/integer.cc | 109 +++++++++++++++++++++++++ src/arch/power/insts/integer.hh | 54 ++++++++++++ src/arch/power/isa/decoder.isa | 35 ++++---- src/arch/power/isa/formats/integer.isa | 44 ++++++---- 4 files changed, 209 insertions(+), 33 deletions(-) diff --git a/src/arch/power/insts/integer.cc b/src/arch/power/insts/integer.cc index 8f7956277..d3672472c 100644 --- a/src/arch/power/insts/integer.cc +++ b/src/arch/power/insts/integer.cc @@ -277,6 +277,115 @@ IntDispArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const } +string +IntLogicOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + stringstream ss; + bool printSecondSrc = true; + + // Generate the correct mnemonic + string myMnemonic(mnemonic); + + // Special cases + if (!myMnemonic.compare("or") && _srcRegIdx[0] == _srcRegIdx[1]) { + myMnemonic = "mr"; + printSecondSrc = false; + } else if (!myMnemonic.compare("extsb") || + !myMnemonic.compare("extsh") || + !myMnemonic.compare("cntlzw")) { + printSecondSrc = false; + } + + // Additional characters depending on isa bits being set + if (rcSet) myMnemonic = myMnemonic + "."; + ccprintf(ss, "%-10s ", myMnemonic); + + // Print the first destination only + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + } + + // Print the first source register + if (_numSrcRegs > 0) { + if (_numDestRegs > 0) { + ss << ", "; + } + printReg(ss, _srcRegIdx[0]); + + // Print the second source register + if (printSecondSrc) { + + // If the instruction updates the CR, the destination register + // Ra is read and thus, it becomes the second source register + // due to its higher precedence over Rb. In this case, it must + // be skipped. + if (rcSet) { + if (_numSrcRegs > 2) { + ss << ", "; + printReg(ss, _srcRegIdx[2]); + } + } else { + if (_numSrcRegs > 1) { + ss << ", "; + printReg(ss, _srcRegIdx[1]); + } + } + } + } + + return ss.str(); +} + + +string +IntImmLogicOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + stringstream ss; + bool printRegs = true; + + // Generate the correct mnemonic + string myMnemonic(mnemonic); + + // Special cases + if (!myMnemonic.compare("ori") && + _destRegIdx[0].index() == 0 && _srcRegIdx[0].index() == 0) { + myMnemonic = "nop"; + printRegs = false; + } else if (!myMnemonic.compare("xori") && + _destRegIdx[0].index() == 0 && _srcRegIdx[0].index() == 0) { + myMnemonic = "xnop"; + printRegs = false; + } else if (!myMnemonic.compare("andi_")) { + myMnemonic = "andi."; + } else if (!myMnemonic.compare("andis_")) { + myMnemonic = "andis."; + } + + ccprintf(ss, "%-10s ", myMnemonic); + + if (printRegs) { + + // Print the first destination only + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + } + + // Print the source register + if (_numSrcRegs > 0) { + if (_numDestRegs > 0) { + ss << ", "; + } + printReg(ss, _srcRegIdx[0]); + } + + // Print the immediate value + ss << ", " << uimm; + } + + return ss.str(); +} + + string IntCompOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const { diff --git a/src/arch/power/insts/integer.hh b/src/arch/power/insts/integer.hh index d035f512e..6658760f5 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -481,6 +481,60 @@ class IntImmCompLogicOp : public IntCompOp }; +/** + * Class for integer logical operations. + */ +class IntLogicOp : public IntOp +{ + protected: + + /// Constructor + IntLogicOp(const char *mnem, MachInst _machInst, OpClass __opClass) + : IntOp(mnem, _machInst, __opClass) + { + } + + inline int + findLeadingZeros(uint32_t rs) const + { + if (rs) { + #if defined(__GNUC__) || (defined(__clang__) && \ + __has_builtin(__builtin_clz)) + return __builtin_clz(rs); + #else + return 31 - findMsbSet(rs); + #endif + } else { + return 32; + } + } + + std::string generateDisassembly( + Addr pc, const SymbolTable *symtab) const override; +}; + + +/** + * Class for integer immediate logical operations. + */ +class IntImmLogicOp : public IntLogicOp +{ + protected: + + uint32_t uimm; + + /// Constructor + IntImmLogicOp(const char *mnem, MachInst _machInst, OpClass __opClass) + : IntLogicOp(mnem, _machInst, __opClass), + uimm(machInst.si) + { + } + + std::string generateDisassembly( + Addr pc, const SymbolTable *symtab) const override; +}; + + /** * Class for integer operations with a shift. */ diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa index af83a3989..d80846f99 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -503,25 +503,28 @@ decode PO default Unknown::unknown() { // Integer logic instructions use source registers Rs and Rb, // with destination register Ra. format IntLogicOp { - 28: and({{ Ra = Rs & Rb; }}); - 316: xor({{ Ra = Rs ^ Rb; }}); - 476: nand({{ Ra = ~(Rs & Rb); }}); - 444: or({{ Ra = Rs | Rb; }}); - 124: nor({{ Ra = ~(Rs | Rb); }}); - 60: andc({{ Ra = Rs & ~Rb; }}); - 954: extsb({{ Ra = sext<8>(Rs); }}); - 284: eqv({{ Ra = ~(Rs ^ Rb); }}); - 412: orc({{ Ra = Rs | ~Rb; }}); - 922: extsh({{ Ra = sext<16>(Rs); }}); - 26: cntlzw({{ Ra = Rs == 0 ? 32 : 31 - findMsbSet(Rs); }}); + 28: and({{ Ra = Rs & Rb; }}, true); + 316: xor({{ Ra = Rs ^ Rb; }}, true); + 476: nand({{ Ra = ~(Rs & Rb); }}, true); + 444: or({{ Ra = Rs | Rb; }}, true); + 124: nor({{ Ra = ~(Rs | Rb); }}, true); + 60: andc({{ Ra = Rs & ~Rb; }}, true); + 284: eqv({{ Ra = ~(Rs ^ Rb); }}, true); + 412: orc({{ Ra = Rs | ~Rb; }}, true); + 954: extsb({{ Ra = Rs_sb; }}, true); + 922: extsh({{ Ra = Rs_sh; }}, true); + 26: cntlzw({{ Ra = findLeadingZeros(Rs_uw); }}, true); + 508: cmpb({{ - uint32_t val = 0; - for (int n = 0; n < 32; n += 8) { - if(bits(Rs, n+7, n) == bits(Rb, n+7, n)) { - val = insertBits(val, n+7, n, 0xff); + uint64_t mask = 0xff; + uint64_t res = 0; + for (int i = 0; i < 8; ++i) { + if ((Rs & mask) == (Rb & mask)) { + res |= mask; } + mask <<= 8; } - Ra = val; + Ra = res; }}); 24: slw({{ diff --git a/src/arch/power/isa/formats/integer.isa b/src/arch/power/isa/formats/integer.isa index 41fe64c04..7afaef068 100644 --- a/src/arch/power/isa/formats/integer.isa +++ b/src/arch/power/isa/formats/integer.isa @@ -202,12 +202,14 @@ def format IntImmLogicOp(code, computeCR0 = 0, inst_flags = []) {{ # Set up the dictionary and deal with computing CR0 dict = {'result':'Ra'} + + # Code when Rc is set if computeCR0: code += readXERCode + computeCR0Code % dict # Generate the class (header_output, decoder_output, decode_block, exec_output) = \ - GenAluOp(name, Name, 'IntImmOp', code, inst_flags, BasicDecode, + GenAluOp(name, Name, 'IntImmLogicOp', code, inst_flags, BasicDecode, BasicConstructor) }}; @@ -275,29 +277,37 @@ def format IntImmCompLogicOp(code, inst_flags = []) {{ // Integer instructions that perform logic operations. The result is -// always written into Ra. All instructions have 2 versions depending on +// always written into Ra. Some instructions have 2 versions depending on // whether the Rc bit is set to compute the CR0 code. This is determined // at decode as before. -def format IntLogicOp(code, inst_flags = []) {{ +def format IntLogicOp(code, computeCR0 = 0, inst_flags = []) {{ dict = {'result':'Ra'} - # Code when Rc is set - code_rc1 = code + readXERCode + computeCR0Code % dict + # Deal with computing CR0 + if computeCR0: + # Setup the 2 code versions and add code to access XER if necessary + code_rc1 = code + readXERCode + computeCR0Code % dict - # Generate the first class - (header_output, decoder_output, decode_block, exec_output) = \ - GenAluOp(name, Name, 'IntOp', code, inst_flags, - CheckRcDecode, BasicConstructor) + # Generate the first class + (header_output, decoder_output, decode_block, exec_output) = \ + GenAluOp(name, Name, 'IntLogicOp', code, inst_flags, + CheckRcDecode, BasicConstructor) - # Generate the second class - (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \ - GenAluOp(name, Name + 'RcSet', 'IntOp', code_rc1, inst_flags, - CheckRcDecode, IntRcConstructor) + # Generate the second class + (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \ + GenAluOp(name, Name + 'RcSet', 'IntLogicOp', code_rc1, inst_flags, + CheckRcDecode, IntRcConstructor) - # Finally, add to the other outputs - header_output += header_output_rc1 - decoder_output += decoder_output_rc1 - exec_output += exec_output_rc1 + # Finally, add to the other outputs + header_output += header_output_rc1 + decoder_output += decoder_output_rc1 + exec_output += exec_output_rc1 + + else: + # Generate the class + (header_output, decoder_output, decode_block, exec_output) = \ + GenAluOp(name, Name, 'IntLogicOp', code, inst_flags, + BasicDecode, BasicConstructor) }}; -- 2.30.2