diff options
Diffstat (limited to 'pcm/pcm.c')
-rw-r--r-- | pcm/pcm.c | 157 |
1 files changed, 123 insertions, 34 deletions
@@ -47,6 +47,37 @@ int binary_print(unsigned int value) printf("(0x%x)\n", value); } +struct list_head *list_head_alloc(struct list_head *prev, struct list_head *next, void *data) +{ + struct list_head *list; + + list = calloc(1, sizeof(struct list_head)); + list->data = data; + list->prev = prev; + list->next = next; + + if (prev != NULL) + prev->next = list; + if (next != NULL) + next->prev = list; + + return list; +} + +void list_head_free(struct list_head *list) +{ + if (list == NULL) + return; + + if (list->next != NULL) + list->next->prev = list->prev; + if (list->prev != NULL) + list->prev->next = list->next; + + memset(list, 0, sizeof(struct list_head)); + free(list); +} + /* * PCM OPS */ @@ -63,6 +94,11 @@ int pcm_ops_register(struct pcm_ops *ops) return 0; } +void pcm_ops_unregister(void) +{ + pcm_ops = NULL; +} + int pcm_ops_asm_write(unsigned int value, char *mnemonic) { if (pcm_ops == NULL || pcm_ops->asm_write == NULL) @@ -79,6 +115,22 @@ int pcm_ops_disasm_write(unsigned int value, char *mnemonic) return pcm_ops->disasm_write(pcm_ops->data, value, mnemonic); } +int pcm_ops_func_address(char *func) +{ + if (pcm_ops == NULL || pcm_ops->func_address == NULL) + return -1; + + return pcm_ops->func_address(pcm_ops->data, func); +} + +int pcm_ops_label_address(char *func) +{ + if (pcm_ops == NULL || pcm_ops->label_address == NULL) + return -1; + + return pcm_ops->label_address(pcm_ops->data, func); +} + static int pcm_ops_asm_format(unsigned int value, const char *format, ...) { char *mnemonic = NULL; @@ -139,38 +191,18 @@ complete: * PCM OP codes */ -static int pcm_op_padding_asm(char *arguments[], unsigned int count, unsigned int padding) +static int pcm_op_padding_asm(unsigned int padding) { - unsigned int value; - unsigned int i; int rc; + int i; - if (arguments == NULL) - return -1; - - i = 0; - - /* Grab padding from following nops first. */ - while (arguments[i] != NULL && count > 0 && padding > 0) { - if (strncmp(arguments[i], "nop", 3) != 0) - break; - - rc = pcm_ops_asm_write(PCM_OP_NOP_VALUE, "nop"); - if (rc < 0) - return -1; - - padding--; - i++; - } - - /* Generate leftover padding. */ - while (padding-- > 0) { + for (i = 0; i < padding; i++) { rc = pcm_ops_asm_write(PCM_OP_NOP_VALUE, "nop"); if (rc < 0) return -1; } - return i; + return padding; } static int pcm_op_immediate_asm(char *arguments[], unsigned int count) @@ -291,7 +323,7 @@ static int pcm_op_loadi_disasm(struct pcm_op_desc *desc, unsigned int *arguments return 1; } -static int pcm_op_jump_call_asm(struct pcm_op_desc *desc, char *arguments[], unsigned int count) +static int pcm_op_jump_asm(struct pcm_op_desc *desc, char *arguments[], unsigned int count) { unsigned int value; unsigned int address; @@ -301,7 +333,12 @@ static int pcm_op_jump_call_asm(struct pcm_op_desc *desc, char *arguments[], uns return -1; value = desc->value; - address = strtol(arguments[1], NULL, 16); + + rc = pcm_ops_label_address(arguments[1]); + if (rc < 0) + address = strtol(arguments[1], NULL, 16); + else + address = rc; value |= (address & PCM_OP_JUMP_ADDRESS_MASK) << PCM_OP_JUMP_ADDRESS_SHIFT; @@ -312,7 +349,7 @@ static int pcm_op_jump_call_asm(struct pcm_op_desc *desc, char *arguments[], uns return 1; } -static int pcm_op_jump_call_disasm(struct pcm_op_desc *desc, unsigned int *arguments, unsigned int count) +static int pcm_op_jump_disasm(struct pcm_op_desc *desc, unsigned int *arguments, unsigned int count) { unsigned int value; unsigned int address; @@ -331,6 +368,51 @@ static int pcm_op_jump_call_disasm(struct pcm_op_desc *desc, unsigned int *argum return 0; } +static int pcm_op_call_asm(struct pcm_op_desc *desc, char *arguments[], unsigned int count) +{ + unsigned int value; + unsigned int address; + int rc; + + if (desc == NULL || arguments == NULL || arguments[1] == NULL || count < 2) + return -1; + + value = desc->value; + + rc = pcm_ops_func_address(arguments[1]); + if (rc < 0) + address = strtol(arguments[1], NULL, 16); + else + address = rc; + + value |= (address & PCM_OP_CALL_ADDRESS_MASK) << PCM_OP_CALL_ADDRESS_SHIFT; + + rc = pcm_ops_asm_format(value, "%s 0x%04x", arguments[0], address); + if (rc < 0) + return -1; + + return 1; +} + +static int pcm_op_call_disasm(struct pcm_op_desc *desc, unsigned int *arguments, unsigned int count) +{ + unsigned int value; + unsigned int address; + int rc; + + if (desc == NULL || arguments == NULL || count < 1) + return -1; + + value = arguments[0]; + address = (value >> PCM_OP_CALL_ADDRESS_SHIFT) & PCM_OP_CALL_ADDRESS_MASK; + + rc = pcm_ops_disasm_format(arguments[0], "%s 0x%04x", desc->mnemonic, address); + if (rc < 0) + return -1; + + return 0; +} + static struct pcm_op_desc pcm_op_descs[] = { { .mnemonic = "nop", @@ -353,16 +435,16 @@ static struct pcm_op_desc pcm_op_descs[] = { .mask = PCM_OP_JUMP_MASK, .value = PCM_OP_JUMP_VALUE, .padding = 1, - .asm_callback = pcm_op_jump_call_asm, - .disasm_callback = pcm_op_jump_call_disasm, + .asm_callback = pcm_op_jump_asm, + .disasm_callback = pcm_op_jump_disasm, }, { .mnemonic = "call", .mask = PCM_OP_CALL_MASK, .value = PCM_OP_CALL_VALUE, .padding = 1, - .asm_callback = pcm_op_jump_call_asm, - .disasm_callback = pcm_op_jump_call_disasm, + .asm_callback = pcm_op_call_asm, + .disasm_callback = pcm_op_call_disasm, }, { .mnemonic = "ret", @@ -440,11 +522,9 @@ int pcm_op_asm(char *arguments[], unsigned int count) else count = 0; - rc = pcm_op_padding_asm(arguments, count, desc->padding); + rc = pcm_op_padding_asm(desc->padding); if (rc < 0) return -1; - - increment += rc; } return increment; @@ -477,3 +557,12 @@ int pcm_op_disasm(unsigned int *arguments, unsigned int count) return increment; } + +/* + * PCM padding + */ + +int pcm_padding_asm(unsigned int padding) +{ + return pcm_op_padding_asm(padding); +} |