Initial Commit

This commit is contained in:
Thomas Fehmel
2016-10-18 14:21:45 +02:00
commit 657a54ba18
176 changed files with 43750 additions and 0 deletions

104
assembler/Makefile Normal file
View File

@@ -0,0 +1,104 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
-include ../makefile.init
RM := rm -rf
CC = gcc -g
IDIR=inc
ODIR=obj
SDIR=src
CFLAGS = -Wall
_DEPS = command.h files.h labels.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJS = output.o msg.o check.o label.o main.o handle_o.o handle_oi.o handle_omi.o handle_omr.o handle_omr2.o handle_or2.o handle_or2i.o handle_or3.o handle_ori.o handle_or.o handle_om.o
OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS))
_FLEX_OBJ = asm.tab.o lex.yy.o
FLEX_OBJS = $(patsubst %,$(ODIR)/%,$(_FLEX_OBJ))
_FLEX_COMPILES = asm.tab.c asm.tab.h lex.yy.c
FLEX_COMPILES = $(patsubst %,$(ODIR)/%,$(_FLEX_COMPILES))
# All Target
all: $(ODIR) asm
$(ODIR):
mkdir -p $(ODIR)
# Tool invocations
asm: flex bison $(FLEX_OBJS) $(OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C Linker'
$(CC) -o "asm" -I"inc/" $(OBJS) $(FLEX_OBJS) $(CFLAGS)
@echo 'Finished building target: $@'
@echo ' '
bison: $(SDIR)/asm.y
bison -o obj/asm.tab.c -d $(SDIR)/asm.y
flex: $(SDIR)/asm.l
flex -o obj/lex.yy.c $(SDIR)/asm.l
# Object Files
#obj/%.o: src/%.c $(DEPS)
# $(CC) -c -o $@ $< $(CFLAGS)
obj/asm.tab.c: bison
obj/asm.tab.h: bison
obj/lex.yy.c : flex
$(ODIR)/output.o: $(SDIR)/output.c
$(CC) -c $(CFLAGS) -o $@ $<
$(ODIR)/msg.o: $(SDIR)/msg.c
$(CC) -c $(CFLAGS) -o $@ $<
$(ODIR)/check.o: $(SDIR)/check.c
$(CC) -c $(CFLAGS) -o $@ $<
$(ODIR)/main.o: $(SDIR)/main.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/label.o: $(SDIR)/label.c
$(CC) -c $(CFLAGS) -o $@ $<
$(ODIR)/handle_or3.o: $(SDIR)/handle_or3.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_or2i.o: $(SDIR)/handle_or2i.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_ori.o: $(SDIR)/handle_ori.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_omr2.o: $(SDIR)/handle_omr2.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_omi.o: $(SDIR)/handle_omi.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_omr.o: $(SDIR)/handle_omr.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_oi.o: $(SDIR)/handle_oi.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_o.o: $(SDIR)/handle_o.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_or2.o: $(SDIR)/handle_or2.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_or.o: $(SDIR)/handle_or.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/handle_om.o: $(SDIR)/handle_om.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/asm.tab.o: $(ODIR)/asm.tab.c
$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/lex.yy.o: $(ODIR)/lex.yy.c
$(CC) -c -o $@ $< $(CFLAGS)
# Other Targets
clean:
-$(RM) $(OBJS) $(FLEX_OBJS) $(FLEX_COMPILES) asm
-@echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets

33
assembler/inc/check.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* This file declares functions for
* - checking instruction parameters for their validity
*/
#ifndef CHECK_H_
#define CHECK_H_
/*
* returns a valid register number or throws error if r out of range
* r: number of register to be checked
*/
int reg(int r);
/*
* returns a valid 8bit signed value or throws error if imm out of range
* imm: immediate to be checked
*/
int signed8(int imm);
/*
* returns a valid 4bit unsigned value or throws error if imm out of range
* imm: immediate to be checked
*/
int unsigned4(int imm);
/*
* returns a valid 32bit signed value or throws error if imm out of range
* imm: immediate to be checked
*/
int word(int imm);
#endif /* CHECK_H_ */

85
assembler/inc/global.h Normal file
View File

@@ -0,0 +1,85 @@
/*
* This file
* - defines globally used constants
* - defines enum types
* - declares globally used variables
*/
#ifndef GLOBAL_H_
#define GLOBAL_H_
#include <stdio.h>
// maximal filename length
#define MAX_FILENAME_LENGTH (128);
// nop instruction for 16bit
#define nop16 (0b0000000000000000)
// number of link register
#define lr_num (13)
// all supported modes
typedef enum {
mode_eq, mode_neq, mode_ge, mode_gg, mode_le, mode_ll,
mode_cond_true, mode_cond_unconditional
} opmode_t;
// all supported (pseudo) instructions and directives
typedef enum {
op_add, op_sub, op_and, op_or, op_xor, op_lsh, op_rsh, op_addi,
op_cmp, op_ssr,
op_ldr, op_ld08, op_ld16, op_ld32, op_st08, op_st16, op_st32,
op_brt, op_br, op_call, op_trap, op_reti,
op_tst,
op_mov, op_nop, op_ret, op_clr,
op_word, // used for direct placement of words (=32 bit)
op_addr, // used for setting of current address (forward movement only)
op_align, // used for aligning next instruction/immediate value
} op_t;
// input file
extern FILE* f_in;
// output file
extern FILE* f_out;
// map file, 0 if unused
extern FILE* f_map;
// input filename
char* inputfile;
// do verbose output, boolean value
int verbose;
// automatically align 32bit instructions, boolean value
int autoalign;
// fill branch delay slot with nop, boolean value
int fillbds;
// continue even after error, boolean value
int continueonerror;
// error has happened in first run, boolean value
int errorhappened;
// buffer of the currently parsed line
char linebuf[500];
/* in first run, boolean value
* 1 if in first run
* 0 if in second run
*/
int isfirstrun;
// current address (byte address)
int address;
// destructor, closes programs and cleans up memory
// exitvalue: value for exit
void destruct();
#endif /* GLOBAL_H_ */

99
assembler/inc/handle.h Normal file
View File

@@ -0,0 +1,99 @@
/*
* This file declares functions for
* - handling of instructions
*/
#ifndef HANDLE_H_
#define HANDLE_H_
#include "global.h"
/*
* outputs instruction to output for instructions width or3 instruction type
* opcode: opcode of instruction
* r1: register 1
* r2: register 2
* r3: register 3
*/
void handle_or3(op_t opcode, int r1, int r2, int r3);
/*
* outputs instruction to output for instructions width ori instruction type
* opcode: opcode of instruction
* r1: register 1
* imm: immediate
*/
void handle_ori(op_t opcode, int r1, int imm);
/*
* outputs instruction to output for instructions width omr2 instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* r1: register 1
* r2: register 2
*/
void handle_omr2(op_t opcode, opmode_t mode, int r1, int r2);
/*
* outputs instruction to output for instructions width omi instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* imm: immediate
*/
void handle_omi(op_t opcode, opmode_t mode, int imm);
/*
* outputs instruction to output for instructions width omr instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* r1: register 1
*/
void handle_omr(op_t opcode, opmode_t mode, int r1);
/*
* outputs instruction to output for instructions width oi instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* imm: immediate
*/
void handle_oi(op_t opcode, int imm);
/*
* outputs instruction to output for instructions width o instruction type
* opcode: opcode of instruction
*/
void handle_o(op_t opcode);
/*
* outputs instruction to output for instructions width or instruction type
* opcode: opcode of instruction
* r1: register 1
*/
void handle_or(op_t opcode, int r1);
/*
* outputs instruction to output for instructions width or2 instruction type
* opcode: opcode of instruction
* r1: register 1
* r2: register 2
*/
void handle_or2(op_t opcode, int r1, int r2);
/*
* outputs instruction to output for instructions width or2i instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* r1: register 1
* r2: register 2
* imm: immediate
*/
void handle_or2i(op_t opcode, int r1, int r2, int imm);
/*
* outputs instruction to output for instructions width om instruction type
* opcode: opcode of instruction
* mode: mode of instruction
*/
void handle_om(op_t opcode, opmode_t mode);
#endif /* HANDLE_H_ */

51
assembler/inc/label.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* This file declares functions and declares variables for
* - handling of labels
* and defines constants, types.
*/
#ifndef LABEL_H_
#define LABEL_H_
// maximum length of label names
#define LABEL_MAX_NAME_LENGTH (64)
// struct of a label item in list
typedef struct {
// name of the label
char name[LABEL_MAX_NAME_LENGTH];
// address the label points to
int address;
// next item in list
void* next;
} label_t;
// head of list
label_t* label_listhead;
/*
* adds a label to the list
* name: name of the label
* address: address the label points to
*/
void label_add(char* name, int address);
/*
* returns absolute address of a label
* name: name of the label
* return: absolute address of label or -1 if label not found
*/
int label_absolute(char* name);
/*
* returns relative address of a label
* name: name of the label
* return: relative address of label or -1 if label not found
*/
int label_relative(char* name);
/*
* frees the allocated space used for the list of labels
*/
void label_free();
#endif /* LABEL_H_ */

21
assembler/inc/msg.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* This file declares functions for
* - checking instruction parameters for range
*/
#ifndef MSG_H_
#define MSG_H_
/*
* verbose output (if flag is set)
* msg: verbose message
*/
void yyverbose(char* msg);
/*
* error handler
* msg: error message
*/
void yyerror(char* msg);
#endif /* MSG_H_ */

36
assembler/inc/output.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* This file declares functions for
* - writing to output file
* - writing to map file
*/
#ifndef OUTPUT_H_
#define OUTPUT_H_
/*
* outputs a number of length bits, given in instr to the output stream and inserts a linebreak after each 32bit
* instr: number to be printed
* length: number of bits to be printed
*/
void output_instr(int instr, int length);
/*
* outputs a number of 16bits and updates address
* instr: number to be printed
*/
void output_instr16(int instr);
/*
* outputs a number of 32bits and updates address
* instr: number to be printed
*/
void output_instr32(int instr);
/*
* outputs a line to the mapfile (if specified and if in first run)
* s: string to be put to mapfile
*/
void output_line(char* s);
#endif /* OUTPUT_H_ */

105
assembler/src/asm.l Normal file
View File

@@ -0,0 +1,105 @@
%option nodefault yylineno
%{
#include <string.h>
#include "../inc/msg.h"
#include "../inc/label.h"
#include "../inc/global.h"
#include "../inc/output.h"
#include "../obj/asm.tab.h"
void yyerror(char *s);
union yylval {
op_t op;
int i;
};
%}
LABELNAME [_a-zA-Z][_a-zA-Z0-9]*
%%
\n.* { strncpy(linebuf, yytext+1, sizeof(linebuf)); /* save the next line */
yyless(1); /* give back all but the \n to rescan */
output_line(linebuf); return EOL;
}
\r\n.* {
strncpy(linebuf, yytext+2, sizeof(linebuf)); /* save the next line */
yyless(2); /* give back all but the \r\n to rescan */
output_line(linebuf); return EOL;
}
<<EOF>> { yyterminate(); return EOL; }
[ \t] { /* ignore whitespace*/ }
[,] { return ','; }
"//".*$ { /* comment */ }
[r][0-9]+ { yylval.i = atoi(yytext+1); return REGISTER; }
(sp) { yylval.i = 12; return REGISTER; }
(lr) { yylval.i = 13; return REGISTER; }
(sr) { yylval.i = 14; return REGISTER; }
(pc) { yylval.i = 15; return REGISTER; }
[+-]?"0x"?[0-9A-F]+ { yylval.i = strtol(yytext, 0, 0); return IMMEDIATE; }
(add) { yylval.op = op_add; return MNEMONIC; }
(sub) { yylval.op = op_sub; return MNEMONIC; }
(and) { yylval.op = op_and; return MNEMONIC; }
(or) { yylval.op = op_or; return MNEMONIC; }
(xor) { yylval.op = op_xor; return MNEMONIC; }
(lsh) { yylval.op = op_lsh; return MNEMONIC; }
(rsh) { yylval.op = op_rsh; return MNEMONIC; }
(addi) { yylval.op = op_addi; return MNEMONIC; }
(cmp) { yylval.op = op_cmp; return MNEMONIC; }
(ssr) { yylval.op = op_ssr; return MNEMONIC; }
(ldr) { yylval.op = op_ldr; return MNEMONIC; }
(ld08) { yylval.op = op_ld08; return MNEMONIC; }
(ld16) { yylval.op = op_ld16; return MNEMONIC; }
(ld32) { yylval.op = op_ld32; return MNEMONIC; }
(st08) { yylval.op = op_st08; return MNEMONIC; }
(st16) { yylval.op = op_st16; return MNEMONIC; }
(st32) { yylval.op = op_st32; return MNEMONIC; }
(brt) { yylval.op = op_brt; return MNEMONIC; }
(br) { yylval.op = op_br; return MNEMONIC; }
(call) { yylval.op = op_call; return MNEMONIC; }
(trap) { yylval.op = op_trap; return MNEMONIC; }
(reti) { yylval.op = op_reti; return MNEMONIC; }
(tst) { yylval.op = op_tst; return MNEMONIC; }
(mov) { yylval.op = op_mov; return MNEMONIC; }
(nop) { yylval.op = op_nop; return MNEMONIC; }
(ret) { yylval.op = op_ret; return MNEMONIC; }
(clr) { yylval.op = op_clr; return MNEMONIC; }
(\.word) { yylval.op = op_word; return MNEMONIC; }
(\.address) { yylval.op = op_addr; return MNEMONIC; }
(\.align) { yylval.m = op_align; return MNEMONIC; }
(eq) { yylval.m = mode_eq; return MODE; }
(neq) { yylval.m = mode_neq; return MODE; }
(gg) { yylval.m = mode_gg; return MODE; }
(ge) { yylval.m = mode_ge; return MODE; }
(ll) { yylval.m = mode_ll; return MODE; }
(le) { yylval.m = mode_le; return MODE; }
(true) { yylval.m = mode_cond_true; return MODE; }
(always) { yylval.m = mode_cond_unconditional; return MODE; }
{LABELNAME} { strcpy(yylval.s, yytext); return LABEL; }
(\>{LABELNAME}) { yylval.i = label_relative(yytext+1); return IMMEDIATE; }
(\={LABELNAME}) { yylval.i = label_absolute(yytext+1); return IMMEDIATE; }
: { return ':'; }
. { yyerror("unexpected input"); }
%%
int yywrap() { return 1; }

59
assembler/src/asm.y Normal file
View File

@@ -0,0 +1,59 @@
%{
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/handle.h"
#include "../inc/label.h"
#include "../inc/global.h"
%}
%union {
int i;
op_t op;
opmode_t m;
char s[32];
}
%token EOL
%token <op> MNEMONIC
%token <m> MODE
%token <i> REGISTER
%token <i> IMMEDIATE
%token <s> LABEL
%%
line:
| line lbldef
| line r3-line EOL
| line r2-line EOL
| line ri-line EOL
| line r2i-line EOL
| line mr2-line EOL
| line mi-line EOL
| line mr-line EOL
| line i-line EOL
| line o-line EOL
| line or-line EOL
| line om-line EOL
| line EOL
| line error-line EOL
;
r3-line: MNEMONIC REGISTER ',' REGISTER ',' REGISTER { handle_or3($1, $2, $4, $6); }
r2-line: MNEMONIC REGISTER ',' REGISTER { handle_or2($1, $2, $4); }
ri-line: MNEMONIC REGISTER ',' IMMEDIATE { handle_ori($1, $2, $4); }
r2i-line: MNEMONIC REGISTER ',' REGISTER ',' IMMEDIATE { handle_or2i($1, $2, $4, $6); }
mr2-line: MNEMONIC MODE REGISTER ',' REGISTER { handle_omr2($1, $2, $3, $5); }
mi-line: MNEMONIC MODE IMMEDIATE { handle_omi($1, $2, $3); }
mr-line: MNEMONIC MODE REGISTER { handle_omr($1, $2, $3); }
i-line: MNEMONIC IMMEDIATE { handle_oi($1, $2); }
o-line: MNEMONIC { handle_o($1); }
or-line: MNEMONIC REGISTER { handle_or($1, $2); }
om-line: MNEMONIC MODE { handle_om($1, $2); }
lbldef: LABEL ':' { label_add($1, address); }
error-line: error { }
%%

70
assembler/src/check.c Normal file
View File

@@ -0,0 +1,70 @@
/*
* This file implements functions for
* - checking instruction parameters for their validity
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/global.h"
/*
* returns a valid register number or throws error if r out of range
* r: number of register to be checked
*/
int reg(int r) {
if ((r >= 0) && (r <= 15)) {
// in valid range
return r;
} else {
// out of valid range
yyerror("register number out of range");
return 0;
}
}
/*
* returns a valid 8bit signed value or throws error if imm out of range
* imm: immediate to be checked
*/
int signed8(int imm) {
if ((imm >= -128) && (imm <= 127)) {
// in valid range
return imm & 0xFF;
} else {
// out of valid range
yyerror(
"immediate value out of bounds. expecting 8bit signed immediate.");
return 0;
}
}
/*
* returns a valid 4bit unsigned value or throws error if imm out of range
* imm: immediate to be checked
*/
int unsigned4(int imm) {
if ((imm >= 0) && (imm <= 15)) {
// in valid range
return imm & 0x0F;
} else {
// out of valid range
yyerror(
"immediate value out of bounds. expecting 4bit unsigned immediate.");
return 0;
}
}
/*
* returns a valid 32bit signed value or throws error if imm out of range
* imm: immediate to be checked
*/
int word(int imm) {
if ((imm >= -2147483648) && (imm <= 2147483647)) {
// in valid range
return imm;
} else {
// out of valid range
yyerror(
"immediate value out of bounds. expecting 32bit signed immediate.");
return 0;
}
}

72
assembler/src/handle_o.c Normal file
View File

@@ -0,0 +1,72 @@
/*
* This file implements functions for
* - handling of instructions of type o
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width o instruction type
* opcode: opcode of instruction
*/
void handle_o(op_t opcode) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_reti: // reti instruction
// opcode: bct
instr |= (0b1100) << 12;
// mode: reti
instr |= (0b0000) << 8;
// output instruction
output_instr16(instr);
break;
case op_ret: // return instruction (unconditional)
// model with branch always to lr
// opcode: branch
instr |= (0b1100) << 12;
// mode: to register
instr |= (0b0110) << 8;
// register a: LR
instr |= lr_num << 4;
// output instruction
output_instr16(instr);
// fill branch delay with nop if flag is set
if (fillbds) {
yyverbose("filled branch delay slot with nop.");
output_instr16(nop16);
}
break;
case op_nop: // no operation instruction
// model with or r0, r0, r0
// opcode: or
instr |= (0b0000) << 12;
// all registers: r0
// output instruction
output_instr16(instr);
break;
case op_align: // make address be word-aligned
if ((address % 4) != 0) {
// not word-aligned, insert nop
output_instr16(nop16);
} else {
// already word-aligned, put verbose message
yyverbose("Already aligned, ignoring .align directive.");
}
break;
default: // invalid opcode for o-instruction
yyerror("opcode not compatible with o syntax");
break;
}
}

90
assembler/src/handle_oi.c Normal file
View File

@@ -0,0 +1,90 @@
/*
* This file implements functions for
* - handling of instructions of type i
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width oi instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* imm: immediate
*/
void handle_oi(op_t opcode, int imm) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_word: // add immediate word
// immediate word
instr = word(imm);
// output instruction
output_instr32(instr);
break;
case op_addr: // move to new address
if (imm >= address) {
// if new address is larger than current address
while (imm - 2 >= address) {
// add nop until next new address is equal to immediate value
output_instr16(nop16);
}
} else {
// new address smaller than current address
// backward setting of address not possible
yyerror("can't move backwards with .address");
}
break;
case op_trap: // trap instruction
// opcode: bct
instr |= (0b1100) << 12;
// mode: trap
instr |= (0b1100) << 8;
// immediate: irq number
instr |= signed8(imm) << 0;
// output
output_instr16(instr);
break;
case op_br: // branch instruction to immediate (unconditional)
// opcode: bct
instr |= (0b1100) << 12;
// immediate: branch target
instr |= signed8(imm) << 0;
// mode: branch and unconditional to immediate
instr |= (0b0100) << 8;
// output
output_instr16(instr);
// fill branch delay with nop if flag is set
if (fillbds) {
yyverbose("filled branch delay slot with nop.");
output_instr16(nop16);
}
break;
case op_call: // call instruction to immediate (unconditional)
// opcode: bct
instr |= (0b1100) << 12;
// immediate: call target
instr |= signed8(imm) << 0;
// mode: call unconditional to immediate
instr |= (0b1000) << 8;
// output
output_instr16(instr);
break;
default:
// invalid opcode for oi-instruction
yyerror("opcode not compatible with i syntax");
break;
}
}

55
assembler/src/handle_om.c Normal file
View File

@@ -0,0 +1,55 @@
/*
* This file implements functions for
* - handling of instructions of type om
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width om instruction type
* opcode: opcode of instruction
* mode: mode of instruction
*/
void handle_om(op_t opcode, opmode_t mode) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_ret: // return instruction
// model with branch to lr
// opcode: branch
instr |= (0b1100) << 12;
// mode: to register and condition
switch (mode) {
case mode_cond_true: // if true
instr |= (0b0111) << 8;
break;
case mode_cond_unconditional: // always
instr |= (0b0110) << 8;
break;
default: // invalid mode for branch instruction
yyerror("mode invalid for ret instruction.");
}
// register a: LR
instr |= lr_num << 4;
// output instruction
output_instr16(instr);
// fill branch delay with nop if flag is set
if (fillbds) {
yyverbose("filled branch delay slot with nop.");
output_instr16(nop16);
}
break;
default: // invalid opcode for o-instruction
yyerror("opcode not compatible with om syntax");
break;
}
}

View File

@@ -0,0 +1,74 @@
/*
* This file implements functions for
* - handling of instructions of type omi
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width omi instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* imm: immediate
*/
void handle_omi(op_t opcode, opmode_t mode, int imm) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_br: // branch instruction to immediate
// opcode: bct
instr |= (0b1100) << 12;
// immediate: branch target
instr |= signed8(imm) << 0;
// mode: branch and (un)conditional to immediate
switch (mode) {
case mode_cond_true: // if true
instr |= (0b0101) << 8;
break;
case mode_cond_unconditional: // always
instr |= (0b0100) << 8;
break;
default: // invalid mode for branch instruction
yyerror("mode invalid for branch instruction.");
}
// output
output_instr16(instr);
// fill branch delay with nop if flag is set
if (fillbds) {
yyverbose("filled branch delay slot with nop.");
output_instr16(nop16);
}
break;
case op_call: // call instruction to immediate
// opcode: bct
instr |= (0b1100) << 12;
// immediate: call target
instr |= signed8(imm) << 0;
// mode: call (un)conditional to immediate
switch (mode) {
case mode_cond_true: // if true
instr |= (0b1001) << 8;
break;
case mode_cond_unconditional: // always
instr |= (0b1000) << 8;
break;
default: // invalid mode for branch instruction
yyerror("mode invalid for call instruction.");
}
// output
output_instr16(instr);
break;
default: // invalid opcode for omi-instruction
yyerror("opcode not compatible with mi syntax");
break;
}
}

100
assembler/src/handle_omr.c Normal file
View File

@@ -0,0 +1,100 @@
/*
* This file implements functions for
* - handling of instructions of type omr
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width omr instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* r1: register 1
*/
void handle_omr(op_t opcode, opmode_t mode, int r1) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_brt: // branch to table instruction
// opcode: branch to table
instr |= (0b1100) << 12;
// register a: branch target register
instr |= reg(r1) << 4;
// mode: branch to table (un)conditional to register
switch (mode) {
case mode_cond_true: // if true
instr |= (0b0011) << 8;
break;
case mode_cond_unconditional: // always
instr |= (0b0010) << 8;
break;
default: // invalid mode for branch to table instruction
yyerror("mode invalid for branch to table instruction.");
}
// output
output_instr16(instr);
// fill branch delay with nop if flag is set
if (fillbds) {
yyverbose("filled branch delay slot with nop.");
output_instr16(nop16);
}
break;
case op_br: // branch instruction to register
// opcode: bct
instr |= (0b1100) << 12;
// register a: branch target register
instr |= reg(r1) << 4;
// mode: branch to table (un)conditional to register
switch (mode) {
case mode_cond_true: // if true
instr |= (0b0111) << 8;
break;
case mode_cond_unconditional: // always
instr |= (0b0110) << 8;
break;
default: // invalid mode for branch instruction
yyerror("mode invalid for branch instruction.");
}
// output
output_instr16(instr);
// fill branch delay with nop if flag is set
if (fillbds) {
yyverbose("filled branch delay slot with nop.");
output_instr16(nop16);
}
break;
case op_call: // call instruction to register
// opcode: bct
instr |= (0b1100) << 12;
// register a: call target
instr |= reg(r1) << 4;
// mode: call (un)conditional to register
switch (mode) {
case mode_cond_true: // if true
instr |= (0b1011) << 8;
break;
case mode_cond_unconditional: // always
instr |= (0b1010) << 8;
break;
default: // invalid mode for call instruction
yyerror("mode invalid for call instruction.");
}
// output
output_instr16(instr);
break;
default: // invalid opcode for omr-instruction
yyerror("opcode not compatible with mr syntax");
break;
}
}

View File

@@ -0,0 +1,64 @@
/*
* This file implements functions for
* - handling of instructions of type omr2
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width omr2 instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* r1: register 1
* r2: register 2
*/
void handle_omr2(op_t opcode, opmode_t mode, int r1, int r2) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_cmp: // compare instruction
// opcode: compare
instr |= (0b1000) << 12;
// register a: first register
instr |= r1 << 4;
// register b: second register
instr |= r2 << 0;
// mode
switch (mode) {
case mode_eq: // equal
instr |= (0b0000) << 8;
break;
case mode_neq: // not equal
instr |= (0b1000) << 8;
break;
case mode_gg: // greater than
instr |= (0b0010) << 8;
break;
case mode_ge: // greater than or equal
instr |= (0b0001) << 8;
break;
case mode_ll: // less than
instr |= (0b1001) << 8;
break;
case mode_le: // less than or equal
instr |= (0b1010) << 8;
break;
default: // invalid mode for compare instruction
yyerror("mode invalid for call instruction.");
break;
}
// output
output_instr16(instr);
break;
default: // invalid opcode for omr2-instruction
yyerror("opcode not compatible with omr2 syntax");
break;
}
}

39
assembler/src/handle_or.c Normal file
View File

@@ -0,0 +1,39 @@
/*
* This file implements functions for
* - handling of instructions of type or
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width or instruction type
* opcode: opcode of instruction
* r1: register 1
*/
void handle_or(op_t opcode, int r1) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_clr: // clear register, model as xor r1, r1, r1
// opcode: cor
instr |= (0b0100) << 12;
// register d: register 1
instr |= reg(r1) << 8;
// register a: register 1
instr |= reg(r1) << 4;
// register b: register 1
instr |= reg(r1) << 0;
// output
output_instr16(instr);
break;
default: // invalid opcode for or-instruction
yyerror("opcode not compatible with or syntax");
break;
}
}

130
assembler/src/handle_or2.c Normal file
View File

@@ -0,0 +1,130 @@
/*
* This file implements functions for
* - handling of instructions of type or2
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width or2 instruction type
* opcode: opcode of instruction
* r1: register 1
* r2: register 2
*/
void handle_or2(op_t opcode, int r1, int r2) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_mov: // move instruction, model with or r1, r2, r2
// opcode: or
instr |= (0b0000) << 12;
// register d: register 1
instr |= reg(r1) << 8;
// register a: register 2
instr |= reg(r2) << 4;
// register b: register 2
instr |= reg(r2) << 0;
// output
output_instr16(instr);
break;
case op_ld08: // load byte instruction
// opcode: mem
instr |= (0b1011) << 12;
// mode: load byte
instr |= (0b0000) << 8;
// register a: register 1
instr |= reg(r1) << 4;
// register b: register 2
instr |= reg(r2) << 0;
// output
output_instr16(instr);
break;
case op_ld16: // load halfword
// opcode: mem
instr |= (0b1011) << 12;
// mode: load halfword
instr |= (0b0001) << 8;
// register a: register 1
instr |= reg(r1) << 4;
// register b: register 2
instr |= reg(r2) << 0;
// output
output_instr16(instr);
break;
case op_ld32: // load word
// opcode: mem
instr |= (0b1011) << 12;
// mode: load word
instr |= (0b0010) << 8;
// register a: register 1
instr |= reg(r1) << 4;
// register b: register 2
instr |= reg(r2) << 0;
// output
output_instr16(instr);
break;
case op_st08: // store byte
// opcode: mem
instr |= (0b1011) << 12;
// mode: store byte
instr |= (0b1000) << 8;
// register a: register 1
instr |= reg(r1) << 4;
// register b: register 2
instr |= reg(r2) << 0;
// output
output_instr16(instr);
break;
case op_st16: // store halfword
// opcode: mem
instr |= (0b1011) << 12;
// mode: store halfword
instr |= (0b1001) << 8;
// register a: register 1
instr |= reg(r1) << 4;
// register b: register 2
instr |= reg(r2) << 0;
// output
output_instr16(instr);
break;
case op_st32: // store word
// opcode: mem
instr |= (0b1011) << 12;
// mode: store word
instr |= (0b1010) << 8;
// register a: register 1
instr |= reg(r1) << 4;
// register b: register 2
instr |= reg(r2) << 0;
// output
output_instr16(instr);
break;
case op_tst: // test and set
// opcode: test and set instruction
instr |= (0b1001) << 12;
// register d: register 1
instr |= reg(r1) << 8;
// register a: register 2
instr |= reg(r2) << 4;
// output
output_instr16(instr);
break;
default: // invalid opcode for ri-instruction
yyerror("opcode not compatible with ri syntax");
break;
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file implements functions for
* - handling of instructions of type or2i
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width or2i instruction type
* opcode: opcode of instruction
* mode: mode of instruction
* r1: register 1
* r2: register 2
* imm: immediate
*/
void handle_or2i(op_t opcode, int r1, int r2, int imm) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_lsh: // left shift instruction
// immediate must not be 0
if (imm == 0)
yyerror("lsh with immediate=0 not allowed");
// opcode: left shift instruction
instr |= (0b0101) << 12;
// register d: register 1
instr |= reg(r1) << 8;
// register a: register 2
instr |= reg(r2) << 4;
// immediate: imm-1 (+1 in processor)
instr |= unsigned4(imm - 1) << 0;
// output
output_instr16(instr);
break;
case op_rsh: // right shift instruction
// immediate must not be zero
if (imm == 0)
yyerror("rsh with immediate=0 not allowed");
// opcode: right shift instruction
instr |= (0b0110) << 12;
// register d: register 1
instr |= reg(r1) << 8;
// register a: register 2
instr |= reg(r2) << 4;
// immediate: imm-1 (+1 in processor)
instr |= unsigned4(imm - 1) << 0;
// output
output_instr16(instr);
break;
default: // invalid opcode for or2i-instruction
yyerror("opcode not compatible with or2i syntax");
break;
}
}

View File

@@ -0,0 +1,74 @@
/*
* This file implements functions for
* - handling of instructions of type or3
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width or3 instruction type
* opcode: opcode of instruction
* r1: register 1
* r2: register 2
* r3: register 3
*/
void handle_or3(op_t opcode, int r1, int r2, int r3) {
// instruction to be build
int instr = 0;
// here, scheme is simple and always the same
// register d: register 1
instr |= r1 << 8;
// register a: register 2
instr |= r2 << 4;
// register b: register 3
instr |= r3 << 0;
// opcode
switch (opcode) {
case op_add: // add instruction
// opcode
instr |= (0b0011) << 12;
// output
output_instr16(instr);
break;
case op_sub: // subtract instruction
// opcode
instr |= (0b0001) << 12;
// output
output_instr16(instr);
break;
case op_and: // bitwise and instruction
// opcode
instr |= (0b0010) << 12;
// output
output_instr16(instr);
break;
case op_or: // bitwise or instruction
// opcode
instr |= (0b0000) << 12;
// output
output_instr16(instr);
break;
case op_xor: // bitwise xor instruction
// opcode
instr |= (0b0100) << 12;
// output
output_instr16(instr);
break;
default: // invalid opcode for or3-instruction
yyerror("opcode not compatible with or3 syntax");
break;
}
}

View File

@@ -0,0 +1,50 @@
/*
* This file implements functions for
* - handling of instructions of type oi
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/output.h"
#include "../inc/check.h"
#include "../inc/global.h"
/*
* outputs instruction to output for instructions width ori instruction type
* opcode: opcode of instruction
* r1: register 1
* imm: immediate
*/
void handle_ori(op_t opcode, int r1, int imm) {
// instruction to be build
int instr = 0;
switch (opcode) {
case op_addi: // add immediate instruction
// opcode: add immediate instruction
instr |= (0b0111) << 12;
// register d: register 1
instr |= reg(r1) << 8;
// immediate: value to add
instr |= signed8(imm) << 0;
// output
output_instr16(instr);
break;
case op_ldr: // load pc-relative instruction
// opcode: load pc-relative instruction
instr |= (0b1010) << 12;
// register d: register 1
instr |= reg(r1) << 8;
// immediate: pc-offset
instr |= signed8(imm) << 0;
// output
output_instr16(instr);
break;
default: // invalid opcode for ori-instruction
yyerror("opcode not compatible with ori syntax");
break;
}
}

175
assembler/src/label.c Normal file
View File

@@ -0,0 +1,175 @@
/*
* This file implements functions for
* - handling of labels
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../inc/msg.h"
#include "../inc/label.h"
#include "../inc/global.h"
/*
* adds a label to the list
* name: name of the label
* address: address the label points to
*/
void label_add(char* name, int address) {
// new element inserted
label_t* newelement;
// tail of list
label_t* tail;
// verbose message: added label (in second run)
if (verbose) {
char msg[64 + LABEL_MAX_NAME_LENGTH];
char tmpname[LABEL_MAX_NAME_LENGTH];
strncpy(tmpname, name, LABEL_MAX_NAME_LENGTH);
sprintf(msg, "adding label '%s' at address '0x%08x'.", tmpname,
address);
yyverbose(msg);
}
// don't add labels in second run
if (!isfirstrun) {
return;
}
// check if label already exists
if (label_absolute(name) != -1) {
yyerror("label already exists.");
return;
}
// allocate memory for new label
newelement = malloc(sizeof(label_t));
if (newelement == 0) {
fprintf(stderr, "no free memory.");
return;
}
// copy data to new label
strncpy(newelement->name, name, LABEL_MAX_NAME_LENGTH);
newelement->address = address;
newelement->next = 0;
// find tail of list
if (label_listhead == 0) {
// empty list, insert as list head
label_listhead = newelement;
} else {
// list not empty find tail
tail = label_listhead;
while (tail->next != 0) {
tail = tail->next;
}
// set next item pointer
tail->next = newelement;
}
// output information to map file
if (f_map) {
fprintf(f_map, "0x%x: %s\n", newelement->address, newelement->name);
}
}
/*
* returns absolute address of a label
* name: name of the label
* return: absolute address of label or -1 if label not found
*/
int label_absolute(char* name) {
// tail of search
label_t* tail;
if (label_listhead == 0) {
// if empty list, label is not in list, return -1
return -1;
} else {
// list not empty find tail
// start search at list head
tail = label_listhead;
while (1) {
if (strcmp(tail->name, name) == 0) {
// name of search tail matches searched name
// return address
return tail->address;
}
if (tail->next != 0) {
// end of list not reached, update tail pointer
tail = tail->next;
} else {
// end of list, not found
if (!isfirstrun) { // second run: label must be found.
yyerror("label not found.");
}
// return -1, as label is not found
return -1;
}
}
}
// program does not reach this point due to earlier returns
}
/*
* returns relative address of a label
* name: name of the label
* return: relative address of label or -1 if label not found
*/
int label_relative(char* name) {
// absolute address of label
int absolute;
// find absolute address
absolute = label_absolute(name);
if (absolute > 0) {
// label found, calculate relative address
return (absolute - address) / 2 - 1;
} else {
// label not found, error message already prompted in label_absolute
return -1;
}
}
/*
* frees the allocated space used for the list of labels
*/
void label_free() {
// current element pointer
label_t* ptr;
// next element pointer
label_t* next;
// start at list head
ptr = label_listhead;
while (ptr != 0) {
// walk through list until end of list reached
// store next pointer
next = ptr->next;
// delete current item
free(ptr);
// proceed in list
ptr = next;
}
// reset list head
label_listhead = 0;
}

232
assembler/src/main.c Normal file
View File

@@ -0,0 +1,232 @@
/*
* This file implements the main function
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include "../inc/msg.h"
#include "../inc/label.h"
#include "../inc/global.h"
#include "../inc/output.h"
#include "../obj/asm.tab.h"
// reference to linenumber supplied by flex/bison
extern int yylineno;
// reference to yyrestart function supplied by flex/bison
void yyrestart(FILE* inputfile);
// file variable definitions and initialization
FILE* f_in = 0;
FILE* f_out = 0;
FILE* f_map = 0;
/*
* main function
* argc: number of arguments
* argv: arguments
*/
int main(int argc, char **argv) {
// output filename
char* output = 0;
// mapfile filename
char* map = 0;
// index of command line argument
int option_index = 0;
// character of command line argument
int c;
static struct option long_options[] = { { "verbose", 0, 0, 0 }, {
"autoalign", 0, 0, 0 }, { "fillbds", 0, 0, 0 }, {
"continue-on-error", 0, 0, 0 }, { 0, 0, 0, 0 } };
// reset flags
verbose = 0;
autoalign = 0;
continueonerror = 0;
errorhappened = 0;
while (1) {
// iterate through all command line options
// reset option_index
option_index = 0;
// get next option
c = getopt_long(argc, argv, "vm:o:", long_options, &option_index);
if (c == -1)
// no more options available, end loop
break;
// check which option it was
switch (c) {
case 0: // long option
if (strcmp(long_options[option_index].name, "verbose") == 0) {
// verbose flag
verbose = 1;
} else if (strcmp(long_options[option_index].name, "autoalign")
== 0) {
// auto-align flag
autoalign = 1;
} else if (strcmp(long_options[option_index].name, "fillbds")
== 0) {
// fill branch delay slot flag
fillbds = 1;
} else if (strcmp(long_options[option_index].name,
"continue-on-error") == 0) {
// continue on error flag
continueonerror = 1;
} else {
// unknown option
fprintf(stderr, "error: unknown command line option \"%s\"\n",
long_options[option_index].name);
destruct(EXIT_FAILURE);
}
break;
case 'v':
// verbose flag (short version)
verbose = 1;
break;
case 'm':
// map file
map = (char*) optarg;
break;
case 'o':
// output file
output = (char*) optarg;
break;
default:
// unknown option
fprintf(stderr, "error: unknown command line option \"%s\"\n",
long_options[option_index].name);
destruct(EXIT_FAILURE);
}
}
// Check non-option command line arguments
if (optind < argc) {
// one option still available (input)
inputfile = argv[optind++];
if (optind < argc) {
// more than one option still available, only one input file supported
fprintf(stderr, "too many input files specified.\n");
destruct(EXIT_FAILURE);
}
} else {
// no option available (no input file)
fprintf(stderr, "no input file specified.\n");
destruct(EXIT_FAILURE);
}
// Check if output file is specified
if (output == 0) {
// output file not specified
fprintf(stderr, "no output file specified.\n");
destruct(EXIT_FAILURE);
}
// Open all (specified) files
// open input file (must be specified, is checked before)
f_in = fopen(inputfile, "r");
if (!f_in) {
// could not open input file
fprintf(stderr, "error: could not open input file %s\n", inputfile);
perror(inputfile);
destruct(EXIT_FAILURE);
}
// open output file (must be specified, is checked before)
f_out = fopen(output, "w");
if (!f_out) {
// could not open output file
fprintf(stderr, "error: could not open output file %s\n", output);
perror(output);
destruct(EXIT_FAILURE);
}
// open map file if specified
if (map != 0) {
// mapfile is specified
f_map = fopen(map, "w");
if (!f_map) {
// could not open mapfile
fprintf(stderr, "error: could not open map file %s\n", map);
perror(map);
destruct(EXIT_FAILURE);
}
}
// reset variables
address = 0;
label_listhead = 0;
// start parsing f_in - first run
isfirstrun = 1;
yyrestart(f_in);
yyparse();
// go back to first character in input file
fseek(f_in, 0, SEEK_SET);
yylineno = 1;
// start parsing f_in - second run
address = 0;
isfirstrun = 0;
yyrestart(f_in);
yyparse();
// fill last word
if (address % 4 == 2) {
output_instr16(nop16);
}
// destruction
// final message
if (verbose) {
printf("%s: : info: output written to %s.\n", inputfile, output);
}
// exit main
if (!errorhappened) {
// no error happened
destruct(EXIT_SUCCESS);
} else {
// error happend in between
destruct(EXIT_FAILURE);
}
return 0; // suppress warning, actual program exit in destruct
}
// destructor, closes programs and cleans up memory
// exitvalue: value for exit
void destruct(int exitvalue) {
if (f_in) {
fclose(f_in);
}
if (f_out) {
fclose(f_out);
}
if (f_map) {
fclose(f_map);
}
label_free();
exit(exitvalue);
}

47
assembler/src/msg.c Normal file
View File

@@ -0,0 +1,47 @@
/*
* This file implements functions for
* - checking instruction parameters for range
*/
#include <stdlib.h>
#include <stdio.h>
#include "../inc/global.h"
// reference to linenumber supplied by flex
extern int yylineno;
/*
* verbose output (if flag is set)
* msg: verbose message
*/
void yyverbose(char* msg) {
if (verbose) {
// if verbose flag is set
if (!isfirstrun) {
// output verbose messages in second run
printf("%s:% 3i: info: %s (\"%s\")\n", inputfile, yylineno, msg,
linebuf);
}
}
}
/*
* error handler
* msg: error message
*/
void yyerror(char *s) {
if ((!continueonerror) || (!isfirstrun)) {
// output error messages if either stop at error or in second run
fprintf(stderr, "%s:% 3i: error: %s (\"%s\")\n", inputfile, yylineno, s,
linebuf);
}
// set error happened flag
errorhappened = 1;
if (!continueonerror) {
// if stop on error, stop
destruct(EXIT_FAILURE);
}
}

105
assembler/src/output.c Normal file
View File

@@ -0,0 +1,105 @@
/*
* This file implements functions for
* - writing to output file
* - writing to map file
*/
#include <stdio.h>
#include "../inc/msg.h"
#include "../inc/global.h"
/*
* outputs a number of length bits, given in instr to the output stream and inserts a linebreak after each 32bit
* instr: number to be printed
* length: number of bits to be printed
*/
void output_instr(int instr, int length) {
// index of outputted bit
int i;
for (i=length-1; i>=0; i--) {
// iterate through length bits
if(instr & (1<<i)) {
// if bit is 1 output '1'
fprintf(f_out, "1");
} else {
// if bit is 0 output '0'
fprintf(f_out, "0");
}
}
}
/*
* outputs a number of 16bits and updates address
* instr: number to be printed
*/
void output_instr16(int instr) {
if ((instr & 0xFFFF) == instr) {
// instruction fits into 16 bits
if (!isfirstrun) {
// in second run, output instruction
output_instr(instr, 16);
}
// increment address
address += 2;
// add line break
if ((!isfirstrun) && ((address % 4) == 0)) {
// not in first run and word is filled
fprintf(f_out, "\n");
}
} else {
// instruction does not fit into 16 bit
yyerror("internal error. 16bit instruction did not fit");
}
}
/*
* outputs a number of 32bits and updates address
* instr: number to be printed
*/
void output_instr32(int instr) {
if ((instr & 0xFFFFFFFF) == instr) {
// instruction fits into 32bits
if ((address % 4) != 0) {
// address not aligned
if (autoalign) {
// auto-align flag set
output_instr16(nop16);
} else {
// auto-align flag not set, output error
yyerror("32bit instruction not aligned.");
return;
}
}
// increment address
address += 4;
if (!isfirstrun) {
// in second run, output instruction
output_instr(instr, 32);
fprintf(f_out, "\n");
}
} else {
// instruction does not fit into 32bits
yyerror("internal error. 32bit instruction did not fit");
}
}
/*
* outputs a line to the mapfile (if specified and if in first run)
* s: string to be put to mapfile
*/
void output_line(char* s) {
if (isfirstrun && f_map) {
// if in first run and mapfile is specified
fprintf(f_map, "\t%s\n", s);
}
}