@@ -961,81 +961,239 @@ class Assembler : public AbstractAssembler {
961961
962962#undef INSN
963963
964- enum Aqrl {relaxed = 0b00 , rl = 0b01 , aq = 0b10 , aqrl = 0b11 };
965-
966- #define INSN (NAME, op, funct3, funct7 ) \
967- void NAME (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { \
968- unsigned insn = 0 ; \
969- patch ((address)&insn, 6 , 0 , op); \
970- patch ((address)&insn, 14 , 12 , funct3); \
971- patch_reg ((address)&insn, 7 , Rd); \
972- patch_reg ((address)&insn, 15 , Rs1); \
973- patch_reg ((address)&insn, 20 , Rs2); \
974- patch ((address)&insn, 31 , 27 , funct7); \
975- patch ((address)&insn, 26 , 25 , memory_order); \
976- emit (insn); \
977- }
978-
979- INSN (amoswap_w, 0b0101111 , 0b010 , 0b00001 );
980- INSN (amoadd_w, 0b0101111 , 0b010 , 0b00000 );
981- INSN (amoxor_w, 0b0101111 , 0b010 , 0b00100 );
982- INSN (amoand_w, 0b0101111 , 0b010 , 0b01100 );
983- INSN (amoor_w, 0b0101111 , 0b010 , 0b01000 );
984- INSN (amomin_w, 0b0101111 , 0b010 , 0b10000 );
985- INSN (amomax_w, 0b0101111 , 0b010 , 0b10100 );
986- INSN (amominu_w, 0b0101111 , 0b010 , 0b11000 );
987- INSN (amomaxu_w, 0b0101111 , 0b010 , 0b11100 );
988- INSN (amoswap_d, 0b0101111 , 0b011 , 0b00001 );
989- INSN (amoadd_d, 0b0101111 , 0b011 , 0b00000 );
990- INSN (amoxor_d, 0b0101111 , 0b011 , 0b00100 );
991- INSN (amoand_d, 0b0101111 , 0b011 , 0b01100 );
992- INSN (amoor_d, 0b0101111 , 0b011 , 0b01000 );
993- INSN (amomin_d, 0b0101111 , 0b011 , 0b10000 );
994- INSN (amomax_d , 0b0101111 , 0b011 , 0b10100 );
995- INSN (amominu_d, 0b0101111 , 0b011 , 0b11000 );
996- INSN (amomaxu_d, 0b0101111 , 0b011 , 0b11100 );
997- INSN (amocas_w, 0b0101111 , 0b010 , 0b00101 );
998- INSN (amocas_d, 0b0101111 , 0b011 , 0b00101 );
999- #undef INSN
1000-
1001- enum operand_size { int8, int16, int32, uint32, int64 };
1002-
1003- #define INSN (NAME, op, funct3, funct7 ) \
1004- void NAME (Register Rd, Register Rs1, Aqrl memory_order = relaxed) { \
1005- unsigned insn = 0 ; \
1006- uint32_t val = memory_order & 0x3 ; \
1007- patch ((address)&insn, 6 , 0 , op); \
1008- patch ((address)&insn, 14 , 12 , funct3); \
1009- patch_reg ((address)&insn, 7 , Rd); \
1010- patch_reg ((address)&insn, 15 , Rs1); \
1011- patch ((address)&insn, 25 , 20 , 0b00000 ); \
1012- patch ((address)&insn, 31 , 27 , funct7); \
1013- patch ((address)&insn, 26 , 25 , val); \
1014- emit (insn); \
1015- }
1016-
1017- INSN (lr_w, 0b0101111 , 0b010 , 0b00010 );
1018- INSN (lr_d, 0b0101111 , 0b011 , 0b00010 );
1019-
1020- #undef INSN
1021-
1022- #define INSN (NAME, op, funct3, funct7 ) \
1023- void NAME (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = relaxed) { \
1024- unsigned insn = 0 ; \
1025- uint32_t val = memory_order & 0x3 ; \
1026- patch ((address)&insn, 6 , 0 , op); \
1027- patch ((address)&insn, 14 , 12 , funct3); \
1028- patch_reg ((address)&insn, 7 , Rd); \
1029- patch_reg ((address)&insn, 15 , Rs2); \
1030- patch_reg ((address)&insn, 20 , Rs1); \
1031- patch ((address)&insn, 31 , 27 , funct7); \
1032- patch ((address)&insn, 26 , 25 , val); \
1033- emit (insn); \
964+ enum Aqrl {relaxed = 0b00 , rl = 0b01 , aq = 0b10 , aqrl = 0b11 };
965+
966+ private:
967+
968+ enum AmoWidthFunct3 : uint8_t {
969+ AMO_WIDTH_BYTE = 0b000 , // Zabha extension
970+ AMO_WIDTH_HALFWORD = 0b001 , // Zabha extension
971+ AMO_WIDTH_WORD = 0b010 ,
972+ AMO_WIDTH_DOUBLEWORD = 0b011 ,
973+ AMO_WIDTH_QUADWORD = 0b100 ,
974+ // 0b101 to 0b111 are reserved
975+ };
976+
977+ enum AmoOperationFunct5 : uint8_t {
978+ AMO_ADD = 0b00000 ,
979+ AMO_SWAP = 0b00001 ,
980+ AMO_LR = 0b00010 ,
981+ AMO_SC = 0b00011 ,
982+ AMO_XOR = 0b00100 ,
983+ AMO_OR = 0b01000 ,
984+ AMO_AND = 0b01100 ,
985+ AMO_MIN = 0b10000 ,
986+ AMO_MAX = 0b10100 ,
987+ AMO_MINU = 0b11000 ,
988+ AMO_MAXU = 0b11100 ,
989+ AMO_CAS = 0b00101 // Zacas
990+ };
991+
992+ static constexpr uint32_t OP_AMO_MAJOR = 0b0101111 ;
993+
994+ template <AmoOperationFunct5 funct5, AmoWidthFunct3 width>
995+ void amo_base (Register Rd, Register Rs1, uint8_t Rs2, Aqrl memory_order = aqrl) {
996+ assert (width > AMO_WIDTH_HALFWORD || UseZabha, " Must be" );
997+ assert (funct5 != AMO_CAS || UseZacas, " Must be" );
998+ unsigned insn = 0 ;
999+ patch ((address)&insn, 6 , 0 , OP_AMO_MAJOR);
1000+ patch_reg ((address)&insn, 7 , Rd);
1001+ patch ((address)&insn, 14 , 12 , width);
1002+ patch_reg ((address)&insn, 15 , Rs1);
1003+ patch ((address)&insn, 24 , 20 , Rs2);
1004+ patch ((address)&insn, 26 , 25 , memory_order);
1005+ patch ((address)&insn, 31 , 27 , funct5);
1006+ emit (insn);
10341007 }
10351008
1036- INSN (sc_w, 0b0101111 , 0b010 , 0b00011 );
1037- INSN (sc_d, 0b0101111 , 0b011 , 0b00011 );
1038- #undef INSN
1009+ template <AmoOperationFunct5 funct5, AmoWidthFunct3 width>
1010+ void amo_base (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1011+ amo_base<funct5, width>(Rd, Rs1, Rs2->raw_encoding (), memory_order);
1012+ }
1013+
1014+ public:
1015+
1016+ void amoadd_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1017+ amo_base<AMO_ADD, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1018+ }
1019+
1020+ void amoadd_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1021+ amo_base<AMO_ADD, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1022+ }
1023+
1024+ void amoadd_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1025+ amo_base<AMO_ADD, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1026+ }
1027+
1028+ void amoadd_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1029+ amo_base<AMO_ADD, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1030+ }
1031+
1032+ void amoswap_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1033+ amo_base<AMO_SWAP, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1034+ }
1035+
1036+ void amoswap_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1037+ amo_base<AMO_SWAP, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1038+ }
1039+
1040+ void amoswap_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1041+ amo_base<AMO_SWAP, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1042+ }
1043+
1044+ void amoswap_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1045+ amo_base<AMO_SWAP, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1046+ }
1047+
1048+ void amoxor_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1049+ amo_base<AMO_XOR, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1050+ }
1051+
1052+ void amoxor_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1053+ amo_base<AMO_XOR, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1054+ }
1055+
1056+ void amoxor_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1057+ amo_base<AMO_XOR, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1058+ }
1059+
1060+ void amoxor_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1061+ amo_base<AMO_XOR, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1062+ }
1063+
1064+ void amoor_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1065+ amo_base<AMO_OR, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1066+ }
1067+
1068+ void amoor_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1069+ amo_base<AMO_OR, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1070+ }
1071+
1072+ void amoor_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1073+ amo_base<AMO_OR, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1074+ }
1075+
1076+ void amoor_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1077+ amo_base<AMO_OR, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1078+ }
1079+
1080+ void amoand_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1081+ amo_base<AMO_AND, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1082+ }
1083+
1084+ void amoand_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1085+ amo_base<AMO_AND, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1086+ }
1087+
1088+ void amoand_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1089+ amo_base<AMO_AND, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1090+ }
1091+
1092+ void amoand_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1093+ amo_base<AMO_AND, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1094+ }
1095+
1096+ void amomin_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1097+ amo_base<AMO_MIN, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1098+ }
1099+
1100+ void amomin_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1101+ amo_base<AMO_MIN, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1102+ }
1103+
1104+ void amomin_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1105+ amo_base<AMO_MIN, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1106+ }
1107+
1108+ void amomin_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1109+ amo_base<AMO_MIN, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1110+ }
1111+
1112+ void amominu_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1113+ amo_base<AMO_MINU, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1114+ }
1115+
1116+ void amominu_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1117+ amo_base<AMO_MINU, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1118+ }
1119+
1120+ void amominu_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1121+ amo_base<AMO_MINU, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1122+ }
1123+
1124+ void amominu_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1125+ amo_base<AMO_MINU, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1126+ }
1127+
1128+ void amomax_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1129+ amo_base<AMO_MAX, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1130+ }
1131+
1132+ void amomax_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1133+ amo_base<AMO_MAX, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1134+ }
1135+
1136+ void amomax_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1137+ amo_base<AMO_MAX, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1138+ }
1139+
1140+ void amomax_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1141+ amo_base<AMO_MAX, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1142+ }
1143+
1144+ void amomaxu_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1145+ amo_base<AMO_MAXU, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1146+ }
1147+
1148+ void amomaxu_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1149+ amo_base<AMO_MAXU, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1150+ }
1151+
1152+ void amomaxu_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1153+ amo_base<AMO_MAXU, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1154+ }
1155+
1156+ void amomaxu_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1157+ amo_base<AMO_MAXU, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1158+ }
1159+
1160+ protected:
1161+
1162+ void lr_w (Register Rd, Register Rs1, Aqrl memory_order = aqrl) {
1163+ amo_base<AMO_LR, AMO_WIDTH_WORD>(Rd, Rs1, 0 , memory_order);
1164+ }
1165+
1166+ void lr_d (Register Rd, Register Rs1, Aqrl memory_order = aqrl) {
1167+ amo_base<AMO_LR, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, 0 , memory_order);
1168+ }
1169+
1170+ void sc_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1171+ amo_base<AMO_SC, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1172+ }
1173+
1174+ void sc_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1175+ amo_base<AMO_SC, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1176+ }
1177+
1178+ void amocas_b (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1179+ amo_base<AMO_CAS, AMO_WIDTH_BYTE>(Rd, Rs1, Rs2, memory_order);
1180+ }
1181+
1182+ void amocas_h (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1183+ amo_base<AMO_CAS, AMO_WIDTH_HALFWORD>(Rd, Rs1, Rs2, memory_order);
1184+ }
1185+
1186+ void amocas_w (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1187+ amo_base<AMO_CAS, AMO_WIDTH_WORD>(Rd, Rs1, Rs2, memory_order);
1188+ }
1189+
1190+ void amocas_d (Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {
1191+ amo_base<AMO_CAS, AMO_WIDTH_DOUBLEWORD>(Rd, Rs1, Rs2, memory_order);
1192+ }
1193+
1194+ public:
1195+
1196+ enum operand_size { int8, int16, int32, uint32, int64 };
10391197
10401198// Immediate Instruction
10411199#define INSN (NAME, op, funct3 ) \
0 commit comments