Add argp, and executing functionality

This commit is contained in:
XOR 2023-10-17 16:41:38 +02:00
parent 0c8d7b57cb
commit b42d5e7e67
11 changed files with 269 additions and 28 deletions

3
.gitignore vendored
View file

@ -57,6 +57,7 @@ dkms.conf
*.eipa
!test*.eipa
*.eipaimg
build/*
#Code editor
.vscode/*
@ -67,4 +68,4 @@ compile_commands.json
*.*~
#Code analysis
softwipe*.*
softwipe*.*

View file

@ -7,7 +7,7 @@ LIBS :=
OBJECT_FILES := $(patsubst %.c, %.o, $(wildcard $(SRC_DIR)/*.c))
HEADER_FILES := $(wildcard $(HEADER_DIR)/*.h)
OBJECT_FILES := $(patsubst $(SRC_DIR)/%, $(BUILD_DIR)/%, $(OBJECT_FILES))
MAIN_EXE_NAME := eipaemulator
MAIN_EXE_NAME := eipaemu
all build/eipaemulator: $(OBJECT_FILES)
$(CC) $(CFLAGS) $^ $(LIBS) -o $(BUILD_DIR)/$(MAIN_EXE_NAME)

Binary file not shown.

9
header/argp_commons.h Executable file
View file

@ -0,0 +1,9 @@
#ifndef _ARGP_COMMONS_H_
#define _ARGP_COMMONS_H_
#include "../header/common.h"
#define ARGUMENT_DOC "INPUT_FILE"
#define LONG_DOC "options:"
#endif

41
header/common.h Executable file
View file

@ -0,0 +1,41 @@
/*
This code is part of the EIPA Platform
Here, common macros are specified
*/
#ifndef _COMMON_H_
#define _COMMON_H_
// Maximum Memory Adresses
#define MAX_MEMORY 268435456
// Intitial size and grow size for dynamic buffers
#define TABLE_INIT_SIZE 50
#define TABLE_GROW_SIZE 30
#define VER_MAJOR "0"
#define VER_MINOR "0"
#define VER_PATCH "1"
// alpha, beta or stable
#define TAG "alpha"
#define INSTR_INP 0b0001
#define INSTR_OUT 0b0010
#define INSTR_LDA 0b0011
#define INSTR_STA 0b0100
#define INSTR_INC 0b0101
#define INSTR_DEC 0b0110
#define INSTR_JPP 0b0111
#define INSTR_JPZ 0b1000
#define INSTR_JPN 0b1001
#define INSTR_JPU 0b1010
#define INSTR_EOJ 0b1011
#define ADRESS_BITS 0b00001111111111111111111111111111
// const char *argp_program_bug_address = "eipabugs@outlook.com";
#define EIPA_BUG_ADRESS "eipabugs@outlook.com"
#endif

13
header/execute.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef _EXECUTE_H_
#define _EXECUTE_H_
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
// Executes given memory
int execute(uint32_t *memory);
#endif

9
header/helpers.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef _HELPER_H_
#define _HELPER_H_
#include <stdint.h>
#include <stdio.h>
void print_target_code(uint32_t *target_code);
#endif

97
src/execute.c Normal file
View file

@ -0,0 +1,97 @@
#include "../header/execute.h"
int execute(uint32_t *memory)
{
uint32_t instr_ptr = 0;
uint32_t instr_curr;
uint32_t cpu_register = 0;
while((instr_curr = memory[instr_ptr]) >> 28 != INSTR_EOJ)
{
uint8_t op_code = memory[instr_ptr] >> 28; // Get only the first 4 bits
uint32_t adress = memory[instr_ptr] & ADRESS_BITS; // Discard the first 4 bits
// This check should be unnecessary when using the official EIPA Assembler, but
// some people might want to hand-craft their EIPA Images
if(adress > MAX_MEMORY)
{
printf("ERROR: Adress on instruction %u is too big\n", instr_ptr);
return 1;
}
// Run the instruction
switch(op_code)
{
case INSTR_INP:
{
printf("Input: ");
int check = scanf("%u", memory + adress);
fflush(stdin);
if(!check)
{
printf("ERROR: Received invalid input on a INP instruction\n");
return 1;
}
instr_ptr++;
break;
}
case INSTR_OUT:
printf("%u\n", memory[adress]);
instr_ptr++;
break;
case INSTR_LDA:
cpu_register = memory[adress];
instr_ptr++;
break;
case INSTR_STA:
memory[adress] = cpu_register;
instr_ptr++;
break;
case INSTR_INC:
cpu_register++;
instr_ptr++;
break;
case INSTR_DEC:
cpu_register--;
instr_ptr++;
break;
case INSTR_JPP:
if(cpu_register > 0)
{
instr_ptr = adress;
}
else
{
instr_ptr++;
}
break;
case INSTR_JPZ:
if(cpu_register == 0)
{
instr_ptr = adress;
}
else
{
instr_ptr++;
}
break;
case INSTR_JPN:
if(cpu_register < 0)
{
instr_ptr = adress;
}
else
{
instr_ptr++;
}
break;
case INSTR_JPU:
instr_ptr = adress;
break;
default:
printf("ERROR: Unknown opcode %u\n", op_code);
}
}
return 0;
}

16
src/helpers.c Normal file
View file

@ -0,0 +1,16 @@
#include "../header/helpers.h"
void print_target_code(uint32_t *target_code)
{
int instruction_index = 0;
while (target_code[instruction_index] != 0)
{
int i = 0;
for (i = (sizeof(target_code[instruction_index]) * 8) - 1; i >= 0; i--)
{
putchar(target_code[instruction_index] & (1u << i) ? '1' : '0');
}
printf("\n");
instruction_index++;
}
}

View file

@ -2,40 +2,95 @@
// Read an EIPA image and print it out in Binary form
#ifndef WIN_COMPILE
#include <argp.h>
#else
#include "../header/argp/argp.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#define MAX_MEMORY 268435456
#include "../header/argp_commons.h"
#include "../header/common.h"
#include "../header/helpers.h"
#include "../header/execute.h"
void print_target_code(__uint32_t *target_code)
const char *argp_program_version =
VER_MAJOR "." VER_MINOR "." VER_PATCH " || " TAG;
const char *argp_program_bug_address = EIPA_BUG_ADRESS;
// Here, the argumets get stored by the parser, so acess them from here
struct cmd_arguments
{
int instruction_index = 0;
while (target_code[instruction_index] != 0)
char *input_file;
};
// Parses the command line options & arguments
static error_t parser_function(int key, char *arg, struct argp_state *state)
{
struct cmd_arguments *save_arguments = state->input;
switch (key)
{
int i = 0;
for (i = (sizeof(target_code[instruction_index]) * 8) - 1; i >= 0; i--)
case ARGP_KEY_ARG:
// If we got more than one non-option argument
if (state->arg_num >= 1)
{
putchar(target_code[instruction_index] & (1u << i) ? '1' : '0');
argp_usage(state);
}
printf("\n");
instruction_index++;
save_arguments->input_file = arg;
break;
case ARGP_KEY_END:
// If we didn't receive 1 Argument yet
if (state->arg_num < 1)
{
argp_usage(state);
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
}
int main(int argc, char const *argv[])
{
if(argc < 2)
{
printf("Specify input file\n");
}
FILE *input = fopen(argv[1], "r");
if(input == NULL) return -1;
__uint32_t *target_code = malloc(MAX_MEMORY*sizeof(target_code));
fread(target_code, sizeof(target_code), MAX_MEMORY, input);
print_target_code(target_code);
return 0;
}
// This array stores structs containing information about the cli options
static struct argp_option argp_options[] = {{0}};
// Contains the neccesary stuff for argp
static struct argp argument_parser =
{
.options = argp_options,
.parser = parser_function,
.args_doc = ARGUMENT_DOC,
.doc = LONG_DOC};
int main(int argc, char **argv)
{
// Parse CLI Arguments
// set defaults
struct cmd_arguments arguments;
arguments.input_file = "";
if (argp_parse(&argument_parser, argc, argv, 0, 0, &arguments) != 0)
{
printf("Error: Failed to parse CLI Arguments - Error code\n");
return EXIT_FAILURE;
}
FILE *input = fopen(arguments.input_file, "r");
if (input == NULL)
return -1;
// Allocate the memory of the Emulated device
uint32_t *memory = malloc(MAX_MEMORY * sizeof(memory));
// Load the binary into memory
fread(memory, sizeof(memory), MAX_MEMORY, input);
execute(memory);
free(memory);
return 0;
}

BIN
test/loopprint.eimg Normal file

Binary file not shown.