pcm: Add support for mask operation
authorPaul Kocialkowski <contact@paulk.fr>
Tue, 14 Mar 2017 11:37:22 +0000 (12:37 +0100)
committerPaul Kocialkowski <contact@paulk.fr>
Tue, 14 Mar 2017 11:37:22 +0000 (12:37 +0100)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
pcm/pcm.c
pcm/pcm.h

index d75087e..2753540 100644 (file)
--- a/pcm/pcm.c
+++ b/pcm/pcm.c
@@ -459,6 +459,119 @@ static int pcm_op_or_disasm(struct pcm_op_desc *desc, unsigned int *arguments, u
        return 2;
 }
 
+static int pcm_op_mask_asm(struct pcm_op_desc *desc, char *arguments[], unsigned int count)
+{
+       unsigned int value;
+       unsigned int reg_dst;
+       unsigned int reg_src;
+       unsigned int reg_value;
+       unsigned int shift;
+       size_t mnemonic_length;
+       size_t length;
+       char *string;
+       int rc;
+
+       if (desc == NULL || arguments == NULL || count < 4 || arguments[1] == NULL || arguments[2] == NULL || arguments[3] == NULL)
+               return -1;
+
+       value = desc->value;
+
+       mnemonic_length = strlen(desc->mnemonic);
+       length = strlen(arguments[0]);
+
+       if (length > mnemonic_length) {
+               switch (arguments[0][mnemonic_length]) {
+                       case 'i':
+                               value |= PCM_OP_MASK_INVERT_BIT;
+                               break;
+                       default:
+                               return -1;
+               }
+       }
+
+       string = arguments[1];
+       if (string[0] == 'r')
+               string = &string[1];
+
+       reg_dst = atoi(string);
+       value |= (reg_dst & PCM_OP_MASK_REG_DST_MASK) << PCM_OP_MASK_REG_DST_SHIFT;
+
+       string = arguments[2];
+       if (string[0] == 'r')
+               string = &string[1];
+
+       reg_src = atoi(string);
+       value |= (reg_src & PCM_OP_MASK_REG_SRC_MASK) << PCM_OP_MASK_REG_SRC_SHIFT;
+
+       string = arguments[3];
+       if (string[0] == 'r')
+               string = &string[1];
+
+       reg_value = atoi(string);
+       value |= (reg_value & PCM_OP_MASK_REG_VALUE_MASK) << PCM_OP_MASK_REG_VALUE_SHIFT;
+
+       if (count >= 6 && arguments[4] != NULL && arguments[5] != NULL) {
+               if (arguments[4][0] == '<')
+                       value |= PCM_OP_MASK_SHIFT_LEFT_BIT;
+               else if (arguments[4][0] != '>')
+                       return -1;
+
+               shift = atoi(arguments[5]);
+               value |= (shift & PCM_OP_MASK_SHIFT_MASK) << PCM_OP_MASK_SHIFT_SHIFT;
+
+               rc = pcm_ops_asm_format(value, "%s r%d r%d r%d %s %d", arguments[0], reg_dst, reg_src, reg_value, arguments[4][0] == '<' ? "<<" : ">>", shift);
+       } else {
+               rc = pcm_ops_asm_format(value, "%s r%d r%d r%d", arguments[0], reg_dst, reg_src, reg_value);
+       }
+
+       if (rc < 0)
+               return -1;
+
+       return 1;
+}
+
+static int pcm_op_mask_disasm(struct pcm_op_desc *desc, unsigned int *arguments, unsigned int count)
+{
+       unsigned int value;
+       unsigned int reg_dst;
+       unsigned int reg_src;
+       unsigned int reg_value;
+       unsigned int shift;
+       char *s;
+       char *c;
+       int rc;
+
+       if (desc == NULL || arguments == NULL || count < 1)
+               return -1;
+
+       value = arguments[0];
+       reg_dst = (value >> PCM_OP_MASK_REG_DST_SHIFT) & PCM_OP_MASK_REG_DST_MASK;
+       reg_src = (value >> PCM_OP_MASK_REG_SRC_SHIFT) & PCM_OP_MASK_REG_SRC_MASK;
+       reg_value = (value >> PCM_OP_MASK_REG_VALUE_SHIFT) & PCM_OP_MASK_REG_VALUE_MASK;
+       shift = (value >> PCM_OP_MASK_SHIFT_SHIFT) & PCM_OP_MASK_SHIFT_MASK;
+
+       if (value & PCM_OP_MASK_INVERT_BIT)
+               c = "i";
+       else
+               c = "\0";
+
+       if (shift != 0) {
+               if (value & PCM_OP_MASK_SHIFT_LEFT_BIT)
+                       s = "<<";
+               else
+                       s = ">>";
+
+               rc = pcm_ops_disasm_format(value, "%s%s r%d r%d r%d %s %d", desc->mnemonic, c, reg_dst, reg_src, reg_value, s, shift);
+       } else {
+               rc = pcm_ops_disasm_format(value, "%s%s r%d r%d r%d", desc->mnemonic, c, reg_dst, reg_src, reg_value);
+       }
+
+       if (rc < 0)
+               return -1;
+
+       return 1;
+}
+
 static int pcm_op_load_asm(struct pcm_op_desc *desc, char *arguments[], unsigned int count)
 {
        unsigned int value;
@@ -769,6 +882,14 @@ static struct pcm_op_desc pcm_op_descs[] = {
                .disasm_callback = pcm_op_or_disasm,
        },
        {
+               .mnemonic = "mask",
+               .mask = PCM_OP_MASK_MASK,
+               .value = PCM_OP_MASK_VALUE,
+               .padding = 0,
+               .asm_callback = pcm_op_mask_asm,
+               .disasm_callback = pcm_op_mask_disasm,
+       },
+       {
                .mnemonic = "load",
                .mask = PCM_OP_LOAD_MASK,
                .value = PCM_OP_LOAD_VALUE,
index 454bc76..311bb56 100644 (file)
--- a/pcm/pcm.h
+++ b/pcm/pcm.h
 #define PCM_OP_OR_REG_SRC_SHIFT                                        0
 #define PCM_OP_OR_REG_SRC_MASK                                 0x0f
 
+#define PCM_OP_MASK_MASK                                       0xfc0043f0
+#define PCM_OP_MASK_VALUE                                      0x80000000
+#define PCM_OP_MASK_REG_DST_SHIFT                              22
+#define PCM_OP_MASK_REG_DST_MASK                               0x0f
+#define PCM_OP_MASK_REG_SRC_SHIFT                              0
+#define PCM_OP_MASK_REG_SRC_MASK                               0x0f
+#define PCM_OP_MASK_REG_VALUE_SHIFT                            10
+#define PCM_OP_MASK_REG_VALUE_MASK                             0x0f
+#define PCM_OP_MASK_SHIFT_SHIFT                                        15
+#define PCM_OP_MASK_SHIFT_MASK                                 0x1f
+#define PCM_OP_MASK_SHIFT_LEFT_BIT                             (1 << 20)
+#define PCM_OP_MASK_INVERT_BIT                                 (1 << 21)
+
 #define PCM_OP_LOAD_MASK                                       0xfc2fffff
 #define PCM_OP_LOAD_VALUE                                      0x1800001f
 #define PCM_OP_LOAD_REG_SHIFT                                  22