diff options
author | Paul Kocialkowski <contact@paulk.fr> | 2017-02-23 22:41:04 +0100 |
---|---|---|
committer | Paul Kocialkowski <contact@paulk.fr> | 2017-02-23 22:41:35 +0100 |
commit | ebbc17fb5fe384349f39560006681628d47069a3 (patch) | |
tree | 33e891c2aba4e937aa140951ff1e9ba61db17fcb | |
parent | 6e60012b1b3bd66b9ec96efb76496ea4dc2b8b0c (diff) | |
download | mt8173-pcm-tools-ebbc17fb5fe384349f39560006681628d47069a3.tar.gz mt8173-pcm-tools-ebbc17fb5fe384349f39560006681628d47069a3.tar.bz2 mt8173-pcm-tools-ebbc17fb5fe384349f39560006681628d47069a3.zip |
MT8173 PCM assembler introduction
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | pcm-analysis/pcm-analysis.c | 2 | ||||
-rw-r--r-- | pcm-asm/pcm-asm.c | 2 | ||||
-rw-r--r-- | pcm-assembler/Makefile | 68 | ||||
l--------- | pcm-assembler/pcm | 1 | ||||
-rw-r--r-- | pcm-assembler/pcm-assembler.c | 502 | ||||
-rw-r--r-- | pcm-assembler/pcm-assembler.h | 68 | ||||
-rw-r--r-- | pcm-disasm/pcm-disasm.c | 2 | ||||
-rw-r--r-- | pcm/pcm.c | 157 | ||||
-rw-r--r-- | pcm/pcm.h | 20 |
11 files changed, 815 insertions, 35 deletions
@@ -1,2 +1 @@ build -mt8173-pcm diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6f570e9 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2016-2017 Paul Kocialkowski <contact@paulk.fr> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +PROJECTS = pcm-analysis pcm-assembler pcm-asm pcm-disasm + +all: + @$(foreach project,$(PROJECTS),make -C "$(project)" ;) + +.PHONY: clean +clean: + @$(foreach project,$(PROJECTS),make -C "$(project)" clean ;) + +.PHONY: distclean +distclean: + @$(foreach project,$(PROJECTS),make -C "$(project)" distclean ;) diff --git a/pcm-analysis/pcm-analysis.c b/pcm-analysis/pcm-analysis.c index d7d4699..1558c01 100644 --- a/pcm-analysis/pcm-analysis.c +++ b/pcm-analysis/pcm-analysis.c @@ -33,6 +33,8 @@ struct pcm_ops_data pcm_ops_data = { struct pcm_ops pcm_ops = { .asm_write = NULL, .disasm_write = pcm_disasm_write, + .func_address = NULL, + .label_address = NULL, .data = (void *) &pcm_ops_data, }; diff --git a/pcm-asm/pcm-asm.c b/pcm-asm/pcm-asm.c index 665f344..54595fd 100644 --- a/pcm-asm/pcm-asm.c +++ b/pcm-asm/pcm-asm.c @@ -30,6 +30,8 @@ struct pcm_ops pcm_ops = { .asm_write = pcm_asm_write, .disasm_write = NULL, + .func_address = NULL, + .label_address = NULL, .data = NULL, }; diff --git a/pcm-assembler/Makefile b/pcm-assembler/Makefile new file mode 100644 index 0000000..e3405a7 --- /dev/null +++ b/pcm-assembler/Makefile @@ -0,0 +1,68 @@ +# Tools + +CC = gcc + +# Project + +NAME = pcm-assembler + +# Directories + +BUILD = build +OUTPUT = . + +# Sources + +SOURCES = pcm/pcm.c pcm-assembler.c +OBJECTS = $(SOURCES:.c=.o) +DEPS = $(SOURCES:.c=.d) + +# Compiler + +INCLUDES = . + +CFLAGS = $(foreach include,$(INCLUDES),-I$(include)) +LDFLAGS = + +# Produced files + +BUILD_OBJECTS = $(addprefix $(BUILD)/,$(OBJECTS)) +BUILD_DEPS = $(addprefix $(BUILD)/,$(DEPS)) +BUILD_BINARY = $(BUILD)/$(NAME) +BUILD_DIRS = $(sort $(dir $(BUILD_BINARY) $(BUILD_OBJECTS))) + +OUTPUT_BINARY = $(OUTPUT)/$(NAME) +OUTPUT_DIRS = $(sort $(dir $(OUTPUT_BINARY))) + +all: $(OUTPUT_BINARY) + +$(BUILD_DIRS): + @mkdir -p $@ + +$(BUILD_OBJECTS): $(BUILD)/%.o: %.c | $(BUILD_DIRS) + @echo " CC $<" + @$(CC) $(CFLAGS) -MMD -MF $(BUILD)/$*.d -c $< -o $@ + +$(BUILD_BINARY): $(BUILD_OBJECTS) + @echo " LINK $@" + @$(CC) $(CFLAGS) -o $@ $(BUILD_OBJECTS) $(LDFLAGS) + +$(OUTPUT_DIRS): + @mkdir -p $@ + +$(OUTPUT_BINARY): $(BUILD_BINARY) | $(OUTPUT_DIRS) + @echo " BINARY $@" + @cp $< $@ + +.PHONY: clean +clean: + @echo " CLEAN" + @rm -rf $(foreach object,$(basename $(BUILD_OBJECTS)),$(object)*) $(basename $(BUILD_BINARY))* + @rm -rf $(OUTPUT_BINARY) + +.PHONY: distclean +distclean: clean + @echo " DISTCLEAN" + @rm -rf $(BUILD) + +-include $(BUILD_DEPS) diff --git a/pcm-assembler/pcm b/pcm-assembler/pcm new file mode 120000 index 0000000..7c6d901 --- /dev/null +++ b/pcm-assembler/pcm @@ -0,0 +1 @@ +../pcm
\ No newline at end of file diff --git a/pcm-assembler/pcm-assembler.c b/pcm-assembler/pcm-assembler.c new file mode 100644 index 0000000..2e25e65 --- /dev/null +++ b/pcm-assembler/pcm-assembler.c @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2016-2017 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <pcm/pcm.h> +#include "pcm-assembler.h" + +struct pcm_ops_data pcm_ops_data = { + .func_address = NULL, + .func_address_current = NULL, + .fd = -1, +}; + +struct pcm_ops pcm_ops = { + .asm_write = NULL, + .disasm_write = NULL, + .func_address = NULL, + .label_address = NULL, + .data = &pcm_ops_data, +}; + +int pcm_asm_write(void *data, unsigned int value, char *mnemonic) +{ + struct pcm_ops_data *ops_data; + + if (data == NULL) + return -1; + + ops_data = (struct pcm_ops_data *) data; + + if (ops_data->fd < 0) + return -1; + + write(ops_data->fd, &value, sizeof(value)); + + return 0; +} + +int pcm_asm_write_dummy(void *data, unsigned int value, char *mnemonic) +{ + return 0; +} + +int pcm_func_address(void *data, char *func) +{ + struct pcm_func_address *func_address; + + func_address = pcm_func_address_find(func); + if (func_address == NULL) { + if (func[0] != '0') + fprintf(stderr, "Unable to find address for func %s\n", func); + + return -1; + } + + return func_address->address; +} + +int pcm_label_address(void *data, char *label) +{ + struct pcm_label_address *label_address; + + label_address = pcm_label_address_find(label); + if (label_address == NULL) { + if (label[0] != '0') + fprintf(stderr, "Unable to find address for label %s\n", label); + + return -1; + } + + return label_address->address; +} + +int pcm_address_dummy(void *data, char *string) +{ + return -1; +} + +int pcm_func_address_register(char *func, unsigned int address) +{ + struct pcm_func_address *func_address; + struct list_head *list; + + if (func == NULL) + return -1; + + func_address = (struct pcm_func_address *) calloc(1, sizeof(struct pcm_func_address)); + func_address->func = strdup(func); + func_address->address = address; + + list = list_head_alloc(pcm_ops_data.func_address, NULL, (void *) func_address); + pcm_ops_data.func_address = list; + + return 0; +} + +void pcm_func_address_flush(void) +{ + struct pcm_func_address *func_address; + struct list_head *list; + struct list_head *list_prev; + + list = pcm_ops_data.func_address; + while (list != NULL) { + if (list->data != NULL) { + pcm_ops_data.func_address_current = list; + pcm_label_address_flush(); + + func_address = list->data; + + if (func_address->func != NULL) + free(func_address->func); + + free(list->data); + } + + list_prev = list->prev; + + list_head_free(list); + +list_continue: + list = list_prev; + } + + pcm_ops_data.func_address = NULL; +} + +struct pcm_func_address *pcm_func_address_find(char *func) +{ + struct pcm_func_address *func_address; + struct list_head *list; + struct list_head *list_prev; + + if (func == NULL) + return NULL; + + list = pcm_ops_data.func_address; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + func_address = (struct pcm_func_address *) list->data; + + if (func_address->func != NULL && strcmp(func, func_address->func) == 0) + return func_address; + +list_continue: + list = list->prev; + } + + return NULL; +} + +int pcm_func_address_current_set(char *func) +{ + struct pcm_func_address *func_address; + struct list_head *list; + struct list_head *list_prev; + + if (func == NULL) + return -1; + + list = pcm_ops_data.func_address; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + func_address = (struct pcm_func_address *) list->data; + + if (func_address->func != NULL && strcmp(func, func_address->func) == 0) { + pcm_ops_data.func_address_current = list; + return 0; + } + +list_continue: + list = list->prev; + } + + return -1; +} + +int pcm_label_address_register(char *label, unsigned int address) +{ + struct pcm_func_address *func_address; + struct pcm_label_address *label_address; + struct list_head *list; + + if (label == NULL || pcm_ops_data.func_address == NULL || pcm_ops_data.func_address->data == NULL) + return -1; + + func_address = pcm_ops_data.func_address->data; + + label_address = (struct pcm_label_address *) calloc(1, sizeof(struct pcm_label_address)); + label_address->label = strdup(label); + label_address->address = address; + + list = list_head_alloc(func_address->label_address, NULL, (void *) label_address); + func_address->label_address = list; + + return 0; +} + +void pcm_label_address_flush(void) +{ + struct pcm_func_address *func_address; + struct pcm_label_address *label_address; + struct list_head *list; + struct list_head *list_prev; + + if (pcm_ops_data.func_address_current == NULL || pcm_ops_data.func_address_current->data == NULL) + return; + + func_address = pcm_ops_data.func_address_current->data; + + list = func_address->label_address; + while (list != NULL) { + if (list->data != NULL) { + label_address = list->data; + + if (label_address->label != NULL) + free(label_address->label); + + free(list->data); + } + + list_prev = list->prev; + + list_head_free(list); + +list_continue: + list = list_prev; + } + + func_address->label_address = NULL; +} + +struct pcm_label_address *pcm_label_address_find(char *label) +{ + struct pcm_func_address *func_address; + struct pcm_label_address *label_address; + struct list_head *list; + struct list_head *list_prev; + + if (label == NULL || pcm_ops_data.func_address_current == NULL || pcm_ops_data.func_address_current->data == NULL) + return NULL; + + func_address = pcm_ops_data.func_address_current->data; + + list = func_address->label_address; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + label_address = (struct pcm_label_address *) list->data; + + if (label_address->label != NULL && strcmp(label, label_address->label) == 0) + return label_address; + +list_continue: + list = list->prev; + } + + return NULL; +} + +int source_data(char *file, char **data) +{ + struct stat stat_data; + size_t size; + int fd = -1; + int rc; + + if (file == NULL || data == NULL) + return -1; + + rc = stat(file, &stat_data); + if (rc < 0) { + fprintf(stderr, "Invalid file: %s\n", file); + goto error; + } + + size = stat_data.st_size; + *data = malloc(size); + + fd = open(file, O_RDONLY, 0644); + if (fd < 0) { + fprintf(stderr, "Unable to open file: %s\n", file); + goto error; + } + + rc = read(fd, *data, size); + if (rc <= 0) { + fprintf(stderr, "Unable to read file: %s\n", file); + goto error; + } + + rc = size; + goto complete; + +error: + rc = -1; + + if (*data != NULL) + free(*data); + +complete: + if (fd >= 0) + close(fd); + + return rc; +} + +int arguments_parse(int stage, char *arguments[], unsigned int count, unsigned int address) +{ + unsigned int location; + char *mnemonic; + int rc; + + if (arguments == NULL || arguments[0] == NULL || count == 0) + return -1; + + mnemonic = arguments[0]; + + if (strcmp(mnemonic, ".loc") == 0) { + location = strtol(arguments[1], NULL, 16); + + if (address > (location - 1)) { + fprintf(stderr, "Unable to set location to 0x%x from address 0x%x\n", location, address); + return -1; + } + + return pcm_padding_asm(location - 1 - address); + } else if (strcmp(mnemonic, ".func") == 0) { + if (stage == 0) { + rc = pcm_func_address_register(arguments[1], address); + if (rc < 0) + return -1; + } + + rc = pcm_func_address_current_set(arguments[1]); + if (rc < 0) + return -1; + + return 0; + } else if (strcmp(mnemonic, ".label") == 0) { + rc = pcm_label_address_register(arguments[1], address); + if (rc < 0) + return -1; + + return 0; + } else { + return 1 + pcm_op_asm(arguments, count); + } +} + +int assemble(int stage, char *data, size_t size) +{ + unsigned int address; + unsigned int count; + char *arguments[PCM_ASSEMBLER_ARGUMENTS_MAX]; + char *argument; + char *token; + char *line = NULL; + int rc; + + if (data == NULL || size == 0) + return -1; + + if (stage == 0) { + pcm_ops.asm_write = pcm_asm_write_dummy; + pcm_ops.func_address = pcm_address_dummy; + pcm_ops.label_address = pcm_address_dummy; + } else { + pcm_ops.asm_write = pcm_asm_write; + pcm_ops.func_address = pcm_func_address; + pcm_ops.label_address = pcm_label_address; + } + + address = 0; + + token = strtok(data, "\n"); + + while (token != NULL) { + line = strdup(token); + + argument = strtok(line, " "); + count = 0; + + while (argument != NULL && count < PCM_ASSEMBLER_ARGUMENTS_MAX) { + arguments[count++] = argument; + argument = strtok(NULL, " "); + } + + if (count == PCM_ASSEMBLER_ARGUMENTS_MAX) + goto error; + + rc = arguments_parse(stage, arguments, count, address); + if (rc < 0) + goto error; + + address += rc; + + free(line); + line = NULL; + + token = strtok(token + strlen(token) + 1, "\n"); + } + + rc = 0; + goto complete; + +error: + rc = -1; + + if (line != NULL) + free(line); + +complete: + return rc; +} + +int main(int argc, char *argv[]) +{ + char *data = NULL; + size_t size; + int fd = -1; + int rc; + int i; + + if (argc < 3 || argv[1] == NULL || argv[2] == NULL) + return 1; + + rc = source_data(argv[1], &data); + if (rc < 0 || data == NULL) + goto error; + + size = rc; + + rc = pcm_ops_register(&pcm_ops); + if (rc < 0) { + fprintf(stderr, "Unable to set PCM OPS\n"); + goto error; + } + + rc = assemble(0, data, size); + if (rc < 0) { + fprintf(stderr, "Unable to assemble source\n"); + goto error; + } + + fd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644); + if (fd < 0) { + fprintf(stderr, "Unable to open output file\n"); + } + + pcm_ops_data.fd = fd; + + rc = assemble(1, data, size); + if (rc < 0) { + fprintf(stderr, "Unable to assemble source\n"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = 1; + +complete: + if (fd >= 0) + close(fd); + + pcm_func_address_flush(); + + if (data != NULL) + free(data); + + return rc; +} diff --git a/pcm-assembler/pcm-assembler.h b/pcm-assembler/pcm-assembler.h new file mode 100644 index 0000000..ef7a655 --- /dev/null +++ b/pcm-assembler/pcm-assembler.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016-2017 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _PCM_ASSEMBLER_H_ +#define _PCM_ASSEMBLER_H_ + +/* + * Values + */ + +#define PCM_ASSEMBLER_ARGUMENTS_MAX 64 + +/* + * Structures + */ + +struct pcm_label_address { + char *label; + unsigned int address; +}; + +struct pcm_func_address { + char *func; + unsigned int address; + + struct list_head *label_address; +}; + +struct pcm_ops_data { + struct list_head *func_address; + struct list_head *func_address_current; + + int fd; +}; + +/* + * Functions + */ + +int pcm_asm_write(void *data, unsigned int value, char *mnemonic); +int pcm_asm_write_dummy(void *data, unsigned int value, char *mnemonic); +int pcm_func_address(void *data, char *func); +int pcm_label_address(void *data, char *func); +int pcm_address_dummy(void *data, char *string); + +int pcm_func_address_register(char *func, unsigned int address); +void pcm_func_address_flush(void); +struct pcm_func_address *pcm_func_address_find(char *func); +int pcm_func_address_current_set(char *func); +int pcm_label_address_register(char *label, unsigned int address); +void pcm_label_address_flush(void); +struct pcm_label_address *pcm_label_address_find(char *label); + +#endif diff --git a/pcm-disasm/pcm-disasm.c b/pcm-disasm/pcm-disasm.c index 2df3d98..afe1b73 100644 --- a/pcm-disasm/pcm-disasm.c +++ b/pcm-disasm/pcm-disasm.c @@ -30,6 +30,8 @@ struct pcm_ops pcm_ops = { .asm_write = NULL, .disasm_write = pcm_disasm_write, + .func_address = NULL, + .label_address = NULL, .data = NULL, }; @@ -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); +} @@ -49,11 +49,21 @@ * Structures */ +/* Utils */ + +struct list_head { + struct list_head *next; + struct list_head *prev; + void *data; +}; + /* PCM OPS */ struct pcm_ops { int (*asm_write)(void *data, unsigned int value, char *mnemonic); int (*disasm_write)(void *data, unsigned int value, char *mnemonic); + int (*func_address)(void *data, char *func); + int (*label_address)(void *data, char *label); void *data; }; @@ -76,15 +86,25 @@ struct pcm_op_desc { int binary_print(unsigned int value); +struct list_head *list_head_alloc(struct list_head *prev, struct list_head *next, void *data); +void list_head_free(struct list_head *list); + /* PCM OPS */ int pcm_ops_register(struct pcm_ops *ops); +void pcm_ops_unregister(void); int pcm_ops_asm_write(unsigned int value, char *mnemonic); int pcm_ops_disasm_write(unsigned int value, char *mnemonic); +int pcm_ops_func_address(char *func); +int pcm_ops_label_address(char *func); /* PCM OP codes */ int pcm_op_asm(char *arguments[], unsigned int count); int pcm_op_disasm(unsigned int *arguments, unsigned int count); +/* PCM padding */ + +int pcm_padding_asm(unsigned int padding); + #endif |