MT8173 PCM assembler introduction
authorPaul Kocialkowski <contact@paulk.fr>
Thu, 23 Feb 2017 21:41:04 +0000 (22:41 +0100)
committerPaul Kocialkowski <contact@paulk.fr>
Thu, 23 Feb 2017 21:41:35 +0000 (22:41 +0100)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
.gitignore
Makefile [new file with mode: 0644]
pcm-analysis/pcm-analysis.c
pcm-asm/pcm-asm.c
pcm-assembler/Makefile [new file with mode: 0644]
pcm-assembler/pcm [new symlink]
pcm-assembler/pcm-assembler.c [new file with mode: 0644]
pcm-assembler/pcm-assembler.h [new file with mode: 0644]
pcm-disasm/pcm-disasm.c
pcm/pcm.c
pcm/pcm.h

index 5434ccb..378eac2 100644 (file)
@@ -1,2 +1 @@
 build
-mt8173-pcm
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 ;)
index d7d4699..1558c01 100644 (file)
@@ -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,
 };
 
index 665f344..54595fd 100644 (file)
@@ -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 (file)
index 0000000..e3405a7
--- /dev/null
@@ -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 (symlink)
index 0000000..7c6d901
--- /dev/null
@@ -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 (file)
index 0000000..2e25e65
--- /dev/null
@@ -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 (file)
index 0000000..ef7a655
--- /dev/null
@@ -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
index 2df3d98..afe1b73 100644 (file)
@@ -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,
 };
 
index 35a6faa..09ec0a8 100644 (file)
--- a/pcm/pcm.c
+++ b/pcm/pcm.c
@@ -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);
+}
index d7a4cad..8f31f35 100644 (file)
--- a/pcm/pcm.h
+++ b/pcm/pcm.h
  * 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