Initial Commit
This commit is contained in:
104
assembler/Makefile
Normal file
104
assembler/Makefile
Normal 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
33
assembler/inc/check.h
Normal 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
85
assembler/inc/global.h
Normal 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
99
assembler/inc/handle.h
Normal 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
51
assembler/inc/label.h
Normal 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
21
assembler/inc/msg.h
Normal 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
36
assembler/inc/output.h
Normal 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
105
assembler/src/asm.l
Normal 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
59
assembler/src/asm.y
Normal 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
70
assembler/src/check.c
Normal 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
72
assembler/src/handle_o.c
Normal 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
90
assembler/src/handle_oi.c
Normal 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
55
assembler/src/handle_om.c
Normal 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;
|
||||
}
|
||||
}
|
||||
74
assembler/src/handle_omi.c
Normal file
74
assembler/src/handle_omi.c
Normal 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
100
assembler/src/handle_omr.c
Normal 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;
|
||||
}
|
||||
}
|
||||
64
assembler/src/handle_omr2.c
Normal file
64
assembler/src/handle_omr2.c
Normal 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
39
assembler/src/handle_or.c
Normal 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
130
assembler/src/handle_or2.c
Normal 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;
|
||||
}
|
||||
}
|
||||
63
assembler/src/handle_or2i.c
Normal file
63
assembler/src/handle_or2i.c
Normal 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;
|
||||
}
|
||||
}
|
||||
74
assembler/src/handle_or3.c
Normal file
74
assembler/src/handle_or3.c
Normal 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;
|
||||
}
|
||||
}
|
||||
50
assembler/src/handle_ori.c
Normal file
50
assembler/src/handle_ori.c
Normal 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
175
assembler/src/label.c
Normal 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
232
assembler/src/main.c
Normal 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
47
assembler/src/msg.c
Normal 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
105
assembler/src/output.c
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user