diff options
Diffstat (limited to 'pcm-assembler')
-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 |
4 files changed, 639 insertions, 0 deletions
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 |