summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2017-02-23 22:41:04 +0100
committerPaul Kocialkowski <contact@paulk.fr>2017-02-23 22:41:35 +0100
commitebbc17fb5fe384349f39560006681628d47069a3 (patch)
tree33e891c2aba4e937aa140951ff1e9ba61db17fcb
parent6e60012b1b3bd66b9ec96efb76496ea4dc2b8b0c (diff)
downloadmt8173-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--.gitignore1
-rw-r--r--Makefile27
-rw-r--r--pcm-analysis/pcm-analysis.c2
-rw-r--r--pcm-asm/pcm-asm.c2
-rw-r--r--pcm-assembler/Makefile68
l---------pcm-assembler/pcm1
-rw-r--r--pcm-assembler/pcm-assembler.c502
-rw-r--r--pcm-assembler/pcm-assembler.h68
-rw-r--r--pcm-disasm/pcm-disasm.c2
-rw-r--r--pcm/pcm.c157
-rw-r--r--pcm/pcm.h20
11 files changed, 815 insertions, 35 deletions
diff --git a/.gitignore b/.gitignore
index 5434ccb..378eac2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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,
};
diff --git a/pcm/pcm.c b/pcm/pcm.c
index 35a6faa..09ec0a8 100644
--- 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);
+}
diff --git a/pcm/pcm.h b/pcm/pcm.h
index d7a4cad..8f31f35 100644
--- a/pcm/pcm.h
+++ b/pcm/pcm.h
@@ -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